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