LLVMBuild: Add explicit information on whether targets define an assembly printer...
[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     def get_library_name(self):
139         return self.library_name or self.name
140
141     def get_llvmconfig_component_name(self):
142         return self.get_library_name().lower()
143
144 class LibraryGroupComponentInfo(ComponentInfo):
145     type_name = 'LibraryGroup'
146
147     @staticmethod
148     def parse(subpath, items):
149         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
150         kwargs['required_libraries'] = items.get_list('required_libraries')
151         kwargs['add_to_library_groups'] = items.get_list(
152             'add_to_library_groups')
153         return LibraryGroupComponentInfo(subpath, **kwargs)
154
155     def __init__(self, subpath, name, parent, required_libraries = [],
156                  add_to_library_groups = []):
157         ComponentInfo.__init__(self, subpath, name, [], parent)
158
159         # The names of the library components which are required when linking
160         # with this component.
161         self.required_libraries = list(required_libraries)
162
163         # The names of the library group components this component should be
164         # considered part of.
165         self.add_to_library_groups = list(add_to_library_groups)
166
167     def get_component_references(self):
168         for r in ComponentInfo.get_component_references(self):
169             yield r
170         for r in self.required_libraries:
171             yield ('required library', r)
172         for r in self.add_to_library_groups:
173             yield ('library group', r)
174
175     def get_llvmbuild_fragment(self):
176         result = StringIO.StringIO()
177         print >>result, 'type = %s' % self.type_name
178         print >>result, 'name = %s' % self.name
179         print >>result, 'parent = %s' % self.parent
180         if self.required_libraries:
181             print >>result, 'required_libraries = %s' % ' '.join(
182                 self.required_libraries)
183         if self.add_to_library_groups:
184             print >>result, 'add_to_library_groups = %s' % ' '.join(
185                 self.add_to_library_groups)
186         return result.getvalue()
187
188     def get_llvmconfig_component_name(self):
189         return self.name.lower()
190
191 class TargetGroupComponentInfo(ComponentInfo):
192     type_name = 'TargetGroup'
193
194     @staticmethod
195     def parse(subpath, items):
196         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
197         kwargs['required_libraries'] = items.get_list('required_libraries')
198         kwargs['add_to_library_groups'] = items.get_list(
199             'add_to_library_groups')
200         kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
201         kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
202                                                            False)
203         kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
204                                                           False)
205         kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
206                                                              False)
207         return TargetGroupComponentInfo(subpath, **kwargs)
208
209     def __init__(self, subpath, name, parent, required_libraries = [],
210                  add_to_library_groups = [], has_jit = False,
211                  has_asmprinter = False, has_asmparser = False,
212                  has_disassembler = False):
213         ComponentInfo.__init__(self, subpath, name, [], parent)
214
215         # The names of the library components which are required when linking
216         # with this component.
217         self.required_libraries = list(required_libraries)
218
219         # The names of the library group components this component should be
220         # considered part of.
221         self.add_to_library_groups = list(add_to_library_groups)
222
223         # Whether or not this target supports the JIT.
224         self.has_jit = bool(has_jit)
225
226         # Whether or not this target defines an assembly printer.
227         self.has_asmprinter = bool(has_asmprinter)
228
229         # Whether or not this target defines an assembly parser.
230         self.has_asmparser = bool(has_asmparser)
231
232         # Whether or not this target defines an disassembler.
233         self.has_disassembler = bool(has_disassembler)
234
235         # Whether or not this target is enabled. This is set in response to
236         # configuration parameters.
237         self.enabled = False
238
239     def get_component_references(self):
240         for r in ComponentInfo.get_component_references(self):
241             yield r
242         for r in self.required_libraries:
243             yield ('required library', r)
244         for r in self.add_to_library_groups:
245             yield ('library group', r)
246
247     def get_llvmbuild_fragment(self):
248         result = StringIO.StringIO()
249         print >>result, 'type = %s' % self.type_name
250         print >>result, 'name = %s' % self.name
251         print >>result, 'parent = %s' % self.parent
252         if self.required_libraries:
253             print >>result, 'required_libraries = %s' % ' '.join(
254                 self.required_libraries)
255         if self.add_to_library_groups:
256             print >>result, 'add_to_library_groups = %s' % ' '.join(
257                 self.add_to_library_groups)
258         for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
259                          'has_jit'):
260             if getattr(self, bool_key):
261                 print >>result, '%s = 1' % (bool_key,)
262         return result.getvalue()
263
264     def get_llvmconfig_component_name(self):
265         return self.name.lower()
266
267 class ToolComponentInfo(ComponentInfo):
268     type_name = 'Tool'
269
270     @staticmethod
271     def parse(subpath, items):
272         kwargs = ComponentInfo.parse_items(items)
273         kwargs['required_libraries'] = items.get_list('required_libraries')
274         return ToolComponentInfo(subpath, **kwargs)
275
276     def __init__(self, subpath, name, dependencies, parent,
277                  required_libraries):
278         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
279
280         # The names of the library components which are required to link this
281         # tool.
282         self.required_libraries = list(required_libraries)
283
284     def get_component_references(self):
285         for r in ComponentInfo.get_component_references(self):
286             yield r
287         for r in self.required_libraries:
288             yield ('required library', r)
289
290     def get_llvmbuild_fragment(self):
291         result = StringIO.StringIO()
292         print >>result, 'type = %s' % self.type_name
293         print >>result, 'name = %s' % self.name
294         print >>result, 'parent = %s' % self.parent
295         print >>result, 'required_libraries = %s' % ' '.join(
296             self.required_libraries)
297         return result.getvalue()
298
299 class BuildToolComponentInfo(ToolComponentInfo):
300     type_name = 'BuildTool'
301
302     @staticmethod
303     def parse(subpath, items):
304         kwargs = ComponentInfo.parse_items(items)
305         kwargs['required_libraries'] = items.get_list('required_libraries')
306         return BuildToolComponentInfo(subpath, **kwargs)
307
308 ###
309
310 class IniFormatParser(dict):
311     def get_list(self, key):
312         # Check if the value is defined.
313         value = self.get(key)
314         if value is None:
315             return []
316
317         # Lists are just whitespace separated strings.
318         return value.split()
319
320     def get_optional_string(self, key):
321         value = self.get_list(key)
322         if not value:
323             return None
324         if len(value) > 1:
325             raise ParseError("multiple values for scalar key: %r" % key)
326         return value[0]
327
328     def get_string(self, key):
329         value = self.get_optional_string(key)
330         if not value:
331             raise ParseError("missing value for required string: %r" % key)
332         return value
333
334     def get_optional_bool(self, key, default = None):
335         value = self.get_optional_string(key)
336         if not value:
337             return default
338         if value not in ('0', '1'):
339             raise ParseError("invalid value(%r) for boolean property: %r" % (
340                     value, key))
341         return bool(int(value))
342
343     def get_bool(self, key):
344         value = self.get_optional_bool(key)
345         if value is None:
346             raise ParseError("missing value for required boolean: %r" % key)
347         return value
348
349 _component_type_map = dict(
350     (t.type_name, t)
351     for t in (GroupComponentInfo,
352               LibraryComponentInfo, LibraryGroupComponentInfo,
353               ToolComponentInfo, BuildToolComponentInfo,
354               TargetGroupComponentInfo))
355 def load_from_path(path, subpath):
356     # Load the LLVMBuild.txt file as an .ini format file.
357     parser = ConfigParser.RawConfigParser()
358     parser.read(path)
359
360     # We load each section which starts with 'component' as a distinct component
361     # description (so multiple components can be described in one file).
362     for section in parser.sections():
363         if not section.startswith('component'):
364             # We don't expect arbitrary sections currently, warn the user.
365             warning("ignoring unknown section %r in %r" % (section, path))
366             continue
367
368         # Determine the type of the component to instantiate.
369         if not parser.has_option(section, 'type'):
370             fatal("invalid component %r in %r: %s" % (
371                     section, path, "no component type"))
372
373         type_name = parser.get(section, 'type')
374         type_class = _component_type_map.get(type_name)
375         if type_class is None:
376             fatal("invalid component %r in %r: %s" % (
377                     section, path, "invalid component type: %r" % type_name))
378
379         # Instantiate the component based on the remaining values.
380         try:
381             info = type_class.parse(subpath,
382                                     IniFormatParser(parser.items(section)))
383         except TypeError:
384             print >>sys.stderr, "error: invalid component %r in %r: %s" % (
385                 section, path, "unable to instantiate: %r" % type_name)
386             import traceback
387             traceback.print_exc()
388             raise SystemExit, 1
389         except ParseError,e:
390             fatal("unable to load component %r in %r: %s" % (
391                     section, path, e.message))
392
393         yield info