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 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   
 35  __revision__ = "src/engine/SCons/Defaults.py 5110 2010/07/25 16:14:38 bdeegan" 
 36   
 37   
 38   
 39  import os 
 40  import os.path 
 41  import errno 
 42  import shutil 
 43  import stat 
 44  import string 
 45  import time 
 46  import types 
 47  import sys 
 48   
 49  import SCons.Action 
 50  import SCons.Builder 
 51  import SCons.CacheDir 
 52  import SCons.Environment 
 53  import SCons.PathList 
 54  import SCons.Subst 
 55  import SCons.Tool 
 56   
 57  # A placeholder for a default Environment (for fetching source files 
 58  # from source code management systems and the like).  This must be 
 59  # initialized later, after the top-level directory is set by the calling 
 60  # interface. 
 61  _default_env = None 
 62   
 63  # Lazily instantiate the default environment so the overhead of creating 
 64  # it doesn't apply when it's not needed. 
65 -def _fetch_DefaultEnvironment(*args, **kw):
66 """ 67 Returns the already-created default construction environment. 68 """ 69 global _default_env 70 return _default_env
71
72 -def DefaultEnvironment(*args, **kw):
73 """ 74 Initial public entry point for creating the default construction 75 Environment. 76 77 After creating the environment, we overwrite our name 78 (DefaultEnvironment) with the _fetch_DefaultEnvironment() function, 79 which more efficiently returns the initialized default construction 80 environment without checking for its existence. 81 82 (This function still exists with its _default_check because someone 83 else (*cough* Script/__init__.py *cough*) may keep a reference 84 to this function. So we can't use the fully functional idiom of 85 having the name originally be a something that *only* creates the 86 construction environment and then overwrites the name.) 87 """ 88 global _default_env 89 if not _default_env: 90 import SCons.Util 91 _default_env = apply(SCons.Environment.Environment, args, kw) 92 if SCons.Util.md5: 93 _default_env.Decider('MD5') 94 else: 95 _default_env.Decider('timestamp-match') 96 global DefaultEnvironment 97 DefaultEnvironment = _fetch_DefaultEnvironment 98 _default_env._CacheDir_path = None 99 return _default_env
100 101 # Emitters for setting the shared attribute on object files, 102 # and an action for checking that all of the source files 103 # going into a shared library are, in fact, shared.
104 -def StaticObjectEmitter(target, source, env):
105 for tgt in target: 106 tgt.attributes.shared = None 107 return (target, source)
108
109 -def SharedObjectEmitter(target, source, env):
110 for tgt in target: 111 tgt.attributes.shared = 1 112 return (target, source)
113
114 -def SharedFlagChecker(source, target, env):
115 same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME') 116 if same == '0' or same == '' or same == 'False': 117 for src in source: 118 try: 119 shared = src.attributes.shared 120 except AttributeError: 121 shared = None 122 if not shared: 123 raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
124 125 SharedCheck = SCons.Action.Action(SharedFlagChecker, None) 126 127 # Some people were using these variable name before we made 128 # SourceFileScanner part of the public interface. Don't break their 129 # SConscript files until we've given them some fair warning and a 130 # transition period. 131 CScan = SCons.Tool.CScanner 132 DScan = SCons.Tool.DScanner 133 LaTeXScan = SCons.Tool.LaTeXScanner 134 ObjSourceScan = SCons.Tool.SourceFileScanner 135 ProgScan = SCons.Tool.ProgramScanner 136 137 # These aren't really tool scanners, so they don't quite belong with 138 # the rest of those in Tool/__init__.py, but I'm not sure where else 139 # they should go. Leave them here for now. 140 import SCons.Scanner.Dir 141 DirScanner = SCons.Scanner.Dir.DirScanner() 142 DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner() 143 144 # Actions for common languages. 145 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR") 146 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR") 147 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR") 148 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR") 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 '[' + string.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):
185 SCons.Node.FS.invalidate_node_memos(dest) 186 if SCons.Util.is_List(src) and os.path.isdir(dest): 187 for file in src: 188 shutil.copy2(file, dest) 189 return 0 190 elif os.path.isfile(src): 191 return shutil.copy2(src, dest) 192 else: 193 return shutil.copytree(src, dest, 1)
194 195 Copy = ActionFactory(copy_func, 196 lambda dest, src: 'Copy("%s", "%s")' % (dest, src), 197 convert=str) 198
199 -def delete_func(dest, must_exist=0):
200 SCons.Node.FS.invalidate_node_memos(dest) 201 if not SCons.Util.is_List(dest): 202 dest = [dest] 203 for entry in dest: 204 entry = str(entry) 205 if not must_exist and not os.path.exists(entry): 206 continue 207 if not os.path.exists(entry) or os.path.isfile(entry): 208 os.unlink(entry) 209 continue 210 else: 211 shutil.rmtree(entry, 1) 212 continue
213
214 -def delete_strfunc(dest, must_exist=0):
215 return 'Delete(%s)' % get_paths_str(dest)
216 217 Delete = ActionFactory(delete_func, delete_strfunc) 218
219 -def mkdir_func(dest):
220 SCons.Node.FS.invalidate_node_memos(dest) 221 if not SCons.Util.is_List(dest): 222 dest = [dest] 223 for entry in dest: 224 try: 225 os.makedirs(str(entry)) 226 except os.error, e: 227 p = str(entry) 228 if (e[0] == errno.EEXIST or (sys.platform=='win32' and e[0]==183)) \ 229 and os.path.isdir(str(entry)): 230 pass # not an error if already exists 231 else: 232 raise
233 234 Mkdir = ActionFactory(mkdir_func, 235 lambda dir: 'Mkdir(%s)' % get_paths_str(dir)) 236
237 -def move_func(dest, src):
238 SCons.Node.FS.invalidate_node_memos(dest) 239 SCons.Node.FS.invalidate_node_memos(src) 240 shutil.move(src, dest)
241 242 Move = ActionFactory(move_func, 243 lambda dest, src: 'Move("%s", "%s")' % (dest, src), 244 convert=str) 245
246 -def touch_func(dest):
247 SCons.Node.FS.invalidate_node_memos(dest) 248 if not SCons.Util.is_List(dest): 249 dest = [dest] 250 for file in dest: 251 file = str(file) 252 mtime = int(time.time()) 253 if os.path.exists(file): 254 atime = os.path.getatime(file) 255 else: 256 open(file, 'w') 257 atime = mtime 258 os.utime(file, (atime, mtime))
259 260 Touch = ActionFactory(touch_func, 261 lambda file: 'Touch(%s)' % get_paths_str(file)) 262 263 # Internal utility functions 264
265 -def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
266 """ 267 Creates a new list from 'list' by first interpolating each element 268 in the list using the 'env' dictionary and then calling f on the 269 list, and finally calling _concat_ixes to concatenate 'prefix' and 270 'suffix' onto each element of the list. 271 """ 272 if not list: 273 return list 274 275 l = f(SCons.PathList.PathList(list).subst_path(env, target, source)) 276 if l is not None: 277 list = l 278 279 return _concat_ixes(prefix, list, suffix, env)
280
281 -def _concat_ixes(prefix, list, suffix, env):
282 """ 283 Creates a new list from 'list' by concatenating the 'prefix' and 284 'suffix' arguments onto each element of the list. A trailing space 285 on 'prefix' or leading space on 'suffix' will cause them to be put 286 into separate list elements rather than being concatenated. 287 """ 288 289 result = [] 290 291 # ensure that prefix and suffix are strings 292 prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW)) 293 suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW)) 294 295 for x in list: 296 if isinstance(x, SCons.Node.FS.File): 297 result.append(x) 298 continue 299 x = str(x) 300 if x: 301 302 if prefix: 303 if prefix[-1] == ' ': 304 result.append(prefix[:-1]) 305 elif x[:len(prefix)] != prefix: 306 x = prefix + x 307 308 result.append(x) 309 310 if suffix: 311 if suffix[0] == ' ': 312 result.append(suffix[1:]) 313 elif x[-len(suffix):] != suffix: 314 result[-1] = result[-1]+suffix 315 316 return result
317
318 -def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None):
319 """ 320 This is a wrapper around _concat()/_concat_ixes() that checks for the 321 existence of prefixes or suffixes on list elements and strips them 322 where it finds them. This is used by tools (like the GNU linker) 323 that need to turn something like 'libfoo.a' into '-lfoo'. 324 """ 325 326 if not list: 327 return list 328 329 if not callable(c): 330 env_c = env['_concat'] 331 if env_c != _concat and callable(env_c): 332 # There's a custom _concat() method in the construction 333 # environment, and we've allowed people to set that in 334 # the past (see test/custom-concat.py), so preserve the 335 # backwards compatibility. 336 c = env_c 337 else: 338 c = _concat_ixes 339 340 stripprefixes = map(env.subst, SCons.Util.flatten(stripprefixes)) 341 stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes)) 342 343 stripped = [] 344 for l in SCons.PathList.PathList(list).subst_path(env, None, None): 345 if isinstance(l, SCons.Node.FS.File): 346 stripped.append(l) 347 continue 348 349 if not SCons.Util.is_String(l): 350 l = str(l) 351 352 for stripprefix in stripprefixes: 353 lsp = len(stripprefix) 354 if l[:lsp] == stripprefix: 355 l = l[lsp:] 356 # Do not strip more than one prefix 357 break 358 359 for stripsuffix in stripsuffixes: 360 lss = len(stripsuffix) 361 if l[-lss:] == stripsuffix: 362 l = l[:-lss] 363 # Do not strip more than one suffix 364 break 365 366 stripped.append(l) 367 368 return c(prefix, stripped, suffix, env)
369
370 -def processDefines(defs):
371 """process defines, resolving strings, lists, dictionaries, into a list of 372 strings 373 """ 374 if SCons.Util.is_List(defs): 375 l = [] 376 for d in defs: 377 if SCons.Util.is_List(d) or type(d) is types.TupleType: 378 l.append(str(d[0]) + '=' + str(d[1])) 379 else: 380 l.append(str(d)) 381 elif SCons.Util.is_Dict(defs): 382 # The items in a dictionary are stored in random order, but 383 # if the order of the command-line options changes from 384 # invocation to invocation, then the signature of the command 385 # line will change and we'll get random unnecessary rebuilds. 386 # Consequently, we have to sort the keys to ensure a 387 # consistent order... 388 l = [] 389 keys = defs.keys() 390 keys.sort() 391 for k in keys: 392 v = defs[k] 393 if v is None: 394 l.append(str(k)) 395 else: 396 l.append(str(k) + '=' + str(v)) 397 else: 398 l = [str(defs)] 399 return l
400
401 -def _defines(prefix, defs, suffix, env, c=_concat_ixes):
402 """A wrapper around _concat_ixes that turns a list or string 403 into a list of C preprocessor command-line definitions. 404 """ 405 406 return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
407
408 -class NullCmdGenerator:
409 """This is a callable class that can be used in place of other 410 command generators if you don't want them to do anything. 411 412 The __call__ method for this class simply returns the thing 413 you instantiated it with. 414 415 Example usage: 416 env["DO_NOTHING"] = NullCmdGenerator 417 env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}" 418 """ 419
420 - def __init__(self, cmd):
421 self.cmd = cmd
422
423 - def __call__(self, target, source, env, for_signature=None):
424 return self.cmd
425
426 -class Variable_Method_Caller:
427 """A class for finding a construction variable on the stack and 428 calling one of its methods. 429 430 We use this to support "construction variables" in our string 431 eval()s that actually stand in for methods--specifically, use 432 of "RDirs" in call to _concat that should actually execute the 433 "TARGET.RDirs" method. (We used to support this by creating a little 434 "build dictionary" that mapped RDirs to the method, but this got in 435 the way of Memoizing construction environments, because we had to 436 create new environment objects to hold the variables.) 437 """
438 - def __init__(self, variable, method):
439 self.variable = variable 440 self.method = method
441 - def __call__(self, *args, **kw):
442 try: 1/0 443 except ZeroDivisionError: 444 # Don't start iterating with the current stack-frame to 445 # prevent creating reference cycles (f_back is safe). 446 frame = sys.exc_info()[2].tb_frame.f_back 447 variable = self.variable 448 while frame: 449 if frame.f_locals.has_key(variable): 450 v = frame.f_locals[variable] 451 if v: 452 method = getattr(v, self.method) 453 return apply(method, args, kw) 454 frame = frame.f_back 455 return None
456 457 ConstructionEnvironment = { 458 'BUILDERS' : {}, 459 'SCANNERS' : [], 460 'CONFIGUREDIR' : '#/.sconf_temp', 461 'CONFIGURELOG' : '#/config.log', 462 'CPPSUFFIXES' : SCons.Tool.CSuffixes, 463 'DSUFFIXES' : SCons.Tool.DSuffixes, 464 'ENV' : {}, 465 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes, 466 # 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions 467 '_concat' : _concat, 468 '_defines' : _defines, 469 '_stripixes' : _stripixes, 470 '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', 471 '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', 472 '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', 473 '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', 474 'TEMPFILE' : NullCmdGenerator, 475 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), 476 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'), 477 'File' : Variable_Method_Caller('TARGET', 'File'), 478 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'), 479 } 480 481 # Local Variables: 482 # tab-width:4 483 # indent-tabs-mode:nil 484 # End: 485 # vim: set expandtab tabstop=4 shiftwidth=4: 486