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