|  | """ | 
|  | Descriptor objects for entities that are part of the LLVM project. | 
|  | """ | 
|  |  | 
|  | from __future__ import absolute_import, print_function | 
|  | try: | 
|  | import configparser | 
|  | except: | 
|  | import ConfigParser as configparser | 
|  | import sys | 
|  |  | 
|  | from llvmbuild.util import fatal, warning | 
|  |  | 
|  | class ParseError(Exception): | 
|  | pass | 
|  |  | 
|  | class ComponentInfo(object): | 
|  | """ | 
|  | Base class for component descriptions. | 
|  | """ | 
|  |  | 
|  | type_name = None | 
|  |  | 
|  | @staticmethod | 
|  | def parse_items(items, has_dependencies = True): | 
|  | kwargs = {} | 
|  | kwargs['name'] = items.get_string('name') | 
|  | kwargs['parent'] = items.get_optional_string('parent') | 
|  | if has_dependencies: | 
|  | kwargs['dependencies'] = items.get_list('dependencies') | 
|  | return kwargs | 
|  |  | 
|  | def __init__(self, subpath, name, dependencies, parent): | 
|  | if not subpath.startswith('/'): | 
|  | raise ValueError("invalid subpath: %r" % subpath) | 
|  | self.subpath = subpath | 
|  | self.name = name | 
|  | self.dependencies = list(dependencies) | 
|  |  | 
|  | # The name of the parent component to logically group this component | 
|  | # under. | 
|  | self.parent = parent | 
|  |  | 
|  | # The parent instance, once loaded. | 
|  | self.parent_instance = None | 
|  | self.children = [] | 
|  |  | 
|  | # The original source path. | 
|  | self._source_path = None | 
|  |  | 
|  | # A flag to mark "special" components which have some amount of magic | 
|  | # handling (generally based on command line options). | 
|  | self._is_special_group = False | 
|  |  | 
|  | def set_parent_instance(self, parent): | 
|  | assert parent.name == self.parent, "Unexpected parent!" | 
|  | self.parent_instance = parent | 
|  | self.parent_instance.children.append(self) | 
|  |  | 
|  | def get_component_references(self): | 
|  | """get_component_references() -> iter | 
|  |  | 
|  | Return an iterator over the named references to other components from | 
|  | this object. Items are of the form (reference-type, component-name). | 
|  | """ | 
|  |  | 
|  | # Parent references are handled specially. | 
|  | for r in self.dependencies: | 
|  | yield ('dependency', r) | 
|  |  | 
|  | def get_llvmbuild_fragment(self): | 
|  | abstract | 
|  |  | 
|  | def get_parent_target_group(self): | 
|  | """get_parent_target_group() -> ComponentInfo or None | 
|  |  | 
|  | Return the nearest parent target group (if any), or None if the | 
|  | component is not part of any target group. | 
|  | """ | 
|  |  | 
|  | # If this is a target group, return it. | 
|  | if self.type_name == 'TargetGroup': | 
|  | return self | 
|  |  | 
|  | # Otherwise recurse on the parent, if any. | 
|  | if self.parent_instance: | 
|  | return self.parent_instance.get_parent_target_group() | 
|  |  | 
|  | class GroupComponentInfo(ComponentInfo): | 
|  | """ | 
|  | Group components have no semantics as far as the build system are concerned, | 
|  | but exist to help organize other components into a logical tree structure. | 
|  | """ | 
|  |  | 
|  | type_name = 'Group' | 
|  |  | 
|  | @staticmethod | 
|  | def parse(subpath, items): | 
|  | kwargs = ComponentInfo.parse_items(items, has_dependencies = False) | 
|  | return GroupComponentInfo(subpath, **kwargs) | 
|  |  | 
|  | def __init__(self, subpath, name, parent): | 
|  | ComponentInfo.__init__(self, subpath, name, [], parent) | 
|  |  | 
|  | def get_llvmbuild_fragment(self): | 
|  | return """\ | 
|  | type = %s | 
|  | name = %s | 
|  | parent = %s | 
|  | """ % (self.type_name, self.name, self.parent) | 
|  |  | 
|  | class LibraryComponentInfo(ComponentInfo): | 
|  | type_name = 'Library' | 
|  |  | 
|  | @staticmethod | 
|  | def parse_items(items): | 
|  | kwargs = ComponentInfo.parse_items(items) | 
|  | kwargs['library_name'] = items.get_optional_string('library_name') | 
|  | kwargs['required_libraries'] = items.get_list('required_libraries') | 
|  | kwargs['add_to_library_groups'] = items.get_list( | 
|  | 'add_to_library_groups') | 
|  | kwargs['installed'] = items.get_optional_bool('installed', True) | 
|  | return kwargs | 
|  |  | 
|  | @staticmethod | 
|  | def parse(subpath, items): | 
|  | kwargs = LibraryComponentInfo.parse_items(items) | 
|  | return LibraryComponentInfo(subpath, **kwargs) | 
|  |  | 
|  | def __init__(self, subpath, name, dependencies, parent, library_name, | 
|  | required_libraries, add_to_library_groups, installed): | 
|  | ComponentInfo.__init__(self, subpath, name, dependencies, parent) | 
|  |  | 
|  | # If given, the name to use for the library instead of deriving it from | 
|  | # the component name. | 
|  | self.library_name = library_name | 
|  |  | 
|  | # The names of the library components which are required when linking | 
|  | # with this component. | 
|  | self.required_libraries = list(required_libraries) | 
|  |  | 
|  | # The names of the library group components this component should be | 
|  | # considered part of. | 
|  | self.add_to_library_groups = list(add_to_library_groups) | 
|  |  | 
|  | # Whether or not this library is installed. | 
|  | self.installed = installed | 
|  |  | 
|  | def get_component_references(self): | 
|  | for r in ComponentInfo.get_component_references(self): | 
|  | yield r | 
|  | for r in self.required_libraries: | 
|  | yield ('required library', r) | 
|  | for r in self.add_to_library_groups: | 
|  | yield ('library group', r) | 
|  |  | 
|  | def get_llvmbuild_fragment(self): | 
|  | result = """\ | 
|  | type = %s | 
|  | name = %s | 
|  | parent = %s | 
|  | """ % (self.type_name, self.name, self.parent) | 
|  | if self.library_name is not None: | 
|  | result += 'library_name = %s\n' % self.library_name | 
|  | if self.required_libraries: | 
|  | result += 'required_libraries = %s\n' % ' '.join( | 
|  | self.required_libraries) | 
|  | if self.add_to_library_groups: | 
|  | result += 'add_to_library_groups = %s\n' % ' '.join( | 
|  | self.add_to_library_groups) | 
|  | if not self.installed: | 
|  | result += 'installed = 0\n' | 
|  | return result | 
|  |  | 
|  | def get_library_name(self): | 
|  | return self.library_name or self.name | 
|  |  | 
|  | def get_prefixed_library_name(self): | 
|  | """ | 
|  | get_prefixed_library_name() -> str | 
|  |  | 
|  | Return the library name prefixed by the project name. This is generally | 
|  | what the library name will be on disk. | 
|  | """ | 
|  |  | 
|  | basename = self.get_library_name() | 
|  |  | 
|  | # FIXME: We need to get the prefix information from an explicit project | 
|  | # object, or something. | 
|  | if basename in ('gtest', 'gtest_main'): | 
|  | return basename | 
|  |  | 
|  | return 'LLVM%s' % basename | 
|  |  | 
|  | def get_llvmconfig_component_name(self): | 
|  | return self.get_library_name().lower() | 
|  |  | 
|  | class OptionalLibraryComponentInfo(LibraryComponentInfo): | 
|  | type_name = "OptionalLibrary" | 
|  |  | 
|  | @staticmethod | 
|  | def parse(subpath, items): | 
|  | kwargs = LibraryComponentInfo.parse_items(items) | 
|  | return OptionalLibraryComponentInfo(subpath, **kwargs) | 
|  |  | 
|  | def __init__(self, subpath, name, dependencies, parent, library_name, | 
|  | required_libraries, add_to_library_groups, installed): | 
|  | LibraryComponentInfo.__init__(self, subpath, name, dependencies, parent, | 
|  | library_name, required_libraries, | 
|  | add_to_library_groups, installed) | 
|  |  | 
|  | class LibraryGroupComponentInfo(ComponentInfo): | 
|  | type_name = 'LibraryGroup' | 
|  |  | 
|  | @staticmethod | 
|  | def parse(subpath, items): | 
|  | kwargs = ComponentInfo.parse_items(items, has_dependencies = False) | 
|  | kwargs['required_libraries'] = items.get_list('required_libraries') | 
|  | kwargs['add_to_library_groups'] = items.get_list( | 
|  | 'add_to_library_groups') | 
|  | return LibraryGroupComponentInfo(subpath, **kwargs) | 
|  |  | 
|  | def __init__(self, subpath, name, parent, required_libraries = [], | 
|  | add_to_library_groups = []): | 
|  | ComponentInfo.__init__(self, subpath, name, [], parent) | 
|  |  | 
|  | # The names of the library components which are required when linking | 
|  | # with this component. | 
|  | self.required_libraries = list(required_libraries) | 
|  |  | 
|  | # The names of the library group components this component should be | 
|  | # considered part of. | 
|  | self.add_to_library_groups = list(add_to_library_groups) | 
|  |  | 
|  | def get_component_references(self): | 
|  | for r in ComponentInfo.get_component_references(self): | 
|  | yield r | 
|  | for r in self.required_libraries: | 
|  | yield ('required library', r) | 
|  | for r in self.add_to_library_groups: | 
|  | yield ('library group', r) | 
|  |  | 
|  | def get_llvmbuild_fragment(self): | 
|  | result = """\ | 
|  | type = %s | 
|  | name = %s | 
|  | parent = %s | 
|  | """ % (self.type_name, self.name, self.parent) | 
|  | if self.required_libraries and not self._is_special_group: | 
|  | result += 'required_libraries = %s\n' % ' '.join( | 
|  | self.required_libraries) | 
|  | if self.add_to_library_groups: | 
|  | result += 'add_to_library_groups = %s\n' % ' '.join( | 
|  | self.add_to_library_groups) | 
|  | return result | 
|  |  | 
|  | def get_llvmconfig_component_name(self): | 
|  | return self.name.lower() | 
|  |  | 
|  | class TargetGroupComponentInfo(ComponentInfo): | 
|  | type_name = 'TargetGroup' | 
|  |  | 
|  | @staticmethod | 
|  | def parse(subpath, items): | 
|  | kwargs = ComponentInfo.parse_items(items, has_dependencies = False) | 
|  | kwargs['required_libraries'] = items.get_list('required_libraries') | 
|  | kwargs['add_to_library_groups'] = items.get_list( | 
|  | 'add_to_library_groups') | 
|  | kwargs['has_jit'] = items.get_optional_bool('has_jit', False) | 
|  | kwargs['has_asmprinter'] = items.get_optional_bool('has_asmprinter', | 
|  | False) | 
|  | kwargs['has_asmparser'] = items.get_optional_bool('has_asmparser', | 
|  | False) | 
|  | kwargs['has_disassembler'] = items.get_optional_bool('has_disassembler', | 
|  | False) | 
|  | return TargetGroupComponentInfo(subpath, **kwargs) | 
|  |  | 
|  | def __init__(self, subpath, name, parent, required_libraries = [], | 
|  | add_to_library_groups = [], has_jit = False, | 
|  | has_asmprinter = False, has_asmparser = False, | 
|  | has_disassembler = False): | 
|  | ComponentInfo.__init__(self, subpath, name, [], parent) | 
|  |  | 
|  | # The names of the library components which are required when linking | 
|  | # with this component. | 
|  | self.required_libraries = list(required_libraries) | 
|  |  | 
|  | # The names of the library group components this component should be | 
|  | # considered part of. | 
|  | self.add_to_library_groups = list(add_to_library_groups) | 
|  |  | 
|  | # Whether or not this target supports the JIT. | 
|  | self.has_jit = bool(has_jit) | 
|  |  | 
|  | # Whether or not this target defines an assembly printer. | 
|  | self.has_asmprinter = bool(has_asmprinter) | 
|  |  | 
|  | # Whether or not this target defines an assembly parser. | 
|  | self.has_asmparser = bool(has_asmparser) | 
|  |  | 
|  | # Whether or not this target defines an disassembler. | 
|  | self.has_disassembler = bool(has_disassembler) | 
|  |  | 
|  | # Whether or not this target is enabled. This is set in response to | 
|  | # configuration parameters. | 
|  | self.enabled = False | 
|  |  | 
|  | def get_component_references(self): | 
|  | for r in ComponentInfo.get_component_references(self): | 
|  | yield r | 
|  | for r in self.required_libraries: | 
|  | yield ('required library', r) | 
|  | for r in self.add_to_library_groups: | 
|  | yield ('library group', r) | 
|  |  | 
|  | def get_llvmbuild_fragment(self): | 
|  | result = """\ | 
|  | type = %s | 
|  | name = %s | 
|  | parent = %s | 
|  | """ % (self.type_name, self.name, self.parent) | 
|  | if self.required_libraries: | 
|  | result += 'required_libraries = %s\n' % ' '.join( | 
|  | self.required_libraries) | 
|  | if self.add_to_library_groups: | 
|  | result += 'add_to_library_groups = %s\n' % ' '.join( | 
|  | self.add_to_library_groups) | 
|  | for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler', | 
|  | 'has_jit'): | 
|  | if getattr(self, bool_key): | 
|  | result += '%s = 1\n' % (bool_key,) | 
|  | return result | 
|  |  | 
|  | def get_llvmconfig_component_name(self): | 
|  | return self.name.lower() | 
|  |  | 
|  | class ToolComponentInfo(ComponentInfo): | 
|  | type_name = 'Tool' | 
|  |  | 
|  | @staticmethod | 
|  | def parse(subpath, items): | 
|  | kwargs = ComponentInfo.parse_items(items) | 
|  | kwargs['required_libraries'] = items.get_list('required_libraries') | 
|  | return ToolComponentInfo(subpath, **kwargs) | 
|  |  | 
|  | def __init__(self, subpath, name, dependencies, parent, | 
|  | required_libraries): | 
|  | ComponentInfo.__init__(self, subpath, name, dependencies, parent) | 
|  |  | 
|  | # The names of the library components which are required to link this | 
|  | # tool. | 
|  | self.required_libraries = list(required_libraries) | 
|  |  | 
|  | def get_component_references(self): | 
|  | for r in ComponentInfo.get_component_references(self): | 
|  | yield r | 
|  | for r in self.required_libraries: | 
|  | yield ('required library', r) | 
|  |  | 
|  | def get_llvmbuild_fragment(self): | 
|  | return """\ | 
|  | type = %s | 
|  | name = %s | 
|  | parent = %s | 
|  | required_libraries = %s | 
|  | """ % (self.type_name, self.name, self.parent, | 
|  | ' '.join(self.required_libraries)) | 
|  |  | 
|  | class BuildToolComponentInfo(ToolComponentInfo): | 
|  | type_name = 'BuildTool' | 
|  |  | 
|  | @staticmethod | 
|  | def parse(subpath, items): | 
|  | kwargs = ComponentInfo.parse_items(items) | 
|  | kwargs['required_libraries'] = items.get_list('required_libraries') | 
|  | return BuildToolComponentInfo(subpath, **kwargs) | 
|  |  | 
|  | ### | 
|  |  | 
|  | class IniFormatParser(dict): | 
|  | def get_list(self, key): | 
|  | # Check if the value is defined. | 
|  | value = self.get(key) | 
|  | if value is None: | 
|  | return [] | 
|  |  | 
|  | # Lists are just whitespace separated strings. | 
|  | return value.split() | 
|  |  | 
|  | def get_optional_string(self, key): | 
|  | value = self.get_list(key) | 
|  | if not value: | 
|  | return None | 
|  | if len(value) > 1: | 
|  | raise ParseError("multiple values for scalar key: %r" % key) | 
|  | return value[0] | 
|  |  | 
|  | def get_string(self, key): | 
|  | value = self.get_optional_string(key) | 
|  | if not value: | 
|  | raise ParseError("missing value for required string: %r" % key) | 
|  | return value | 
|  |  | 
|  | def get_optional_bool(self, key, default = None): | 
|  | value = self.get_optional_string(key) | 
|  | if not value: | 
|  | return default | 
|  | if value not in ('0', '1'): | 
|  | raise ParseError("invalid value(%r) for boolean property: %r" % ( | 
|  | value, key)) | 
|  | return bool(int(value)) | 
|  |  | 
|  | def get_bool(self, key): | 
|  | value = self.get_optional_bool(key) | 
|  | if value is None: | 
|  | raise ParseError("missing value for required boolean: %r" % key) | 
|  | return value | 
|  |  | 
|  | _component_type_map = dict( | 
|  | (t.type_name, t) | 
|  | for t in (GroupComponentInfo, | 
|  | LibraryComponentInfo, LibraryGroupComponentInfo, | 
|  | ToolComponentInfo, BuildToolComponentInfo, | 
|  | TargetGroupComponentInfo, OptionalLibraryComponentInfo)) | 
|  | def load_from_path(path, subpath): | 
|  | # Load the LLVMBuild.txt file as an .ini format file. | 
|  | parser = configparser.RawConfigParser() | 
|  | parser.read(path) | 
|  |  | 
|  | # Extract the common section. | 
|  | if parser.has_section("common"): | 
|  | common = IniFormatParser(parser.items("common")) | 
|  | parser.remove_section("common") | 
|  | else: | 
|  | common = IniFormatParser({}) | 
|  |  | 
|  | return common, _read_components_from_parser(parser, path, subpath) | 
|  |  | 
|  | def _read_components_from_parser(parser, path, subpath): | 
|  | # We load each section which starts with 'component' as a distinct component | 
|  | # description (so multiple components can be described in one file). | 
|  | for section in parser.sections(): | 
|  | if not section.startswith('component'): | 
|  | # We don't expect arbitrary sections currently, warn the user. | 
|  | warning("ignoring unknown section %r in %r" % (section, path)) | 
|  | continue | 
|  |  | 
|  | # Determine the type of the component to instantiate. | 
|  | if not parser.has_option(section, 'type'): | 
|  | fatal("invalid component %r in %r: %s" % ( | 
|  | section, path, "no component type")) | 
|  |  | 
|  | type_name = parser.get(section, 'type') | 
|  | type_class = _component_type_map.get(type_name) | 
|  | if type_class is None: | 
|  | fatal("invalid component %r in %r: %s" % ( | 
|  | section, path, "invalid component type: %r" % type_name)) | 
|  |  | 
|  | # Instantiate the component based on the remaining values. | 
|  | try: | 
|  | info = type_class.parse(subpath, | 
|  | IniFormatParser(parser.items(section))) | 
|  | except TypeError: | 
|  | print("error: invalid component %r in %r: %s" % ( | 
|  | section, path, "unable to instantiate: %r" % type_name), file=sys.stderr) | 
|  | import traceback | 
|  | traceback.print_exc() | 
|  | raise SystemExit(1) | 
|  | except ParseError: | 
|  | e = sys.exc_info()[1] | 
|  | fatal("unable to load component %r in %r: %s" % ( | 
|  | section, path, e.message)) | 
|  |  | 
|  | info._source_path = path | 
|  | yield info |