blob: 230ae219f2f218adcc28fd05da4d8c61f67e30a3 [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
Daniel Dunbar43120df2011-11-03 17:56:21 +00006import StringIO
Daniel Dunbardf578252011-11-03 17:56:06 +00007import sys
8
Daniel Dunbar9da6b122011-11-03 17:56:10 +00009from util import *
10
11class ParseError(Exception):
12 pass
13
Daniel Dunbardf578252011-11-03 17:56:06 +000014class ComponentInfo(object):
15 """
16 Base class for component descriptions.
17 """
18
19 type_name = None
20
Daniel Dunbar9da6b122011-11-03 17:56:10 +000021 @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
Daniel Dunbardf578252011-11-03 17:56:06 +000030 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
Daniel Dunbar86c119a2011-11-03 17:56:16 +000041 # The parent instance, once loaded.
42 self.parent_instance = None
43 self.children = []
44
Daniel Dunbara3217162011-12-12 22:45:35 +000045 # The original source path.
46 self._source_path = None
47
Daniel Dunbar54d8c7f2011-12-12 22:45:41 +000048 # A flag to mark "special" components which have some amount of magic
49 # handling (generally based on command line options).
50 self._is_special_group = False
51
Daniel Dunbar86c119a2011-11-03 17:56:16 +000052 def set_parent_instance(self, parent):
53 assert parent.name == self.parent, "Unexpected parent!"
54 self.parent_instance = parent
55 self.parent_instance.children.append(self)
56
Daniel Dunbar1cf14af2011-11-03 17:56:12 +000057 def get_component_references(self):
58 """get_component_references() -> iter
59
60 Return an iterator over the named references to other components from
61 this object. Items are of the form (reference-type, component-name).
62 """
63
64 # Parent references are handled specially.
65 for r in self.dependencies:
66 yield ('dependency', r)
67
Daniel Dunbar43120df2011-11-03 17:56:21 +000068 def get_llvmbuild_fragment(self):
69 abstract
70
Daniel Dunbardf578252011-11-03 17:56:06 +000071class GroupComponentInfo(ComponentInfo):
72 """
73 Group components have no semantics as far as the build system are concerned,
74 but exist to help organize other components into a logical tree structure.
75 """
76
77 type_name = 'Group'
78
Daniel Dunbar9da6b122011-11-03 17:56:10 +000079 @staticmethod
80 def parse(subpath, items):
81 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
82 return GroupComponentInfo(subpath, **kwargs)
83
Daniel Dunbardf578252011-11-03 17:56:06 +000084 def __init__(self, subpath, name, parent):
85 ComponentInfo.__init__(self, subpath, name, [], parent)
86
Daniel Dunbar43120df2011-11-03 17:56:21 +000087 def get_llvmbuild_fragment(self):
88 result = StringIO.StringIO()
89 print >>result, 'type = %s' % self.type_name
90 print >>result, 'name = %s' % self.name
91 print >>result, 'parent = %s' % self.parent
92 return result.getvalue()
93
Daniel Dunbardf578252011-11-03 17:56:06 +000094class LibraryComponentInfo(ComponentInfo):
95 type_name = 'Library'
96
Daniel Dunbar9da6b122011-11-03 17:56:10 +000097 @staticmethod
98 def parse(subpath, items):
99 kwargs = ComponentInfo.parse_items(items)
Daniel Dunbar43120df2011-11-03 17:56:21 +0000100 kwargs['library_name'] = items.get_optional_string('library_name')
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000101 kwargs['required_libraries'] = items.get_list('required_libraries')
102 kwargs['add_to_library_groups'] = items.get_list(
103 'add_to_library_groups')
104 return LibraryComponentInfo(subpath, **kwargs)
105
106 def __init__(self, subpath, name, dependencies, parent, library_name,
107 required_libraries, add_to_library_groups):
Daniel Dunbardf578252011-11-03 17:56:06 +0000108 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
109
110 # If given, the name to use for the library instead of deriving it from
111 # the component name.
112 self.library_name = library_name
113
114 # The names of the library components which are required when linking
115 # with this component.
116 self.required_libraries = list(required_libraries)
117
118 # The names of the library group components this component should be
119 # considered part of.
120 self.add_to_library_groups = list(add_to_library_groups)
121
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000122 def get_component_references(self):
123 for r in ComponentInfo.get_component_references(self):
124 yield r
125 for r in self.required_libraries:
126 yield ('required library', r)
127 for r in self.add_to_library_groups:
128 yield ('library group', r)
129
Daniel Dunbar43120df2011-11-03 17:56:21 +0000130 def get_llvmbuild_fragment(self):
131 result = StringIO.StringIO()
132 print >>result, 'type = %s' % self.type_name
133 print >>result, 'name = %s' % self.name
134 print >>result, 'parent = %s' % self.parent
135 if self.library_name is not None:
136 print >>result, 'library_name = %s' % self.library_name
137 if self.required_libraries:
138 print >>result, 'required_libraries = %s' % ' '.join(
139 self.required_libraries)
140 if self.add_to_library_groups:
141 print >>result, 'add_to_library_groups = %s' % ' '.join(
142 self.add_to_library_groups)
143 return result.getvalue()
144
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000145 def get_library_name(self):
146 return self.library_name or self.name
147
Daniel Dunbar5086de62011-11-29 00:06:50 +0000148 def get_prefixed_library_name(self):
149 """
150 get_prefixed_library_name() -> str
151
152 Return the library name prefixed by the project name. This is generally
153 what the library name will be on disk.
154 """
155
156 basename = self.get_library_name()
157
158 # FIXME: We need to get the prefix information from an explicit project
159 # object, or something.
160 if basename in ('gtest', 'gtest_main'):
161 return basename
162
163 return 'LLVM%s' % basename
164
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000165 def get_llvmconfig_component_name(self):
166 return self.get_library_name().lower()
167
Daniel Dunbardf578252011-11-03 17:56:06 +0000168class LibraryGroupComponentInfo(ComponentInfo):
169 type_name = 'LibraryGroup'
170
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000171 @staticmethod
172 def parse(subpath, items):
173 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
174 kwargs['required_libraries'] = items.get_list('required_libraries')
175 kwargs['add_to_library_groups'] = items.get_list(
176 'add_to_library_groups')
177 return LibraryGroupComponentInfo(subpath, **kwargs)
178
Daniel Dunbardf578252011-11-03 17:56:06 +0000179 def __init__(self, subpath, name, parent, required_libraries = [],
180 add_to_library_groups = []):
181 ComponentInfo.__init__(self, subpath, name, [], parent)
182
183 # The names of the library components which are required when linking
184 # with this component.
185 self.required_libraries = list(required_libraries)
186
187 # The names of the library group components this component should be
188 # considered part of.
189 self.add_to_library_groups = list(add_to_library_groups)
190
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000191 def get_component_references(self):
192 for r in ComponentInfo.get_component_references(self):
193 yield r
194 for r in self.required_libraries:
195 yield ('required library', r)
196 for r in self.add_to_library_groups:
197 yield ('library group', r)
198
Daniel Dunbar43120df2011-11-03 17:56:21 +0000199 def get_llvmbuild_fragment(self):
200 result = StringIO.StringIO()
201 print >>result, 'type = %s' % self.type_name
202 print >>result, 'name = %s' % self.name
203 print >>result, 'parent = %s' % self.parent
Daniel Dunbar54d8c7f2011-12-12 22:45:41 +0000204 if self.required_libraries and not self._is_special_group:
Daniel Dunbar43120df2011-11-03 17:56:21 +0000205 print >>result, 'required_libraries = %s' % ' '.join(
206 self.required_libraries)
207 if self.add_to_library_groups:
208 print >>result, 'add_to_library_groups = %s' % ' '.join(
209 self.add_to_library_groups)
210 return result.getvalue()
211
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000212 def get_llvmconfig_component_name(self):
213 return self.name.lower()
214
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000215class TargetGroupComponentInfo(ComponentInfo):
216 type_name = 'TargetGroup'
217
218 @staticmethod
219 def parse(subpath, items):
220 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
221 kwargs['required_libraries'] = items.get_list('required_libraries')
222 kwargs['add_to_library_groups'] = items.get_list(
223 'add_to_library_groups')
224 kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000225 kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
226 False)
227 kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
228 False)
229 kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
230 False)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000231 return TargetGroupComponentInfo(subpath, **kwargs)
232
233 def __init__(self, subpath, name, parent, required_libraries = [],
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000234 add_to_library_groups = [], has_jit = False,
235 has_asmprinter = False, has_asmparser = False,
236 has_disassembler = False):
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000237 ComponentInfo.__init__(self, subpath, name, [], parent)
238
239 # The names of the library components which are required when linking
240 # with this component.
241 self.required_libraries = list(required_libraries)
242
243 # The names of the library group components this component should be
244 # considered part of.
245 self.add_to_library_groups = list(add_to_library_groups)
246
247 # Whether or not this target supports the JIT.
248 self.has_jit = bool(has_jit)
249
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000250 # Whether or not this target defines an assembly printer.
251 self.has_asmprinter = bool(has_asmprinter)
252
253 # Whether or not this target defines an assembly parser.
254 self.has_asmparser = bool(has_asmparser)
255
256 # Whether or not this target defines an disassembler.
257 self.has_disassembler = bool(has_disassembler)
258
Daniel Dunbaraffc6cf2011-11-10 00:50:07 +0000259 # Whether or not this target is enabled. This is set in response to
260 # configuration parameters.
261 self.enabled = False
262
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000263 def get_component_references(self):
264 for r in ComponentInfo.get_component_references(self):
265 yield r
266 for r in self.required_libraries:
267 yield ('required library', r)
268 for r in self.add_to_library_groups:
269 yield ('library group', r)
270
271 def get_llvmbuild_fragment(self):
272 result = StringIO.StringIO()
273 print >>result, 'type = %s' % self.type_name
274 print >>result, 'name = %s' % self.name
275 print >>result, 'parent = %s' % self.parent
276 if self.required_libraries:
277 print >>result, 'required_libraries = %s' % ' '.join(
278 self.required_libraries)
279 if self.add_to_library_groups:
280 print >>result, 'add_to_library_groups = %s' % ' '.join(
281 self.add_to_library_groups)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000282 for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
283 'has_jit'):
284 if getattr(self, bool_key):
285 print >>result, '%s = 1' % (bool_key,)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000286 return result.getvalue()
287
288 def get_llvmconfig_component_name(self):
289 return self.name.lower()
290
Daniel Dunbardf578252011-11-03 17:56:06 +0000291class ToolComponentInfo(ComponentInfo):
292 type_name = 'Tool'
293
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000294 @staticmethod
295 def parse(subpath, items):
296 kwargs = ComponentInfo.parse_items(items)
297 kwargs['required_libraries'] = items.get_list('required_libraries')
298 return ToolComponentInfo(subpath, **kwargs)
299
Daniel Dunbardf578252011-11-03 17:56:06 +0000300 def __init__(self, subpath, name, dependencies, parent,
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000301 required_libraries):
Daniel Dunbardf578252011-11-03 17:56:06 +0000302 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
303
304 # The names of the library components which are required to link this
305 # tool.
306 self.required_libraries = list(required_libraries)
307
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000308 def get_component_references(self):
309 for r in ComponentInfo.get_component_references(self):
310 yield r
311 for r in self.required_libraries:
312 yield ('required library', r)
313
Daniel Dunbar43120df2011-11-03 17:56:21 +0000314 def get_llvmbuild_fragment(self):
315 result = StringIO.StringIO()
316 print >>result, 'type = %s' % self.type_name
317 print >>result, 'name = %s' % self.name
318 print >>result, 'parent = %s' % self.parent
319 print >>result, 'required_libraries = %s' % ' '.join(
320 self.required_libraries)
321 return result.getvalue()
322
Daniel Dunbardf578252011-11-03 17:56:06 +0000323class BuildToolComponentInfo(ToolComponentInfo):
324 type_name = 'BuildTool'
325
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000326 @staticmethod
327 def parse(subpath, items):
328 kwargs = ComponentInfo.parse_items(items)
329 kwargs['required_libraries'] = items.get_list('required_libraries')
330 return BuildToolComponentInfo(subpath, **kwargs)
331
332###
333
334class IniFormatParser(dict):
335 def get_list(self, key):
336 # Check if the value is defined.
337 value = self.get(key)
338 if value is None:
339 return []
340
341 # Lists are just whitespace separated strings.
342 return value.split()
343
344 def get_optional_string(self, key):
345 value = self.get_list(key)
346 if not value:
347 return None
348 if len(value) > 1:
349 raise ParseError("multiple values for scalar key: %r" % key)
350 return value[0]
351
352 def get_string(self, key):
353 value = self.get_optional_string(key)
354 if not value:
355 raise ParseError("missing value for required string: %r" % key)
356 return value
357
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000358 def get_optional_bool(self, key, default = None):
359 value = self.get_optional_string(key)
360 if not value:
361 return default
362 if value not in ('0', '1'):
363 raise ParseError("invalid value(%r) for boolean property: %r" % (
364 value, key))
365 return bool(int(value))
366
367 def get_bool(self, key):
368 value = self.get_optional_bool(key)
369 if value is None:
370 raise ParseError("missing value for required boolean: %r" % key)
371 return value
372
Daniel Dunbardf578252011-11-03 17:56:06 +0000373_component_type_map = dict(
374 (t.type_name, t)
375 for t in (GroupComponentInfo,
376 LibraryComponentInfo, LibraryGroupComponentInfo,
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000377 ToolComponentInfo, BuildToolComponentInfo,
378 TargetGroupComponentInfo))
Daniel Dunbardf578252011-11-03 17:56:06 +0000379def load_from_path(path, subpath):
380 # Load the LLVMBuild.txt file as an .ini format file.
381 parser = ConfigParser.RawConfigParser()
382 parser.read(path)
383
Daniel Dunbare5609ab2011-12-12 22:45:59 +0000384 # Extract the common section.
385 if parser.has_section("common"):
386 common = IniFormatParser(parser.items("common"))
387 parser.remove_section("common")
388 else:
389 common = IniFormatParser({})
390
391 return common, _read_components_from_parser(parser, path, subpath)
392
393def _read_components_from_parser(parser, path, subpath):
Daniel Dunbardf578252011-11-03 17:56:06 +0000394 # We load each section which starts with 'component' as a distinct component
395 # description (so multiple components can be described in one file).
396 for section in parser.sections():
397 if not section.startswith('component'):
398 # We don't expect arbitrary sections currently, warn the user.
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000399 warning("ignoring unknown section %r in %r" % (section, path))
Daniel Dunbardf578252011-11-03 17:56:06 +0000400 continue
401
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000402 # Determine the type of the component to instantiate.
Daniel Dunbardf578252011-11-03 17:56:06 +0000403 if not parser.has_option(section, 'type'):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000404 fatal("invalid component %r in %r: %s" % (
405 section, path, "no component type"))
Daniel Dunbardf578252011-11-03 17:56:06 +0000406
407 type_name = parser.get(section, 'type')
408 type_class = _component_type_map.get(type_name)
409 if type_class is None:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000410 fatal("invalid component %r in %r: %s" % (
411 section, path, "invalid component type: %r" % type_name))
Daniel Dunbardf578252011-11-03 17:56:06 +0000412
413 # Instantiate the component based on the remaining values.
414 try:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000415 info = type_class.parse(subpath,
416 IniFormatParser(parser.items(section)))
Daniel Dunbardf578252011-11-03 17:56:06 +0000417 except TypeError:
418 print >>sys.stderr, "error: invalid component %r in %r: %s" % (
419 section, path, "unable to instantiate: %r" % type_name)
420 import traceback
421 traceback.print_exc()
422 raise SystemExit, 1
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000423 except ParseError,e:
424 fatal("unable to load component %r in %r: %s" % (
425 section, path, e.message))
Daniel Dunbardf578252011-11-03 17:56:06 +0000426
Daniel Dunbara3217162011-12-12 22:45:35 +0000427 info._source_path = path
Daniel Dunbardf578252011-11-03 17:56:06 +0000428 yield info