""" 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 = [] 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_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: 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) return TargetGroupComponentInfo(subpath, **kwargs) def __init__(self, subpath, name, parent, required_libraries = [], add_to_library_groups = [], has_jit = 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 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) if self.has_jit: print >>result, 'has_jit = %s' % ' '.join( int(self.has_jit)) 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) # 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)) yield info