1# Status: minor updates by Steven Watanabe to make gcc work 2# 3# Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and 4# distribute this software is granted provided this copyright notice appears in 5# all copies. This software is provided "as is" without express or implied 6# warranty, and with no claim as to its suitability for any purpose. 7 8""" Defines standard features and rules. 9""" 10 11import b2.build.targets as targets 12 13import sys 14from b2.build import feature, property, virtual_target, generators, type, property_set, scanner 15from b2.util.utility import * 16from b2.util import path, regex, bjam_signature 17import b2.tools.types 18from b2.manager import get_manager 19 20 21# Records explicit properties for a variant. 22# The key is the variant name. 23__variant_explicit_properties = {} 24 25def reset (): 26 """ Clear the module state. This is mainly for testing purposes. 27 """ 28 global __variant_explicit_properties 29 30 __variant_explicit_properties = {} 31 32@bjam_signature((["name"], ["parents_or_properties", "*"], ["explicit_properties", "*"])) 33def variant (name, parents_or_properties, explicit_properties = []): 34 """ Declares a new variant. 35 First determines explicit properties for this variant, by 36 refining parents' explicit properties with the passed explicit 37 properties. The result is remembered and will be used if 38 this variant is used as parent. 39 40 Second, determines the full property set for this variant by 41 adding to the explicit properties default values for all properties 42 which neither present nor are symmetric. 43 44 Lastly, makes appropriate value of 'variant' property expand 45 to the full property set. 46 name: Name of the variant 47 parents_or_properties: Specifies parent variants, if 48 'explicit_properties' are given, 49 and explicit_properties otherwise. 50 explicit_properties: Explicit properties. 51 """ 52 parents = [] 53 if not explicit_properties: 54 explicit_properties = parents_or_properties 55 else: 56 parents = parents_or_properties 57 58 inherited = property_set.empty() 59 if parents: 60 61 # If we allow multiple parents, we'd have to to check for conflicts 62 # between base variants, and there was no demand for so to bother. 63 if len (parents) > 1: 64 raise BaseException ("Multiple base variants are not yet supported") 65 66 p = parents[0] 67 # TODO: the check may be stricter 68 if not feature.is_implicit_value (p): 69 raise BaseException ("Invalid base variant '%s'" % p) 70 71 inherited = __variant_explicit_properties[p] 72 73 explicit_properties = property_set.create_with_validation(explicit_properties) 74 explicit_properties = inherited.refine(explicit_properties) 75 76 # Record explicitly specified properties for this variant 77 # We do this after inheriting parents' properties, so that 78 # they affect other variants, derived from this one. 79 __variant_explicit_properties[name] = explicit_properties 80 81 feature.extend('variant', [name]) 82 feature.compose ("<variant>" + name, explicit_properties.all()) 83 84__os_names = """ 85 amiga aix bsd cygwin darwin dos emx freebsd hpux iphone linux netbsd 86 openbsd osf qnx qnxnto sgi solaris sun sunos svr4 sysv ultrix unix unixware 87 vms windows 88""".split() 89 90# Translates from bjam current OS to the os tags used in host-os and target-os, 91# i.e. returns the running host-os. 92# 93def default_host_os(): 94 host_os = os_name() 95 if host_os not in (x.upper() for x in __os_names): 96 if host_os == 'NT': host_os = 'windows' 97 elif host_os == 'AS400': host_os = 'unix' 98 elif host_os == 'MINGW': host_os = 'windows' 99 elif host_os == 'BSDI': host_os = 'bsd' 100 elif host_os == 'COHERENT': host_os = 'unix' 101 elif host_os == 'DRAGONFLYBSD': host_os = 'bsd' 102 elif host_os == 'IRIX': host_os = 'sgi' 103 elif host_os == 'MACOSX': host_os = 'darwin' 104 elif host_os == 'KFREEBSD': host_os = 'freebsd' 105 elif host_os == 'LINUX': host_os = 'linux' 106 elif host_os == 'HAIKU': host_os = 'haiku' 107 else: host_os = 'unix' 108 return host_os.lower() 109 110def register_globals (): 111 """ Registers all features and variants declared by this module. 112 """ 113 114 # This feature is used to determine which OS we're on. 115 # In future, this may become <target-os> and <host-os> 116 # TODO: check this. Compatibility with bjam names? Subfeature for version? 117 os = sys.platform 118 feature.feature ('os', [os], ['propagated', 'link-incompatible']) 119 120 121 # The two OS features define a known set of abstract OS names. The host-os is 122 # the OS under which bjam is running. Even though this should really be a fixed 123 # property we need to list all the values to prevent unknown value errors. Both 124 # set the default value to the current OS to account for the default use case of 125 # building on the target OS. 126 feature.feature('host-os', __os_names) 127 feature.set_default('host-os', default_host_os()) 128 129 feature.feature('target-os', __os_names, ['propagated', 'link-incompatible']) 130 feature.set_default('target-os', default_host_os()) 131 132 feature.feature ('toolset', [], ['implicit', 'propagated' ,'symmetric']) 133 134 feature.feature ('stdlib', ['native'], ['propagated', 'composite']) 135 136 feature.feature ('link', ['shared', 'static'], ['propagated']) 137 feature.feature ('runtime-link', ['shared', 'static'], ['propagated']) 138 feature.feature ('runtime-debugging', ['on', 'off'], ['propagated']) 139 140 141 feature.feature ('optimization', ['off', 'speed', 'space'], ['propagated']) 142 feature.feature ('profiling', ['off', 'on'], ['propagated']) 143 feature.feature ('inlining', ['off', 'on', 'full'], ['propagated']) 144 145 feature.feature ('threading', ['single', 'multi'], ['propagated']) 146 feature.feature ('rtti', ['on', 'off'], ['propagated']) 147 feature.feature ('exception-handling', ['on', 'off'], ['propagated']) 148 149 # Whether there is support for asynchronous EH (e.g. catching SEGVs). 150 feature.feature ('asynch-exceptions', ['on', 'off'], ['propagated']) 151 152 # Whether all extern "C" functions are considered nothrow by default. 153 feature.feature ('extern-c-nothrow', ['off', 'on'], ['propagated']) 154 155 feature.feature ('debug-symbols', ['on', 'off'], ['propagated']) 156 feature.feature ('define', [], ['free']) 157 feature.feature ('undef', [], ['free']) 158 feature.feature ('include', [], ['free', 'path']) #order-sensitive 159 feature.feature ('cflags', [], ['free']) 160 feature.feature ('cxxflags', [], ['free']) 161 feature.feature ('asmflags', [], ['free']) 162 feature.feature ('linkflags', [], ['free']) 163 feature.feature ('archiveflags', [], ['free']) 164 feature.feature ('version', [], ['free']) 165 166 feature.feature ('location-prefix', [], ['free']) 167 168 feature.feature ('action', [], ['free']) 169 170 171 # The following features are incidental, since 172 # in themself they have no effect on build products. 173 # Not making them incidental will result in problems in corner 174 # cases, for example: 175 # 176 # unit-test a : a.cpp : <use>b ; 177 # lib b : a.cpp b ; 178 # 179 # Here, if <use> is not incidental, we'll decide we have two 180 # targets for a.obj with different properties, and will complain. 181 # 182 # Note that making feature incidental does not mean it's ignored. It may 183 # be ignored when creating the virtual target, but the rest of build process 184 # will use them. 185 feature.feature ('use', [], ['free', 'dependency', 'incidental']) 186 feature.feature ('dependency', [], ['free', 'dependency', 'incidental']) 187 feature.feature ('implicit-dependency', [], ['free', 'dependency', 'incidental']) 188 189 feature.feature('warnings', [ 190 'on', # Enable default/"reasonable" warning level for the tool. 191 'all', # Enable all possible warnings issued by the tool. 192 'off'], # Disable all warnings issued by the tool. 193 ['incidental', 'propagated']) 194 195 feature.feature('warnings-as-errors', [ 196 'off', # Do not fail the compilation if there are warnings. 197 'on'], # Fail the compilation if there are warnings. 198 ['incidental', 'propagated']) 199 200 feature.feature('c++-template-depth', 201 [str(i) for i in range(64,1024+1,64)] + 202 [str(i) for i in range(20,1000+1,10)] + 203 # Maximum template instantiation depth guaranteed for ANSI/ISO C++ 204 # conforming programs. 205 ['17'], 206 ['incidental', 'optional', 'propagated']) 207 208 feature.feature ('source', [], ['free', 'dependency', 'incidental']) 209 feature.feature ('library', [], ['free', 'dependency', 'incidental']) 210 feature.feature ('file', [], ['free', 'dependency', 'incidental']) 211 feature.feature ('find-shared-library', [], ['free']) #order-sensitive ; 212 feature.feature ('find-static-library', [], ['free']) #order-sensitive ; 213 feature.feature ('library-path', [], ['free', 'path']) #order-sensitive ; 214 # Internal feature. 215 feature.feature ('library-file', [], ['free', 'dependency']) 216 217 feature.feature ('name', [], ['free']) 218 feature.feature ('tag', [], ['free']) 219 feature.feature ('search', [], ['free', 'path']) #order-sensitive ; 220 feature.feature ('location', [], ['free', 'path']) 221 222 feature.feature ('dll-path', [], ['free', 'path']) 223 feature.feature ('hardcode-dll-paths', ['true', 'false'], ['incidental']) 224 225 226 # This is internal feature which holds the paths of all dependency 227 # dynamic libraries. On Windows, it's needed so that we can all 228 # those paths to PATH, when running applications. 229 # On Linux, it's needed to add proper -rpath-link command line options. 230 feature.feature ('xdll-path', [], ['free', 'path']) 231 232 #provides means to specify def-file for windows dlls. 233 feature.feature ('def-file', [], ['free', 'dependency']) 234 235 # This feature is used to allow specific generators to run. 236 # For example, QT tools can only be invoked when QT library 237 # is used. In that case, <allow>qt will be in usage requirement 238 # of the library. 239 feature.feature ('allow', [], ['free']) 240 241 # The addressing model to generate code for. Currently a limited set only 242 # specifying the bit size of pointers. 243 feature.feature('address-model', ['16', '32', '64'], ['propagated', 'optional']) 244 245 # Type of CPU architecture to compile for. 246 feature.feature('architecture', [ 247 # x86 and x86-64 248 'x86', 249 250 # ia64 251 'ia64', 252 253 # Sparc 254 'sparc', 255 256 # RS/6000 & PowerPC 257 'power', 258 259 # MIPS/SGI 260 'mips1', 'mips2', 'mips3', 'mips4', 'mips32', 'mips32r2', 'mips64', 261 262 # HP/PA-RISC 263 'parisc', 264 265 # Advanced RISC Machines 266 'arm', 267 268 # Combined architectures for platforms/toolsets that support building for 269 # multiple architectures at once. "combined" would be the default multi-arch 270 # for the toolset. 271 'combined', 272 'combined-x86-power'], 273 274 ['propagated', 'optional']) 275 276 # The specific instruction set in an architecture to compile. 277 feature.feature('instruction-set', [ 278 # x86 and x86-64 279 'native', 'i486', 'i586', 'i686', 'pentium', 'pentium-mmx', 'pentiumpro', 'pentium2', 'pentium3', 280 'pentium3m', 'pentium-m', 'pentium4', 'pentium4m', 'prescott', 'nocona', 'core2', 'corei7', 'corei7-avx', 'core-avx-i', 281 'conroe', 'conroe-xe', 'conroe-l', 'allendale', 'merom', 'merom-xe', 'kentsfield', 'kentsfield-xe', 'penryn', 'wolfdale', 282 'yorksfield', 'nehalem', 'sandy-bridge', 'ivy-bridge', 'haswell', 'k6', 'k6-2', 'k6-3', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp', 283 'athlon-mp', 'k8', 'opteron', 'athlon64', 'athlon-fx', 'k8-sse3', 'opteron-sse3', 'athlon64-sse3', 'amdfam10', 'barcelona', 284 'bdver1', 'bdver2', 'bdver3', 'btver1', 'btver2', 'winchip-c6', 'winchip2', 'c3', 'c3-2', 'atom', 285 286 # ia64 287 'itanium', 'itanium1', 'merced', 'itanium2', 'mckinley', 288 289 # Sparc 290 'v7', 'cypress', 'v8', 'supersparc', 'sparclite', 'hypersparc', 'sparclite86x', 'f930', 'f934', 291 'sparclet', 'tsc701', 'v9', 'ultrasparc', 'ultrasparc3', 292 293 # RS/6000 & PowerPC 294 '401', '403', '405', '405fp', '440', '440fp', '505', '601', '602', 295 '603', '603e', '604', '604e', '620', '630', '740', '7400', 296 '7450', '750', '801', '821', '823', '860', '970', '8540', 297 'power-common', 'ec603e', 'g3', 'g4', 'g5', 'power', 'power2', 298 'power3', 'power4', 'power5', 'powerpc', 'powerpc64', 'rios', 299 'rios1', 'rsc', 'rios2', 'rs64a', 300 301 # MIPS 302 '4kc', '4kp', '5kc', '20kc', 'm4k', 'r2000', 'r3000', 'r3900', 'r4000', 303 'r4100', 'r4300', 'r4400', 'r4600', 'r4650', 304 'r6000', 'r8000', 'rm7000', 'rm9000', 'orion', 'sb1', 'vr4100', 305 'vr4111', 'vr4120', 'vr4130', 'vr4300', 306 'vr5000', 'vr5400', 'vr5500', 307 308 # HP/PA-RISC 309 '700', '7100', '7100lc', '7200', '7300', '8000', 310 311 # Advanced RISC Machines 312 'armv2', 'armv2a', 'armv3', 'armv3m', 'armv4', 'armv4t', 'armv5', 313 'armv5t', 'armv5te', 'armv6', 'armv6j', 'iwmmxt', 'ep9312'], 314 315 ['propagated', 'optional']) 316 317 feature.feature('conditional', [], ['incidental', 'free']) 318 319 # The value of 'no' prevents building of a target. 320 feature.feature('build', ['yes', 'no'], ['optional']) 321 322 # Windows-specific features 323 feature.feature ('user-interface', ['console', 'gui', 'wince', 'native', 'auto'], []) 324 feature.feature ('variant', [], ['implicit', 'composite', 'propagated', 'symmetric']) 325 326 327 variant ('debug', ['<optimization>off', '<debug-symbols>on', '<inlining>off', '<runtime-debugging>on']) 328 variant ('release', ['<optimization>speed', '<debug-symbols>off', '<inlining>full', 329 '<runtime-debugging>off', '<define>NDEBUG']) 330 variant ('profile', ['release'], ['<profiling>on', '<debug-symbols>on']) 331 332 333reset () 334register_globals () 335 336class SearchedLibTarget (virtual_target.AbstractFileTarget): 337 def __init__ (self, name, project, shared, search, action): 338 virtual_target.AbstractFileTarget.__init__ (self, name, 'SEARCHED_LIB', project, action) 339 340 self.shared_ = shared 341 self.search_ = search 342 343 def shared (self): 344 return self.shared_ 345 346 def search (self): 347 return self.search_ 348 349 def actualize_location (self, target): 350 bjam.call("NOTFILE", target) 351 352 def path (self): 353 #FIXME: several functions rely on this not being None 354 return "" 355 356 357class CScanner (scanner.Scanner): 358 def __init__ (self, includes): 359 scanner.Scanner.__init__ (self) 360 361 self.includes_ = [] 362 363 for i in includes: 364 self.includes_.extend(i.split("&&")) 365 366 def pattern (self): 367 return r'#[ \t]*include[ ]*(<(.*)>|"(.*)")' 368 369 def process (self, target, matches, binding): 370 371 angle = regex.transform (matches, "<(.*)>") 372 quoted = regex.transform (matches, '"(.*)"') 373 374 g = str(id(self)) 375 b = os.path.normpath(os.path.dirname(binding[0])) 376 377 # Attach binding of including file to included targets. 378 # When target is directly created from virtual target 379 # this extra information is unnecessary. But in other 380 # cases, it allows to distinguish between two headers of the 381 # same name included from different places. 382 # We don't need this extra information for angle includes, 383 # since they should not depend on including file (we can't 384 # get literal "." in include path). 385 g2 = g + "#" + b 386 387 g = "<" + g + ">" 388 g2 = "<" + g2 + ">" 389 angle = [g + x for x in angle] 390 quoted = [g2 + x for x in quoted] 391 392 all = angle + quoted 393 bjam.call("mark-included", target, all) 394 395 engine = get_manager().engine() 396 engine.set_target_variable(angle, "SEARCH", get_value(self.includes_)) 397 engine.set_target_variable(quoted, "SEARCH", [b] + get_value(self.includes_)) 398 399 # Just propagate current scanner to includes, in a hope 400 # that includes do not change scanners. 401 get_manager().scanners().propagate(self, angle + quoted) 402 403scanner.register (CScanner, 'include') 404type.set_scanner ('CPP', CScanner) 405type.set_scanner ('C', CScanner) 406 407# Ported to trunk@47077 408class LibGenerator (generators.Generator): 409 """ The generator class for libraries (target type LIB). Depending on properties it will 410 request building of the approapriate specific type -- SHARED_LIB, STATIC_LIB or 411 SHARED_LIB. 412 """ 413 414 def __init__(self, id, composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []): 415 generators.Generator.__init__(self, id, composing, source_types, target_types_and_names, requirements) 416 417 def run(self, project, name, prop_set, sources): 418 419 # The lib generator is composing, and can be only invoked with 420 # explicit name. This check is present in generator.run (and so in 421 # builtin.LinkingGenerator), but duplicate it here to avoid doing 422 # extra work. 423 if name: 424 properties = prop_set.raw() 425 # Determine the needed target type 426 actual_type = None 427 properties_grist = get_grist(properties) 428 if '<source>' not in properties_grist and \ 429 ('<search>' in properties_grist or '<name>' in properties_grist): 430 actual_type = 'SEARCHED_LIB' 431 elif '<file>' in properties_grist: 432 # The generator for 433 actual_type = 'LIB' 434 elif '<link>shared' in properties: 435 actual_type = 'SHARED_LIB' 436 else: 437 actual_type = 'STATIC_LIB' 438 439 prop_set = prop_set.add_raw(['<main-target-type>LIB']) 440 441 # Construct the target. 442 return generators.construct(project, name, actual_type, prop_set, sources) 443 444 def viable_source_types(self): 445 return ['*'] 446 447generators.register(LibGenerator("builtin.lib-generator")) 448 449generators.override("builtin.prebuilt", "builtin.lib-generator") 450 451def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]): 452 """The implementation of the 'lib' rule. Beyond standard syntax that rule allows 453 simplified: 'lib a b c ;'.""" 454 455 if len(names) > 1: 456 if any(r.startswith('<name>') for r in requirements): 457 get_manager().errors()("When several names are given to the 'lib' rule\n" + 458 "it is not allowed to specify the <name> feature.") 459 460 if sources: 461 get_manager().errors()("When several names are given to the 'lib' rule\n" + 462 "it is not allowed to specify sources.") 463 464 project = get_manager().projects().current() 465 result = [] 466 467 for name in names: 468 r = requirements[:] 469 470 # Support " lib a ; " and " lib a b c ; " syntax. 471 if not sources and not any(r.startswith("<name>") for r in requirements) \ 472 and not any(r.startswith("<file") for r in requirements): 473 r.append("<name>" + name) 474 475 result.append(targets.create_typed_metatarget(name, "LIB", sources, 476 r, 477 default_build, 478 usage_requirements)) 479 return result 480 481get_manager().projects().add_rule("lib", lib) 482 483 484# Updated to trunk@47077 485class SearchedLibGenerator (generators.Generator): 486 def __init__ (self, id = 'SearchedLibGenerator', composing = False, source_types = [], target_types_and_names = ['SEARCHED_LIB'], requirements = []): 487 # TODO: the comment below looks strange. There are no requirements! 488 # The requirements cause the generators to be tried *only* when we're building 489 # lib target and there's 'search' feature. This seems ugly --- all we want 490 # is make sure SearchedLibGenerator is not invoked deep in transformation 491 # search. 492 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements) 493 494 def run(self, project, name, prop_set, sources): 495 496 if not name: 497 return None 498 499 # If name is empty, it means we're called not from top-level. 500 # In this case, we just fail immediately, because SearchedLibGenerator 501 # cannot be used to produce intermediate targets. 502 503 properties = prop_set.raw () 504 shared = '<link>shared' in properties 505 506 a = virtual_target.NullAction (project.manager(), prop_set) 507 508 real_name = feature.get_values ('<name>', properties) 509 if real_name: 510 real_name = real_name[0] 511 else: 512 real_name = name 513 search = feature.get_values('<search>', properties) 514 usage_requirements = property_set.create(['<xdll-path>' + p for p in search]) 515 t = SearchedLibTarget(real_name, project, shared, search, a) 516 517 # We return sources for a simple reason. If there's 518 # lib png : z : <name>png ; 519 # the 'z' target should be returned, so that apps linking to 520 # 'png' will link to 'z', too. 521 return(usage_requirements, [b2.manager.get_manager().virtual_targets().register(t)] + sources) 522 523generators.register (SearchedLibGenerator ()) 524 525class PrebuiltLibGenerator(generators.Generator): 526 527 def __init__(self, id, composing, source_types, target_types_and_names, requirements): 528 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements) 529 530 def run(self, project, name, properties, sources): 531 f = properties.get("file") 532 return f + sources 533 534generators.register(PrebuiltLibGenerator("builtin.prebuilt", False, [], 535 ["LIB"], ["<file>"])) 536 537generators.override("builtin.prebuilt", "builtin.lib-generator") 538 539 540class CompileAction (virtual_target.Action): 541 def __init__ (self, manager, sources, action_name, prop_set): 542 virtual_target.Action.__init__ (self, manager, sources, action_name, prop_set) 543 544 def adjust_properties (self, prop_set): 545 """ For all virtual targets for the same dependency graph as self, 546 i.e. which belong to the same main target, add their directories 547 to include path. 548 """ 549 s = self.targets () [0].creating_subvariant () 550 551 return prop_set.add_raw (s.implicit_includes ('include', 'H')) 552 553class CCompilingGenerator (generators.Generator): 554 """ Declare a special compiler generator. 555 The only thing it does is changing the type used to represent 556 'action' in the constructed dependency graph to 'CompileAction'. 557 That class in turn adds additional include paths to handle a case 558 when a source file includes headers which are generated themselfs. 559 """ 560 def __init__ (self, id, composing, source_types, target_types_and_names, requirements): 561 # TODO: (PF) What to do with optional_properties? It seemed that, in the bjam version, the arguments are wrong. 562 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements) 563 564 def action_class (self): 565 return CompileAction 566 567def register_c_compiler (id, source_types, target_types, requirements, optional_properties = []): 568 g = CCompilingGenerator (id, False, source_types, target_types, requirements + optional_properties) 569 return generators.register (g) 570 571 572class LinkingGenerator (generators.Generator): 573 """ The generator class for handling EXE and SHARED_LIB creation. 574 """ 575 def __init__ (self, id, composing, source_types, target_types_and_names, requirements): 576 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements) 577 578 def run (self, project, name, prop_set, sources): 579 580 sources.extend(prop_set.get('<library>')) 581 582 # Add <library-path> properties for all searched libraries 583 extra = [] 584 for s in sources: 585 if s.type () == 'SEARCHED_LIB': 586 search = s.search() 587 extra.extend(property.Property('<library-path>', sp) for sp in search) 588 589 # It's possible that we have libraries in sources which did not came 590 # from 'lib' target. For example, libraries which are specified 591 # just as filenames as sources. We don't have xdll-path properties 592 # for such target, but still need to add proper dll-path properties. 593 extra_xdll_path = [] 594 for s in sources: 595 if type.is_derived (s.type (), 'SHARED_LIB') and not s.action (): 596 # Unfortunately, we don't have a good way to find the path 597 # to a file, so use this nasty approach. 598 p = s.project() 599 location = path.root(s.name(), p.get('source-location')[0]) 600 extra_xdll_path.append(os.path.dirname(location)) 601 602 # Hardcode DLL paths only when linking executables. 603 # Pros: do not need to relink libraries when installing. 604 # Cons: "standalone" libraries (plugins, python extensions) can not 605 # hardcode paths to dependent libraries. 606 if prop_set.get('<hardcode-dll-paths>') == ['true'] \ 607 and type.is_derived(self.target_types_ [0], 'EXE'): 608 xdll_path = prop_set.get('<xdll-path>') 609 extra.extend(property.Property('<dll-path>', sp) \ 610 for sp in extra_xdll_path) 611 extra.extend(property.Property('<dll-path>', sp) \ 612 for sp in xdll_path) 613 614 if extra: 615 prop_set = prop_set.add_raw (extra) 616 result = generators.Generator.run(self, project, name, prop_set, sources) 617 618 if result: 619 ur = self.extra_usage_requirements(result, prop_set) 620 ur = ur.add(property_set.create(['<xdll-path>' + p for p in extra_xdll_path])) 621 else: 622 return None 623 return (ur, result) 624 625 def extra_usage_requirements (self, created_targets, prop_set): 626 627 result = property_set.empty () 628 extra = [] 629 630 # Add appropriate <xdll-path> usage requirements. 631 raw = prop_set.raw () 632 if '<link>shared' in raw: 633 paths = [] 634 635 # TODO: is it safe to use the current directory? I think we should use 636 # another mechanism to allow this to be run from anywhere. 637 pwd = os.getcwd() 638 639 for t in created_targets: 640 if type.is_derived(t.type(), 'SHARED_LIB'): 641 paths.append(path.root(path.make(t.path()), pwd)) 642 643 extra += replace_grist(paths, '<xdll-path>') 644 645 # We need to pass <xdll-path> features that we've got from sources, 646 # because if shared library is built, exe which uses it must know paths 647 # to other shared libraries this one depends on, to be able to find them 648 # all at runtime. 649 650 # Just pass all features in property_set, it's theorically possible 651 # that we'll propagate <xdll-path> features explicitly specified by 652 # the user, but then the user's to blaim for using internal feature. 653 values = prop_set.get('<xdll-path>') 654 extra += replace_grist(values, '<xdll-path>') 655 656 if extra: 657 result = property_set.create(extra) 658 659 return result 660 661 def generated_targets (self, sources, prop_set, project, name): 662 663 # sources to pass to inherited rule 664 sources2 = [] 665 # sources which are libraries 666 libraries = [] 667 668 # Searched libraries are not passed as argument to linker 669 # but via some option. So, we pass them to the action 670 # via property. 671 fsa = [] 672 fst = [] 673 for s in sources: 674 if type.is_derived(s.type(), 'SEARCHED_LIB'): 675 n = s.name() 676 if s.shared(): 677 fsa.append(n) 678 679 else: 680 fst.append(n) 681 682 else: 683 sources2.append(s) 684 685 add = [] 686 if fsa: 687 add.append("<find-shared-library>" + '&&'.join(fsa)) 688 if fst: 689 add.append("<find-static-library>" + '&&'.join(fst)) 690 691 spawn = generators.Generator.generated_targets(self, sources2, prop_set.add_raw(add), project, name) 692 return spawn 693 694 695def register_linker(id, source_types, target_types, requirements): 696 g = LinkingGenerator(id, True, source_types, target_types, requirements) 697 generators.register(g) 698 699class ArchiveGenerator (generators.Generator): 700 """ The generator class for handling STATIC_LIB creation. 701 """ 702 def __init__ (self, id, composing, source_types, target_types_and_names, requirements): 703 generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements) 704 705 def run (self, project, name, prop_set, sources): 706 sources += prop_set.get ('<library>') 707 708 result = generators.Generator.run (self, project, name, prop_set, sources) 709 710 return result 711 712 713def register_archiver(id, source_types, target_types, requirements): 714 g = ArchiveGenerator(id, True, source_types, target_types, requirements) 715 generators.register(g) 716 717class DummyGenerator(generators.Generator): 718 """Generator that accepts everything and produces nothing. Useful as a general 719 fallback for toolset-specific actions like PCH generation. 720 """ 721 def run (self, project, name, prop_set, sources): 722 return (property_set.empty(), []) 723 724 725get_manager().projects().add_rule("variant", variant) 726 727import stage 728import symlink 729import message 730