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