llvm-build: Add an explicit component type to represent 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     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         return TargetGroupComponentInfo(subpath, **kwargs)
202
203     def __init__(self, subpath, name, parent, required_libraries = [],
204                  add_to_library_groups = [], has_jit = False):
205         ComponentInfo.__init__(self, subpath, name, [], parent)
206
207         # The names of the library components which are required when linking
208         # with this component.
209         self.required_libraries = list(required_libraries)
210
211         # The names of the library group components this component should be
212         # considered part of.
213         self.add_to_library_groups = list(add_to_library_groups)
214
215         # Whether or not this target supports the JIT.
216         self.has_jit = bool(has_jit)
217
218     def get_component_references(self):
219         for r in ComponentInfo.get_component_references(self):
220             yield r
221         for r in self.required_libraries:
222             yield ('required library', r)
223         for r in self.add_to_library_groups:
224             yield ('library group', r)
225
226     def get_llvmbuild_fragment(self):
227         result = StringIO.StringIO()
228         print >>result, 'type = %s' % self.type_name
229         print >>result, 'name = %s' % self.name
230         print >>result, 'parent = %s' % self.parent
231         if self.required_libraries:
232             print >>result, 'required_libraries = %s' % ' '.join(
233                 self.required_libraries)
234         if self.add_to_library_groups:
235             print >>result, 'add_to_library_groups = %s' % ' '.join(
236                 self.add_to_library_groups)
237         if self.has_jit:
238             print >>result, 'has_jit = %s' % ' '.join(
239                 int(self.has_jit))
240         return result.getvalue()
241
242     def get_llvmconfig_component_name(self):
243         return self.name.lower()
244
245 class ToolComponentInfo(ComponentInfo):
246     type_name = 'Tool'
247
248     @staticmethod
249     def parse(subpath, items):
250         kwargs = ComponentInfo.parse_items(items)
251         kwargs['required_libraries'] = items.get_list('required_libraries')
252         return ToolComponentInfo(subpath, **kwargs)
253
254     def __init__(self, subpath, name, dependencies, parent,
255                  required_libraries):
256         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
257
258         # The names of the library components which are required to link this
259         # tool.
260         self.required_libraries = list(required_libraries)
261
262     def get_component_references(self):
263         for r in ComponentInfo.get_component_references(self):
264             yield r
265         for r in self.required_libraries:
266             yield ('required library', r)
267
268     def get_llvmbuild_fragment(self):
269         result = StringIO.StringIO()
270         print >>result, 'type = %s' % self.type_name
271         print >>result, 'name = %s' % self.name
272         print >>result, 'parent = %s' % self.parent
273         print >>result, 'required_libraries = %s' % ' '.join(
274             self.required_libraries)
275         return result.getvalue()
276
277 class BuildToolComponentInfo(ToolComponentInfo):
278     type_name = 'BuildTool'
279
280     @staticmethod
281     def parse(subpath, items):
282         kwargs = ComponentInfo.parse_items(items)
283         kwargs['required_libraries'] = items.get_list('required_libraries')
284         return BuildToolComponentInfo(subpath, **kwargs)
285
286 ###
287
288 class IniFormatParser(dict):
289     def get_list(self, key):
290         # Check if the value is defined.
291         value = self.get(key)
292         if value is None:
293             return []
294
295         # Lists are just whitespace separated strings.
296         return value.split()
297
298     def get_optional_string(self, key):
299         value = self.get_list(key)
300         if not value:
301             return None
302         if len(value) > 1:
303             raise ParseError("multiple values for scalar key: %r" % key)
304         return value[0]
305
306     def get_string(self, key):
307         value = self.get_optional_string(key)
308         if not value:
309             raise ParseError("missing value for required string: %r" % key)
310         return value
311
312     def get_optional_bool(self, key, default = None):
313         value = self.get_optional_string(key)
314         if not value:
315             return default
316         if value not in ('0', '1'):
317             raise ParseError("invalid value(%r) for boolean property: %r" % (
318                     value, key))
319         return bool(int(value))
320
321     def get_bool(self, key):
322         value = self.get_optional_bool(key)
323         if value is None:
324             raise ParseError("missing value for required boolean: %r" % key)
325         return value
326
327 _component_type_map = dict(
328     (t.type_name, t)
329     for t in (GroupComponentInfo,
330               LibraryComponentInfo, LibraryGroupComponentInfo,
331               ToolComponentInfo, BuildToolComponentInfo,
332               TargetGroupComponentInfo))
333 def load_from_path(path, subpath):
334     # Load the LLVMBuild.txt file as an .ini format file.
335     parser = ConfigParser.RawConfigParser()
336     parser.read(path)
337
338     # We load each section which starts with 'component' as a distinct component
339     # description (so multiple components can be described in one file).
340     for section in parser.sections():
341         if not section.startswith('component'):
342             # We don't expect arbitrary sections currently, warn the user.
343             warning("ignoring unknown section %r in %r" % (section, path))
344             continue
345
346         # Determine the type of the component to instantiate.
347         if not parser.has_option(section, 'type'):
348             fatal("invalid component %r in %r: %s" % (
349                     section, path, "no component type"))
350
351         type_name = parser.get(section, 'type')
352         type_class = _component_type_map.get(type_name)
353         if type_class is None:
354             fatal("invalid component %r in %r: %s" % (
355                     section, path, "invalid component type: %r" % type_name))
356
357         # Instantiate the component based on the remaining values.
358         try:
359             info = type_class.parse(subpath,
360                                     IniFormatParser(parser.items(section)))
361         except TypeError:
362             print >>sys.stderr, "error: invalid component %r in %r: %s" % (
363                 section, path, "unable to instantiate: %r" % type_name)
364             import traceback
365             traceback.print_exc()
366             raise SystemExit, 1
367         except ParseError,e:
368             fatal("unable to load component %r in %r: %s" % (
369                     section, path, e.message))
370
371         yield info