aboutsummaryrefslogtreecommitdiff
path: root/utils/llvm-build/llvmbuild/componentinfo.py
diff options
context:
space:
mode:
Diffstat (limited to 'utils/llvm-build/llvmbuild/componentinfo.py')
-rw-r--r--utils/llvm-build/llvmbuild/componentinfo.py428
1 files changed, 428 insertions, 0 deletions
diff --git a/utils/llvm-build/llvmbuild/componentinfo.py b/utils/llvm-build/llvmbuild/componentinfo.py
new file mode 100644
index 000000000000..230ae219f2f2
--- /dev/null
+++ b/utils/llvm-build/llvmbuild/componentinfo.py
@@ -0,0 +1,428 @@
+"""
+Descriptor objects for entities that are part of the LLVM project.
+"""
+
+import ConfigParser
+import StringIO
+import sys
+
+from 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
+
+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):
+ result = StringIO.StringIO()
+ print >>result, 'type = %s' % self.type_name
+ print >>result, 'name = %s' % self.name
+ print >>result, 'parent = %s' % self.parent
+ return result.getvalue()
+
+class LibraryComponentInfo(ComponentInfo):
+ type_name = 'Library'
+
+ @staticmethod
+ def parse(subpath, 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')
+ return LibraryComponentInfo(subpath, **kwargs)
+
+ def __init__(self, subpath, name, dependencies, parent, library_name,
+ required_libraries, add_to_library_groups):
+ 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)
+
+ 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 = StringIO.StringIO()
+ print >>result, 'type = %s' % self.type_name
+ print >>result, 'name = %s' % self.name
+ print >>result, 'parent = %s' % self.parent
+ if self.library_name is not None:
+ print >>result, 'library_name = %s' % self.library_name
+ if self.required_libraries:
+ print >>result, 'required_libraries = %s' % ' '.join(
+ self.required_libraries)
+ if self.add_to_library_groups:
+ print >>result, 'add_to_library_groups = %s' % ' '.join(
+ self.add_to_library_groups)
+ return result.getvalue()
+
+ 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 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 = StringIO.StringIO()
+ print >>result, 'type = %s' % self.type_name
+ print >>result, 'name = %s' % self.name
+ print >>result, 'parent = %s' % self.parent
+ if self.required_libraries and not self._is_special_group:
+ print >>result, 'required_libraries = %s' % ' '.join(
+ self.required_libraries)
+ if self.add_to_library_groups:
+ print >>result, 'add_to_library_groups = %s' % ' '.join(
+ self.add_to_library_groups)
+ return result.getvalue()
+
+ 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 = StringIO.StringIO()
+ print >>result, 'type = %s' % self.type_name
+ print >>result, 'name = %s' % self.name
+ print >>result, 'parent = %s' % self.parent
+ if self.required_libraries:
+ print >>result, 'required_libraries = %s' % ' '.join(
+ self.required_libraries)
+ if self.add_to_library_groups:
+ print >>result, 'add_to_library_groups = %s' % ' '.join(
+ self.add_to_library_groups)
+ for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
+ 'has_jit'):
+ if getattr(self, bool_key):
+ print >>result, '%s = 1' % (bool_key,)
+ return result.getvalue()
+
+ 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):
+ result = StringIO.StringIO()
+ print >>result, 'type = %s' % self.type_name
+ print >>result, 'name = %s' % self.name
+ print >>result, 'parent = %s' % self.parent
+ print >>result, 'required_libraries = %s' % ' '.join(
+ self.required_libraries)
+ return result.getvalue()
+
+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))
+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:
+ fatal("unable to load component %r in %r: %s" % (
+ section, path, e.message))
+
+ info._source_path = path
+ yield info