mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-11-03 14:21:30 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188424 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			476 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			476 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""
 | 
						|
Descriptor objects for entities that are part of the LLVM project.
 | 
						|
"""
 | 
						|
 | 
						|
from __future__ import absolute_import
 | 
						|
try:
 | 
						|
    import configparser
 | 
						|
except:
 | 
						|
    import ConfigParser as configparser
 | 
						|
import sys
 | 
						|
 | 
						|
from llvmbuild.util import *
 | 
						|
 | 
						|
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 >>sys.stderr, "error: invalid component %r in %r: %s" % (
 | 
						|
                section, path, "unable to instantiate: %r" % type_name)
 | 
						|
            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
 |