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 - 2014 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  2014/09/27 12:51:43 garyo" 
 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 -def chmod_func(dest, mode):
173 SCons.Node.FS.invalidate_node_memos(dest) 174 if not SCons.Util.is_List(dest): 175 dest = [dest] 176 for element in dest: 177 os.chmod(str(element), mode)
178
179 -def chmod_strfunc(dest, mode):
180 return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
181 182 Chmod = ActionFactory(chmod_func, chmod_strfunc) 183
184 -def copy_func(dest, src, symlinks=True):
185 """ 186 If symlinks (is true), then a symbolic link will be 187 shallow copied and recreated as a symbolic link; otherwise, copying 188 a symbolic link will be equivalent to copying the symbolic link's 189 final target regardless of symbolic link depth. 190 """ 191 192 dest = str(dest) 193 src = str(src) 194 195 SCons.Node.FS.invalidate_node_memos(dest) 196 if SCons.Util.is_List(src) and os.path.isdir(dest): 197 for file in src: 198 shutil.copy2(file, dest) 199 return 0 200 elif os.path.islink(src): 201 linkto = os.readlink(src) 202 if symlinks: 203 return os.symlink(linkto, dest) 204 else: 205 return copy_func(dest, linkto, symlinks) 206 elif os.path.isfile(src): 207 return shutil.copy2(src, dest) 208 else: 209 return shutil.copytree(src, dest, symlinks)
210 211 Copy = ActionFactory( 212 copy_func, 213 lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src) 214 ) 215
216 -def delete_func(dest, must_exist=0):
217 SCons.Node.FS.invalidate_node_memos(dest) 218 if not SCons.Util.is_List(dest): 219 dest = [dest] 220 for entry in dest: 221 entry = str(entry) 222 # os.path.exists returns False with broken links that exist 223 entry_exists = os.path.exists(entry) or os.path.islink(entry) 224 if not entry_exists and not must_exist: 225 continue 226 # os.path.isdir returns True when entry is a link to a dir 227 if os.path.isdir(entry) and not os.path.islink(entry): 228 shutil.rmtree(entry, 1) 229 continue 230 os.unlink(entry)
231
232 -def delete_strfunc(dest, must_exist=0):
233 return 'Delete(%s)' % get_paths_str(dest)
234 235 Delete = ActionFactory(delete_func, delete_strfunc) 236
237 -def mkdir_func(dest):
238 SCons.Node.FS.invalidate_node_memos(dest) 239 if not SCons.Util.is_List(dest): 240 dest = [dest] 241 for entry in dest: 242 try: 243 os.makedirs(str(entry)) 244 except os.error, e: 245 p = str(entry) 246 if (e.args[0] == errno.EEXIST or 247 (sys.platform=='win32' and e.args[0]==183)) \ 248 and os.path.isdir(str(entry)): 249 pass # not an error if already exists 250 else: 251 raise
252 253 Mkdir = ActionFactory(mkdir_func, 254 lambda dir: 'Mkdir(%s)' % get_paths_str(dir)) 255
256 -def move_func(dest, src):
257 SCons.Node.FS.invalidate_node_memos(dest) 258 SCons.Node.FS.invalidate_node_memos(src) 259 shutil.move(src, dest)
260 261 Move = ActionFactory(move_func, 262 lambda dest, src: 'Move("%s", "%s")' % (dest, src), 263 convert=str) 264
265 -def touch_func(dest):
266 SCons.Node.FS.invalidate_node_memos(dest) 267 if not SCons.Util.is_List(dest): 268 dest = [dest] 269 for file in dest: 270 file = str(file) 271 mtime = int(time.time()) 272 if os.path.exists(file): 273 atime = os.path.getatime(file) 274 else: 275 open(file, 'w') 276 atime = mtime 277 os.utime(file, (atime, mtime))
278 279 Touch = ActionFactory(touch_func, 280 lambda file: 'Touch(%s)' % get_paths_str(file)) 281 282 # Internal utility functions 283
284 -def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
285 """ 286 Creates a new list from 'list' by first interpolating each element 287 in the list using the 'env' dictionary and then calling f on the 288 list, and finally calling _concat_ixes to concatenate 'prefix' and 289 'suffix' onto each element of the list. 290 """ 291 if not list: 292 return list 293 294 l = f(SCons.PathList.PathList(list).subst_path(env, target, source)) 295 if l is not None: 296 list = l 297 298 return _concat_ixes(prefix, list, suffix, env)
299
300 -def _concat_ixes(prefix, list, suffix, env):
301 """ 302 Creates a new list from 'list' by concatenating the 'prefix' and 303 'suffix' arguments onto each element of the list. A trailing space 304 on 'prefix' or leading space on 'suffix' will cause them to be put 305 into separate list elements rather than being concatenated. 306 """ 307 308 result = [] 309 310 # ensure that prefix and suffix are strings 311 prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW)) 312 suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW)) 313 314 for x in list: 315 if isinstance(x, SCons.Node.FS.File): 316 result.append(x) 317 continue 318 x = str(x) 319 if x: 320 321 if prefix: 322 if prefix[-1] == ' ': 323 result.append(prefix[:-1]) 324 elif x[:len(prefix)] != prefix: 325 x = prefix + x 326 327 result.append(x) 328 329 if suffix: 330 if suffix[0] == ' ': 331 result.append(suffix[1:]) 332 elif x[-len(suffix):] != suffix: 333 result[-1] = result[-1]+suffix 334 335 return result
336
337 -def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
338 """ 339 This is a wrapper around _concat()/_concat_ixes() that checks for 340 the existence of prefixes or suffixes on list items and strips them 341 where it finds them. This is used by tools (like the GNU linker) 342 that need to turn something like 'libfoo.a' into '-lfoo'. 343 """ 344 345 if not itms: 346 return itms 347 348 if not callable(c): 349 env_c = env['_concat'] 350 if env_c != _concat and callable(env_c): 351 # There's a custom _concat() method in the construction 352 # environment, and we've allowed people to set that in 353 # the past (see test/custom-concat.py), so preserve the 354 # backwards compatibility. 355 c = env_c 356 else: 357 c = _concat_ixes 358 359 stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes))) 360 stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes))) 361 362 stripped = [] 363 for l in SCons.PathList.PathList(itms).subst_path(env, None, None): 364 if isinstance(l, SCons.Node.FS.File): 365 stripped.append(l) 366 continue 367 368 if not SCons.Util.is_String(l): 369 l = str(l) 370 371 for stripprefix in stripprefixes: 372 lsp = len(stripprefix) 373 if l[:lsp] == stripprefix: 374 l = l[lsp:] 375 # Do not strip more than one prefix 376 break 377 378 for stripsuffix in stripsuffixes: 379 lss = len(stripsuffix) 380 if l[-lss:] == stripsuffix: 381 l = l[:-lss] 382 # Do not strip more than one suffix 383 break 384 385 stripped.append(l) 386 387 return c(prefix, stripped, suffix, env)
388
389 -def processDefines(defs):
390 """process defines, resolving strings, lists, dictionaries, into a list of 391 strings 392 """ 393 if SCons.Util.is_List(defs): 394 l = [] 395 for d in defs: 396 if d is None: 397 continue 398 elif SCons.Util.is_List(d) or isinstance(d, tuple): 399 if len(d) >= 2: 400 l.append(str(d[0]) + '=' + str(d[1])) 401 else: 402 l.append(str(d[0])) 403 elif SCons.Util.is_Dict(d): 404 for macro,value in d.iteritems(): 405 if value is not None: 406 l.append(str(macro) + '=' + str(value)) 407 else: 408 l.append(str(macro)) 409 elif SCons.Util.is_String(d): 410 l.append(str(d)) 411 else: 412 raise SCons.Errors.UserError("DEFINE %s is not a list, dict, string or None."%repr(d)) 413 elif SCons.Util.is_Dict(defs): 414 # The items in a dictionary are stored in random order, but 415 # if the order of the command-line options changes from 416 # invocation to invocation, then the signature of the command 417 # line will change and we'll get random unnecessary rebuilds. 418 # Consequently, we have to sort the keys to ensure a 419 # consistent order... 420 l = [] 421 for k,v in sorted(defs.items()): 422 if v is None: 423 l.append(str(k)) 424 else: 425 l.append(str(k) + '=' + str(v)) 426 else: 427 l = [str(defs)] 428 return l
429
430 -def _defines(prefix, defs, suffix, env, c=_concat_ixes):
431 """A wrapper around _concat_ixes that turns a list or string 432 into a list of C preprocessor command-line definitions. 433 """ 434 435 return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
436
437 -class NullCmdGenerator(object):
438 """This is a callable class that can be used in place of other 439 command generators if you don't want them to do anything. 440 441 The __call__ method for this class simply returns the thing 442 you instantiated it with. 443 444 Example usage: 445 env["DO_NOTHING"] = NullCmdGenerator 446 env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}" 447 """ 448
449 - def __init__(self, cmd):
450 self.cmd = cmd
451
452 - def __call__(self, target, source, env, for_signature=None):
453 return self.cmd
454
455 -class Variable_Method_Caller(object):
456 """A class for finding a construction variable on the stack and 457 calling one of its methods. 458 459 We use this to support "construction variables" in our string 460 eval()s that actually stand in for methods--specifically, use 461 of "RDirs" in call to _concat that should actually execute the 462 "TARGET.RDirs" method. (We used to support this by creating a little 463 "build dictionary" that mapped RDirs to the method, but this got in 464 the way of Memoizing construction environments, because we had to 465 create new environment objects to hold the variables.) 466 """
467 - def __init__(self, variable, method):
468 self.variable = variable 469 self.method = method
470 - def __call__(self, *args, **kw):
471 try: 1//0 472 except ZeroDivisionError: 473 # Don't start iterating with the current stack-frame to 474 # prevent creating reference cycles (f_back is safe). 475 frame = sys.exc_info()[2].tb_frame.f_back 476 variable = self.variable 477 while frame: 478 if variable in frame.f_locals: 479 v = frame.f_locals[variable] 480 if v: 481 method = getattr(v, self.method) 482 return method(*args, **kw) 483 frame = frame.f_back 484 return None
485 486 ConstructionEnvironment = { 487 'BUILDERS' : {}, 488 'SCANNERS' : [], 489 'CONFIGUREDIR' : '#/.sconf_temp', 490 'CONFIGURELOG' : '#/config.log', 491 'CPPSUFFIXES' : SCons.Tool.CSuffixes, 492 'DSUFFIXES' : SCons.Tool.DSuffixes, 493 'ENV' : {}, 494 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes, 495 # 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions 496 '_concat' : _concat, 497 '_defines' : _defines, 498 '_stripixes' : _stripixes, 499 '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', 500 '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', 501 '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', 502 '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', 503 'TEMPFILE' : NullCmdGenerator, 504 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), 505 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'), 506 'File' : Variable_Method_Caller('TARGET', 'File'), 507 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'), 508 } 509 510 # Local Variables: 511 # tab-width:4 512 # indent-tabs-mode:nil 513 # End: 514 # vim: set expandtab tabstop=4 shiftwidth=4: 515