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