blob: c32cc1aeb0663cd7616e9b24fdb861f44bde2fa1 [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')
Preston Gurd75493542012-05-07 19:38:40 +0000119 return kwargs
120
121 @staticmethod
122 def parse(subpath, items):
123 kwargs = LibraryComponentInfo.parse_items(items)
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000124 return LibraryComponentInfo(subpath, **kwargs)
125
126 def __init__(self, subpath, name, dependencies, parent, library_name,
127 required_libraries, add_to_library_groups):
Daniel Dunbardf578252011-11-03 17:56:06 +0000128 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
129
130 # If given, the name to use for the library instead of deriving it from
131 # the component name.
132 self.library_name = library_name
133
134 # The names of the library components which are required when linking
135 # with this component.
136 self.required_libraries = list(required_libraries)
137
138 # The names of the library group components this component should be
139 # considered part of.
140 self.add_to_library_groups = list(add_to_library_groups)
141
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000142 def get_component_references(self):
143 for r in ComponentInfo.get_component_references(self):
144 yield r
145 for r in self.required_libraries:
146 yield ('required library', r)
147 for r in self.add_to_library_groups:
148 yield ('library group', r)
149
Daniel Dunbar43120df2011-11-03 17:56:21 +0000150 def get_llvmbuild_fragment(self):
151 result = StringIO.StringIO()
152 print >>result, 'type = %s' % self.type_name
153 print >>result, 'name = %s' % self.name
154 print >>result, 'parent = %s' % self.parent
155 if self.library_name is not None:
156 print >>result, 'library_name = %s' % self.library_name
157 if self.required_libraries:
158 print >>result, 'required_libraries = %s' % ' '.join(
159 self.required_libraries)
160 if self.add_to_library_groups:
161 print >>result, 'add_to_library_groups = %s' % ' '.join(
162 self.add_to_library_groups)
163 return result.getvalue()
164
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000165 def get_library_name(self):
166 return self.library_name or self.name
167
Daniel Dunbar5086de62011-11-29 00:06:50 +0000168 def get_prefixed_library_name(self):
169 """
170 get_prefixed_library_name() -> str
171
172 Return the library name prefixed by the project name. This is generally
173 what the library name will be on disk.
174 """
175
176 basename = self.get_library_name()
177
178 # FIXME: We need to get the prefix information from an explicit project
179 # object, or something.
180 if basename in ('gtest', 'gtest_main'):
181 return basename
182
183 return 'LLVM%s' % basename
184
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000185 def get_llvmconfig_component_name(self):
186 return self.get_library_name().lower()
187
Preston Gurd75493542012-05-07 19:38:40 +0000188class OptionalLibraryComponentInfo(LibraryComponentInfo):
189 type_name = "OptionalLibrary"
190
191 @staticmethod
192 def parse(subpath, items):
193 kwargs = LibraryComponentInfo.parse_items(items)
194 return OptionalLibraryComponentInfo(subpath, **kwargs)
195
196 def __init__(self, subpath, name, dependencies, parent, library_name,
197 required_libraries, add_to_library_groups):
198 LibraryComponentInfo.__init__(self, subpath, name, dependencies, parent,
199 library_name, required_libraries,
200 add_to_library_groups)
201
Daniel Dunbardf578252011-11-03 17:56:06 +0000202class LibraryGroupComponentInfo(ComponentInfo):
203 type_name = 'LibraryGroup'
204
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000205 @staticmethod
206 def parse(subpath, items):
207 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
208 kwargs['required_libraries'] = items.get_list('required_libraries')
209 kwargs['add_to_library_groups'] = items.get_list(
210 'add_to_library_groups')
211 return LibraryGroupComponentInfo(subpath, **kwargs)
212
Daniel Dunbardf578252011-11-03 17:56:06 +0000213 def __init__(self, subpath, name, parent, required_libraries = [],
214 add_to_library_groups = []):
215 ComponentInfo.__init__(self, subpath, name, [], parent)
216
217 # The names of the library components which are required when linking
218 # with this component.
219 self.required_libraries = list(required_libraries)
220
221 # The names of the library group components this component should be
222 # considered part of.
223 self.add_to_library_groups = list(add_to_library_groups)
224
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000225 def get_component_references(self):
226 for r in ComponentInfo.get_component_references(self):
227 yield r
228 for r in self.required_libraries:
229 yield ('required library', r)
230 for r in self.add_to_library_groups:
231 yield ('library group', r)
232
Daniel Dunbar43120df2011-11-03 17:56:21 +0000233 def get_llvmbuild_fragment(self):
234 result = StringIO.StringIO()
235 print >>result, 'type = %s' % self.type_name
236 print >>result, 'name = %s' % self.name
237 print >>result, 'parent = %s' % self.parent
Daniel Dunbar54d8c7f2011-12-12 22:45:41 +0000238 if self.required_libraries and not self._is_special_group:
Daniel Dunbar43120df2011-11-03 17:56:21 +0000239 print >>result, 'required_libraries = %s' % ' '.join(
240 self.required_libraries)
241 if self.add_to_library_groups:
242 print >>result, 'add_to_library_groups = %s' % ' '.join(
243 self.add_to_library_groups)
244 return result.getvalue()
245
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000246 def get_llvmconfig_component_name(self):
247 return self.name.lower()
248
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000249class TargetGroupComponentInfo(ComponentInfo):
250 type_name = 'TargetGroup'
251
252 @staticmethod
253 def parse(subpath, items):
254 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
255 kwargs['required_libraries'] = items.get_list('required_libraries')
256 kwargs['add_to_library_groups'] = items.get_list(
257 'add_to_library_groups')
258 kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000259 kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
260 False)
261 kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
262 False)
263 kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
264 False)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000265 return TargetGroupComponentInfo(subpath, **kwargs)
266
267 def __init__(self, subpath, name, parent, required_libraries = [],
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000268 add_to_library_groups = [], has_jit = False,
269 has_asmprinter = False, has_asmparser = False,
270 has_disassembler = False):
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000271 ComponentInfo.__init__(self, subpath, name, [], parent)
272
273 # The names of the library components which are required when linking
274 # with this component.
275 self.required_libraries = list(required_libraries)
276
277 # The names of the library group components this component should be
278 # considered part of.
279 self.add_to_library_groups = list(add_to_library_groups)
280
281 # Whether or not this target supports the JIT.
282 self.has_jit = bool(has_jit)
283
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000284 # Whether or not this target defines an assembly printer.
285 self.has_asmprinter = bool(has_asmprinter)
286
287 # Whether or not this target defines an assembly parser.
288 self.has_asmparser = bool(has_asmparser)
289
290 # Whether or not this target defines an disassembler.
291 self.has_disassembler = bool(has_disassembler)
292
Daniel Dunbaraffc6cf2011-11-10 00:50:07 +0000293 # Whether or not this target is enabled. This is set in response to
294 # configuration parameters.
295 self.enabled = False
296
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000297 def get_component_references(self):
298 for r in ComponentInfo.get_component_references(self):
299 yield r
300 for r in self.required_libraries:
301 yield ('required library', r)
302 for r in self.add_to_library_groups:
303 yield ('library group', r)
304
305 def get_llvmbuild_fragment(self):
306 result = StringIO.StringIO()
307 print >>result, 'type = %s' % self.type_name
308 print >>result, 'name = %s' % self.name
309 print >>result, 'parent = %s' % self.parent
310 if self.required_libraries:
311 print >>result, 'required_libraries = %s' % ' '.join(
312 self.required_libraries)
313 if self.add_to_library_groups:
314 print >>result, 'add_to_library_groups = %s' % ' '.join(
315 self.add_to_library_groups)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000316 for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
317 'has_jit'):
318 if getattr(self, bool_key):
319 print >>result, '%s = 1' % (bool_key,)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000320 return result.getvalue()
321
322 def get_llvmconfig_component_name(self):
323 return self.name.lower()
324
Daniel Dunbardf578252011-11-03 17:56:06 +0000325class ToolComponentInfo(ComponentInfo):
326 type_name = 'Tool'
327
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000328 @staticmethod
329 def parse(subpath, items):
330 kwargs = ComponentInfo.parse_items(items)
331 kwargs['required_libraries'] = items.get_list('required_libraries')
332 return ToolComponentInfo(subpath, **kwargs)
333
Daniel Dunbardf578252011-11-03 17:56:06 +0000334 def __init__(self, subpath, name, dependencies, parent,
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000335 required_libraries):
Daniel Dunbardf578252011-11-03 17:56:06 +0000336 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
337
338 # The names of the library components which are required to link this
339 # tool.
340 self.required_libraries = list(required_libraries)
341
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000342 def get_component_references(self):
343 for r in ComponentInfo.get_component_references(self):
344 yield r
345 for r in self.required_libraries:
346 yield ('required library', r)
347
Daniel Dunbar43120df2011-11-03 17:56:21 +0000348 def get_llvmbuild_fragment(self):
349 result = StringIO.StringIO()
350 print >>result, 'type = %s' % self.type_name
351 print >>result, 'name = %s' % self.name
352 print >>result, 'parent = %s' % self.parent
353 print >>result, 'required_libraries = %s' % ' '.join(
354 self.required_libraries)
355 return result.getvalue()
356
Daniel Dunbardf578252011-11-03 17:56:06 +0000357class BuildToolComponentInfo(ToolComponentInfo):
358 type_name = 'BuildTool'
359
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000360 @staticmethod
361 def parse(subpath, items):
362 kwargs = ComponentInfo.parse_items(items)
363 kwargs['required_libraries'] = items.get_list('required_libraries')
364 return BuildToolComponentInfo(subpath, **kwargs)
365
366###
367
368class IniFormatParser(dict):
369 def get_list(self, key):
370 # Check if the value is defined.
371 value = self.get(key)
372 if value is None:
373 return []
374
375 # Lists are just whitespace separated strings.
376 return value.split()
377
378 def get_optional_string(self, key):
379 value = self.get_list(key)
380 if not value:
381 return None
382 if len(value) > 1:
383 raise ParseError("multiple values for scalar key: %r" % key)
384 return value[0]
385
386 def get_string(self, key):
387 value = self.get_optional_string(key)
388 if not value:
389 raise ParseError("missing value for required string: %r" % key)
390 return value
391
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000392 def get_optional_bool(self, key, default = None):
393 value = self.get_optional_string(key)
394 if not value:
395 return default
396 if value not in ('0', '1'):
397 raise ParseError("invalid value(%r) for boolean property: %r" % (
398 value, key))
399 return bool(int(value))
400
401 def get_bool(self, key):
402 value = self.get_optional_bool(key)
403 if value is None:
404 raise ParseError("missing value for required boolean: %r" % key)
405 return value
406
Daniel Dunbardf578252011-11-03 17:56:06 +0000407_component_type_map = dict(
408 (t.type_name, t)
409 for t in (GroupComponentInfo,
410 LibraryComponentInfo, LibraryGroupComponentInfo,
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000411 ToolComponentInfo, BuildToolComponentInfo,
Preston Gurd75493542012-05-07 19:38:40 +0000412 TargetGroupComponentInfo, OptionalLibraryComponentInfo))
Daniel Dunbardf578252011-11-03 17:56:06 +0000413def load_from_path(path, subpath):
414 # Load the LLVMBuild.txt file as an .ini format file.
415 parser = ConfigParser.RawConfigParser()
416 parser.read(path)
417
Daniel Dunbare5609ab2011-12-12 22:45:59 +0000418 # Extract the common section.
419 if parser.has_section("common"):
420 common = IniFormatParser(parser.items("common"))
421 parser.remove_section("common")
422 else:
423 common = IniFormatParser({})
424
425 return common, _read_components_from_parser(parser, path, subpath)
426
427def _read_components_from_parser(parser, path, subpath):
Daniel Dunbardf578252011-11-03 17:56:06 +0000428 # We load each section which starts with 'component' as a distinct component
429 # description (so multiple components can be described in one file).
430 for section in parser.sections():
431 if not section.startswith('component'):
432 # We don't expect arbitrary sections currently, warn the user.
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000433 warning("ignoring unknown section %r in %r" % (section, path))
Daniel Dunbardf578252011-11-03 17:56:06 +0000434 continue
435
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000436 # Determine the type of the component to instantiate.
Daniel Dunbardf578252011-11-03 17:56:06 +0000437 if not parser.has_option(section, 'type'):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000438 fatal("invalid component %r in %r: %s" % (
439 section, path, "no component type"))
Daniel Dunbardf578252011-11-03 17:56:06 +0000440
441 type_name = parser.get(section, 'type')
442 type_class = _component_type_map.get(type_name)
443 if type_class is None:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000444 fatal("invalid component %r in %r: %s" % (
445 section, path, "invalid component type: %r" % type_name))
Daniel Dunbardf578252011-11-03 17:56:06 +0000446
447 # Instantiate the component based on the remaining values.
448 try:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000449 info = type_class.parse(subpath,
450 IniFormatParser(parser.items(section)))
Daniel Dunbardf578252011-11-03 17:56:06 +0000451 except TypeError:
452 print >>sys.stderr, "error: invalid component %r in %r: %s" % (
453 section, path, "unable to instantiate: %r" % type_name)
454 import traceback
455 traceback.print_exc()
456 raise SystemExit, 1
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000457 except ParseError,e:
458 fatal("unable to load component %r in %r: %s" % (
459 section, path, e.message))
Daniel Dunbardf578252011-11-03 17:56:06 +0000460
Daniel Dunbara3217162011-12-12 22:45:35 +0000461 info._source_path = path
Daniel Dunbardf578252011-11-03 17:56:06 +0000462 yield info