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