230ae219f2f218adcc28fd05da4d8c61f67e30a3
[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         # The original source path.
46         self._source_path = None
47
48         # A flag to mark "special" components which have some amount of magic
49         # handling (generally based on command line options).
50         self._is_special_group = False
51
52     def set_parent_instance(self, parent):
53         assert parent.name == self.parent, "Unexpected parent!"
54         self.parent_instance = parent
55         self.parent_instance.children.append(self)
56
57     def get_component_references(self):
58         """get_component_references() -> iter
59
60         Return an iterator over the named references to other components from
61         this object. Items are of the form (reference-type, component-name).
62         """
63
64         # Parent references are handled specially.
65         for r in self.dependencies:
66             yield ('dependency', r)
67
68     def get_llvmbuild_fragment(self):
69         abstract
70
71 class GroupComponentInfo(ComponentInfo):
72     """
73     Group components have no semantics as far as the build system are concerned,
74     but exist to help organize other components into a logical tree structure.
75     """
76
77     type_name = 'Group'
78
79     @staticmethod
80     def parse(subpath, items):
81         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
82         return GroupComponentInfo(subpath, **kwargs)
83
84     def __init__(self, subpath, name, parent):
85         ComponentInfo.__init__(self, subpath, name, [], parent)
86
87     def get_llvmbuild_fragment(self):
88         result = StringIO.StringIO()
89         print >>result, 'type = %s' % self.type_name
90         print >>result, 'name = %s' % self.name
91         print >>result, 'parent = %s' % self.parent
92         return result.getvalue()
93
94 class LibraryComponentInfo(ComponentInfo):
95     type_name = 'Library'
96
97     @staticmethod
98     def parse(subpath, items):
99         kwargs = ComponentInfo.parse_items(items)
100         kwargs['library_name'] = items.get_optional_string('library_name')
101         kwargs['required_libraries'] = items.get_list('required_libraries')
102         kwargs['add_to_library_groups'] = items.get_list(
103             'add_to_library_groups')
104         return LibraryComponentInfo(subpath, **kwargs)
105
106     def __init__(self, subpath, name, dependencies, parent, library_name,
107                  required_libraries, add_to_library_groups):
108         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
109
110         # If given, the name to use for the library instead of deriving it from
111         # the component name.
112         self.library_name = library_name
113
114         # The names of the library components which are required when linking
115         # with this component.
116         self.required_libraries = list(required_libraries)
117
118         # The names of the library group components this component should be
119         # considered part of.
120         self.add_to_library_groups = list(add_to_library_groups)
121
122     def get_component_references(self):
123         for r in ComponentInfo.get_component_references(self):
124             yield r
125         for r in self.required_libraries:
126             yield ('required library', r)
127         for r in self.add_to_library_groups:
128             yield ('library group', r)
129
130     def get_llvmbuild_fragment(self):
131         result = StringIO.StringIO()
132         print >>result, 'type = %s' % self.type_name
133         print >>result, 'name = %s' % self.name
134         print >>result, 'parent = %s' % self.parent
135         if self.library_name is not None:
136             print >>result, 'library_name = %s' % self.library_name
137         if self.required_libraries:
138             print >>result, 'required_libraries = %s' % ' '.join(
139                 self.required_libraries)
140         if self.add_to_library_groups:
141             print >>result, 'add_to_library_groups = %s' % ' '.join(
142                 self.add_to_library_groups)
143         return result.getvalue()
144
145     def get_library_name(self):
146         return self.library_name or self.name
147
148     def get_prefixed_library_name(self):
149         """
150         get_prefixed_library_name() -> str
151
152         Return the library name prefixed by the project name. This is generally
153         what the library name will be on disk.
154         """
155
156         basename = self.get_library_name()
157
158         # FIXME: We need to get the prefix information from an explicit project
159         # object, or something.
160         if basename in ('gtest', 'gtest_main'):
161             return basename
162
163         return 'LLVM%s' % basename
164
165     def get_llvmconfig_component_name(self):
166         return self.get_library_name().lower()
167
168 class LibraryGroupComponentInfo(ComponentInfo):
169     type_name = 'LibraryGroup'
170
171     @staticmethod
172     def parse(subpath, items):
173         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
174         kwargs['required_libraries'] = items.get_list('required_libraries')
175         kwargs['add_to_library_groups'] = items.get_list(
176             'add_to_library_groups')
177         return LibraryGroupComponentInfo(subpath, **kwargs)
178
179     def __init__(self, subpath, name, parent, required_libraries = [],
180                  add_to_library_groups = []):
181         ComponentInfo.__init__(self, subpath, name, [], parent)
182
183         # The names of the library components which are required when linking
184         # with this component.
185         self.required_libraries = list(required_libraries)
186
187         # The names of the library group components this component should be
188         # considered part of.
189         self.add_to_library_groups = list(add_to_library_groups)
190
191     def get_component_references(self):
192         for r in ComponentInfo.get_component_references(self):
193             yield r
194         for r in self.required_libraries:
195             yield ('required library', r)
196         for r in self.add_to_library_groups:
197             yield ('library group', r)
198
199     def get_llvmbuild_fragment(self):
200         result = StringIO.StringIO()
201         print >>result, 'type = %s' % self.type_name
202         print >>result, 'name = %s' % self.name
203         print >>result, 'parent = %s' % self.parent
204         if self.required_libraries and not self._is_special_group:
205             print >>result, 'required_libraries = %s' % ' '.join(
206                 self.required_libraries)
207         if self.add_to_library_groups:
208             print >>result, 'add_to_library_groups = %s' % ' '.join(
209                 self.add_to_library_groups)
210         return result.getvalue()
211
212     def get_llvmconfig_component_name(self):
213         return self.name.lower()
214
215 class TargetGroupComponentInfo(ComponentInfo):
216     type_name = 'TargetGroup'
217
218     @staticmethod
219     def parse(subpath, items):
220         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
221         kwargs['required_libraries'] = items.get_list('required_libraries')
222         kwargs['add_to_library_groups'] = items.get_list(
223             'add_to_library_groups')
224         kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
225         kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
226                                                            False)
227         kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
228                                                           False)
229         kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
230                                                              False)
231         return TargetGroupComponentInfo(subpath, **kwargs)
232
233     def __init__(self, subpath, name, parent, required_libraries = [],
234                  add_to_library_groups = [], has_jit = False,
235                  has_asmprinter = False, has_asmparser = False,
236                  has_disassembler = False):
237         ComponentInfo.__init__(self, subpath, name, [], parent)
238
239         # The names of the library components which are required when linking
240         # with this component.
241         self.required_libraries = list(required_libraries)
242
243         # The names of the library group components this component should be
244         # considered part of.
245         self.add_to_library_groups = list(add_to_library_groups)
246
247         # Whether or not this target supports the JIT.
248         self.has_jit = bool(has_jit)
249
250         # Whether or not this target defines an assembly printer.
251         self.has_asmprinter = bool(has_asmprinter)
252
253         # Whether or not this target defines an assembly parser.
254         self.has_asmparser = bool(has_asmparser)
255
256         # Whether or not this target defines an disassembler.
257         self.has_disassembler = bool(has_disassembler)
258
259         # Whether or not this target is enabled. This is set in response to
260         # configuration parameters.
261         self.enabled = False
262
263     def get_component_references(self):
264         for r in ComponentInfo.get_component_references(self):
265             yield r
266         for r in self.required_libraries:
267             yield ('required library', r)
268         for r in self.add_to_library_groups:
269             yield ('library group', r)
270
271     def get_llvmbuild_fragment(self):
272         result = StringIO.StringIO()
273         print >>result, 'type = %s' % self.type_name
274         print >>result, 'name = %s' % self.name
275         print >>result, 'parent = %s' % self.parent
276         if self.required_libraries:
277             print >>result, 'required_libraries = %s' % ' '.join(
278                 self.required_libraries)
279         if self.add_to_library_groups:
280             print >>result, 'add_to_library_groups = %s' % ' '.join(
281                 self.add_to_library_groups)
282         for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
283                          'has_jit'):
284             if getattr(self, bool_key):
285                 print >>result, '%s = 1' % (bool_key,)
286         return result.getvalue()
287
288     def get_llvmconfig_component_name(self):
289         return self.name.lower()
290
291 class ToolComponentInfo(ComponentInfo):
292     type_name = 'Tool'
293
294     @staticmethod
295     def parse(subpath, items):
296         kwargs = ComponentInfo.parse_items(items)
297         kwargs['required_libraries'] = items.get_list('required_libraries')
298         return ToolComponentInfo(subpath, **kwargs)
299
300     def __init__(self, subpath, name, dependencies, parent,
301                  required_libraries):
302         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
303
304         # The names of the library components which are required to link this
305         # tool.
306         self.required_libraries = list(required_libraries)
307
308     def get_component_references(self):
309         for r in ComponentInfo.get_component_references(self):
310             yield r
311         for r in self.required_libraries:
312             yield ('required library', r)
313
314     def get_llvmbuild_fragment(self):
315         result = StringIO.StringIO()
316         print >>result, 'type = %s' % self.type_name
317         print >>result, 'name = %s' % self.name
318         print >>result, 'parent = %s' % self.parent
319         print >>result, 'required_libraries = %s' % ' '.join(
320             self.required_libraries)
321         return result.getvalue()
322
323 class BuildToolComponentInfo(ToolComponentInfo):
324     type_name = 'BuildTool'
325
326     @staticmethod
327     def parse(subpath, items):
328         kwargs = ComponentInfo.parse_items(items)
329         kwargs['required_libraries'] = items.get_list('required_libraries')
330         return BuildToolComponentInfo(subpath, **kwargs)
331
332 ###
333
334 class IniFormatParser(dict):
335     def get_list(self, key):
336         # Check if the value is defined.
337         value = self.get(key)
338         if value is None:
339             return []
340
341         # Lists are just whitespace separated strings.
342         return value.split()
343
344     def get_optional_string(self, key):
345         value = self.get_list(key)
346         if not value:
347             return None
348         if len(value) > 1:
349             raise ParseError("multiple values for scalar key: %r" % key)
350         return value[0]
351
352     def get_string(self, key):
353         value = self.get_optional_string(key)
354         if not value:
355             raise ParseError("missing value for required string: %r" % key)
356         return value
357
358     def get_optional_bool(self, key, default = None):
359         value = self.get_optional_string(key)
360         if not value:
361             return default
362         if value not in ('0', '1'):
363             raise ParseError("invalid value(%r) for boolean property: %r" % (
364                     value, key))
365         return bool(int(value))
366
367     def get_bool(self, key):
368         value = self.get_optional_bool(key)
369         if value is None:
370             raise ParseError("missing value for required boolean: %r" % key)
371         return value
372
373 _component_type_map = dict(
374     (t.type_name, t)
375     for t in (GroupComponentInfo,
376               LibraryComponentInfo, LibraryGroupComponentInfo,
377               ToolComponentInfo, BuildToolComponentInfo,
378               TargetGroupComponentInfo))
379 def load_from_path(path, subpath):
380     # Load the LLVMBuild.txt file as an .ini format file.
381     parser = ConfigParser.RawConfigParser()
382     parser.read(path)
383
384     # Extract the common section.
385     if parser.has_section("common"):
386         common = IniFormatParser(parser.items("common"))
387         parser.remove_section("common")
388     else:
389         common = IniFormatParser({})
390
391     return common, _read_components_from_parser(parser, path, subpath)
392
393 def _read_components_from_parser(parser, path, subpath):
394     # We load each section which starts with 'component' as a distinct component
395     # description (so multiple components can be described in one file).
396     for section in parser.sections():
397         if not section.startswith('component'):
398             # We don't expect arbitrary sections currently, warn the user.
399             warning("ignoring unknown section %r in %r" % (section, path))
400             continue
401
402         # Determine the type of the component to instantiate.
403         if not parser.has_option(section, 'type'):
404             fatal("invalid component %r in %r: %s" % (
405                     section, path, "no component type"))
406
407         type_name = parser.get(section, 'type')
408         type_class = _component_type_map.get(type_name)
409         if type_class is None:
410             fatal("invalid component %r in %r: %s" % (
411                     section, path, "invalid component type: %r" % type_name))
412
413         # Instantiate the component based on the remaining values.
414         try:
415             info = type_class.parse(subpath,
416                                     IniFormatParser(parser.items(section)))
417         except TypeError:
418             print >>sys.stderr, "error: invalid component %r in %r: %s" % (
419                 section, path, "unable to instantiate: %r" % type_name)
420             import traceback
421             traceback.print_exc()
422             raise SystemExit, 1
423         except ParseError,e:
424             fatal("unable to load component %r in %r: %s" % (
425                     section, path, e.message))
426
427         info._source_path = path
428         yield info