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