22ce0b4fde72569d2a2321673c2e598bae62b149
[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 sys
7
8 from util import *
9
10 class ParseError(Exception):
11     pass
12
13 class ComponentInfo(object):
14     """
15     Base class for component descriptions.
16     """
17
18     type_name = None
19
20     @staticmethod
21     def parse_items(items, has_dependencies = True):
22         kwargs = {}
23         kwargs['name'] = items.get_string('name')
24         kwargs['parent'] = items.get_optional_string('parent')
25         if has_dependencies:
26             kwargs['dependencies'] = items.get_list('dependencies')
27         return kwargs
28
29     def __init__(self, subpath, name, dependencies, parent):
30         if not subpath.startswith('/'):
31             raise ValueError,"invalid subpath: %r" % subpath
32         self.subpath = subpath
33         self.name = name
34         self.dependencies = list(dependencies)
35
36         # The name of the parent component to logically group this component
37         # under.
38         self.parent = parent
39
40     def get_component_references(self):
41         """get_component_references() -> iter
42
43         Return an iterator over the named references to other components from
44         this object. Items are of the form (reference-type, component-name).
45         """
46
47         # Parent references are handled specially.
48         for r in self.dependencies:
49             yield ('dependency', r)
50
51 class GroupComponentInfo(ComponentInfo):
52     """
53     Group components have no semantics as far as the build system are concerned,
54     but exist to help organize other components into a logical tree structure.
55     """
56
57     type_name = 'Group'
58
59     @staticmethod
60     def parse(subpath, items):
61         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
62         return GroupComponentInfo(subpath, **kwargs)
63
64     def __init__(self, subpath, name, parent):
65         ComponentInfo.__init__(self, subpath, name, [], parent)
66
67 class LibraryComponentInfo(ComponentInfo):
68     type_name = 'Library'
69
70     @staticmethod
71     def parse(subpath, items):
72         kwargs = ComponentInfo.parse_items(items)
73         kwargs['library_name'] = items.get_optional_string('name')
74         kwargs['required_libraries'] = items.get_list('required_libraries')
75         kwargs['add_to_library_groups'] = items.get_list(
76             'add_to_library_groups')
77         return LibraryComponentInfo(subpath, **kwargs)
78
79     def __init__(self, subpath, name, dependencies, parent, library_name,
80                  required_libraries, add_to_library_groups):
81         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
82
83         # If given, the name to use for the library instead of deriving it from
84         # the component name.
85         self.library_name = library_name
86
87         # The names of the library components which are required when linking
88         # with this component.
89         self.required_libraries = list(required_libraries)
90
91         # The names of the library group components this component should be
92         # considered part of.
93         self.add_to_library_groups = list(add_to_library_groups)
94
95     def get_component_references(self):
96         for r in ComponentInfo.get_component_references(self):
97             yield r
98         for r in self.required_libraries:
99             yield ('required library', r)
100         for r in self.add_to_library_groups:
101             yield ('library group', r)
102
103 class LibraryGroupComponentInfo(ComponentInfo):
104     type_name = 'LibraryGroup'
105
106     @staticmethod
107     def parse(subpath, items):
108         kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
109         kwargs['required_libraries'] = items.get_list('required_libraries')
110         kwargs['add_to_library_groups'] = items.get_list(
111             'add_to_library_groups')
112         return LibraryGroupComponentInfo(subpath, **kwargs)
113
114     def __init__(self, subpath, name, parent, required_libraries = [],
115                  add_to_library_groups = []):
116         ComponentInfo.__init__(self, subpath, name, [], parent)
117
118         # The names of the library components which are required when linking
119         # with this component.
120         self.required_libraries = list(required_libraries)
121
122         # The names of the library group components this component should be
123         # considered part of.
124         self.add_to_library_groups = list(add_to_library_groups)
125
126     def get_component_references(self):
127         for r in ComponentInfo.get_component_references(self):
128             yield r
129         for r in self.required_libraries:
130             yield ('required library', r)
131         for r in self.add_to_library_groups:
132             yield ('library group', r)
133
134 class ToolComponentInfo(ComponentInfo):
135     type_name = 'Tool'
136
137     @staticmethod
138     def parse(subpath, items):
139         kwargs = ComponentInfo.parse_items(items)
140         kwargs['required_libraries'] = items.get_list('required_libraries')
141         return ToolComponentInfo(subpath, **kwargs)
142
143     def __init__(self, subpath, name, dependencies, parent,
144                  required_libraries):
145         ComponentInfo.__init__(self, subpath, name, dependencies, parent)
146
147         # The names of the library components which are required to link this
148         # tool.
149         self.required_libraries = list(required_libraries)
150
151     def get_component_references(self):
152         for r in ComponentInfo.get_component_references(self):
153             yield r
154         for r in self.required_libraries:
155             yield ('required library', r)
156
157 class BuildToolComponentInfo(ToolComponentInfo):
158     type_name = 'BuildTool'
159
160     @staticmethod
161     def parse(subpath, items):
162         kwargs = ComponentInfo.parse_items(items)
163         kwargs['required_libraries'] = items.get_list('required_libraries')
164         return BuildToolComponentInfo(subpath, **kwargs)
165
166 ###
167
168 class IniFormatParser(dict):
169     def get_list(self, key):
170         # Check if the value is defined.
171         value = self.get(key)
172         if value is None:
173             return []
174
175         # Lists are just whitespace separated strings.
176         return value.split()
177
178     def get_optional_string(self, key):
179         value = self.get_list(key)
180         if not value:
181             return None
182         if len(value) > 1:
183             raise ParseError("multiple values for scalar key: %r" % key)
184         return value[0]
185
186     def get_string(self, key):
187         value = self.get_optional_string(key)
188         if not value:
189             raise ParseError("missing value for required string: %r" % key)
190         return value
191
192 _component_type_map = dict(
193     (t.type_name, t)
194     for t in (GroupComponentInfo,
195               LibraryComponentInfo, LibraryGroupComponentInfo,
196               ToolComponentInfo, BuildToolComponentInfo))
197 def load_from_path(path, subpath):
198     # Load the LLVMBuild.txt file as an .ini format file.
199     parser = ConfigParser.RawConfigParser()
200     parser.read(path)
201
202     # We load each section which starts with 'component' as a distinct component
203     # description (so multiple components can be described in one file).
204     for section in parser.sections():
205         if not section.startswith('component'):
206             # We don't expect arbitrary sections currently, warn the user.
207             warning("ignoring unknown section %r in %r" % (section, path))
208             continue
209
210         # Determine the type of the component to instantiate.
211         if not parser.has_option(section, 'type'):
212             fatal("invalid component %r in %r: %s" % (
213                     section, path, "no component type"))
214
215         type_name = parser.get(section, 'type')
216         type_class = _component_type_map.get(type_name)
217         if type_class is None:
218             fatal("invalid component %r in %r: %s" % (
219                     section, path, "invalid component type: %r" % type_name))
220
221         # Instantiate the component based on the remaining values.
222         try:
223             info = type_class.parse(subpath,
224                                     IniFormatParser(parser.items(section)))
225         except TypeError:
226             print >>sys.stderr, "error: invalid component %r in %r: %s" % (
227                 section, path, "unable to instantiate: %r" % type_name)
228             import traceback
229             traceback.print_exc()
230             raise SystemExit, 1
231         except ParseError,e:
232             fatal("unable to load component %r in %r: %s" % (
233                     section, path, e.message))
234
235         yield info