Package SCons :: Module Defaults
[hide private]
[frames] | no frames]

Source Code for Module SCons.Defaults

  1  """SCons.Defaults 
  2   
  3  Builders and other things for the local site.  Here's where we'll 
  4  duplicate the functionality of autoconf until we move it into the 
  5  installation procedure or use something like qmconf. 
  6   
  7  The code that reads the registry to find MSVC components was borrowed 
  8  from distutils.msvccompiler. 
  9   
 10  """ 
 11   
 12  # 
 13  # Copyright (c) 2001 - 2016 The SCons Foundation 
 14  # 
 15  # Permission is hereby granted, free of charge, to any person obtaining 
 16  # a copy of this software and associated documentation files (the 
 17  # "Software"), to deal in the Software without restriction, including 
 18  # without limitation the rights to use, copy, modify, merge, publish, 
 19  # distribute, sublicense, and/or sell copies of the Software, and to 
 20  # permit persons to whom the Software is furnished to do so, subject to 
 21  # the following conditions: 
 22  # 
 23  # The above copyright notice and this permission notice shall be included 
 24  # in all copies or substantial portions of the Software. 
 25  # 
 26  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 27  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 28  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 29  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
 30  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
 31  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
 32  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 33  # 
 34  from __future__ import division 
 35   
 36  __revision__ = "src/engine/SCons/Defaults.py rel_2.5.0:3543:937e55cd78f7 2016/04/09 11:29:54 bdbaddog" 
 37   
 38   
 39  import os 
 40  import errno 
 41  import shutil 
 42  import stat 
 43  import time 
 44  import sys 
 45   
 46  import SCons.Action 
 47  import SCons.Builder 
 48  import SCons.CacheDir 
 49  import SCons.Environment 
 50  import SCons.PathList 
 51  import SCons.Subst 
 52  import SCons.Tool 
 53   
 54  # A placeholder for a default Environment (for fetching source files 
 55  # from source code management systems and the like).  This must be 
 56  # initialized later, after the top-level directory is set by the calling 
 57  # interface. 
 58  _default_env = None 
 59   
 60  # Lazily instantiate the default environment so the overhead of creating 
 61  # it doesn't apply when it's not needed. 
