blob: e684ac2b7d21ca90e4a355dca607a30855e5b9ec [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 Dunbar177a1192012-05-15 18:44:12 +000071 def get_parent_target_group(self):
72 """get_parent_target_group() -> ComponentInfo or None
73
74 Return the nearest parent target group (if any), or None if the
75 component is not part of any target group.
76 """
77
78 # If this is a target group, return it.
79 if self.type_name == 'TargetGroup':
80 return self
81
82 # Otherwise recurse on the parent, if any.
83 if self.parent_instance:
84 return self.parent_instance.get_parent_target_group()
85
Daniel Dunbardf578252011-11-03 17:56:06 +000086class GroupComponentInfo(ComponentInfo):
87 """
88 Group components have no semantics as far as the build system are concerned,
89 but exist to help organize other components into a logical tree structure.
90 """
91
92 type_name = 'Group'
93
Daniel Dunbar9da6b122011-11-03 17:56:10 +000094 @staticmethod
95 def parse(subpath, items):
96 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
97 return GroupComponentInfo(subpath, **kwargs)
98
Daniel Dunbardf578252011-11-03 17:56:06 +000099 def __init__(self, subpath, name, parent):
100 ComponentInfo.__init__(self, subpath, name, [], parent)
101
Daniel Dunbar43120df2011-11-03 17:56:21 +0000102 def get_llvmbuild_fragment(self):
103 result = StringIO.StringIO()
104 print >>result, 'type = %s' % self.type_name
105 print >>result, 'name = %s' % self.name
106 print >>result, 'parent = %s' % self.parent
107 return result.getvalue()
108
Daniel Dunbardf578252011-11-03 17:56:06 +0000109class LibraryComponentInfo(ComponentInfo):
110 type_name = 'Library'
111
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000112 @staticmethod
Preston Gurd75493542012-05-07 19:38:40 +0000113 def parse_items(items):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000114 kwargs = ComponentInfo.parse_items(items)
Daniel Dunbar43120df2011-11-03 17:56:21 +0000115 kwargs['library_name'] = items.get_optional_string('library_name')
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000116 kwargs['required_libraries'] = items.get_list('required_libraries')
117 kwargs['add_to_library_groups'] = items.get_list(
118 'add_to_library_groups')
Daniel Dunbarb5cd41e2012-05-15 18:44:17 +0000119 kwargs['installed'] = items.get_optional_bool('installed', True)
Preston Gurd75493542012-05-07 19:38:40 +0000120 return kwargs
121
122 @staticmethod
123 def parse(subpath, items):
124 kwargs = LibraryComponentInfo.parse_items(items)
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000125 return LibraryComponentInfo(subpath, **kwargs)
126
127 def __init__(self, subpath, name, dependencies, parent, library_name,
Daniel Dunbarb5cd41e2012-05-15 18:44:17 +0000128 required_libraries, add_to_library_groups, installed):
Daniel Dunbardf578252011-11-03 17:56:06 +0000129 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
130
131 # If given, the name to use for the library instead of deriving it from
132 # the component name.
133 self.library_name = library_name
134
135 # The names of the library components which are required when linking
136 # with this component.
137 self.required_libraries = list(required_libraries)
138
139 # The names of the library group components this component should be
140 # considered part of.
141 self.add_to_library_groups = list(add_to_library_groups)
142
Daniel Dunbarb5cd41e2012-05-15 18:44:17 +0000143 # Whether or not this library is installed.
144 self.installed = installed
145
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000146 def get_component_references(self):
147 for r in ComponentInfo.get_component_references(self):
148 yield r
149 for r in self.required_libraries:
150 yield ('required library', r)
151 for r in self.add_to_library_groups:
152 yield ('library group', r)
153
Daniel Dunbar43120df2011-11-03 17:56:21 +0000154 def get_llvmbuild_fragment(self):
155 result = StringIO.StringIO()
156 print >>result, 'type = %s' % self.type_name
157 print >>result, 'name = %s' % self.name
158 print >>result, 'parent = %s' % self.parent
159 if self.library_name is not None:
160 print >>result, 'library_name = %s' % self.library_name
161 if self.required_libraries:
162 print >>result, 'required_libraries = %s' % ' '.join(
163 self.required_libraries)
164 if self.add_to_library_groups:
165 print >>result, 'add_to_library_groups = %s' % ' '.join(
166 self.add_to_library_groups)
Daniel Dunbarb5cd41e2012-05-15 18:44:17 +0000167 if not self.installed:
168 print >>result, 'installed = 0'
Daniel Dunbar43120df2011-11-03 17:56:21 +0000169 return result.getvalue()
170
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000171 def get_library_name(self):
172 return self.library_name or self.name
173
Daniel Dunbar5086de62011-11-29 00:06:50 +0000174 def get_prefixed_library_name(self):
175 """
176 get_prefixed_library_name() -> str
177
178 Return the library name prefixed by the project name. This is generally
179 what the library name will be on disk.
180 """
181
182 basename = self.get_library_name()
183
184 # FIXME: We need to get the prefix information from an explicit project
185 # object, or something.
186 if basename in ('gtest', 'gtest_main'):
187 return basename
188
189 return 'LLVM%s' % basename
190
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000191 def get_llvmconfig_component_name(self):
192 return self.get_library_name().lower()
193
Preston Gurd75493542012-05-07 19:38:40 +0000194class OptionalLibraryComponentInfo(LibraryComponentInfo):
195 type_name = "OptionalLibrary"
196
197 @staticmethod
198 def parse(subpath, items):
199 kwargs = LibraryComponentInfo.parse_items(items)
200 return OptionalLibraryComponentInfo(subpath, **kwargs)
201
202 def __init__(self, subpath, name, dependencies, parent, library_name,
Daniel Dunbarb5cd41e2012-05-15 18:44:17 +0000203 required_libraries, add_to_library_groups, installed):
Preston Gurd75493542012-05-07 19:38:40 +0000204 LibraryComponentInfo.__init__(self, subpath, name, dependencies, parent,
205 library_name, required_libraries,
Daniel Dunbarb5cd41e2012-05-15 18:44:17 +0000206 add_to_library_groups, installed)
Preston Gurd75493542012-05-07 19:38:40 +0000207
Daniel Dunbardf578252011-11-03 17:56:06 +0000208class LibraryGroupComponentInfo(ComponentInfo):
209 type_name = 'LibraryGroup'
210
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000211 @staticmethod
212 def parse(subpath, items):
213 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
214 kwargs['required_libraries'] = items.get_list('required_libraries')
215 kwargs['add_to_library_groups'] = items.get_list(
216 'add_to_library_groups')
217 return LibraryGroupComponentInfo(subpath, **kwargs)
218
Daniel Dunbardf578252011-11-03 17:56:06 +0000219 def __init__(self, subpath, name, parent, required_libraries = [],
220 add_to_library_groups = []):
221 ComponentInfo.__init__(self, subpath, name, [], parent)
222
223 # The names of the library components which are required when linking
224 # with this component.
225 self.required_libraries = list(required_libraries)
226
227 # The names of the library group components this component should be
228 # considered part of.
229 self.add_to_library_groups = list(add_to_library_groups)
230
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000231 def get_component_references(self):
232 for r in ComponentInfo.get_component_references(self):
233 yield r
234 for r in self.required_libraries:
235 yield ('required library', r)
236 for r in self.add_to_library_groups:
237 yield ('library group', r)
238
Daniel Dunbar43120df2011-11-03 17:56:21 +0000239 def get_llvmbuild_fragment(self):
240 result = StringIO.StringIO()
241 print >>result, 'type = %s' % self.type_name
242 print >>result, 'name = %s' % self.name
243 print >>result, 'parent = %s' % self.parent
Daniel Dunbar54d8c7f2011-12-12 22:45:41 +0000244 if self.required_libraries and not self._is_special_group:
Daniel Dunbar43120df2011-11-03 17:56:21 +0000245 print >>result, 'required_libraries = %s' % ' '.join(
246 self.required_libraries)
247 if self.add_to_library_groups:
248 print >>result, 'add_to_library_groups = %s' % ' '.join(
249 self.add_to_library_groups)
250 return result.getvalue()
251
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000252 def get_llvmconfig_component_name(self):
253 return self.name.lower()
254
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000255class TargetGroupComponentInfo(ComponentInfo):
256 type_name = 'TargetGroup'
257
258 @staticmethod
259 def parse(subpath, items):
260 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
261 kwargs['required_libraries'] = items.get_list('required_libraries')
262 kwargs['add_to_library_groups'] = items.get_list(
263 'add_to_library_groups')
264 kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000265 kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
266 False)
267 kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
268 False)
269 kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
270 False)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000271 return TargetGroupComponentInfo(subpath, **kwargs)
272
273 def __init__(self, subpath, name, parent, required_libraries = [],
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000274 add_to_library_groups = [], has_jit = False,
275 has_asmprinter = False, has_asmparser = False,
276 has_disassembler = False):
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000277 ComponentInfo.__init__(self, subpath, name, [], parent)
278
279 # The names of the library components which are required when linking
280 # with this component.
281 self.required_libraries = list(required_libraries)
282
283 # The names of the library group components this component should be
284 # considered part of.
285 self.add_to_library_groups = list(add_to_library_groups)
286
287 # Whether or not this target supports the JIT.
288 self.has_jit = bool(has_jit)
289
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000290 # Whether or not this target defines an assembly printer.
291 self.has_asmprinter = bool(has_asmprinter)
292
293 # Whether or not this target defines an assembly parser.
294 self.has_asmparser = bool(has_asmparser)
295
296 # Whether or not this target defines an disassembler.
297 self.has_disassembler = bool(has_disassembler)
298
Daniel Dunbaraffc6cf2011-11-10 00:50:07 +0000299 # Whether or not this target is enabled. This is set in response to
300 # configuration parameters.
301 self.enabled = False
302
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000303 def get_component_references(self):
304 for r in ComponentInfo.get_component_references(self):
305 yield r
306 for r in self.required_libraries:
307 yield ('required library', r)
308 for r in self.add_to_library_groups:
309 yield ('library group', r)
310
311 def get_llvmbuild_fragment(self):
312 result = StringIO.StringIO()
313 print >>result, 'type = %s' % self.type_name
314 print >>result, 'name = %s' % self.name
315 print >>result, 'parent = %s' % self.parent
316 if self.required_libraries:
317 print >>result, 'required_libraries = %s' % ' '.join(
318 self.required_libraries)
319 if self.add_to_library_groups:
320 print >>result, 'add_to_library_groups = %s' % ' '.join(
321 self.add_to_library_groups)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000322 for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
323 'has_jit'):
324 if getattr(self, bool_key):
325 print >>result, '%s = 1' % (bool_key,)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000326 return result.getvalue()
327
328 def get_llvmconfig_component_name(self):
329 return self.name.lower()
330
Daniel Dunbardf578252011-11-03 17:56:06 +0000331class ToolComponentInfo(ComponentInfo):
332 type_name = 'Tool'
333
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000334 @staticmethod
335 def parse(subpath, items):
336 kwargs = ComponentInfo.parse_items(items)
337 kwargs['required_libraries'] = items.get_list('required_libraries')
338 return ToolComponentInfo(subpath, **kwargs)
339
Daniel Dunbardf578252011-11-03 17:56:06 +0000340 def __init__(self, subpath, name, dependencies, parent,
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000341 required_libraries):
Daniel Dunbardf578252011-11-03 17:56:06 +0000342 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
343
344 # The names of the library components which are required to link this
345 # tool.
346 self.required_libraries = list(required_libraries)
347
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000348 def get_component_references(self):
349 for r in ComponentInfo.get_component_references(self):
350 yield r
351 for r in self.required_libraries:
352 yield ('required library', r)
353
Daniel Dunbar43120df2011-11-03 17:56:21 +0000354 def get_llvmbuild_fragment(self):
355 result = StringIO.StringIO()
356 print >>result, 'type = %s' % self.type_name
357 print >>result, 'name = %s' % self.name
358 print >>result, 'parent = %s' % self.parent
359 print >>result, 'required_libraries = %s' % ' '.join(
360 self.required_libraries)
361 return result.getvalue()
362
Daniel Dunbardf578252011-11-03 17:56:06 +0000363class BuildToolComponentInfo(ToolComponentInfo):
364 type_name = 'BuildTool'
365
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000366 @staticmethod
367 def parse(subpath, items):
368 kwargs = ComponentInfo.parse_items(items)
369 kwargs['required_libraries'] = items.get_list('required_libraries')
370 return BuildToolComponentInfo(subpath, **kwargs)
371
372###
373
374class IniFormatParser(dict):
375 def get_list(self, key):
376 # Check if the value is defined.
377 value = self.get(key)
378 if value is None:
379 return []
380
381 # Lists are just whitespace separated strings.
382 return value.split()
383
384 def get_optional_string(self, key):
385 value = self.get_list(key)
386 if not value:
387 return None
388 if len(value) > 1:
389 raise ParseError("multiple values for scalar key: %r" % key)
390 return value[0]
391
392 def get_string(self, key):
393 value = self.get_optional_string(key)
394 if not value:
395 raise ParseError("missing value for required string: %r" % key)
396 return value
397
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000398 def get_optional_bool(self, key, default = None):
399 value = self.get_optional_string(key)
400 if not value:
401 return default
402 if value not in ('0', '1'):
403 raise ParseError("invalid value(%r) for boolean property: %r" % (
404 value, key))
405 return bool(int(value))
406
407 def get_bool(self, key):
408 value = self.get_optional_bool(key)
409 if value is None:
410 raise ParseError("missing value for required boolean: %r" % key)
411 return value
412
Daniel Dunbardf578252011-11-03 17:56:06 +0000413_component_type_map = dict(
414 (t.type_name, t)
415 for t in (GroupComponentInfo,
416 LibraryComponentInfo, LibraryGroupComponentInfo,
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000417 ToolComponentInfo, BuildToolComponentInfo,
Preston Gurd75493542012-05-07 19:38:40 +0000418 TargetGroupComponentInfo, OptionalLibraryComponentInfo))
Daniel Dunbardf578252011-11-03 17:56:06 +0000419def load_from_path(path, subpath):
420 # Load the LLVMBuild.txt file as an .ini format file.
421 parser = ConfigParser.RawConfigParser()
422 parser.read(path)
423
Daniel Dunbare5609ab2011-12-12 22:45:59 +0000424 # Extract the common section.
425 if parser.has_section("common"):
426 common = IniFormatParser(parser.items("common"))
427 parser.remove_section("common")
428 else:
429 common = IniFormatParser({})
430
431 return common, _read_components_from_parser(parser, path, subpath)
432
433def _read_components_from_parser(parser, path, subpath):
Daniel Dunbardf578252011-11-03 17:56:06 +0000434 # We load each section which starts with 'component' as a distinct component
435 # description (so multiple components can be described in one file).
436 for section in parser.sections():
437 if not section.startswith('component'):
438 # We don't expect arbitrary sections currently, warn the user.
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000439 warning("ignoring unknown section %r in %r" % (section, path))
Daniel Dunbardf578252011-11-03 17:56:06 +0000440 continue
441
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000442 # Determine the type of the component to instantiate.
Daniel Dunbardf578252011-11-03 17:56:06 +0000443 if not parser.has_option(section, 'type'):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000444 fatal("invalid component %r in %r: %s" % (
445 section, path, "no component type"))
Daniel Dunbardf578252011-11-03 17:56:06 +0000446
447 type_name = parser.get(section, 'type')
448 type_class = _component_type_map.get(type_name)
449 if type_class is None:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000450 fatal("invalid component %r in %r: %s" % (
451 section, path, "invalid component type: %r" % type_name))
Daniel Dunbardf578252011-11-03 17:56:06 +0000452
453 # Instantiate the component based on the remaining values.
454 try:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000455 info = type_class.parse(subpath,
456 IniFormatParser(parser.items(section)))
Daniel Dunbardf578252011-11-03 17:56:06 +0000457 except TypeError:
458 print >>sys.stderr, "error: invalid component %r in %r: %s" % (
459 section, path, "unable to instantiate: %r" % type_name)
460 import traceback
461 traceback.print_exc()
462 raise SystemExit, 1
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000463 except ParseError,e:
464 fatal("unable to load component %r in %r: %s" % (
465 section, path, e.message))
Daniel Dunbardf578252011-11-03 17:56:06 +0000466
Daniel Dunbara3217162011-12-12 22:45:35 +0000467 info._source_path = path
Daniel Dunbardf578252011-11-03 17:56:06 +0000468 yield info