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