blob: 737b857dfbbafd17ffcf5941b442906d6eed50a9 [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
Preston Gurd75493542012-05-07 19:38:40 +000098 def parse_items(items):
Daniel Dunbar9da6b122011-11-03 17:56:10 +000099 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')
Preston Gurd75493542012-05-07 19:38:40 +0000104 return kwargs
105
106 @staticmethod
107 def parse(subpath, items):
108 kwargs = LibraryComponentInfo.parse_items(items)
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000109 return LibraryComponentInfo(subpath, **kwargs)
110
111 def __init__(self, subpath, name, dependencies, parent, library_name,
112 required_libraries, add_to_library_groups):
Daniel Dunbardf578252011-11-03 17:56:06 +0000113 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
114
115 # If given, the name to use for the library instead of deriving it from
116 # the component name.
117 self.library_name = library_name
118
119 # The names of the library components which are required when linking
120 # with this component.
121 self.required_libraries = list(required_libraries)
122
123 # The names of the library group components this component should be
124 # considered part of.
125 self.add_to_library_groups = list(add_to_library_groups)
126
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000127 def get_component_references(self):
128 for r in ComponentInfo.get_component_references(self):
129 yield r
130 for r in self.required_libraries:
131 yield ('required library', r)
132 for r in self.add_to_library_groups:
133 yield ('library group', r)
134
Daniel Dunbar43120df2011-11-03 17:56:21 +0000135 def get_llvmbuild_fragment(self):
136 result = StringIO.StringIO()
137 print >>result, 'type = %s' % self.type_name
138 print >>result, 'name = %s' % self.name
139 print >>result, 'parent = %s' % self.parent
140 if self.library_name is not None:
141 print >>result, 'library_name = %s' % self.library_name
142 if self.required_libraries:
143 print >>result, 'required_libraries = %s' % ' '.join(
144 self.required_libraries)
145 if self.add_to_library_groups:
146 print >>result, 'add_to_library_groups = %s' % ' '.join(
147 self.add_to_library_groups)
148 return result.getvalue()
149
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000150 def get_library_name(self):
151 return self.library_name or self.name
152
Daniel Dunbar5086de62011-11-29 00:06:50 +0000153 def get_prefixed_library_name(self):
154 """
155 get_prefixed_library_name() -> str
156
157 Return the library name prefixed by the project name. This is generally
158 what the library name will be on disk.
159 """
160
161 basename = self.get_library_name()
162
163 # FIXME: We need to get the prefix information from an explicit project
164 # object, or something.
165 if basename in ('gtest', 'gtest_main'):
166 return basename
167
168 return 'LLVM%s' % basename
169
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000170 def get_llvmconfig_component_name(self):
171 return self.get_library_name().lower()
172
Preston Gurd75493542012-05-07 19:38:40 +0000173class OptionalLibraryComponentInfo(LibraryComponentInfo):
174 type_name = "OptionalLibrary"
175
176 @staticmethod
177 def parse(subpath, items):
178 kwargs = LibraryComponentInfo.parse_items(items)
179 return OptionalLibraryComponentInfo(subpath, **kwargs)
180
181 def __init__(self, subpath, name, dependencies, parent, library_name,
182 required_libraries, add_to_library_groups):
183 LibraryComponentInfo.__init__(self, subpath, name, dependencies, parent,
184 library_name, required_libraries,
185 add_to_library_groups)
186
Daniel Dunbardf578252011-11-03 17:56:06 +0000187class LibraryGroupComponentInfo(ComponentInfo):
188 type_name = 'LibraryGroup'
189
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000190 @staticmethod
191 def parse(subpath, items):
192 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
193 kwargs['required_libraries'] = items.get_list('required_libraries')
194 kwargs['add_to_library_groups'] = items.get_list(
195 'add_to_library_groups')
196 return LibraryGroupComponentInfo(subpath, **kwargs)
197
Daniel Dunbardf578252011-11-03 17:56:06 +0000198 def __init__(self, subpath, name, parent, required_libraries = [],
199 add_to_library_groups = []):
200 ComponentInfo.__init__(self, subpath, name, [], parent)
201
202 # The names of the library components which are required when linking
203 # with this component.
204 self.required_libraries = list(required_libraries)
205
206 # The names of the library group components this component should be
207 # considered part of.
208 self.add_to_library_groups = list(add_to_library_groups)
209
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000210 def get_component_references(self):
211 for r in ComponentInfo.get_component_references(self):
212 yield r
213 for r in self.required_libraries:
214 yield ('required library', r)
215 for r in self.add_to_library_groups:
216 yield ('library group', r)
217
Daniel Dunbar43120df2011-11-03 17:56:21 +0000218 def get_llvmbuild_fragment(self):
219 result = StringIO.StringIO()
220 print >>result, 'type = %s' % self.type_name
221 print >>result, 'name = %s' % self.name
222 print >>result, 'parent = %s' % self.parent
Daniel Dunbar54d8c7f2011-12-12 22:45:41 +0000223 if self.required_libraries and not self._is_special_group:
Daniel Dunbar43120df2011-11-03 17:56:21 +0000224 print >>result, 'required_libraries = %s' % ' '.join(
225 self.required_libraries)
226 if self.add_to_library_groups:
227 print >>result, 'add_to_library_groups = %s' % ' '.join(
228 self.add_to_library_groups)
229 return result.getvalue()
230
Daniel Dunbarefe2f642011-11-03 17:56:28 +0000231 def get_llvmconfig_component_name(self):
232 return self.name.lower()
233
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000234class TargetGroupComponentInfo(ComponentInfo):
235 type_name = 'TargetGroup'
236
237 @staticmethod
238 def parse(subpath, items):
239 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
240 kwargs['required_libraries'] = items.get_list('required_libraries')
241 kwargs['add_to_library_groups'] = items.get_list(
242 'add_to_library_groups')
243 kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000244 kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
245 False)
246 kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
247 False)
248 kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
249 False)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000250 return TargetGroupComponentInfo(subpath, **kwargs)
251
252 def __init__(self, subpath, name, parent, required_libraries = [],
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000253 add_to_library_groups = [], has_jit = False,
254 has_asmprinter = False, has_asmparser = False,
255 has_disassembler = False):
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000256 ComponentInfo.__init__(self, subpath, name, [], parent)
257
258 # The names of the library components which are required when linking
259 # with this component.
260 self.required_libraries = list(required_libraries)
261
262 # The names of the library group components this component should be
263 # considered part of.
264 self.add_to_library_groups = list(add_to_library_groups)
265
266 # Whether or not this target supports the JIT.
267 self.has_jit = bool(has_jit)
268
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000269 # Whether or not this target defines an assembly printer.
270 self.has_asmprinter = bool(has_asmprinter)
271
272 # Whether or not this target defines an assembly parser.
273 self.has_asmparser = bool(has_asmparser)
274
275 # Whether or not this target defines an disassembler.
276 self.has_disassembler = bool(has_disassembler)
277
Daniel Dunbaraffc6cf2011-11-10 00:50:07 +0000278 # Whether or not this target is enabled. This is set in response to
279 # configuration parameters.
280 self.enabled = False
281
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000282 def get_component_references(self):
283 for r in ComponentInfo.get_component_references(self):
284 yield r
285 for r in self.required_libraries:
286 yield ('required library', r)
287 for r in self.add_to_library_groups:
288 yield ('library group', r)
289
290 def get_llvmbuild_fragment(self):
291 result = StringIO.StringIO()
292 print >>result, 'type = %s' % self.type_name
293 print >>result, 'name = %s' % self.name
294 print >>result, 'parent = %s' % self.parent
295 if self.required_libraries:
296 print >>result, 'required_libraries = %s' % ' '.join(
297 self.required_libraries)
298 if self.add_to_library_groups:
299 print >>result, 'add_to_library_groups = %s' % ' '.join(
300 self.add_to_library_groups)
Daniel Dunbar5ed55062011-11-11 00:23:56 +0000301 for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
302 'has_jit'):
303 if getattr(self, bool_key):
304 print >>result, '%s = 1' % (bool_key,)
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000305 return result.getvalue()
306
307 def get_llvmconfig_component_name(self):
308 return self.name.lower()
309
Daniel Dunbardf578252011-11-03 17:56:06 +0000310class ToolComponentInfo(ComponentInfo):
311 type_name = 'Tool'
312
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000313 @staticmethod
314 def parse(subpath, items):
315 kwargs = ComponentInfo.parse_items(items)
316 kwargs['required_libraries'] = items.get_list('required_libraries')
317 return ToolComponentInfo(subpath, **kwargs)
318
Daniel Dunbardf578252011-11-03 17:56:06 +0000319 def __init__(self, subpath, name, dependencies, parent,
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000320 required_libraries):
Daniel Dunbardf578252011-11-03 17:56:06 +0000321 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
322
323 # The names of the library components which are required to link this
324 # tool.
325 self.required_libraries = list(required_libraries)
326
Daniel Dunbar1cf14af2011-11-03 17:56:12 +0000327 def get_component_references(self):
328 for r in ComponentInfo.get_component_references(self):
329 yield r
330 for r in self.required_libraries:
331 yield ('required library', r)
332
Daniel Dunbar43120df2011-11-03 17:56:21 +0000333 def get_llvmbuild_fragment(self):
334 result = StringIO.StringIO()
335 print >>result, 'type = %s' % self.type_name
336 print >>result, 'name = %s' % self.name
337 print >>result, 'parent = %s' % self.parent
338 print >>result, 'required_libraries = %s' % ' '.join(
339 self.required_libraries)
340 return result.getvalue()
341
Daniel Dunbardf578252011-11-03 17:56:06 +0000342class BuildToolComponentInfo(ToolComponentInfo):
343 type_name = 'BuildTool'
344
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000345 @staticmethod
346 def parse(subpath, items):
347 kwargs = ComponentInfo.parse_items(items)
348 kwargs['required_libraries'] = items.get_list('required_libraries')
349 return BuildToolComponentInfo(subpath, **kwargs)
350
351###
352
353class IniFormatParser(dict):
354 def get_list(self, key):
355 # Check if the value is defined.
356 value = self.get(key)
357 if value is None:
358 return []
359
360 # Lists are just whitespace separated strings.
361 return value.split()
362
363 def get_optional_string(self, key):
364 value = self.get_list(key)
365 if not value:
366 return None
367 if len(value) > 1:
368 raise ParseError("multiple values for scalar key: %r" % key)
369 return value[0]
370
371 def get_string(self, key):
372 value = self.get_optional_string(key)
373 if not value:
374 raise ParseError("missing value for required string: %r" % key)
375 return value
376
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000377 def get_optional_bool(self, key, default = None):
378 value = self.get_optional_string(key)
379 if not value:
380 return default
381 if value not in ('0', '1'):
382 raise ParseError("invalid value(%r) for boolean property: %r" % (
383 value, key))
384 return bool(int(value))
385
386 def get_bool(self, key):
387 value = self.get_optional_bool(key)
388 if value is None:
389 raise ParseError("missing value for required boolean: %r" % key)
390 return value
391
Daniel Dunbardf578252011-11-03 17:56:06 +0000392_component_type_map = dict(
393 (t.type_name, t)
394 for t in (GroupComponentInfo,
395 LibraryComponentInfo, LibraryGroupComponentInfo,
Daniel Dunbarc352caf2011-11-10 00:49:51 +0000396 ToolComponentInfo, BuildToolComponentInfo,
Preston Gurd75493542012-05-07 19:38:40 +0000397 TargetGroupComponentInfo, OptionalLibraryComponentInfo))
Daniel Dunbardf578252011-11-03 17:56:06 +0000398def load_from_path(path, subpath):
399 # Load the LLVMBuild.txt file as an .ini format file.
400 parser = ConfigParser.RawConfigParser()
401 parser.read(path)
402
Daniel Dunbare5609ab2011-12-12 22:45:59 +0000403 # Extract the common section.
404 if parser.has_section("common"):
405 common = IniFormatParser(parser.items("common"))
406 parser.remove_section("common")
407 else:
408 common = IniFormatParser({})
409
410 return common, _read_components_from_parser(parser, path, subpath)
411
412def _read_components_from_parser(parser, path, subpath):
Daniel Dunbardf578252011-11-03 17:56:06 +0000413 # We load each section which starts with 'component' as a distinct component
414 # description (so multiple components can be described in one file).
415 for section in parser.sections():
416 if not section.startswith('component'):
417 # We don't expect arbitrary sections currently, warn the user.
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000418 warning("ignoring unknown section %r in %r" % (section, path))
Daniel Dunbardf578252011-11-03 17:56:06 +0000419 continue
420
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000421 # Determine the type of the component to instantiate.
Daniel Dunbardf578252011-11-03 17:56:06 +0000422 if not parser.has_option(section, 'type'):
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000423 fatal("invalid component %r in %r: %s" % (
424 section, path, "no component type"))
Daniel Dunbardf578252011-11-03 17:56:06 +0000425
426 type_name = parser.get(section, 'type')
427 type_class = _component_type_map.get(type_name)
428 if type_class is None:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000429 fatal("invalid component %r in %r: %s" % (
430 section, path, "invalid component type: %r" % type_name))
Daniel Dunbardf578252011-11-03 17:56:06 +0000431
432 # Instantiate the component based on the remaining values.
433 try:
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000434 info = type_class.parse(subpath,
435 IniFormatParser(parser.items(section)))
Daniel Dunbardf578252011-11-03 17:56:06 +0000436 except TypeError:
437 print >>sys.stderr, "error: invalid component %r in %r: %s" % (
438 section, path, "unable to instantiate: %r" % type_name)
439 import traceback
440 traceback.print_exc()
441 raise SystemExit, 1
Daniel Dunbar9da6b122011-11-03 17:56:10 +0000442 except ParseError,e:
443 fatal("unable to load component %r in %r: %s" % (
444 section, path, e.message))
Daniel Dunbardf578252011-11-03 17:56:06 +0000445
Daniel Dunbara3217162011-12-12 22:45:35 +0000446 info._source_path = path
Daniel Dunbardf578252011-11-03 17:56:06 +0000447 yield info