llvm-build: Add --write-llvmbuild option, which writes out the component tree.
[oota-llvm.git] / utils / llvm-build / llvmbuild / componentinfo.py
1 """
2 Descriptor objects for entities that are part of the LLVM project.
3 """
4
5 import ConfigParser
6 import StringIO
7 import sys
8
9 from util import *
10
11 class ParseError(Exception):
12     pass
13
14 class ComponentInfo(object):
15     """
16     Base class for component descriptions.
17     """
18
19     type_name = None
20
21     @staticmethod
22     def parse_items(items, has_dependencies = True):
23         kwargs = {}
24         kwargs['name'] = items.get_string('name')
25         kwargs['parent'] = items.get_optional_string('parent')
26         if has_dependencies:
27             kwargs['dependencies'] = items.get_list('dependencies')
28         return kwargs
29
30     def __init__(self, subpath, name, dependencies, parent):
31         if not subpath.startswith('/'):
32             raise ValueError,"invalid subpath: %r" % subpath
33         self.subpath = subpath
34         self.name = name
35         self.dependencies = list(dependencies)
36
37         # The name of the parent component to logically group this component
38         # under.
39         self.parent = parent
40
41         # The parent instance, once loaded.
42         self.parent_instance = None
43         self.children = []
44
45     def set_parent_instance(self, parent):
46         assert parent.name == self.parent, "Unexpected parent!"
47         self.parent_instance = parent
48         self.parent_instance.children.append(self)
49
50     def get_component_references(self):
51         """get_component_references() -> iter
52
53         Return an iterator over the named references to other components from
54         this object. Items are of the form (reference-type, component-name).
55         """
56
57         # Parent references are handled specially.
58         for r in self.dependencies:
59             yield ('dependency', r)
60
61     def get_llvmbuild_fragment(self):
62         abstract
63
64 class GroupComponentInfo(ComponentInfo):
65     """
66     Group components have no semantics as far as the build system are concerned,
67     but exist to help organize other components into a logical tree structure.
68     """
69
70     type_name = 'Group'
71
72     @staticmethod
73     def parse(subpath, items):
74         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
75         return GroupComponentInfo(subpath, **kwargs)
76
77     def __init__(self, subpath, name, parent):
78         ComponentInfo.__init__(self, subpath, name, [], parent)
79
80     def get_llvmbuild_fragment(self):
81         result = StringIO.StringIO()
82         print >>result, 'type = %s' % self.type_name
83         print >>result, 'name = %s' % self.name
84         print >>result, 'parent = %s' % self.parent
85         return result.getvalue()
86
87 class LibraryComponentInfo(ComponentInfo):
88     type_name = 'Library'
89
90     @staticmethod
91     def parse(subpath, items):
92         kwargs = ComponentInfo.parse_items(items)
93         kwargs['library_name'] = items.get_optional_string('library_name')
94         kwargs['required_libraries'] = items.get_list('required_libraries')
95         kwargs['add_to_library_groups'] = items.get_list(
96             'add_to_library_groups')
97         return LibraryComponentInfo(subpath, **kwargs)
98
99     def __init__(self, subpath, name, dependencies, parent, library_name,
100                  required_libraries, add_to_library_groups):
101         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
102
103         # If given, the name to use for the library instead of deriving it from
104         # the component name.
105         self.library_name = library_name
106
107         # The names of the library components which are required when linking
108         # with this component.
109         self.required_libraries = list(required_libraries)
110
111         # The names of the library group components this component should be
112         # considered part of.
113         self.add_to_library_groups = list(add_to_library_groups)
114
115     def get_component_references(self):
116         for r in ComponentInfo.get_component_references(self):
117             yield r
118         for r in self.required_libraries:
119             yield ('required library', r)
120         for r in self.add_to_library_groups:
121             yield ('library group', r)
122
123     def get_llvmbuild_fragment(self):
124         result = StringIO.StringIO()
125         print >>result, 'type = %s' % self.type_name
126         print >>result, 'name = %s' % self.name
127         print >>result, 'parent = %s' % self.parent
128         if self.library_name is not None:
129             print >>result, 'library_name = %s' % self.library_name
130         if self.required_libraries:
131             print >>result, 'required_libraries = %s' % ' '.join(
132                 self.required_libraries)
133         if self.add_to_library_groups:
134             print >>result, 'add_to_library_groups = %s' % ' '.join(
135                 self.add_to_library_groups)
136         return result.getvalue()
137
138 class LibraryGroupComponentInfo(ComponentInfo):
139     type_name = 'LibraryGroup'
140
141     @staticmethod
142     def parse(subpath, items):
143         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
144         kwargs['required_libraries'] = items.get_list('required_libraries')
145         kwargs['add_to_library_groups'] = items.get_list(
146             'add_to_library_groups')
147         return LibraryGroupComponentInfo(subpath, **kwargs)
148
149     def __init__(self, subpath, name, parent, required_libraries = [],
150                  add_to_library_groups = []):
151         ComponentInfo.__init__(self, subpath, name, [], parent)
152
153         # The names of the library components which are required when linking
154         # with this component.
155         self.required_libraries = list(required_libraries)
156
157         # The names of the library group components this component should be
158         # considered part of.
159         self.add_to_library_groups = list(add_to_library_groups)
160
161     def get_component_references(self):
162         for r in ComponentInfo.get_component_references(self):
163             yield r
164         for r in self.required_libraries:
165             yield ('required library', r)
166         for r in self.add_to_library_groups:
167             yield ('library group', r)
168
169     def get_llvmbuild_fragment(self):
170         result = StringIO.StringIO()
171         print >>result, 'type = %s' % self.type_name
172         print >>result, 'name = %s' % self.name
173         print >>result, 'parent = %s' % self.parent
174         if self.required_libraries:
175             print >>result, 'required_libraries = %s' % ' '.join(
176                 self.required_libraries)
177         if self.add_to_library_groups:
178             print >>result, 'add_to_library_groups = %s' % ' '.join(
179                 self.add_to_library_groups)
180         return result.getvalue()
181
182 class ToolComponentInfo(ComponentInfo):
183     type_name = 'Tool'
184
185     @staticmethod
186     def parse(subpath, items):
187         kwargs = ComponentInfo.parse_items(items)
188         kwargs['required_libraries'] = items.get_list('required_libraries')
189         return ToolComponentInfo(subpath, **kwargs)
190
191     def __init__(self, subpath, name, dependencies, parent,
192                  required_libraries):
193         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
194
195         # The names of the library components which are required to link this
196         # tool.
197         self.required_libraries = list(required_libraries)
198
199     def get_component_references(self):
200         for r in ComponentInfo.get_component_references(self):
201             yield r
202         for r in self.required_libraries:
203             yield ('required library', r)
204
205     def get_llvmbuild_fragment(self):
206         result = StringIO.StringIO()
207         print >>result, 'type = %s' % self.type_name
208         print >>result, 'name = %s' % self.name
209         print >>result, 'parent = %s' % self.parent
210         print >>result, 'required_libraries = %s' % ' '.join(
211             self.required_libraries)
212         return result.getvalue()
213
214 class BuildToolComponentInfo(ToolComponentInfo):
215     type_name = 'BuildTool'
216
217     @staticmethod
218     def parse(subpath, items):
219         kwargs = ComponentInfo.parse_items(items)
220         kwargs['required_libraries'] = items.get_list('required_libraries')
221         return BuildToolComponentInfo(subpath, **kwargs)
222
223 ###
224
225 class IniFormatParser(dict):
226     def get_list(self, key):
227         # Check if the value is defined.
228         value = self.get(key)
229         if value is None:
230             return []
231
232         # Lists are just whitespace separated strings.
233         return value.split()
234
235     def get_optional_string(self, key):
236         value = self.get_list(key)
237         if not value:
238             return None
239         if len(value) > 1:
240             raise ParseError("multiple values for scalar key: %r" % key)
241         return value[0]
242
243     def get_string(self, key):
244         value = self.get_optional_string(key)
245         if not value:
246             raise ParseError("missing value for required string: %r" % key)
247         return value
248
249 _component_type_map = dict(
250     (t.type_name, t)
251     for t in (GroupComponentInfo,
252               LibraryComponentInfo, LibraryGroupComponentInfo,
253               ToolComponentInfo, BuildToolComponentInfo))
254 def load_from_path(path, subpath):
255     # Load the LLVMBuild.txt file as an .ini format file.
256     parser = ConfigParser.RawConfigParser()
257     parser.read(path)
258
259     # We load each section which starts with 'component' as a distinct component
260     # description (so multiple components can be described in one file).
261     for section in parser.sections():
262         if not section.startswith('component'):
263             # We don't expect arbitrary sections currently, warn the user.
264             warning("ignoring unknown section %r in %r" % (section, path))
265             continue
266
267         # Determine the type of the component to instantiate.
268         if not parser.has_option(section, 'type'):
269             fatal("invalid component %r in %r: %s" % (
270                     section, path, "no component type"))
271
272         type_name = parser.get(section, 'type')
273         type_class = _component_type_map.get(type_name)
274         if type_class is None:
275             fatal("invalid component %r in %r: %s" % (
276                     section, path, "invalid component type: %r" % type_name))
277
278         # Instantiate the component based on the remaining values.
279         try:
280             info = type_class.parse(subpath,
281                                     IniFormatParser(parser.items(section)))
282         except TypeError:
283             print >>sys.stderr, "error: invalid component %r in %r: %s" % (
284                 section, path, "unable to instantiate: %r" % type_name)
285             import traceback
286             traceback.print_exc()
287             raise SystemExit, 1
288         except ParseError,e:
289             fatal("unable to load component %r in %r: %s" % (
290                     section, path, e.message))
291
292         yield info