blob: 22ce0b4fde72569d2a2321673c2e598bae62b149 [file] [log] [blame]
Daniel Dunbardf578252011-11-03 17:56:06 +00001"""
2Descriptor objects for entities that are part of the LLVM project.
3"""
4
5import ConfigParser
6import sys
7
Daniel Dunbar9da6b122011-11-03 17:56:10 +00008from util import *
9
10class ParseError(Exception):
11 pass
12
Daniel Dunbardf578252011-11-03 17:56:06 +000013class ComponentInfo(object):
14 """
15 Base class for component descriptions.
16 """
17
18 type_name = None
19
Daniel Dunbar9da6b122011-11-03 17:56:10 +000020 @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
Daniel Dunbardf578252011-11-03 17:56:06 +000029 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
Daniel Dunbar1cf14af2011-11-03 17:56:12 +000040 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
Daniel Dunbardf578252011-11-03 17:56:06 +000051class 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
Daniel Dunbar9da6b122011-11-03 17:56:10 +000059 @staticmethod
60 def parse(subpath, items):
61 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
62 return GroupComponentInfo(subpath, **kwargs)
63
Daniel Dunbardf578252011-11-03 17:56:06 +000064 def __init__(self, subpath, name, parent):
65 ComponentInfo.__init__(self, subpath, name, [], parent)
66
67class LibraryComponentInfo(ComponentInfo):
68 type_name = 'Library'
69
Daniel Dunbar9da6b122011-11-03 17:56:10 +000070 @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):
Daniel Dunbardf578252011-11-03 17:56:06 +000081 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
Daniel Dunbar1cf14af2011-11-03 17:56:12 +000095 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
Daniel Dunbardf578252011-11-03 17:56:06 +0000103class LibraryGroupComponentInfo(ComponentInfo):
104 type_name = 'LibraryGroup'
105
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000106 @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
Daniel Dunbardf578252011-11-03 17:56:06 +0000114 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
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000126 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
Daniel Dunbardf578252011-11-03 17:56:06 +0000134class ToolComponentInfo(ComponentInfo):
135 type_name = 'Tool'
136
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000137 @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
Daniel Dunbardf578252011-11-03 17:56:06 +0000143 def __init__(self, subpath, name, dependencies, parent,
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000144 required_libraries):
Daniel Dunbardf578252011-11-03 17:56:06 +0000145 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
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000151 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
Daniel Dunbardf578252011-11-03 17:56:06 +0000157class BuildToolComponentInfo(ToolComponentInfo):
158 type_name = 'BuildTool'
159
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000160 @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
168class 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
Daniel Dunbardf578252011-11-03 17:56:06 +0000192_component_type_map = dict(
193 (t.type_name, t)
194 for t in (GroupComponentInfo,
195 LibraryComponentInfo, LibraryGroupComponentInfo,
196 ToolComponentInfo, BuildToolComponentInfo))
197def 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.
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000207 warning("ignoring unknown section %r in %r" % (section, path))
Daniel Dunbardf578252011-11-03 17:56:06 +0000208 continue
209
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000210 # Determine the type of the component to instantiate.
Daniel Dunbardf578252011-11-03 17:56:06 +0000211 if not parser.has_option(section, 'type'):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000212 fatal("invalid component %r in %r: %s" % (
213 section, path, "no component type"))
Daniel Dunbardf578252011-11-03 17:56:06 +0000214
215 type_name = parser.get(section, 'type')
216 type_class = _component_type_map.get(type_name)
217 if type_class is None:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000218 fatal("invalid component %r in %r: %s" % (
219 section, path, "invalid component type: %r" % type_name))
Daniel Dunbardf578252011-11-03 17:56:06 +0000220
221 # Instantiate the component based on the remaining values.
222 try:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000223 info = type_class.parse(subpath,
224 IniFormatParser(parser.items(section)))
Daniel Dunbardf578252011-11-03 17:56:06 +0000225 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
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000231 except ParseError,e:
232 fatal("unable to load component %r in %r: %s" % (
233 section, path, e.message))
Daniel Dunbardf578252011-11-03 17:56:06 +0000234
235 yield info