1"""SCons.Tool 2 3SCons tool selection. 4 5This looks for modules that define a callable object that can modify 6a construction environment as appropriate for a given tool (or tool 7chain). 8 9Note that because this subsystem just *selects* a callable that can 10modify a construction environment, it's possible for people to define 11their own "tool specification" in an arbitrary callable function. No 12one needs to use or tie in to this subsystem in order to roll their own 13tool definition. 14""" 15 16# 17# Copyright (c) 2001 - 2016 The SCons Foundation 18# 19# Permission is hereby granted, free of charge, to any person obtaining 20# a copy of this software and associated documentation files (the 21# "Software"), to deal in the Software without restriction, including 22# without limitation the rights to use, copy, modify, merge, publish, 23# distribute, sublicense, and/or sell copies of the Software, and to 24# permit persons to whom the Software is furnished to do so, subject to 25# the following conditions: 26# 27# The above copyright notice and this permission notice shall be included 28# in all copies or substantial portions of the Software. 29# 30# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 31# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 32# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 33# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 34# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 35# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 36# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 38__revision__ = "src/engine/SCons/Tool/__init__.py rel_2.5.0:3543:937e55cd78f7 2016/04/09 11:29:54 bdbaddog" 39 40import imp 41import sys 42import re 43import os 44import shutil 45 46import SCons.Builder 47import SCons.Errors 48import SCons.Node.FS 49import SCons.Scanner 50import SCons.Scanner.C 51import SCons.Scanner.D 52import SCons.Scanner.LaTeX 53import SCons.Scanner.Prog 54import SCons.Scanner.SWIG 55 56DefaultToolpath=[] 57 58CScanner = SCons.Scanner.C.CScanner() 59DScanner = SCons.Scanner.D.DScanner() 60LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner() 61PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner() 62ProgramScanner = SCons.Scanner.Prog.ProgramScanner() 63SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner') 64SWIGScanner = SCons.Scanner.SWIG.SWIGScanner() 65 66CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", 67 ".h", ".H", ".hxx", ".hpp", ".hh", 68 ".F", ".fpp", ".FPP", 69 ".m", ".mm", 70 ".S", ".spp", ".SPP", ".sx"] 71 72DSuffixes = ['.d'] 73 74IDLSuffixes = [".idl", ".IDL"] 75 76LaTeXSuffixes = [".tex", ".ltx", ".latex"] 77 78SWIGSuffixes = ['.i'] 79 80for suffix in CSuffixes: 81 SourceFileScanner.add_scanner(suffix, CScanner) 82 83for suffix in DSuffixes: 84 SourceFileScanner.add_scanner(suffix, DScanner) 85 86for suffix in SWIGSuffixes: 87 SourceFileScanner.add_scanner(suffix, SWIGScanner) 88 89# FIXME: what should be done here? Two scanners scan the same extensions, 90# but look for different files, e.g., "picture.eps" vs. "picture.pdf". 91# The builders for DVI and PDF explicitly reference their scanners 92# I think that means this is not needed??? 93for suffix in LaTeXSuffixes: 94 SourceFileScanner.add_scanner(suffix, LaTeXScanner) 95 SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner) 96 97class Tool(object): 98 def __init__(self, name, toolpath=[], **kw): 99 self.name = name 100 self.toolpath = toolpath + DefaultToolpath 101 # remember these so we can merge them into the call 102 self.init_kw = kw 103 104 module = self._tool_module() 105 self.generate = module.generate 106 self.exists = module.exists 107 if hasattr(module, 'options'): 108 self.options = module.options 109 110 def _tool_module(self): 111 # TODO: Interchange zipimport with normal initialization for better error reporting 112 oldpythonpath = sys.path 113 sys.path = self.toolpath + sys.path 114 115 try: 116 try: 117 file, path, desc = imp.find_module(self.name, self.toolpath) 118 try: 119 return imp.load_module(self.name, file, path, desc) 120 finally: 121 if file: 122 file.close() 123 except ImportError, e: 124 if str(e)!="No module named %s"%self.name: 125 raise SCons.Errors.EnvironmentError(e) 126 try: 127 import zipimport 128 except ImportError: 129 pass 130 else: 131 for aPath in self.toolpath: 132 try: 133 importer = zipimport.zipimporter(aPath) 134 return importer.load_module(self.name) 135 except ImportError, e: 136 pass 137 finally: 138 sys.path = oldpythonpath 139 140 full_name = 'SCons.Tool.' + self.name 141 try: 142 return sys.modules[full_name] 143 except KeyError: 144 try: 145 smpath = sys.modules['SCons.Tool'].__path__ 146 try: 147 file, path, desc = imp.find_module(self.name, smpath) 148 module = imp.load_module(full_name, file, path, desc) 149 setattr(SCons.Tool, self.name, module) 150 if file: 151 file.close() 152 return module 153 except ImportError, e: 154 if str(e)!="No module named %s"%self.name: 155 raise SCons.Errors.EnvironmentError(e) 156 try: 157 import zipimport 158 importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] ) 159 module = importer.load_module(full_name) 160 setattr(SCons.Tool, self.name, module) 161 return module 162 except ImportError, e: 163 m = "No tool named '%s': %s" % (self.name, e) 164 raise SCons.Errors.EnvironmentError(m) 165 except ImportError, e: 166 m = "No tool named '%s': %s" % (self.name, e) 167 raise SCons.Errors.EnvironmentError(m) 168 169 def __call__(self, env, *args, **kw): 170 if self.init_kw is not None: 171 # Merge call kws into init kws; 172 # but don't bash self.init_kw. 173 if kw is not None: 174 call_kw = kw 175 kw = self.init_kw.copy() 176 kw.update(call_kw) 177 else: 178 kw = self.init_kw 179 env.Append(TOOLS = [ self.name ]) 180 if hasattr(self, 'options'): 181 import SCons.Variables 182 if 'options' not in env: 183 from SCons.Script import ARGUMENTS 184 env['options']=SCons.Variables.Variables(args=ARGUMENTS) 185 opts=env['options'] 186 187 self.options(opts) 188 opts.Update(env) 189 190 self.generate(env, *args, **kw) 191 192 def __str__(self): 193 return self.name 194 195########################################################################## 196# Create common executable program / library / object builders 197 198def createProgBuilder(env): 199 """This is a utility function that creates the Program 200 Builder in an Environment if it is not there already. 201 202 If it is already there, we return the existing one. 203 """ 204 205 try: 206 program = env['BUILDERS']['Program'] 207 except KeyError: 208 import SCons.Defaults 209 program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction, 210 emitter = '$PROGEMITTER', 211 prefix = '$PROGPREFIX', 212 suffix = '$PROGSUFFIX', 213 src_suffix = '$OBJSUFFIX', 214 src_builder = 'Object', 215 target_scanner = ProgramScanner) 216 env['BUILDERS']['Program'] = program 217 218 return program 219 220def createStaticLibBuilder(env): 221 """This is a utility function that creates the StaticLibrary 222 Builder in an Environment if it is not there already. 223 224 If it is already there, we return the existing one. 225 """ 226 227 try: 228 static_lib = env['BUILDERS']['StaticLibrary'] 229 except KeyError: 230 action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ] 231 if env.Detect('ranlib'): 232 ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR") 233 action_list.append(ranlib_action) 234 235 static_lib = SCons.Builder.Builder(action = action_list, 236 emitter = '$LIBEMITTER', 237 prefix = '$LIBPREFIX', 238 suffix = '$LIBSUFFIX', 239 src_suffix = '$OBJSUFFIX', 240 src_builder = 'StaticObject') 241 env['BUILDERS']['StaticLibrary'] = static_lib 242 env['BUILDERS']['Library'] = static_lib 243 244 return static_lib 245 246def _call_linker_cb(env, callback, args, result = None): 247 """Returns the result of env['LINKCALLBACKS'][callback](*args) 248 if env['LINKCALLBACKS'] is a dictionary and env['LINKCALLBACKS'][callback] 249 is callable. If these conditions are not met, return the value provided as 250 the *result* argument. This function is mainly used for generating library 251 info such as versioned suffixes, symlink maps, sonames etc. by delegating 252 the core job to callbacks configured by current linker tool""" 253 254 Verbose = False 255 256 if Verbose: 257 print '_call_linker_cb: args=%r' % args 258 print '_call_linker_cb: callback=%r' % callback 259 260 try: 261 cbfun = env['LINKCALLBACKS'][callback] 262 except (KeyError, TypeError): 263 if Verbose: 264 print '_call_linker_cb: env["LINKCALLBACKS"][%r] not found or can not be used' % callback 265 pass 266 else: 267 if Verbose: 268 print '_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback 269 print '_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun) 270 if(callable(cbfun)): 271 if Verbose: 272 print '_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback 273 result = cbfun(env, *args) 274 return result 275 276def _call_env_subst(env, string, *args, **kw): 277 kw2 = {} 278 for k in ('raw', 'target', 'source', 'conv', 'executor'): 279 try: kw2[k] = kw[k] 280 except KeyError: pass 281 return env.subst(string, *args, **kw2) 282 283class _ShLibInfoSupport(object): 284 def get_libtype(self): 285 return 'ShLib' 286 def get_lib_prefix(self, env, *args, **kw): 287 return _call_env_subst(env,'$SHLIBPREFIX', *args, **kw) 288 def get_lib_suffix(self, env, *args, **kw): 289 return _call_env_subst(env,'$SHLIBSUFFIX', *args, **kw) 290 def get_lib_version(self, env, *args, **kw): 291 return _call_env_subst(env,'$SHLIBVERSION', *args, **kw) 292 def get_lib_noversionsymlinks(self, env, *args, **kw): 293 return _call_env_subst(env,'$SHLIBNOVERSIONSYMLINKS', *args, **kw) 294 295class _LdModInfoSupport(object): 296 def get_libtype(self): 297 return 'LdMod' 298 def get_lib_prefix(self, env, *args, **kw): 299 return _call_env_subst(env,'$LDMODULEPREFIX', *args, **kw) 300 def get_lib_suffix(self, env, *args, **kw): 301 return _call_env_subst(env,'$LDMODULESUFFIX', *args, **kw) 302 def get_lib_version(self, env, *args, **kw): 303 return _call_env_subst(env,'$LDMODULEVERSION', *args, **kw) 304 def get_lib_noversionsymlinks(self, env, *args, **kw): 305 return _call_env_subst(env,'$LDMODULENOVERSIONSYMLINKS', *args, **kw) 306 307class _ImpLibInfoSupport(object): 308 def get_libtype(self): 309 return 'ImpLib' 310 def get_lib_prefix(self, env, *args, **kw): 311 return _call_env_subst(env,'$IMPLIBPREFIX', *args, **kw) 312 def get_lib_suffix(self, env, *args, **kw): 313 return _call_env_subst(env,'$IMPLIBSUFFIX', *args, **kw) 314 def get_lib_version(self, env, *args, **kw): 315 version = _call_env_subst(env,'$IMPLIBVERSION', *args, **kw) 316 if not version: 317 try: lt = kw['implib_libtype'] 318 except KeyError: pass 319 else: 320 if lt == 'ShLib': 321 version = _call_env_subst(env,'$SHLIBVERSION', *args, **kw) 322 elif lt == 'LdMod': 323 version = _call_env_subst(env,'$LDMODULEVERSION', *args, **kw) 324 return version 325 def get_lib_noversionsymlinks(self, env, *args, **kw): 326 disable = None 327 try: env['IMPLIBNOVERSIONSYMLINKS'] 328 except KeyError: 329 try: lt = kw['implib_libtype'] 330 except KeyError: pass 331 else: 332 if lt == 'ShLib': 333 disable = _call_env_subst(env,'$SHLIBNOVERSIONSYMLINKS', *args, **kw) 334 elif lt == 'LdMod': 335 disable = _call_env_subst(env,'$LDMODULENOVERSIONSYMLINKS', *args, **kw) 336 else: 337 disable = _call_env_subst(env,'$IMPLIBNOVERSIONSYMLINKS', *args, **kw) 338 return disable 339 340class _LibInfoGeneratorBase(object): 341 """Generator base class for library-related info such as suffixes for 342 versioned libraries, symlink maps, sonames etc. It handles commonities 343 of SharedLibrary and LoadableModule 344 """ 345 _support_classes = { 'ShLib' : _ShLibInfoSupport, 346 'LdMod' : _LdModInfoSupport, 347 'ImpLib' : _ImpLibInfoSupport } 348 def __init__(self, libtype, infoname): 349 self.set_libtype(libtype) 350 self.set_infoname(infoname) 351 352 def set_libtype(self, libtype): 353 try: 354 support_class = self._support_classes[libtype] 355 except KeyError: 356 raise ValueError('unsupported libtype %r' % libtype) 357 self._support = support_class() 358 359 def get_libtype(self): 360 return self._support.get_libtype() 361 362 def set_infoname(self, infoname): 363 self.infoname = infoname 364 365 def get_infoname(self): 366 return self.infoname 367 368 def get_lib_prefix(self, env, *args, **kw): 369 return self._support.get_lib_prefix(env,*args,**kw) 370 371 def get_lib_suffix(self, env, *args, **kw): 372 return self._support.get_lib_suffix(env,*args,**kw) 373 374 def get_lib_version(self, env, *args, **kw): 375 return self._support.get_lib_version(env,*args,**kw) 376 377 def get_lib_noversionsymlinks(self, env, *args, **kw): 378 return self._support.get_lib_noversionsymlinks(env,*args,**kw) 379 380 # Returns name of generator linker callback that shall be used to generate 381 # our info for a versioned library. For example, if our libtype is 'ShLib' 382 # and infoname is 'Prefix', it would return 'VersionedShLibPrefix'. 383 def get_versioned_lib_info_generator(self, **kw): 384 try: libtype = kw['generator_libtype'] 385 except KeyError: libtype = self.get_libtype() 386 infoname = self.get_infoname() 387 return 'Versioned%s%s' % (libtype, infoname) 388 389 def generate_versioned_lib_info(self, env, args, result = None, **kw): 390 callback = self.get_versioned_lib_info_generator(**kw) 391 return _call_linker_cb(env, callback, args, result) 392 393class _LibPrefixGenerator(_LibInfoGeneratorBase): 394 """Library prefix generator, used as target_prefix in SharedLibrary and 395 LoadableModule builders""" 396 def __init__(self, libtype): 397 super(_LibPrefixGenerator, self).__init__(libtype, 'Prefix') 398 399 def __call__(self, env, sources = None, **kw): 400 Verbose = False 401 402 if sources and 'source' not in kw: 403 kw2 = kw.copy() 404 kw2['source'] = sources 405 else: 406 kw2 = kw 407 408 prefix = self.get_lib_prefix(env,**kw2) 409 if Verbose: 410 print "_LibPrefixGenerator: input prefix=%r" % prefix 411 412 version = self.get_lib_version(env, **kw2) 413 if Verbose: 414 print "_LibPrefixGenerator: version=%r" % version 415 416 if version: 417 prefix = self.generate_versioned_lib_info(env, [prefix, version], prefix, **kw2) 418 419 if Verbose: 420 print "_LibPrefixGenerator: return prefix=%r" % prefix 421 return prefix 422 423ShLibPrefixGenerator = _LibPrefixGenerator('ShLib') 424LdModPrefixGenerator = _LibPrefixGenerator('LdMod') 425ImpLibPrefixGenerator = _LibPrefixGenerator('ImpLib') 426 427class _LibSuffixGenerator(_LibInfoGeneratorBase): 428 """Library suffix generator, used as target_suffix in SharedLibrary and 429 LoadableModule builders""" 430 def __init__(self, libtype): 431 super(_LibSuffixGenerator, self).__init__(libtype, 'Suffix') 432 433 def __call__(self, env, sources = None, **kw): 434 Verbose = False 435 436 if sources and 'source' not in kw: 437 kw2 = kw.copy() 438 kw2['source'] = sources 439 else: 440 kw2 = kw 441 442 suffix = self.get_lib_suffix(env, **kw2) 443 if Verbose: 444 print "_LibSuffixGenerator: input suffix=%r" % suffix 445 446 version = self.get_lib_version(env, **kw2) 447 if Verbose: 448 print "_LibSuffixGenerator: version=%r" % version 449 450 if version: 451 suffix = self.generate_versioned_lib_info(env, [suffix, version], suffix, **kw2) 452 453 if Verbose: 454 print "_LibSuffixGenerator: return suffix=%r" % suffix 455 return suffix 456 457ShLibSuffixGenerator = _LibSuffixGenerator('ShLib') 458LdModSuffixGenerator = _LibSuffixGenerator('LdMod') 459ImpLibSuffixGenerator = _LibSuffixGenerator('ImpLib') 460 461class _LibSymlinkGenerator(_LibInfoGeneratorBase): 462 """Library symlink map generator. It generates a list of symlinks that 463 should be created by SharedLibrary or LoadableModule builders""" 464 def __init__(self, libtype): 465 super(_LibSymlinkGenerator, self).__init__(libtype, 'Symlinks') 466 467 def __call__(self, env, libnode, **kw): 468 Verbose = False 469 470 if libnode and 'target' not in kw: 471 kw2 = kw.copy() 472 kw2['target'] = libnode 473 else: 474 kw2 = kw 475 476 if Verbose: 477 print "_LibSymLinkGenerator: libnode=%r" % libnode.get_path() 478 479 symlinks = None 480 481 version = self.get_lib_version(env, **kw2) 482 disable = self.get_lib_noversionsymlinks(env, **kw2) 483 if Verbose: 484 print '_LibSymlinkGenerator: version=%r' % version 485 print '_LibSymlinkGenerator: disable=%r' % disable 486 487 if version and not disable: 488 prefix = self.get_lib_prefix(env,**kw2) 489 suffix = self.get_lib_suffix(env,**kw2) 490 symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) 491 492 if Verbose: 493 print '_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks) 494 return symlinks 495 496ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib') 497LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod') 498ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib') 499 500class _LibNameGenerator(_LibInfoGeneratorBase): 501 """Generates "unmangled" library name from a library file node. 502 503 Generally, it's thought to revert modifications done by prefix/suffix 504 generators (_LibPrefixGenerator/_LibSuffixGenerator) used by a library 505 builder. For example, on gnulink the suffix generator used by SharedLibrary 506 builder appends $SHLIBVERSION to $SHLIBSUFFIX producing node name which 507 ends with "$SHLIBSUFFIX.$SHLIBVERSION". Correspondingly, the implementation 508 of _LibNameGenerator replaces "$SHLIBSUFFIX.$SHLIBVERSION" with 509 "$SHLIBSUFFIX" in the node's basename. So that, if $SHLIBSUFFIX is ".so", 510 $SHLIBVERSION is "0.1.2" and the node path is "/foo/bar/libfoo.so.0.1.2", 511 the _LibNameGenerator shall return "libfoo.so". Other link tools may 512 implement it's own way of library name unmangling. 513 """ 514 def __init__(self, libtype): 515 super(_LibNameGenerator, self).__init__(libtype, 'Name') 516 517 def __call__(self, env, libnode, **kw): 518 """Returns "demangled" library name""" 519 Verbose = False 520 521 if libnode and 'target' not in kw: 522 kw2 = kw.copy() 523 kw2['target'] = libnode 524 else: 525 kw2 = kw 526 527 if Verbose: 528 print "_LibNameGenerator: libnode=%r" % libnode.get_path() 529 530 version = self.get_lib_version(env, **kw2) 531 if Verbose: 532 print '_LibNameGenerator: version=%r' % version 533 534 name = None 535 if version: 536 prefix = self.get_lib_prefix(env,**kw2) 537 suffix = self.get_lib_suffix(env,**kw2) 538 name = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) 539 540 if not name: 541 name = os.path.basename(libnode.get_path()) 542 543 if Verbose: 544 print '_LibNameGenerator: return name=%r' % name 545 546 return name 547 548ShLibNameGenerator = _LibNameGenerator('ShLib') 549LdModNameGenerator = _LibNameGenerator('LdMod') 550ImpLibNameGenerator = _LibNameGenerator('ImpLib') 551 552class _LibSonameGenerator(_LibInfoGeneratorBase): 553 """Library soname generator. Returns library soname (e.g. libfoo.so.0) for 554 a given node (e.g. /foo/bar/libfoo.so.0.1.2)""" 555 def __init__(self, libtype): 556 super(_LibSonameGenerator, self).__init__(libtype, 'Soname') 557 558 def __call__(self, env, libnode, **kw): 559 """Returns a SONAME based on a shared library's node path""" 560 Verbose = False 561 562 if libnode and 'target' not in kw: 563 kw2 = kw.copy() 564 kw2['target'] = libnode 565 else: 566 kw2 = kw 567 568 if Verbose: 569 print "_LibSonameGenerator: libnode=%r" % libnode.get_path() 570 571 soname = _call_env_subst(env, '$SONAME', **kw2) 572 if not soname: 573 version = self.get_lib_version(env,**kw2) 574 if Verbose: 575 print "_LibSonameGenerator: version=%r" % version 576 if version: 577 prefix = self.get_lib_prefix(env,**kw2) 578 suffix = self.get_lib_suffix(env,**kw2) 579 soname = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2) 580 581 if not soname: 582 # fallback to library name (as returned by appropriate _LibNameGenerator) 583 soname = _LibNameGenerator(self.get_libtype())(env, libnode) 584 if Verbose: 585 print "_LibSonameGenerator: FALLBACK: soname=%r" % soname 586 587 if Verbose: 588 print "_LibSonameGenerator: return soname=%r" % soname 589 590 return soname 591 592ShLibSonameGenerator = _LibSonameGenerator('ShLib') 593LdModSonameGenerator = _LibSonameGenerator('LdMod') 594 595def StringizeLibSymlinks(symlinks): 596 """Converts list with pairs of nodes to list with pairs of node paths 597 (strings). Used mainly for debugging.""" 598 if SCons.Util.is_List(symlinks): 599 try: 600 return [ (k.get_path(), v.get_path()) for k,v in symlinks ] 601 except (TypeError, ValueError): 602 return symlinks 603 else: 604 return symlinks 605 606def EmitLibSymlinks(env, symlinks, libnode, **kw): 607 """Used by emitters to handle (shared/versioned) library symlinks""" 608 Verbose = False 609 610 # nodes involved in process... all symlinks + library 611 nodes = list(set([ x for x,y in symlinks ] + [libnode])) 612 613 clean_targets = kw.get('clean_targets', []) 614 if not SCons.Util.is_List(clean_targets): 615 clean_targets = [ clean_targets ] 616 617 for link, linktgt in symlinks: 618 env.SideEffect(link, linktgt) 619 if(Verbose): 620 print "EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path()) 621 clean_list = filter(lambda x : x != linktgt, nodes) 622 env.Clean(list(set([linktgt] + clean_targets)), clean_list) 623 if(Verbose): 624 print "EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), map(lambda x : x.get_path(), clean_list)) 625 626def CreateLibSymlinks(env, symlinks): 627 """Physically creates symlinks. The symlinks argument must be a list in 628 form [ (link, linktarget), ... ], where link and linktarget are SCons 629 nodes. 630 """ 631 632 Verbose = False 633 for link, linktgt in symlinks: 634 linktgt = link.get_dir().rel_path(linktgt) 635 link = link.get_path() 636 if(Verbose): 637 print "CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt) 638 # Delete the (previously created) symlink if exists. Let only symlinks 639 # to be deleted to prevent accidental deletion of source files... 640 if env.fs.islink(link): 641 env.fs.unlink(link) 642 if(Verbose): 643 print "CreateLibSymlinks: removed old symlink %r" % link 644 # If a file or directory exists with the same name as link, an OSError 645 # will be thrown, which should be enough, I think. 646 env.fs.symlink(linktgt, link) 647 if(Verbose): 648 print "CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt) 649 return 0 650 651def LibSymlinksActionFunction(target, source, env): 652 for tgt in target: 653 symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None) 654 if symlinks: 655 CreateLibSymlinks(env, symlinks) 656 return 0 657 658def LibSymlinksStrFun(target, source, env, *args): 659 cmd = None 660 for tgt in target: 661 symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None) 662 if symlinks: 663 if cmd is None: cmd = "" 664 if cmd: cmd += "\n" 665 cmd += "Create symlinks for: %r" % tgt.get_path() 666 try: 667 linkstr = ', '.join([ "%r->%r" %(k,v) for k,v in StringizeLibSymlinks(symlinks)]) 668 except (KeyError, ValueError): 669 pass 670 else: 671 cmd += ": %s" % linkstr 672 return cmd 673 674 675LibSymlinksAction = SCons.Action.Action(LibSymlinksActionFunction, LibSymlinksStrFun) 676 677def createSharedLibBuilder(env): 678 """This is a utility function that creates the SharedLibrary 679 Builder in an Environment if it is not there already. 680 681 If it is already there, we return the existing one. 682 """ 683 684 try: 685 shared_lib = env['BUILDERS']['SharedLibrary'] 686 except KeyError: 687 import SCons.Defaults 688 action_list = [ SCons.Defaults.SharedCheck, 689 SCons.Defaults.ShLinkAction, 690 LibSymlinksAction ] 691 shared_lib = SCons.Builder.Builder(action = action_list, 692 emitter = "$SHLIBEMITTER", 693 prefix = ShLibPrefixGenerator, 694 suffix = ShLibSuffixGenerator, 695 target_scanner = ProgramScanner, 696 src_suffix = '$SHOBJSUFFIX', 697 src_builder = 'SharedObject') 698 env['BUILDERS']['SharedLibrary'] = shared_lib 699 700 return shared_lib 701 702def createLoadableModuleBuilder(env): 703 """This is a utility function that creates the LoadableModule 704 Builder in an Environment if it is not there already. 705 706 If it is already there, we return the existing one. 707 """ 708 709 try: 710 ld_module = env['BUILDERS']['LoadableModule'] 711 except KeyError: 712 import SCons.Defaults 713 action_list = [ SCons.Defaults.SharedCheck, 714 SCons.Defaults.LdModuleLinkAction, 715 LibSymlinksAction ] 716 ld_module = SCons.Builder.Builder(action = action_list, 717 emitter = "$LDMODULEEMITTER", 718 prefix = LdModPrefixGenerator, 719 suffix = LdModSuffixGenerator, 720 target_scanner = ProgramScanner, 721 src_suffix = '$SHOBJSUFFIX', 722 src_builder = 'SharedObject') 723 env['BUILDERS']['LoadableModule'] = ld_module 724 725 return ld_module 726 727def createObjBuilders(env): 728 """This is a utility function that creates the StaticObject 729 and SharedObject Builders in an Environment if they 730 are not there already. 731 732 If they are there already, we return the existing ones. 733 734 This is a separate function because soooo many Tools 735 use this functionality. 736 737 The return is a 2-tuple of (StaticObject, SharedObject) 738 """ 739 740 741 try: 742 static_obj = env['BUILDERS']['StaticObject'] 743 except KeyError: 744 static_obj = SCons.Builder.Builder(action = {}, 745 emitter = {}, 746 prefix = '$OBJPREFIX', 747 suffix = '$OBJSUFFIX', 748 src_builder = ['CFile', 'CXXFile'], 749 source_scanner = SourceFileScanner, 750 single_source = 1) 751 env['BUILDERS']['StaticObject'] = static_obj 752 env['BUILDERS']['Object'] = static_obj 753 754 try: 755 shared_obj = env['BUILDERS']['SharedObject'] 756 except KeyError: 757 shared_obj = SCons.Builder.Builder(action = {}, 758 emitter = {}, 759 prefix = '$SHOBJPREFIX', 760 suffix = '$SHOBJSUFFIX', 761 src_builder = ['CFile', 'CXXFile'], 762 source_scanner = SourceFileScanner, 763 single_source = 1) 764 env['BUILDERS']['SharedObject'] = shared_obj 765 766 return (static_obj, shared_obj) 767 768def createCFileBuilders(env): 769 """This is a utility function that creates the CFile/CXXFile 770 Builders in an Environment if they 771 are not there already. 772 773 If they are there already, we return the existing ones. 774 775 This is a separate function because soooo many Tools 776 use this functionality. 777 778 The return is a 2-tuple of (CFile, CXXFile) 779 """ 780 781 try: 782 c_file = env['BUILDERS']['CFile'] 783 except KeyError: 784 c_file = SCons.Builder.Builder(action = {}, 785 emitter = {}, 786 suffix = {None:'$CFILESUFFIX'}) 787 env['BUILDERS']['CFile'] = c_file 788 789 env.SetDefault(CFILESUFFIX = '.c') 790 791 try: 792 cxx_file = env['BUILDERS']['CXXFile'] 793 except KeyError: 794 cxx_file = SCons.Builder.Builder(action = {}, 795 emitter = {}, 796 suffix = {None:'$CXXFILESUFFIX'}) 797 env['BUILDERS']['CXXFile'] = cxx_file 798 env.SetDefault(CXXFILESUFFIX = '.cc') 799 800 return (c_file, cxx_file) 801 802########################################################################## 803# Create common Java builders 804 805def CreateJarBuilder(env): 806 try: 807 java_jar = env['BUILDERS']['Jar'] 808 except KeyError: 809 fs = SCons.Node.FS.get_default_fs() 810 jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR') 811 java_jar = SCons.Builder.Builder(action = jar_com, 812 suffix = '$JARSUFFIX', 813 src_suffix = '$JAVACLASSSUFIX', 814 src_builder = 'JavaClassFile', 815 source_factory = fs.Entry) 816 env['BUILDERS']['Jar'] = java_jar 817 return java_jar 818 819def CreateJavaHBuilder(env): 820 try: 821 java_javah = env['BUILDERS']['JavaH'] 822 except KeyError: 823 fs = SCons.Node.FS.get_default_fs() 824 java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR') 825 java_javah = SCons.Builder.Builder(action = java_javah_com, 826 src_suffix = '$JAVACLASSSUFFIX', 827 target_factory = fs.Entry, 828 source_factory = fs.File, 829 src_builder = 'JavaClassFile') 830 env['BUILDERS']['JavaH'] = java_javah 831 return java_javah 832 833def CreateJavaClassFileBuilder(env): 834 try: 835 java_class_file = env['BUILDERS']['JavaClassFile'] 836 except KeyError: 837 fs = SCons.Node.FS.get_default_fs() 838 javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') 839 java_class_file = SCons.Builder.Builder(action = javac_com, 840 emitter = {}, 841 #suffix = '$JAVACLASSSUFFIX', 842 src_suffix = '$JAVASUFFIX', 843 src_builder = ['JavaFile'], 844 target_factory = fs.Entry, 845 source_factory = fs.File) 846 env['BUILDERS']['JavaClassFile'] = java_class_file 847 return java_class_file 848 849def CreateJavaClassDirBuilder(env): 850 try: 851 java_class_dir = env['BUILDERS']['JavaClassDir'] 852 except KeyError: 853 fs = SCons.Node.FS.get_default_fs() 854 javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') 855 java_class_dir = SCons.Builder.Builder(action = javac_com, 856 emitter = {}, 857 target_factory = fs.Dir, 858 source_factory = fs.Dir) 859 env['BUILDERS']['JavaClassDir'] = java_class_dir 860 return java_class_dir 861 862def CreateJavaFileBuilder(env): 863 try: 864 java_file = env['BUILDERS']['JavaFile'] 865 except KeyError: 866 java_file = SCons.Builder.Builder(action = {}, 867 emitter = {}, 868 suffix = {None:'$JAVASUFFIX'}) 869 env['BUILDERS']['JavaFile'] = java_file 870 env['JAVASUFFIX'] = '.java' 871 return java_file 872 873class ToolInitializerMethod(object): 874 """ 875 This is added to a construction environment in place of a 876 method(s) normally called for a Builder (env.Object, env.StaticObject, 877 etc.). When called, it has its associated ToolInitializer 878 object search the specified list of tools and apply the first 879 one that exists to the construction environment. It then calls 880 whatever builder was (presumably) added to the construction 881 environment in place of this particular instance. 882 """ 883 def __init__(self, name, initializer): 884 """ 885 Note: we store the tool name as __name__ so it can be used by 886 the class that attaches this to a construction environment. 887 """ 888 self.__name__ = name 889 self.initializer = initializer 890 891 def get_builder(self, env): 892 """ 893 Returns the appropriate real Builder for this method name 894 after having the associated ToolInitializer object apply 895 the appropriate Tool module. 896 """ 897 builder = getattr(env, self.__name__) 898 899 self.initializer.apply_tools(env) 900 901 builder = getattr(env, self.__name__) 902 if builder is self: 903 # There was no Builder added, which means no valid Tool 904 # for this name was found (or possibly there's a mismatch 905 # between the name we were called by and the Builder name 906 # added by the Tool module). 907 return None 908 909 self.initializer.remove_methods(env) 910 911 return builder 912 913 def __call__(self, env, *args, **kw): 914 """ 915 """ 916 builder = self.get_builder(env) 917 if builder is None: 918 return [], [] 919 return builder(*args, **kw) 920 921class ToolInitializer(object): 922 """ 923 A class for delayed initialization of Tools modules. 924 925 Instances of this class associate a list of Tool modules with 926 a list of Builder method names that will be added by those Tool 927 modules. As part of instantiating this object for a particular 928 construction environment, we also add the appropriate 929 ToolInitializerMethod objects for the various Builder methods 930 that we want to use to delay Tool searches until necessary. 931 """ 932 def __init__(self, env, tools, names): 933 if not SCons.Util.is_List(tools): 934 tools = [tools] 935 if not SCons.Util.is_List(names): 936 names = [names] 937 self.env = env 938 self.tools = tools 939 self.names = names 940 self.methods = {} 941 for name in names: 942 method = ToolInitializerMethod(name, self) 943 self.methods[name] = method 944 env.AddMethod(method) 945 946 def remove_methods(self, env): 947 """ 948 Removes the methods that were added by the tool initialization 949 so we no longer copy and re-bind them when the construction 950 environment gets cloned. 951 """ 952 for method in self.methods.values(): 953 env.RemoveMethod(method) 954 955 def apply_tools(self, env): 956 """ 957 Searches the list of associated Tool modules for one that 958 exists, and applies that to the construction environment. 959 """ 960 for t in self.tools: 961 tool = SCons.Tool.Tool(t) 962 if tool.exists(env): 963 env.Tool(tool) 964 return 965 966 # If we fall through here, there was no tool module found. 967 # This is where we can put an informative error message 968 # about the inability to find the tool. We'll start doing 969 # this as we cut over more pre-defined Builder+Tools to use 970 # the ToolInitializer class. 971 972def Initializers(env): 973 ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs', '_InternalInstallVersionedLib']) 974 def Install(self, *args, **kw): 975 return self._InternalInstall(*args, **kw) 976 def InstallAs(self, *args, **kw): 977 return self._InternalInstallAs(*args, **kw) 978 def InstallVersionedLib(self, *args, **kw): 979 return self._InternalInstallVersionedLib(*args, **kw) 980 env.AddMethod(Install) 981 env.AddMethod(InstallAs) 982 env.AddMethod(InstallVersionedLib) 983 984def FindTool(tools, env): 985 for tool in tools: 986 t = Tool(tool) 987 if t.exists(env): 988 return tool 989 return None 990 991def FindAllTools(tools, env): 992 def ToolExists(tool, env=env): 993 return Tool(tool).exists(env) 994 return list(filter (ToolExists, tools)) 995 996def tool_list(platform, env): 997 998 other_plat_tools=[] 999 # XXX this logic about what tool to prefer on which platform 1000 # should be moved into either the platform files or 1001 # the tool files themselves. 1002 # The search orders here are described in the man page. If you 1003 # change these search orders, update the man page as well. 1004 if str(platform) == 'win32': 1005 "prefer Microsoft tools on Windows" 1006 linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ] 1007 c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ] 1008 cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ] 1009 assemblers = ['masm', 'nasm', 'gas', '386asm' ] 1010 fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran'] 1011 ars = ['mslib', 'ar', 'tlib'] 1012 other_plat_tools = ['msvs', 'midl'] 1013 elif str(platform) == 'os2': 1014 "prefer IBM tools on OS/2" 1015 linkers = ['ilink', 'gnulink', ]#'mslink'] 1016 c_compilers = ['icc', 'gcc',]# 'msvc', 'cc'] 1017 cxx_compilers = ['icc', 'g++',]# 'msvc', 'c++'] 1018 assemblers = ['nasm',]# 'masm', 'gas'] 1019 fortran_compilers = ['ifl', 'g77'] 1020 ars = ['ar',]# 'mslib'] 1021 elif str(platform) == 'irix': 1022 "prefer MIPSPro on IRIX" 1023 linkers = ['sgilink', 'gnulink'] 1024 c_compilers = ['sgicc', 'gcc', 'cc'] 1025 cxx_compilers = ['sgic++', 'g++', 'c++'] 1026 assemblers = ['as', 'gas'] 1027 fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] 1028 ars = ['sgiar'] 1029 elif str(platform) == 'sunos': 1030 "prefer Forte tools on SunOS" 1031 linkers = ['sunlink', 'gnulink'] 1032 c_compilers = ['suncc', 'gcc', 'cc'] 1033 cxx_compilers = ['sunc++', 'g++', 'c++'] 1034 assemblers = ['as', 'gas'] 1035 fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77', 1036 'gfortran', 'g77', 'fortran'] 1037 ars = ['sunar'] 1038 elif str(platform) == 'hpux': 1039 "prefer aCC tools on HP-UX" 1040 linkers = ['hplink', 'gnulink'] 1041 c_compilers = ['hpcc', 'gcc', 'cc'] 1042 cxx_compilers = ['hpc++', 'g++', 'c++'] 1043 assemblers = ['as', 'gas'] 1044 fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] 1045 ars = ['ar'] 1046 elif str(platform) == 'aix': 1047 "prefer AIX Visual Age tools on AIX" 1048 linkers = ['aixlink', 'gnulink'] 1049 c_compilers = ['aixcc', 'gcc', 'cc'] 1050 cxx_compilers = ['aixc++', 'g++', 'c++'] 1051 assemblers = ['as', 'gas'] 1052 fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran'] 1053 ars = ['ar'] 1054 elif str(platform) == 'darwin': 1055 "prefer GNU tools on Mac OS X, except for some linkers and IBM tools" 1056 linkers = ['applelink', 'gnulink'] 1057 c_compilers = ['gcc', 'cc'] 1058 cxx_compilers = ['g++', 'c++'] 1059 assemblers = ['as'] 1060 fortran_compilers = ['gfortran', 'f95', 'f90', 'g77'] 1061 ars = ['ar'] 1062 elif str(platform) == 'cygwin': 1063 "prefer GNU tools on Cygwin, except for a platform-specific linker" 1064 linkers = ['cyglink', 'mslink', 'ilink'] 1065 c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] 1066 cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++'] 1067 assemblers = ['gas', 'nasm', 'masm'] 1068 fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] 1069 ars = ['ar', 'mslib'] 1070 else: 1071 "prefer GNU tools on all other platforms" 1072 linkers = ['gnulink', 'mslink', 'ilink'] 1073 c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] 1074 cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++'] 1075 assemblers = ['gas', 'nasm', 'masm'] 1076 fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] 1077 ars = ['ar', 'mslib'] 1078 1079 if not str(platform) == 'win32': 1080 other_plat_tools += ['m4', 'rpm'] 1081 1082 c_compiler = FindTool(c_compilers, env) or c_compilers[0] 1083 1084 # XXX this logic about what tool provides what should somehow be 1085 # moved into the tool files themselves. 1086 if c_compiler and c_compiler == 'mingw': 1087 # MinGW contains a linker, C compiler, C++ compiler, 1088 # Fortran compiler, archiver and assembler: 1089 cxx_compiler = None 1090 linker = None 1091 assembler = None 1092 fortran_compiler = None 1093 ar = None 1094 else: 1095 # Don't use g++ if the C compiler has built-in C++ support: 1096 if c_compiler in ('msvc', 'intelc', 'icc'): 1097 cxx_compiler = None 1098 else: 1099 cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0] 1100 linker = FindTool(linkers, env) or linkers[0] 1101 assembler = FindTool(assemblers, env) or assemblers[0] 1102 fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0] 1103 ar = FindTool(ars, env) or ars[0] 1104 1105 d_compilers = ['dmd', 'gdc', 'ldc'] 1106 d_compiler = FindTool(d_compilers, env) or d_compilers[0] 1107 1108 other_tools = FindAllTools(other_plat_tools + [ 1109 #TODO: merge 'install' into 'filesystem' and 1110 # make 'filesystem' the default 1111 'filesystem', 1112 'wix', #'midl', 'msvs', 1113 # Parser generators 1114 'lex', 'yacc', 1115 # Foreign function interface 1116 'rpcgen', 'swig', 1117 # Java 1118 'jar', 'javac', 'javah', 'rmic', 1119 # TeX 1120 'dvipdf', 'dvips', 'gs', 1121 'tex', 'latex', 'pdflatex', 'pdftex', 1122 # Archivers 1123 'tar', 'zip', 1124 # SourceCode factories 1125 'BitKeeper', 'CVS', 'Perforce', 1126 'RCS', 'SCCS', # 'Subversion', 1127 ], env) 1128 1129 tools = ([linker, c_compiler, cxx_compiler, 1130 fortran_compiler, assembler, ar, d_compiler] 1131 + other_tools) 1132 1133 return [x for x in tools if x] 1134 1135# Local Variables: 1136# tab-width:4 1137# indent-tabs-mode:nil 1138# End: 1139# vim: set expandtab tabstop=4 shiftwidth=4: 1140 1141