62 -def _fetch_DefaultEnvironment(*args, **kw):
63 """ 64 Returns the already-created default construction environment. 65 """ 66 global _default_env 67 return _default_env
68
69 -def DefaultEnvironment(*args, **kw):
70 """ 71 Initial public entry point for creating the default construction 72 Environment. 73 74 After creating the environment, we overwrite our name 75 (DefaultEnvironment) with the _fetch_DefaultEnvironment() function, 76 which more efficiently returns the initialized default construction 77 environment without checking for its existence. 78 79 (This function still exists with its _default_check because someone 80 else (*cough* Script/__init__.py *cough*) may keep a reference 81 to this function. So we can't use the fully functional idiom of 82 having the name originally be a something that *only* creates the 83 construction environment and then overwrites the name.) 84 """ 85 global _default_env 86 if not _default_env: 87 import SCons.Util 88 _default_env = SCons.Environment.Environment(*args, **kw) 89 if SCons.Util.md5: 90 _default_env.Decider('MD5') 91 else: 92 _default_env.Decider('timestamp-match') 93 global DefaultEnvironment 94 DefaultEnvironment = _fetch_DefaultEnvironment 95 _default_env._CacheDir_path = None 96 return _default_env
97 98 # Emitters for setting the shared attribute on object files, 99 # and an action for checking that all of the source files 100 # going into a shared library are, in fact, shared.
101 -def StaticObjectEmitter(target, source, env):
102 for tgt in target: 103 tgt.attributes.shared = None 104 return (target, source)
105
106 -def SharedObjectEmitter(target, source, env):
107 for tgt in target: 108 tgt.attributes.shared = 1 109 return (target, source)
110
111 -def SharedFlagChecker(source, target, env):
112 same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME') 113 if same == '0' or same == '' or same == 'False': 114 for src in source: 115 try: 116 shared = src.attributes.shared 117 except AttributeError: 118 shared = None 119 if not shared: 120 raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
121 122 SharedCheck = SCons.Action.Action(SharedFlagChecker, None) 123 124 # Some people were using these variable name before we made 125 # SourceFileScanner part of the public interface. Don't break their 126 # SConscript files until we've given them some fair warning and a 127 # transition period. 128 CScan = SCons.Tool.CScanner 129 DScan = SCons.Tool.DScanner 130 LaTeXScan = SCons.Tool.LaTeXScanner 131 ObjSourceScan = SCons.Tool.SourceFileScanner 132 ProgScan = SCons.Tool.ProgramScanner 133 134 # These aren't really tool scanners, so they don't quite belong with 135 # the rest of those in Tool/__init__.py, but I'm not sure where else 136 # they should go. Leave them here for now. 137 import SCons.Scanner.Dir 138 DirScanner = SCons.Scanner.Dir.DirScanner() 139 DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner() 140 141 # Actions for common languages. 142 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR") 143 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR") 144 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR") 145 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR") 146 147 DAction = SCons.Action.Action("$DCOM", "$DCOMSTR") 148 ShDAction = SCons.Action.Action("$SHDCOM", "$SHDCOMSTR") 149 150 ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR") 151 ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR") 152 153 LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR") 154 ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR") 155 156 LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR") 157 158 # Common tasks that we allow users to perform in platform-independent 159 # ways by creating ActionFactory instances. 160 ActionFactory = SCons.Action.ActionFactory 161
162 -def get_paths_str(dest):
163 # If dest is a list, we need to manually call str() on each element 164 if SCons.Util.is_List(dest): 165 elem_strs = [] 166 for element in dest: 167 elem_strs.append('"' + str(element) + '"') 168 return '[' + ', '.join(elem_strs) + ']' 169 else: 170 return '"' + str(dest) + '"'
171 172 permission_dic = { 173 'u':{ 174 'r':stat.S_IRUSR, 175 'w':stat.S_IWUSR, 176 'x':stat.S_IXUSR 177 }, 178 'g':{ 179 'r':stat.S_IRGRP, 180 'w':stat.S_IWGRP, 181 'x':stat.S_IXGRP 182 }, 183 'o':{ 184 'r':stat.S_IROTH, 185 'w':stat.S_IWOTH, 186 'x':stat.S_IXOTH 187 } 188 } 189
190 -def chmod_func(dest, mode):
191 import SCons.Util 192 from string import digits 193 SCons.Node.FS.invalidate_node_memos(dest) 194 if not SCons.Util.is_List(dest): 195 dest = [dest] 196 if SCons.Util.is_String(mode) and not 0 in [i in digits for i in mode]: 197 mode = int(mode, 8) 198 if not SCons.Util.is_String(mode): 199 for element in dest: 200 os.chmod(str(element), mode) 201 else: 202 mode = str(mode) 203 for operation in mode.split(","): 204 if "=" in operation: 205 operator = "=" 206 elif "+" in operation: 207 operator = "+" 208 elif "-" in operation: 209 operator = "-" 210 else: 211 raise SyntaxError("Could not find +, - or =") 212 operation_list = operation.split(operator) 213 if len(operation_list) is not 2: 214 raise SyntaxError("More than one operator found") 215 user = operation_list[0].strip().replace("a", "ugo") 216 permission = operation_list[1].strip() 217 new_perm = 0 218 for u in user: 219 for p in permission: 220 try: 221 new_perm = new_perm | permission_dic[u][p] 222 except KeyError: 223 raise SyntaxError("Unrecognized user or permission format") 224 for element in dest: 225 curr_perm = os.stat(str(element)).st_mode 226 if operator == "=": 227 os.chmod(str(element), new_perm) 228 elif operator == "+": 229 os.chmod(str(element), curr_perm | new_perm) 230 elif operator == "-": 231 os.chmod(str(element), curr_perm & ~new_perm)
232
233 -def chmod_strfunc(dest, mode):
234 import SCons.Util 235 if not SCons.Util.is_String(mode): 236 return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode) 237 else: 238 return 'Chmod(%s, "%s")' % (get_paths_str(dest), str(mode))
239 240 Chmod = ActionFactory(chmod_func, chmod_strfunc) 241
242 -def copy_func(dest, src, symlinks=True):
243 """ 244 If symlinks (is true), then a symbolic link will be 245 shallow copied and recreated as a symbolic link; otherwise, copying 246 a symbolic link will be equivalent to copying the symbolic link's 247 final target regardless of symbolic link depth. 248 """ 249 250 dest = str(dest) 251 src = str(src) 252 253 SCons.Node.FS.invalidate_node_memos(dest) 254 if SCons.Util.is_List(src) and os.path.isdir(dest): 255 for file in src: 256 shutil.copy2(file, dest) 257 return 0 258 elif os.path.islink(src): 259 if symlinks: 260 return os.symlink(os.readlink(src), dest) 261 else: 262 return copy_func(dest, os.path.realpath(src)) 263 elif os.path.isfile(src): 264 return shutil.copy2(src, dest) 265 else: 266 return shutil.copytree(src, dest, symlinks)
267 268 Copy = ActionFactory( 269 copy_func, 270 lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src) 271 ) 272
273 -def delete_func(dest, must_exist=0):
274 SCons.Node.FS.invalidate_node_memos(dest) 275 if not SCons.Util.is_List(dest): 276 dest = [dest] 277 for entry in dest: 278 entry = str(entry) 279 # os.path.exists returns False with broken links that exist 280 entry_exists = os.path.exists(entry) or os.path.islink(entry) 281 if not entry_exists and not must_exist: 282 continue 283 # os.path.isdir returns True when entry is a link to a dir 284 if os.path.isdir(entry) and not os.path.islink(entry): 285 shutil.rmtree(entry, 1) 286 continue 287 os.unlink(entry)
288
289 -def delete_strfunc(dest, must_exist=0):
290 return 'Delete(%s)' % get_paths_str(dest)
291 292 Delete = ActionFactory(delete_func, delete_strfunc) 293
294 -def mkdir_func(dest):
295 SCons.Node.FS.invalidate_node_memos(dest) 296 if not SCons.Util.is_List(dest): 297 dest = [dest] 298 for entry in dest: 299 try: 300 os.makedirs(str(entry)) 301 except os.error, e: 302 p = str(entry) 303 if (e.args[0] == errno.EEXIST or 304 (sys.platform=='win32' and e.args[0]==183)) \ 305 and os.path.isdir(str(entry)): 306 pass # not an error if already exists 307 else: 308 raise
309 310 Mkdir = ActionFactory(mkdir_func, 311 lambda dir: 'Mkdir(%s)' % get_paths_str(dir)) 312
313 -def move_func(dest, src):
314 SCons.Node.FS.invalidate_node_memos(dest) 315 SCons.Node.FS.invalidate_node_memos(src) 316 shutil.move(src, dest)
317 318 Move = ActionFactory(move_func, 319 lambda dest, src: 'Move("%s", "%s")' % (dest, src), 320 convert=str) 321
322 -def touch_func(dest):
323 SCons.Node.FS.invalidate_node_memos(dest) 324 if not SCons.Util.is_List(dest): 325 dest = [dest] 326 for file in dest: 327 file = str(file) 328 mtime = int(time.time()) 329 if os.path.exists(file): 330 atime = os.path.getatime(file) 331 else: 332 open(file, 'w') 333 atime = mtime 334 os.utime(file, (atime, mtime))
335 336 Touch = ActionFactory(touch_func, 337 lambda file: 'Touch(%s)' % get_paths_str(file)) 338 339 # Internal utility functions 340
341 -def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
342 """ 343 Creates a new list from 'list' by first interpolating each element 344 in the list using the 'env' dictionary and then calling f on the 345 list, and finally calling _concat_ixes to concatenate 'prefix' and 346 'suffix' onto each element of the list. 347 """ 348 if not list: 349 return list 350 351 l = f(SCons.PathList.PathList(list).subst_path(env, target, source)) 352 if l is not None: 353 list = l 354 355 return _concat_ixes(prefix, list, suffix, env)
356
357 -def _concat_ixes(prefix, list, suffix, env):
358 """ 359 Creates a new list from 'list' by concatenating the 'prefix' and 360 'suffix' arguments onto each element of the list. A trailing space 361 on 'prefix' or leading space on 'suffix' will cause them to be put 362 into separate list elements rather than being concatenated. 363 """ 364 365 result = [] 366 367 # ensure that prefix and suffix are strings 368 prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW)) 369 suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW)) 370 371 for x in list: 372 if isinstance(x, SCons.Node.FS.File): 373 result.append(x) 374 continue 375 x = str(x) 376 if x: 377 378 if prefix: 379 if prefix[-1] == ' ': 380 result.append(prefix[:-1]) 381 elif x[:len(prefix)] != prefix: 382 x = prefix + x 383 384 result.append(x) 385 386 if suffix: 387 if suffix[0] == ' ': 388 result.append(suffix[1:]) 389 elif x[-len(suffix):] != suffix: 390 result[-1] = result[-1]+suffix 391 392 return result
393
394 -def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
395 """ 396 This is a wrapper around _concat()/_concat_ixes() that checks for 397 the existence of prefixes or suffixes on list items and strips them 398 where it finds them. This is used by tools (like the GNU linker) 399 that need to turn something like 'libfoo.a' into '-lfoo'. 400 """ 401 402 if not itms: 403 return itms 404 405 if not callable(c): 406 env_c = env['_concat'] 407 if env_c != _concat and callable(env_c): 408 # There's a custom _concat() method in the construction 409 # environment, and we've allowed people to set that in 410 # the past (see test/custom-concat.py), so preserve the 411 # backwards compatibility. 412 c = env_c 413 else: 414 c = _concat_ixes 415 416 stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes))) 417 stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes))) 418 419 stripped = [] 420 for l in SCons.PathList.PathList(itms).subst_path(env, None, None): 421 if isinstance(l, SCons.Node.FS.File): 422 stripped.append(l) 423 continue 424 425 if not SCons.Util.is_String(l): 426 l = str(l) 427 428 for stripprefix in stripprefixes: 429 lsp = len(stripprefix) 430 if l[:lsp] == stripprefix: 431 l = l[lsp:] 432 # Do not strip more than one prefix 433 break 434 435 for stripsuffix in stripsuffixes: 436 lss = len(stripsuffix) 437 if l[-lss:] == stripsuffix: 438 l = l[:-lss] 439 # Do not strip more than one suffix 440 break 441 442 stripped.append(l) 443 444 return c(prefix, stripped, suffix, env)
445
446 -def processDefines(defs):
447 """process defines, resolving strings, lists, dictionaries, into a list of 448 strings 449 """ 450 if SCons.Util.is_List(defs): 451 l = [] 452 for d in defs: 453 if d is None: 454 continue 455 elif SCons.Util.is_List(d) or isinstance(d, tuple): 456 if len(d) >= 2: 457 l.append(str(d[0]) + '=' + str(d[1])) 458 else: 459 l.append(str(d[0])) 460 elif SCons.Util.is_Dict(d): 461 for macro,value in d.iteritems(): 462 if value is not None: 463 l.append(str(macro) + '=' + str(value)) 464 else: 465 l.append(str(macro)) 466 elif SCons.Util.is_String(d): 467 l.append(str(d)) 468 else: 469 raise SCons.Errors.UserError("DEFINE %s is not a list, dict, string or None."%repr(d)) 470 elif SCons.Util.is_Dict(defs): 471 # The items in a dictionary are stored in random order, but 472 # if the order of the command-line options changes from 473 # invocation to invocation, then the signature of the command 474 # line will change and we'll get random unnecessary rebuilds. 475 # Consequently, we have to sort the keys to ensure a 476 # consistent order... 477 l = [] 478 for k,v in sorted(defs.items()): 479 if v is None: 480 l.append(str(k)) 481 else: 482 l.append(str(k) + '=' + str(v)) 483 else: 484 l = [str(defs)] 485 return l
486
487 -def _defines(prefix, defs, suffix, env, c=_concat_ixes):
488 """A wrapper around _concat_ixes that turns a list or string 489 into a list of C preprocessor command-line definitions. 490 """ 491 492 return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
493
494 -class NullCmdGenerator(object):
495 """This is a callable class that can be used in place of other 496 command generators if you don't want them to do anything. 497 498 The __call__ method for this class simply returns the thing 499 you instantiated it with. 500 501 Example usage: 502 env["DO_NOTHING"] = NullCmdGenerator 503 env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}" 504 """ 505
506 - def __init__(self, cmd):
507 self.cmd = cmd
508
509 - def __call__(self, target, source, env, for_signature=None):
510 return self.cmd
511
512 -class Variable_Method_Caller(object):
513 """A class for finding a construction variable on the stack and 514 calling one of its methods. 515 516 We use this to support "construction variables" in our string 517 eval()s that actually stand in for methods--specifically, use 518 of "RDirs" in call to _concat that should actually execute the 519 "TARGET.RDirs" method. (We used to support this by creating a little 520 "build dictionary" that mapped RDirs to the method, but this got in 521 the way of Memoizing construction environments, because we had to 522 create new environment objects to hold the variables.) 523 """
524 - def __init__(self, variable, method):
525 self.variable = variable 526 self.method = method
527 - def __call__(self, *args, **kw):
528 try: 1//0 529 except ZeroDivisionError: 530 # Don't start iterating with the current stack-frame to 531 # prevent creating reference cycles (f_back is safe). 532 frame = sys.exc_info()[2].tb_frame.f_back 533 variable = self.variable 534 while frame: 535 if variable in frame.f_locals: 536 v = frame.f_locals[variable] 537 if v: 538 method = getattr(v, self.method) 539 return method(*args, **kw) 540 frame = frame.f_back 541 return None
542 543 # if env[version_var] id defined, returns env[flags_var], otherwise returns None
544 -def __libversionflags(env, version_var, flags_var):
545 try: 546 if env[version_var]: 547 return env[flags_var] 548 except KeyError: 549 pass 550 return None
551 552 ConstructionEnvironment = { 553 'BUILDERS' : {}, 554 'SCANNERS' : [ SCons.Tool.SourceFileScanner ], 555 'CONFIGUREDIR' : '#/.sconf_temp', 556 'CONFIGURELOG' : '#/config.log', 557 'CPPSUFFIXES' : SCons.Tool.CSuffixes, 558 'DSUFFIXES' : SCons.Tool.DSuffixes, 559 'ENV' : {}, 560 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes, 561 # 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions 562 '_concat' : _concat, 563 '_defines' : _defines, 564 '_stripixes' : _stripixes, 565 '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', 566 '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', 567 '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', 568 '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', 569 570 '__libversionflags' : __libversionflags, 571 '__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}', 572 '__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}', 573 '__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}', 574 575 'TEMPFILE' : NullCmdGenerator, 576 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), 577 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'), 578 'File' : Variable_Method_Caller('TARGET', 'File'), 579 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'), 580 } 581 582 # Local Variables: 583 # tab-width:4 584 # indent-tabs-mode:nil 585 # End: 586 # vim: set expandtab tabstop=4 shiftwidth=4: 587