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