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