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