gn build: Merge r372706
[llvm-complete.git] / utils / llvm-build / llvmbuild / componentinfo.py
blob0e9d08915fba9b9f137620d9d6a1eee70efe0625
1 """
2 Descriptor objects for entities that are part of the LLVM project.
3 """
5 from __future__ import absolute_import, print_function
6 try:
7 import configparser
8 except:
9 import ConfigParser as configparser
10 import sys
12 from llvmbuild.util import fatal, warning
14 class ParseError(Exception):
15 pass
17 class ComponentInfo(object):
18 """
19 Base class for component descriptions.
20 """
22 type_name = None
24 @staticmethod
25 def parse_items(items, has_dependencies = True):
26 kwargs = {}
27 kwargs['name'] = items.get_string('name')
28 kwargs['parent'] = items.get_optional_string('parent')
29 if has_dependencies:
30 kwargs['dependencies'] = items.get_list('dependencies')
31 return kwargs
33 def __init__(self, subpath, name, dependencies, parent):
34 if not subpath.startswith('/'):
35 raise ValueError("invalid subpath: %r" % subpath)
36 self.subpath = subpath
37 self.name = name
38 self.dependencies = list(dependencies)
40 # The name of the parent component to logically group this component
41 # under.
42 self.parent = parent
44 # The parent instance, once loaded.
45 self.parent_instance = None
46 self.children = []
48 # The original source path.
49 self._source_path = None
51 # A flag to mark "special" components which have some amount of magic
52 # handling (generally based on command line options).
53 self._is_special_group = False
55 def set_parent_instance(self, parent):
56 assert parent.name == self.parent, "Unexpected parent!"
57 self.parent_instance = parent
58 self.parent_instance.children.append(self)
60 def get_component_references(self):
61 """get_component_references() -> iter
63 Return an iterator over the named references to other components from
64 this object. Items are of the form (reference-type, component-name).
65 """
67 # Parent references are handled specially.
68 for r in self.dependencies:
69 yield ('dependency', r)
71 def get_llvmbuild_fragment(self):
72 abstract
74 def get_parent_target_group(self):
75 """get_parent_target_group() -> ComponentInfo or None
77 Return the nearest parent target group (if any), or None if the
78 component is not part of any target group.
79 """
81 # If this is a target group, return it.
82 if self.type_name == 'TargetGroup':
83 return self
85 # Otherwise recurse on the parent, if any.
86 if self.parent_instance:
87 return self.parent_instance.get_parent_target_group()
89 class GroupComponentInfo(ComponentInfo):
90 """
91 Group components have no semantics as far as the build system are concerned,
92 but exist to help organize other components into a logical tree structure.
93 """
95 type_name = 'Group'
97 @staticmethod
98 def parse(subpath, items):
99 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
100 return GroupComponentInfo(subpath, **kwargs)
102 def __init__(self, subpath, name, parent):
103 ComponentInfo.__init__(self, subpath, name, [], parent)
105 def get_llvmbuild_fragment(self):
106 return """\
107 type = %s
108 name = %s
109 parent = %s
110 """ % (self.type_name, self.name, self.parent)
112 class LibraryComponentInfo(ComponentInfo):
113 type_name = 'Library'
115 @staticmethod
116 def parse_items(items):
117 kwargs = ComponentInfo.parse_items(items)
118 kwargs['library_name'] = items.get_optional_string('library_name')
119 kwargs['required_libraries'] = items.get_list('required_libraries')
120 kwargs['add_to_library_groups'] = items.get_list(
121 'add_to_library_groups')
122 kwargs['installed'] = items.get_optional_bool('installed', True)
123 return kwargs
125 @staticmethod
126 def parse(subpath, items):
127 kwargs = LibraryComponentInfo.parse_items(items)
128 return LibraryComponentInfo(subpath, **kwargs)
130 def __init__(self, subpath, name, dependencies, parent, library_name,
131 required_libraries, add_to_library_groups, installed):
132 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
134 # If given, the name to use for the library instead of deriving it from
135 # the component name.
136 self.library_name = library_name
138 # The names of the library components which are required when linking
139 # with this component.
140 self.required_libraries = list(required_libraries)
142 # The names of the library group components this component should be
143 # considered part of.
144 self.add_to_library_groups = list(add_to_library_groups)
146 # Whether or not this library is installed.
147 self.installed = installed
149 def get_component_references(self):
150 for r in ComponentInfo.get_component_references(self):
151 yield r
152 for r in self.required_libraries:
153 yield ('required library', r)
154 for r in self.add_to_library_groups:
155 yield ('library group', r)
157 def get_llvmbuild_fragment(self):
158 result = """\
159 type = %s
160 name = %s
161 parent = %s
162 """ % (self.type_name, self.name, self.parent)
163 if self.library_name is not None:
164 result += 'library_name = %s\n' % self.library_name
165 if self.required_libraries:
166 result += 'required_libraries = %s\n' % ' '.join(
167 self.required_libraries)
168 if self.add_to_library_groups:
169 result += 'add_to_library_groups = %s\n' % ' '.join(
170 self.add_to_library_groups)
171 if not self.installed:
172 result += 'installed = 0\n'
173 return result
175 def get_library_name(self):
176 return self.library_name or self.name
178 def get_prefixed_library_name(self):
180 get_prefixed_library_name() -> str
182 Return the library name prefixed by the project name. This is generally
183 what the library name will be on disk.
186 basename = self.get_library_name()
188 # FIXME: We need to get the prefix information from an explicit project
189 # object, or something.
190 if basename in ('gtest', 'gtest_main'):
191 return basename
193 return 'LLVM%s' % basename
195 def get_llvmconfig_component_name(self):
196 return self.get_library_name().lower()
198 class OptionalLibraryComponentInfo(LibraryComponentInfo):
199 type_name = "OptionalLibrary"
201 @staticmethod
202 def parse(subpath, items):
203 kwargs = LibraryComponentInfo.parse_items(items)
204 return OptionalLibraryComponentInfo(subpath, **kwargs)
206 def __init__(self, subpath, name, dependencies, parent, library_name,
207 required_libraries, add_to_library_groups, installed):
208 LibraryComponentInfo.__init__(self, subpath, name, dependencies, parent,
209 library_name, required_libraries,
210 add_to_library_groups, installed)
212 class LibraryGroupComponentInfo(ComponentInfo):
213 type_name = 'LibraryGroup'
215 @staticmethod
216 def parse(subpath, items):
217 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
218 kwargs['required_libraries'] = items.get_list('required_libraries')
219 kwargs['add_to_library_groups'] = items.get_list(
220 'add_to_library_groups')
221 return LibraryGroupComponentInfo(subpath, **kwargs)
223 def __init__(self, subpath, name, parent, required_libraries = [],
224 add_to_library_groups = []):
225 ComponentInfo.__init__(self, subpath, name, [], parent)
227 # The names of the library components which are required when linking
228 # with this component.
229 self.required_libraries = list(required_libraries)
231 # The names of the library group components this component should be
232 # considered part of.
233 self.add_to_library_groups = list(add_to_library_groups)
235 def get_component_references(self):
236 for r in ComponentInfo.get_component_references(self):
237 yield r
238 for r in self.required_libraries:
239 yield ('required library', r)
240 for r in self.add_to_library_groups:
241 yield ('library group', r)
243 def get_llvmbuild_fragment(self):
244 result = """\
245 type = %s
246 name = %s
247 parent = %s
248 """ % (self.type_name, self.name, self.parent)
249 if self.required_libraries and not self._is_special_group:
250 result += 'required_libraries = %s\n' % ' '.join(
251 self.required_libraries)
252 if self.add_to_library_groups:
253 result += 'add_to_library_groups = %s\n' % ' '.join(
254 self.add_to_library_groups)
255 return result
257 def get_llvmconfig_component_name(self):
258 return self.name.lower()
260 class TargetGroupComponentInfo(ComponentInfo):
261 type_name = 'TargetGroup'
263 @staticmethod
264 def parse(subpath, items):
265 kwargs = ComponentInfo.parse_items(items, has_dependencies = False)
266 kwargs['required_libraries'] = items.get_list('required_libraries')
267 kwargs['add_to_library_groups'] = items.get_list(
268 'add_to_library_groups')
269 kwargs['has_jit'] = items.get_optional_bool('has_jit', False)
270 kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter',
271 False)
272 kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser',
273 False)
274 kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler',
275 False)
276 return TargetGroupComponentInfo(subpath, **kwargs)
278 def __init__(self, subpath, name, parent, required_libraries = [],
279 add_to_library_groups = [], has_jit = False,
280 has_asmprinter = False, has_asmparser = False,
281 has_disassembler = False):
282 ComponentInfo.__init__(self, subpath, name, [], parent)
284 # The names of the library components which are required when linking
285 # with this component.
286 self.required_libraries = list(required_libraries)
288 # The names of the library group components this component should be
289 # considered part of.
290 self.add_to_library_groups = list(add_to_library_groups)
292 # Whether or not this target supports the JIT.
293 self.has_jit = bool(has_jit)
295 # Whether or not this target defines an assembly printer.
296 self.has_asmprinter = bool(has_asmprinter)
298 # Whether or not this target defines an assembly parser.
299 self.has_asmparser = bool(has_asmparser)
301 # Whether or not this target defines an disassembler.
302 self.has_disassembler = bool(has_disassembler)
304 # Whether or not this target is enabled. This is set in response to
305 # configuration parameters.
306 self.enabled = False
308 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 for r in self.add_to_library_groups:
314 yield ('library group', r)
316 def get_llvmbuild_fragment(self):
317 result = """\
318 type = %s
319 name = %s
320 parent = %s
321 """ % (self.type_name, self.name, self.parent)
322 if self.required_libraries:
323 result += 'required_libraries = %s\n' % ' '.join(
324 self.required_libraries)
325 if self.add_to_library_groups:
326 result += 'add_to_library_groups = %s\n' % ' '.join(
327 self.add_to_library_groups)
328 for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
329 'has_jit'):
330 if getattr(self, bool_key):
331 result += '%s = 1\n' % (bool_key,)
332 return result
334 def get_llvmconfig_component_name(self):
335 return self.name.lower()
337 class ToolComponentInfo(ComponentInfo):
338 type_name = 'Tool'
340 @staticmethod
341 def parse(subpath, items):
342 kwargs = ComponentInfo.parse_items(items)
343 kwargs['required_libraries'] = items.get_list('required_libraries')
344 return ToolComponentInfo(subpath, **kwargs)
346 def __init__(self, subpath, name, dependencies, parent,
347 required_libraries):
348 ComponentInfo.__init__(self, subpath, name, dependencies, parent)
350 # The names of the library components which are required to link this
351 # tool.
352 self.required_libraries = list(required_libraries)
354 def get_component_references(self):
355 for r in ComponentInfo.get_component_references(self):
356 yield r
357 for r in self.required_libraries:
358 yield ('required library', r)
360 def get_llvmbuild_fragment(self):
361 return """\
362 type = %s
363 name = %s
364 parent = %s
365 required_libraries = %s
366 """ % (self.type_name, self.name, self.parent,
367 ' '.join(self.required_libraries))
369 class BuildToolComponentInfo(ToolComponentInfo):
370 type_name = 'BuildTool'
372 @staticmethod
373 def parse(subpath, items):
374 kwargs = ComponentInfo.parse_items(items)
375 kwargs['required_libraries'] = items.get_list('required_libraries')
376 return BuildToolComponentInfo(subpath, **kwargs)
380 class IniFormatParser(dict):
381 def get_list(self, key):
382 # Check if the value is defined.
383 value = self.get(key)
384 if value is None:
385 return []
387 # Lists are just whitespace separated strings.
388 return value.split()
390 def get_optional_string(self, key):
391 value = self.get_list(key)
392 if not value:
393 return None
394 if len(value) > 1:
395 raise ParseError("multiple values for scalar key: %r" % key)
396 return value[0]
398 def get_string(self, key):
399 value = self.get_optional_string(key)
400 if not value:
401 raise ParseError("missing value for required string: %r" % key)
402 return value
404 def get_optional_bool(self, key, default = None):
405 value = self.get_optional_string(key)
406 if not value:
407 return default
408 if value not in ('0', '1'):
409 raise ParseError("invalid value(%r) for boolean property: %r" % (
410 value, key))
411 return bool(int(value))
413 def get_bool(self, key):
414 value = self.get_optional_bool(key)
415 if value is None:
416 raise ParseError("missing value for required boolean: %r" % key)
417 return value
419 _component_type_map = dict(
420 (t.type_name, t)
421 for t in (GroupComponentInfo,
422 LibraryComponentInfo, LibraryGroupComponentInfo,
423 ToolComponentInfo, BuildToolComponentInfo,
424 TargetGroupComponentInfo, OptionalLibraryComponentInfo))
425 def load_from_path(path, subpath):
426 # Load the LLVMBuild.txt file as an .ini format file.
427 parser = configparser.RawConfigParser()
428 parser.read(path)
430 # Extract the common section.
431 if parser.has_section("common"):
432 common = IniFormatParser(parser.items("common"))
433 parser.remove_section("common")
434 else:
435 common = IniFormatParser({})
437 return common, _read_components_from_parser(parser, path, subpath)
439 def _read_components_from_parser(parser, path, subpath):
440 # We load each section which starts with 'component' as a distinct component
441 # description (so multiple components can be described in one file).
442 for section in parser.sections():
443 if not section.startswith('component'):
444 # We don't expect arbitrary sections currently, warn the user.
445 warning("ignoring unknown section %r in %r" % (section, path))
446 continue
448 # Determine the type of the component to instantiate.
449 if not parser.has_option(section, 'type'):
450 fatal("invalid component %r in %r: %s" % (
451 section, path, "no component type"))
453 type_name = parser.get(section, 'type')
454 type_class = _component_type_map.get(type_name)
455 if type_class is None:
456 fatal("invalid component %r in %r: %s" % (
457 section, path, "invalid component type: %r" % type_name))
459 # Instantiate the component based on the remaining values.
460 try:
461 info = type_class.parse(subpath,
462 IniFormatParser(parser.items(section)))
463 except TypeError:
464 print("error: invalid component %r in %r: %s" % (
465 section, path, "unable to instantiate: %r" % type_name), file=sys.stderr)
466 import traceback
467 traceback.print_exc()
468 raise SystemExit(1)
469 except ParseError:
470 e = sys.exc_info()[1]
471 fatal("unable to load component %r in %r: %s" % (
472 section, path, e.message))
474 info._source_path = path
475 yield info