Package SCons :: Module Environment
[hide private]
[frames] | no frames]

Source Code for Module SCons.Environment

   1  """SCons.Environment 
   2   
   3  Base class for construction Environments.  These are 
   4  the primary objects used to communicate dependency and 
   5  construction information to the build engine. 
   6   
   7  Keyword arguments supplied when the construction Environment 
   8  is created are construction variables used to initialize the 
   9  Environment 
  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/Environment.py 3842 2008/12/20 22:59:52 scons" 
  36   
  37   
  38  import copy 
  39  import os 
  40  import sys 
  41  import re 
  42  import shlex 
  43  import string 
  44  from UserDict import UserDict 
  45   
  46  import SCons.Action 
  47  import SCons.Builder 
  48  from SCons.Debug import logInstanceCreation 
  49  import SCons.Defaults 
  50  import SCons.Errors 
  51  import SCons.Memoize 
  52  import SCons.Node 
  53  import SCons.Node.Alias 
  54  import SCons.Node.FS 
  55  import SCons.Node.Python 
  56  import SCons.Platform 
  57  import SCons.SConsign 
  58  import SCons.Subst 
  59  import SCons.Tool 
  60  import SCons.Util 
  61  import SCons.Warnings 
  62   
63 -class _Null:
64 pass
65 66 _null = _Null 67 68 _warn_copy_deprecated = True 69 _warn_source_signatures_deprecated = True 70 _warn_target_signatures_deprecated = True 71 72 CleanTargets = {} 73 CalculatorArgs = {} 74 75 semi_deepcopy = SCons.Util.semi_deepcopy 76 77 # Pull UserError into the global name space for the benefit of 78 # Environment().SourceSignatures(), which has some import statements 79 # which seem to mess up its ability to reference SCons directly. 80 UserError = SCons.Errors.UserError 81
82 -def alias_builder(env, target, source):
83 pass
84 85 AliasBuilder = SCons.Builder.Builder(action = alias_builder, 86 target_factory = SCons.Node.Alias.default_ans.Alias, 87 source_factory = SCons.Node.FS.Entry, 88 multi = 1, 89 is_explicit = None, 90 name='AliasBuilder') 91
92 -def apply_tools(env, tools, toolpath):
93 # Store the toolpath in the Environment. 94 if toolpath is not None: 95 env['toolpath'] = toolpath 96 97 if not tools: 98 return 99 # Filter out null tools from the list. 100 for tool in filter(None, tools): 101 if SCons.Util.is_List(tool) or type(tool)==type(()): 102 toolname = tool[0] 103 toolargs = tool[1] # should be a dict of kw args 104 tool = apply(env.Tool, [toolname], toolargs) 105 else: 106 env.Tool(tool)
107 108 # These names are (or will be) controlled by SCons; users should never 109 # set or override them. This warning can optionally be turned off, 110 # but scons will still ignore the illegal variable names even if it's off. 111 reserved_construction_var_names = [ 112 'SOURCE', 113 'SOURCES', 114 'TARGET', 115 'TARGETS', 116 ] 117 118 future_reserved_construction_var_names = [ 119 'CHANGED_SOURCES', 120 'CHANGED_TARGETS', 121 'UNCHANGED_SOURCES', 122 'UNCHANGED_TARGETS', 123 ] 124
125 -def copy_non_reserved_keywords(dict):
126 result = semi_deepcopy(dict) 127 for k in result.keys(): 128 if k in reserved_construction_var_names: 129 msg = "Ignoring attempt to set reserved variable `$%s'" 130 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k) 131 del result[k] 132 return result
133
134 -def _set_reserved(env, key, value):
135 msg = "Ignoring attempt to set reserved variable `$%s'" 136 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % key)
137
138 -def _set_future_reserved(env, key, value):
139 env._dict[key] = value 140 msg = "`$%s' will be reserved in a future release and setting it will become ignored" 141 SCons.Warnings.warn(SCons.Warnings.FutureReservedVariableWarning, msg % key)
142
143 -def _set_BUILDERS(env, key, value):
144 try: 145 bd = env._dict[key] 146 for k in bd.keys(): 147 del bd[k] 148 except KeyError: 149 bd = BuilderDict(kwbd, env) 150 env._dict[key] = bd 151 bd.update(value)
152
153 -def _del_SCANNERS(env, key):
154 del env._dict[key] 155 env.scanner_map_delete()
156
157 -def _set_SCANNERS(env, key, value):
158 env._dict[key] = value 159 env.scanner_map_delete()
160
161 -def _delete_duplicates(l, keep_last):
162 """Delete duplicates from a sequence, keeping the first or last.""" 163 seen={} 164 result=[] 165 if keep_last: # reverse in & out, then keep first 166 l.reverse() 167 for i in l: 168 try: 169 if not seen.has_key(i): 170 result.append(i) 171 seen[i]=1 172 except TypeError: 173 # probably unhashable. Just keep it. 174 result.append(i) 175 if keep_last: 176 result.reverse() 177 return result
178 179 180 181 # The following is partly based on code in a comment added by Peter 182 # Shannon at the following page (there called the "transplant" class): 183 # 184 # ASPN : Python Cookbook : Dynamically added methods to a class 185 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 186 # 187 # We had independently been using the idiom as BuilderWrapper, but 188 # factoring out the common parts into this base class, and making 189 # BuilderWrapper a subclass that overrides __call__() to enforce specific 190 # Builder calling conventions, simplified some of our higher-layer code. 191
192 -class MethodWrapper:
193 """ 194 A generic Wrapper class that associates a method (which can 195 actually be any callable) with an object. As part of creating this 196 MethodWrapper object an attribute with the specified (by default, 197 the name of the supplied method) is added to the underlying object. 198 When that new "method" is called, our __call__() method adds the 199 object as the first argument, simulating the Python behavior of 200 supplying "self" on method calls. 201 202 We hang on to the name by which the method was added to the underlying 203 base class so that we can provide a method to "clone" ourselves onto 204 a new underlying object being copied (without which we wouldn't need 205 to save that info). 206 """
207 - def __init__(self, object, method, name=None):
208 if name is None: 209 name = method.__name__ 210 self.object = object 211 self.method = method 212 self.name = name 213 setattr(self.object, name, self)
214
215 - def __call__(self, *args, **kwargs):
216 nargs = (self.object,) + args 217 return apply(self.method, nargs, kwargs)
218
219 - def clone(self, new_object):
220 """ 221 Returns an object that re-binds the underlying "method" to 222 the specified new object. 223 """ 224 return self.__class__(new_object, self.method, self.name)
225
226 -class BuilderWrapper(MethodWrapper):
227 """ 228 A MethodWrapper subclass that that associates an environment with 229 a Builder. 230 231 This mainly exists to wrap the __call__() function so that all calls 232 to Builders can have their argument lists massaged in the same way 233 (treat a lone argument as the source, treat two arguments as target 234 then source, make sure both target and source are lists) without 235 having to have cut-and-paste code to do it. 236 237 As a bit of obsessive backwards compatibility, we also intercept 238 attempts to get or set the "env" or "builder" attributes, which were 239 the names we used before we put the common functionality into the 240 MethodWrapper base class. We'll keep this around for a while in case 241 people shipped Tool modules that reached into the wrapper (like the 242 Tool/qt.py module does, or did). There shouldn't be a lot attribute 243 fetching or setting on these, so a little extra work shouldn't hurt. 244 """
245 - def __call__(self, target=None, source=_null, *args, **kw):
246 if source is _null: 247 source = target 248 target = None 249 if not target is None and not SCons.Util.is_List(target): 250 target = [target] 251 if not source is None and not SCons.Util.is_List(source): 252 source = [source] 253 return apply(MethodWrapper.__call__, (self, target, source) + args, kw)
254
255 - def __repr__(self):
256 return '<BuilderWrapper %s>' % repr(self.name)
257
258 - def __str__(self):
259 return self.__repr__()
260
261 - def __getattr__(self, name):
262 if name == 'env': 263 return self.object 264 elif name == 'builder': 265 return self.method 266 else: 267 raise AttributeError, name
268
269 - def __setattr__(self, name, value):
270 if name == 'env': 271 self.object = value 272 elif name == 'builder': 273 self.method = value 274 else: 275 self.__dict__[name] = value
276 277 # This allows a Builder to be executed directly 278 # through the Environment to which it's attached. 279 # In practice, we shouldn't need this, because 280 # builders actually get executed through a Node. 281 # But we do have a unit test for this, and can't 282 # yet rule out that it would be useful in the 283 # future, so leave it for now. 284 #def execute(self, **kw): 285 # kw['env'] = self.env 286 # apply(self.builder.execute, (), kw) 287
288 -class BuilderDict(UserDict):
289 """This is a dictionary-like class used by an Environment to hold 290 the Builders. We need to do this because every time someone changes 291 the Builders in the Environment's BUILDERS dictionary, we must 292 update the Environment's attributes."""
293 - def __init__(self, dict, env):
294 # Set self.env before calling the superclass initialization, 295 # because it will end up calling our other methods, which will 296 # need to point the values in this dictionary to self.env. 297 self.env = env 298 UserDict.__init__(self, dict)
299
300 - def __semi_deepcopy__(self):
301 return self.__class__(self.data, self.env)
302
303 - def __setitem__(self, item, val):
304 try: 305 method = getattr(self.env, item).method 306 except AttributeError: 307 pass 308 else: 309 self.env.RemoveMethod(method) 310 UserDict.__setitem__(self, item, val) 311 BuilderWrapper(self.env, val, item)
312
313 - def __delitem__(self, item):
314 UserDict.__delitem__(self, item) 315 delattr(self.env, item)
316
317 - def update(self, dict):
318 for i, v in dict.items(): 319 self.__setitem__(i, v)
320 321 322 323 _is_valid_var = re.compile(r'[_a-zA-Z]\w*$') 324
325 -def is_valid_construction_var(varstr):
326 """Return if the specified string is a legitimate construction 327 variable. 328 """ 329 return _is_valid_var.match(varstr)
330 331 332
333 -class SubstitutionEnvironment:
334 """Base class for different flavors of construction environments. 335 336 This class contains a minimal set of methods that handle contruction 337 variable expansion and conversion of strings to Nodes, which may or 338 may not be actually useful as a stand-alone class. Which methods 339 ended up in this class is pretty arbitrary right now. They're 340 basically the ones which we've empirically determined are common to 341 the different construction environment subclasses, and most of the 342 others that use or touch the underlying dictionary of construction 343 variables. 344 345 Eventually, this class should contain all the methods that we 346 determine are necessary for a "minimal" interface to the build engine. 347 A full "native Python" SCons environment has gotten pretty heavyweight 348 with all of the methods and Tools and construction variables we've 349 jammed in there, so it would be nice to have a lighter weight 350 alternative for interfaces that don't need all of the bells and 351 whistles. (At some point, we'll also probably rename this class 352 "Base," since that more reflects what we want this class to become, 353 but because we've released comments that tell people to subclass 354 Environment.Base to create their own flavors of construction 355 environment, we'll save that for a future refactoring when this 356 class actually becomes useful.) 357 """ 358 359 if SCons.Memoize.use_memoizer: 360 __metaclass__ = SCons.Memoize.Memoized_Metaclass 361
362 - def __init__(self, **kw):
363 """Initialization of an underlying SubstitutionEnvironment class. 364 """ 365 if __debug__: logInstanceCreation(self, 'Environment.SubstitutionEnvironment') 366 self.fs = SCons.Node.FS.get_default_fs() 367 self.ans = SCons.Node.Alias.default_ans 368 self.lookup_list = SCons.Node.arg2nodes_lookups 369 self._dict = kw.copy() 370 self._init_special() 371 self.added_methods = []
372 #self._memo = {} 373
374 - def _init_special(self):
375 """Initial the dispatch tables for special handling of 376 special construction variables.""" 377 self._special_del = {} 378 self._special_del['SCANNERS'] = _del_SCANNERS 379 380 self._special_set = {} 381 for key in reserved_construction_var_names: 382 self._special_set[key] = _set_reserved 383 for key in future_reserved_construction_var_names: 384 self._special_set[key] = _set_future_reserved 385 self._special_set['BUILDERS'] = _set_BUILDERS 386 self._special_set['SCANNERS'] = _set_SCANNERS 387 388 # Freeze the keys of self._special_set in a list for use by 389 # methods that need to check. (Empirically, list scanning has 390 # gotten better than dict.has_key() in Python 2.5.) 391 self._special_set_keys = self._special_set.keys()
392
393 - def __cmp__(self, other):
394 return cmp(self._dict, other._dict)
395
396 - def __delitem__(self, key):
397 special = self._special_del.get(key) 398 if special: 399 special(self, key) 400 else: 401 del self._dict[key]
402
403 - def __getitem__(self, key):
404 return self._dict[key]
405
406 - def __setitem__(self, key, value):
407 # This is heavily used. This implementation is the best we have 408 # according to the timings in bench/env.__setitem__.py. 409 # 410 # The "key in self._special_set_keys" test here seems to perform 411 # pretty well for the number of keys we have. A hard-coded 412 # list works a little better in Python 2.5, but that has the 413 # disadvantage of maybe getting out of sync if we ever add more 414 # variable names. Using self._special_set.has_key() works a 415 # little better in Python 2.4, but is worse then this test. 416 # So right now it seems like a good trade-off, but feel free to 417 # revisit this with bench/env.__setitem__.py as needed (and 418 # as newer versions of Python come out). 419 if key in self._special_set_keys: 420 self._special_set[key](self, key, value) 421 else: 422 # If we already have the entry, then it's obviously a valid 423 # key and we don't need to check. If we do check, using a 424 # global, pre-compiled regular expression directly is more 425 # efficient than calling another function or a method. 426 if not self._dict.has_key(key) \ 427 and not _is_valid_var.match(key): 428 raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key 429 self._dict[key] = value
430
431 - def get(self, key, default=None):
432 "Emulates the get() method of dictionaries.""" 433 return self._dict.get(key, default)
434
435 - def has_key(self, key):
436 return self._dict.has_key(key)
437
438 - def __contains__(self, key):
439 return self._dict.__contains__(key)
440
441 - def items(self):
442 return self._dict.items()
443
444 - def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw):
445 if node_factory is _null: 446 node_factory = self.fs.File 447 if lookup_list is _null: 448 lookup_list = self.lookup_list 449 450 if not args: 451 return [] 452 453 args = SCons.Util.flatten(args) 454 455 nodes = [] 456 for v in args: 457 if SCons.Util.is_String(v): 458 n = None 459 for l in lookup_list: 460 n = l(v) 461 if not n is None: 462 break 463 if not n is None: 464 if SCons.Util.is_String(n): 465 # n = self.subst(n, raw=1, **kw) 466 kw['raw'] = 1 467 n = apply(self.subst, (n,), kw) 468 if node_factory: 469 n = node_factory(n) 470 if SCons.Util.is_List(n): 471 nodes.extend(n) 472 else: 473 nodes.append(n) 474 elif node_factory: 475 # v = node_factory(self.subst(v, raw=1, **kw)) 476 kw['raw'] = 1 477 v = node_factory(apply(self.subst, (v,), kw)) 478 if SCons.Util.is_List(v): 479 nodes.extend(v) 480 else: 481 nodes.append(v) 482 else: 483 nodes.append(v) 484 485 return nodes
486
487 - def gvars(self):
488 return self._dict
489
490 - def lvars(self):
491 return {}
492
493 - def subst(self, string, raw=0, target=None, source=None, conv=None):
494 """Recursively interpolates construction variables from the 495 Environment into the specified string, returning the expanded 496 result. Construction variables are specified by a $ prefix 497 in the string and begin with an initial underscore or 498 alphabetic character followed by any number of underscores 499 or alphanumeric characters. The construction variable names 500 may be surrounded by curly braces to separate the name from 501 trailing characters. 502 """ 503 gvars = self.gvars() 504 lvars = self.lvars() 505 lvars['__env__'] = self 506 return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv)
507
508 - def subst_kw(self, kw, raw=0, target=None, source=None):
509 nkw = {} 510 for k, v in kw.items(): 511 k = self.subst(k, raw, target, source) 512 if SCons.Util.is_String(v): 513 v = self.subst(v, raw, target, source) 514 nkw[k] = v 515 return nkw
516
517 - def subst_list(self, string, raw=0, target=None, source=None, conv=None):
518 """Calls through to SCons.Subst.scons_subst_list(). See 519 the documentation for that function.""" 520 gvars = self.gvars() 521 lvars = self.lvars() 522 lvars['__env__'] = self 523 return SCons.Subst.scons_subst_list(string, self, raw, target, source, gvars, lvars, conv)
524
525 - def subst_path(self, path, target=None, source=None):
526 """Substitute a path list, turning EntryProxies into Nodes 527 and leaving Nodes (and other objects) as-is.""" 528 529 if not SCons.Util.is_List(path): 530 path = [path] 531 532 def s(obj): 533 """This is the "string conversion" routine that we have our 534 substitutions use to return Nodes, not strings. This relies 535 on the fact that an EntryProxy object has a get() method that 536 returns the underlying Node that it wraps, which is a bit of 537 architectural dependence that we might need to break or modify 538 in the future in response to additional requirements.""" 539 try: 540 get = obj.get 541 except AttributeError: 542 obj = SCons.Util.to_String_for_subst(obj) 543 else: 544 obj = get() 545 return obj
546 547 r = [] 548 for p in path: 549 if SCons.Util.is_String(p): 550 p = self.subst(p, target=target, source=source, conv=s) 551 if SCons.Util.is_List(p): 552 if len(p) == 1: 553 p = p[0] 554 else: 555 # We have an object plus a string, or multiple 556 # objects that we need to smush together. No choice 557 # but to make them into a string. 558 p = string.join(map(SCons.Util.to_String_for_subst, p), '') 559 else: 560 p = s(p) 561 r.append(p) 562 return r
563 564 subst_target_source = subst 565
566 - def backtick(self, command):
567 import subprocess 568 # common arguments 569 kw = { 'stdin' : 'devnull', 570 'stdout' : subprocess.PIPE, 571 'stderr' : subprocess.PIPE, 572 'universal_newlines' : True, 573 } 574 # if the command is a list, assume it's been quoted 575 # othewise force a shell 576 if not SCons.Util.is_List(command): kw['shell'] = True 577 # run constructed command 578 #TODO(1.5) p = SCons.Action._subproc(self, command, **kw) 579 p = apply(SCons.Action._subproc, (self, command), kw) 580 out,err = p.communicate() 581 status = p.wait() 582 if err: 583 sys.stderr.write(err) 584 if status: 585 raise OSError("'%s' exited %d" % (command, status)) 586 return out
587
588 - def AddMethod(self, function, name=None):
589 """ 590 Adds the specified function as a method of this construction 591 environment with the specified name. If the name is omitted, 592 the default name is the name of the function itself. 593 """ 594 method = MethodWrapper(self, function, name) 595 self.added_methods.append(method)
596
597 - def RemoveMethod(self, function):
598 """ 599 Removes the specified function's MethodWrapper from the 600 added_methods list, so we don't re-bind it when making a clone. 601 """ 602 is_not_func = lambda dm, f=function: not dm.method is f 603 self.added_methods = filter(is_not_func, self.added_methods)
604
605 - def Override(self, overrides):
606 """ 607 Produce a modified environment whose variables are overriden by 608 the overrides dictionaries. "overrides" is a dictionary that 609 will override the variables of this environment. 610 611 This function is much more efficient than Clone() or creating 612 a new Environment because it doesn't copy the construction 613 environment dictionary, it just wraps the underlying construction 614 environment, and doesn't even create a wrapper object if there 615 are no overrides. 616 """ 617 if not overrides: return self 618 o = copy_non_reserved_keywords(overrides) 619 if not o: return self 620 overrides = {} 621 merges = None 622 for key, value in o.items(): 623 if key == 'parse_flags': 624 merges = value 625 else: 626 overrides[key] = SCons.Subst.scons_subst_once(value, self, key) 627 env = OverrideEnvironment(self, overrides) 628 if merges: env.MergeFlags(merges) 629 return env
630
631 - def ParseFlags(self, *flags):
632 """ 633 Parse the set of flags and return a dict with the flags placed 634 in the appropriate entry. The flags are treated as a typical 635 set of command-line flags for a GNU-like toolchain and used to 636 populate the entries in the dict immediately below. If one of 637 the flag strings begins with a bang (exclamation mark), it is 638 assumed to be a command and the rest of the string is executed; 639 the result of that evaluation is then added to the dict. 640 """ 641 dict = { 642 'ASFLAGS' : SCons.Util.CLVar(''), 643 'CFLAGS' : SCons.Util.CLVar(''), 644 'CCFLAGS' : SCons.Util.CLVar(''), 645 'CPPDEFINES' : [], 646 'CPPFLAGS' : SCons.Util.CLVar(''), 647 'CPPPATH' : [], 648 'FRAMEWORKPATH' : SCons.Util.CLVar(''), 649 'FRAMEWORKS' : SCons.Util.CLVar(''), 650 'LIBPATH' : [], 651 'LIBS' : [], 652 'LINKFLAGS' : SCons.Util.CLVar(''), 653 'RPATH' : [], 654 } 655 656 # The use of the "me" parameter to provide our own name for 657 # recursion is an egregious hack to support Python 2.1 and before. 658 def do_parse(arg, me, self = self, dict = dict): 659 # if arg is a sequence, recurse with each element 660 if not arg: 661 return 662 663 if not SCons.Util.is_String(arg): 664 for t in arg: me(t, me) 665 return 666 667 # if arg is a command, execute it 668 if arg[0] == '!': 669 arg = self.backtick(arg[1:]) 670 671 # utility function to deal with -D option 672 def append_define(name, dict = dict): 673 t = string.split(name, '=') 674 if len(t) == 1: 675 dict['CPPDEFINES'].append(name) 676 else: 677 dict['CPPDEFINES'].append([t[0], string.join(t[1:], '=')])
678 679 # Loop through the flags and add them to the appropriate option. 680 # This tries to strike a balance between checking for all possible 681 # flags and keeping the logic to a finite size, so it doesn't 682 # check for some that don't occur often. It particular, if the 683 # flag is not known to occur in a config script and there's a way 684 # of passing the flag to the right place (by wrapping it in a -W 685 # flag, for example) we don't check for it. Note that most 686 # preprocessor options are not handled, since unhandled options 687 # are placed in CCFLAGS, so unless the preprocessor is invoked 688 # separately, these flags will still get to the preprocessor. 689 # Other options not currently handled: 690 # -iqoutedir (preprocessor search path) 691 # -u symbol (linker undefined symbol) 692 # -s (linker strip files) 693 # -static* (linker static binding) 694 # -shared* (linker dynamic binding) 695 # -symbolic (linker global binding) 696 # -R dir (deprecated linker rpath) 697 # IBM compilers may also accept -qframeworkdir=foo 698 699 params = shlex.split(arg) 700 append_next_arg_to = None # for multi-word args 701 for arg in params: 702 if append_next_arg_to: 703 if append_next_arg_to == 'CPPDEFINES': 704 append_define(arg) 705 elif append_next_arg_to == '-include': 706 t = ('-include', self.fs.File(arg)) 707 dict['CCFLAGS'].append(t) 708 elif append_next_arg_to == '-isysroot': 709 t = ('-isysroot', arg) 710 dict['CCFLAGS'].append(t) 711 dict['LINKFLAGS'].append(t) 712 elif append_next_arg_to == '-arch': 713 t = ('-arch', arg) 714 dict['CCFLAGS'].append(t) 715 dict['LINKFLAGS'].append(t) 716 else: 717 dict[append_next_arg_to].append(arg) 718 append_next_arg_to = None 719 elif not arg[0] in ['-', '+']: 720 dict['LIBS'].append(self.fs.File(arg)) 721 elif arg[:2] == '-L': 722 if arg[2:]: 723 dict['LIBPATH'].append(arg[2:]) 724 else: 725 append_next_arg_to = 'LIBPATH' 726 elif arg[:2] == '-l': 727 if arg[2:]: 728 dict['LIBS'].append(arg[2:]) 729 else: 730 append_next_arg_to = 'LIBS' 731 elif arg[:2] == '-I': 732 if arg[2:]: 733 dict['CPPPATH'].append(arg[2:]) 734 else: 735 append_next_arg_to = 'CPPPATH' 736 elif arg[:4] == '-Wa,': 737 dict['ASFLAGS'].append(arg[4:]) 738 dict['CCFLAGS'].append(arg) 739 elif arg[:4] == '-Wl,': 740 if arg[:11] == '-Wl,-rpath=': 741 dict['RPATH'].append(arg[11:]) 742 elif arg[:7] == '-Wl,-R,': 743 dict['RPATH'].append(arg[7:]) 744 elif arg[:6] == '-Wl,-R': 745 dict['RPATH'].append(arg[6:]) 746 else: 747 dict['LINKFLAGS'].append(arg) 748 elif arg[:4] == '-Wp,': 749 dict['CPPFLAGS'].append(arg) 750 elif arg[:2] == '-D': 751 if arg[2:]: 752 append_define(arg[2:]) 753 else: 754 append_next_arg_to = 'CPPDEFINES' 755 elif arg == '-framework': 756 append_next_arg_to = 'FRAMEWORKS' 757 elif arg[:14] == '-frameworkdir=': 758 dict['FRAMEWORKPATH'].append(arg[14:]) 759 elif arg[:2] == '-F': 760 if arg[2:]: 761 dict['FRAMEWORKPATH'].append(arg[2:]) 762 else: 763 append_next_arg_to = 'FRAMEWORKPATH' 764 elif arg == '-mno-cygwin': 765 dict['CCFLAGS'].append(arg) 766 dict['LINKFLAGS'].append(arg) 767 elif arg == '-mwindows': 768 dict['LINKFLAGS'].append(arg) 769 elif arg == '-pthread': 770 dict['CCFLAGS'].append(arg) 771 dict['LINKFLAGS'].append(arg) 772 elif arg[:5] == '-std=': 773 dict['CFLAGS'].append(arg) # C only 774 elif arg[0] == '+': 775 dict['CCFLAGS'].append(arg) 776 dict['LINKFLAGS'].append(arg) 777 elif arg in ['-include', '-isysroot', '-arch']: 778 append_next_arg_to = arg 779 else: 780 dict['CCFLAGS'].append(arg) 781 782 for arg in flags: 783 do_parse(arg, do_parse) 784 return dict 785
786 - def MergeFlags(self, args, unique=1, dict=None):
787 """ 788 Merge the dict in args into the construction variables of this 789 env, or the passed-in dict. If args is not a dict, it is 790 converted into a dict using ParseFlags. If unique is not set, 791 the flags are appended rather than merged. 792 """ 793 794 if dict is None: 795 dict = self 796 if not SCons.Util.is_Dict(args): 797 args = self.ParseFlags(args) 798 if not unique: 799 apply(self.Append, (), args) 800 return self 801 for key, value in args.items(): 802 if not value: 803 continue 804 try: 805 orig = self[key] 806 except KeyError: 807 orig = value 808 else: 809 if not orig: 810 orig = value 811 elif value: 812 # Add orig and value. The logic here was lifted from 813 # part of env.Append() (see there for a lot of comments 814 # about the order in which things are tried) and is 815 # used mainly to handle coercion of strings to CLVar to 816 # "do the right thing" given (e.g.) an original CCFLAGS 817 # string variable like '-pipe -Wall'. 818 try: 819 orig = orig + value 820 except (KeyError, TypeError): 821 try: 822 add_to_orig = orig.append 823 except AttributeError: 824 value.insert(0, orig) 825 orig = value 826 else: 827 add_to_orig(value) 828 t = [] 829 if key[-4:] == 'PATH': 830 ### keep left-most occurence 831 for v in orig: 832 if v not in t: 833 t.append(v) 834 else: 835 ### keep right-most occurence 836 orig.reverse() 837 for v in orig: 838 if v not in t: 839 t.insert(0, v) 840 self[key] = t 841 return self
842 843 # def MergeShellPaths(self, args, prepend=1): 844 # """ 845 # Merge the dict in args into the shell environment in env['ENV']. 846 # Shell path elements are appended or prepended according to prepend. 847 848 # Uses Pre/AppendENVPath, so it always appends or prepends uniquely. 849 850 # Example: env.MergeShellPaths({'LIBPATH': '/usr/local/lib'}) 851 # prepends /usr/local/lib to env['ENV']['LIBPATH']. 852 # """ 853 854 # for pathname, pathval in args.items(): 855 # if not pathval: 856 # continue 857 # if prepend: 858 # apply(self.PrependENVPath, (pathname, pathval)) 859 # else: 860 # apply(self.AppendENVPath, (pathname, pathval)) 861 862 863 # Used by the FindSourceFiles() method, below. 864 # Stuck here for support of pre-2.2 Python versions.
865 -def build_source(ss, result):
866 for s in ss: 867 if isinstance(s, SCons.Node.FS.Dir): 868 build_source(s.all_children(), result) 869 elif s.has_builder(): 870 build_source(s.sources, result) 871 elif isinstance(s.disambiguate(), SCons.Node.FS.File): 872 result.append(s)
873
874 -def default_decide_source(dependency, target, prev_ni):
875 f = SCons.Defaults.DefaultEnvironment().decide_source 876 return f(dependency, target, prev_ni)
877
878 -def default_decide_target(dependency, target, prev_ni):
879 f = SCons.Defaults.DefaultEnvironment().decide_target 880 return f(dependency, target, prev_ni)
881
882 -def default_copy_from_cache(src, dst):
883 f = SCons.Defaults.DefaultEnvironment().copy_from_cache 884 return f(src, dst)
885
886 -class Base(SubstitutionEnvironment):
887 """Base class for "real" construction Environments. These are the 888 primary objects used to communicate dependency and construction 889 information to the build engine. 890 891 Keyword arguments supplied when the construction Environment 892 is created are construction variables used to initialize the 893 Environment. 894 """ 895 896 if SCons.Memoize.use_memoizer: 897 __metaclass__ = SCons.Memoize.Memoized_Metaclass 898 899 memoizer_counters = [] 900 901 ####################################################################### 902 # This is THE class for interacting with the SCons build engine, 903 # and it contains a lot of stuff, so we're going to try to keep this 904 # a little organized by grouping the methods. 905 ####################################################################### 906 907 ####################################################################### 908 # Methods that make an Environment act like a dictionary. These have 909 # the expected standard names for Python mapping objects. Note that 910 # we don't actually make an Environment a subclass of UserDict for 911 # performance reasons. Note also that we only supply methods for 912 # dictionary functionality that we actually need and use. 913 ####################################################################### 914
915 - def __init__(self, 916 platform=None, 917 tools=None, 918 toolpath=None, 919 variables=None, 920 parse_flags = None, 921 **kw):
922 """ 923 Initialization of a basic SCons construction environment, 924 including setting up special construction variables like BUILDER, 925 PLATFORM, etc., and searching for and applying available Tools. 926 927 Note that we do *not* call the underlying base class 928 (SubsitutionEnvironment) initialization, because we need to 929 initialize things in a very specific order that doesn't work 930 with the much simpler base class initialization. 931 """ 932 if __debug__: logInstanceCreation(self, 'Environment.Base') 933 self._memo = {} 934 self.fs = SCons.Node.FS.get_default_fs() 935 self.ans = SCons.Node.Alias.default_ans 936 self.lookup_list = SCons.Node.arg2nodes_lookups 937 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment) 938 self._init_special() 939 self.added_methods = [] 940 941 # We don't use AddMethod, or define these as methods in this 942 # class, because we *don't* want these functions to be bound 943 # methods. They need to operate independently so that the 944 # settings will work properly regardless of whether a given 945 # target ends up being built with a Base environment or an 946 # OverrideEnvironment or what have you. 947 self.decide_target = default_decide_target 948 self.decide_source = default_decide_source 949 950 self.copy_from_cache = default_copy_from_cache 951 952 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self) 953 954 if platform is None: 955 platform = self._dict.get('PLATFORM', None) 956 if platform is None: 957 platform = SCons.Platform.Platform() 958 if SCons.Util.is_String(platform): 959 platform = SCons.Platform.Platform(platform) 960 self._dict['PLATFORM'] = str(platform) 961 platform(self) 962 963 # Apply the passed-in and customizable variables to the 964 # environment before calling the tools, because they may use 965 # some of them during initialization. 966 if kw.has_key('options'): 967 # Backwards compatibility: they may stll be using the 968 # old "options" keyword. 969 variables = kw['options'] 970 del kw['options'] 971 apply(self.Replace, (), kw) 972 keys = kw.keys() 973 if variables: 974 keys = keys + variables.keys() 975 variables.Update(self) 976 977 save = {} 978 for k in keys: 979 try: 980 save[k] = self._dict[k] 981 except KeyError: 982 # No value may have been set if they tried to pass in a 983 # reserved variable name like TARGETS. 984 pass 985 986 SCons.Tool.Initializers(self) 987 988 if tools is None: 989 tools = self._dict.get('TOOLS', None) 990 if tools is None: 991 tools = ['default'] 992 apply_tools(self, tools, toolpath) 993 994 # Now restore the passed-in and customized variables 995 # to the environment, since the values the user set explicitly 996 # should override any values set by the tools. 997 for key, val in save.items(): 998 self._dict[key] = val 999 1000 # Finally, apply any flags to be merged in 1001 if parse_flags: self.MergeFlags(parse_flags)
1002 1003 ####################################################################### 1004 # Utility methods that are primarily for internal use by SCons. 1005 # These begin with lower-case letters. 1006 ####################################################################### 1007
1008 - def get_builder(self, name):
1009 """Fetch the builder with the specified name from the environment. 1010 """ 1011 try: 1012 return self._dict['BUILDERS'][name] 1013 except KeyError: 1014 return None
1015
1016 - def get_CacheDir(self):
1017 try: 1018 path = self._CacheDir_path 1019 except AttributeError: 1020 path = SCons.Defaults.DefaultEnvironment()._CacheDir_path 1021 try: 1022 if path == self._last_CacheDir_path: 1023 return self._last_CacheDir 1024 except AttributeError: 1025 pass 1026 cd = SCons.CacheDir.CacheDir(path) 1027 self._last_CacheDir_path = path 1028 self._last_CacheDir = cd 1029 return cd
1030
1031 - def get_factory(self, factory, default='File'):
1032 """Return a factory function for creating Nodes for this 1033 construction environment. 1034 """ 1035 name = default 1036 try: 1037 is_node = issubclass(factory, SCons.Node.Node) 1038 except TypeError: 1039 # The specified factory isn't a Node itself--it's 1040 # most likely None, or possibly a callable. 1041 pass 1042 else: 1043 if is_node: 1044 # The specified factory is a Node (sub)class. Try to 1045 # return the FS method that corresponds to the Node's 1046 # name--that is, we return self.fs.Dir if they want a Dir, 1047 # self.fs.File for a File, etc. 1048 try: name = factory.__name__ 1049 except AttributeError: pass 1050 else: factory = None 1051 if not factory: 1052 # They passed us None, or we picked up a name from a specified 1053 # class, so return the FS method. (Note that we *don't* 1054 # use our own self.{Dir,File} methods because that would 1055 # cause env.subst() to be called twice on the file name, 1056 # interfering with files that have $$ in them.) 1057 factory = getattr(self.fs, name) 1058 return factory
1059 1060 memoizer_counters.append(SCons.Memoize.CountValue('_gsm')) 1061
1062 - def _gsm(self):
1063 try: 1064 return self._memo['_gsm'] 1065 except KeyError: 1066 pass 1067 1068 result = {} 1069 1070 try: 1071 scanners = self._dict['SCANNERS'] 1072 except KeyError: 1073 pass 1074 else: 1075 # Reverse the scanner list so that, if multiple scanners 1076 # claim they can scan the same suffix, earlier scanners 1077 # in the list will overwrite later scanners, so that 1078 # the result looks like a "first match" to the user. 1079 if not SCons.Util.is_List(scanners): 1080 scanners = [scanners] 1081 else: 1082 scanners = scanners[:] # copy so reverse() doesn't mod original 1083 scanners.reverse() 1084 for scanner in scanners: 1085 for k in scanner.get_skeys(self): 1086 result[k] = scanner 1087 1088 self._memo['_gsm'] = result 1089 1090 return result
1091
1092 - def get_scanner(self, skey):
1093 """Find the appropriate scanner given a key (usually a file suffix). 1094 """ 1095 return self._gsm().get(skey)
1096
1097 - def scanner_map_delete(self, kw=None):
1098 """Delete the cached scanner map (if we need to). 1099 """ 1100 try: 1101 del self._memo['_gsm'] 1102 except KeyError: 1103 pass
1104
1105 - def _update(self, dict):
1106 """Update an environment's values directly, bypassing the normal 1107 checks that occur when users try to set items. 1108 """ 1109 self._dict.update(dict)
1110
1111 - def get_src_sig_type(self):
1112 try: 1113 return self.src_sig_type 1114 except AttributeError: 1115 t = SCons.Defaults.DefaultEnvironment().src_sig_type 1116 self.src_sig_type = t 1117 return t
1118
1119 - def get_tgt_sig_type(self):
1120 try: 1121 return self.tgt_sig_type 1122 except AttributeError: 1123 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type 1124 self.tgt_sig_type = t 1125 return t
1126 1127 ####################################################################### 1128 # Public methods for manipulating an Environment. These begin with 1129 # upper-case letters. The essential characteristic of methods in 1130 # this section is that they do *not* have corresponding same-named 1131 # global functions. For example, a stand-alone Append() function 1132 # makes no sense, because Append() is all about appending values to 1133 # an Environment's construction variables. 1134 ####################################################################### 1135
1136 - def Append(self, **kw):
1137 """Append values to existing construction variables 1138 in an Environment. 1139 """ 1140 kw = copy_non_reserved_keywords(kw) 1141 for key, val in kw.items(): 1142 # It would be easier on the eyes to write this using 1143 # "continue" statements whenever we finish processing an item, 1144 # but Python 1.5.2 apparently doesn't let you use "continue" 1145 # within try:-except: blocks, so we have to nest our code. 1146 try: 1147 orig = self._dict[key] 1148 except KeyError: 1149 # No existing variable in the environment, so just set 1150 # it to the new value. 1151 self._dict[key] = val 1152 else: 1153 try: 1154 # Check if the original looks like a dictionary. 1155 # If it is, we can't just try adding the value because 1156 # dictionaries don't have __add__() methods, and 1157 # things like UserList will incorrectly coerce the 1158 # original dict to a list (which we don't want). 1159 update_dict = orig.update 1160 except AttributeError: 1161 try: 1162 # Most straightforward: just try to add them 1163 # together. This will work in most cases, when the 1164 # original and new values are of compatible types. 1165 self._dict[key] = orig + val 1166 except (KeyError, TypeError): 1167 try: 1168 # Check if the original is a list. 1169 add_to_orig = orig.append 1170 except AttributeError: 1171 # The original isn't a list, but the new 1172 # value is (by process of elimination), 1173 # so insert the original in the new value 1174 # (if there's one to insert) and replace 1175 # the variable with it. 1176 if orig: 1177 val.insert(0, orig) 1178 self._dict[key] = val 1179 else: 1180 # The original is a list, so append the new 1181 # value to it (if there's a value to append). 1182 if val: 1183 add_to_orig(val) 1184 else: 1185 # The original looks like a dictionary, so update it 1186 # based on what we think the value looks like. 1187 if SCons.Util.is_List(val): 1188 for v in val: 1189 orig[v] = None 1190 else: 1191 try: 1192 update_dict(val) 1193 except (AttributeError, TypeError, ValueError): 1194 if SCons.Util.is_Dict(val): 1195 for k, v in val.items(): 1196 orig[k] = v 1197 else: 1198 orig[val] = None 1199 self.scanner_map_delete(kw)
1200
1201 - def AppendENVPath(self, name, newpath, envname = 'ENV', 1202 sep = os.pathsep, delete_existing=1):
1203 """Append path elements to the path 'name' in the 'ENV' 1204 dictionary for this environment. Will only add any particular 1205 path once, and will normpath and normcase all paths to help 1206 assure this. This can also handle the case where the env 1207 variable is a list instead of a string. 1208 1209 If delete_existing is 0, a newpath which is already in the path 1210 will not be moved to the end (it will be left where it is). 1211 """ 1212 1213 orig = '' 1214 if self._dict.has_key(envname) and self._dict[envname].has_key(name): 1215 orig = self._dict[envname][name] 1216 1217 nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing) 1218 1219 if not self._dict.has_key(envname): 1220 self._dict[envname] = {} 1221 1222 self._dict[envname][name] = nv
1223
1224 - def AppendUnique(self, delete_existing=0, **kw):
1225 """Append values to existing construction variables 1226 in an Environment, if they're not already there. 1227 If delete_existing is 1, removes existing values first, so 1228 values move to end. 1229 """ 1230 kw = copy_non_reserved_keywords(kw) 1231 for key, val in kw.items(): 1232 if SCons.Util.is_List(val): 1233 val = _delete_duplicates(val, delete_existing) 1234 if not self._dict.has_key(key) or self._dict[key] in ('', None): 1235 self._dict[key] = val 1236 elif SCons.Util.is_Dict(self._dict[key]) and \ 1237 SCons.Util.is_Dict(val): 1238 self._dict[key].update(val) 1239 elif SCons.Util.is_List(val): 1240 dk = self._dict[key] 1241 if not SCons.Util.is_List(dk): 1242 dk = [dk] 1243 if delete_existing: 1244 dk = filter(lambda x, val=val: x not in val, dk) 1245 else: 1246 val = filter(lambda x, dk=dk: x not in dk, val) 1247 self._dict[key] = dk + val 1248 else: 1249 dk = self._dict[key] 1250 if SCons.Util.is_List(dk): 1251 # By elimination, val is not a list. Since dk is a 1252 # list, wrap val in a list first. 1253 if delete_existing: 1254 dk = filter(lambda x, val=val: x not in val, dk) 1255 self._dict[key] = dk + [val] 1256 else: 1257 if not val in dk: 1258 self._dict[key] = dk + [val] 1259 else: 1260 if delete_existing: 1261 dk = filter(lambda x, val=val: x not in val, dk) 1262 self._dict[key] = dk + val 1263 self.scanner_map_delete(kw)
1264
1265 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1266 """Return a copy of a construction Environment. The 1267 copy is like a Python "deep copy"--that is, independent 1268 copies are made recursively of each objects--except that 1269 a reference is copied when an object is not deep-copyable 1270 (like a function). There are no references to any mutable 1271 objects in the original Environment. 1272 """ 1273 clone = copy.copy(self) 1274 clone._dict = semi_deepcopy(self._dict) 1275 1276 try: 1277 cbd = clone._dict['BUILDERS'] 1278 except KeyError: 1279 pass 1280 else: 1281 clone._dict['BUILDERS'] = BuilderDict(cbd, clone) 1282 1283 # Check the methods added via AddMethod() and re-bind them to 1284 # the cloned environment. Only do this if the attribute hasn't 1285 # been overwritten by the user explicitly and still points to 1286 # the added method. 1287 clone.added_methods = [] 1288 for mw in self.added_methods: 1289 if mw == getattr(self, mw.name): 1290 clone.added_methods.append(mw.clone(clone)) 1291 1292 clone._memo = {} 1293 1294 # Apply passed-in variables before the tools 1295 # so the tools can use the new variables 1296 kw = copy_non_reserved_keywords(kw) 1297 new = {} 1298 for key, value in kw.items(): 1299 new[key] = SCons.Subst.scons_subst_once(value, self, key) 1300 apply(clone.Replace, (), new) 1301 1302 apply_tools(clone, tools, toolpath) 1303 1304 # apply them again in case the tools overwrote them 1305 apply(clone.Replace, (), new) 1306 1307 # Finally, apply any flags to be merged in 1308 if parse_flags: clone.MergeFlags(parse_flags) 1309 1310 if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone') 1311 return clone
1312
1313 - def Copy(self, *args, **kw):
1314 global _warn_copy_deprecated 1315 if _warn_copy_deprecated: 1316 msg = "The env.Copy() method is deprecated; use the env.Clone() method instead." 1317 SCons.Warnings.warn(SCons.Warnings.DeprecatedCopyWarning, msg) 1318 _warn_copy_deprecated = False 1319 return apply(self.Clone, args, kw)
1320
1321 - def _changed_build(self, dependency, target, prev_ni):
1322 if dependency.changed_state(target, prev_ni): 1323 return 1 1324 return self.decide_source(dependency, target, prev_ni)
1325
1326 - def _changed_content(self, dependency, target, prev_ni):
1327 return dependency.changed_content(target, prev_ni)
1328
1329 - def _changed_source(self, dependency, target, prev_ni):
1330 target_env = dependency.get_build_env() 1331 type = target_env.get_tgt_sig_type() 1332 if type == 'source': 1333 return target_env.decide_source(dependency, target, prev_ni) 1334 else: 1335 return target_env.decide_target(dependency, target, prev_ni)
1336
1337 - def _changed_timestamp_then_content(self, dependency, target, prev_ni):
1338 return dependency.changed_timestamp_then_content(target, prev_ni)
1339
1340 - def _changed_timestamp_newer(self, dependency, target, prev_ni):
1341 return dependency.changed_timestamp_newer(target, prev_ni)
1342
1343 - def _changed_timestamp_match(self, dependency, target, prev_ni):
1344 return dependency.changed_timestamp_match(target, prev_ni)
1345
1346 - def _copy_from_cache(self, src, dst):
1347 return self.fs.copy(src, dst)
1348
1349 - def _copy2_from_cache(self, src, dst):
1350 return self.fs.copy2(src, dst)
1351
1352 - def Decider(self, function):
1353 copy_function = self._copy2_from_cache 1354 if function in ('MD5', 'content'): 1355 if not SCons.Util.md5: 1356 raise UserError, "MD5 signatures are not available in this version of Python." 1357 function = self._changed_content 1358 elif function == 'MD5-timestamp': 1359 function = self._changed_timestamp_then_content 1360 elif function in ('timestamp-newer', 'make'): 1361 function = self._changed_timestamp_newer 1362 copy_function = self._copy_from_cache 1363 elif function == 'timestamp-match': 1364 function = self._changed_timestamp_match 1365 elif not callable(function): 1366 raise UserError, "Unknown Decider value %s" % repr(function) 1367 1368 # We don't use AddMethod because we don't want to turn the 1369 # function, which only expects three arguments, into a bound 1370 # method, which would add self as an initial, fourth argument. 1371 self.decide_target = function 1372 self.decide_source = function 1373 1374 self.copy_from_cache = copy_function
1375
1376 - def Detect(self, progs):
1377 """Return the first available program in progs. 1378 """ 1379 if not SCons.Util.is_List(progs): 1380 progs = [ progs ] 1381 for prog in progs: 1382 path = self.WhereIs(prog) 1383 if path: return prog 1384 return None
1385
1386 - def Dictionary(self, *args):
1387 if not args: 1388 return self._dict 1389 dlist = map(lambda x, s=self: s._dict[x], args) 1390 if len(dlist) == 1: 1391 dlist = dlist[0] 1392 return dlist
1393
1394 - def Dump(self, key = None):
1395 """ 1396 Using the standard Python pretty printer, dump the contents of the 1397 scons build environment to stdout. 1398 1399 If the key passed in is anything other than None, then that will 1400 be used as an index into the build environment dictionary and 1401 whatever is found there will be fed into the pretty printer. Note 1402 that this key is case sensitive. 1403 """ 1404 import pprint 1405 pp = pprint.PrettyPrinter(indent=2) 1406 if key: 1407 dict = self.Dictionary(key) 1408 else: 1409 dict = self.Dictionary() 1410 return pp.pformat(dict)
1411
1412 - def FindIxes(self, paths, prefix, suffix):
1413 """ 1414 Search a list of paths for something that matches the prefix and suffix. 1415 1416 paths - the list of paths or nodes. 1417 prefix - construction variable for the prefix. 1418 suffix - construction variable for the suffix. 1419 """ 1420 1421 suffix = self.subst('$'+suffix) 1422 prefix = self.subst('$'+prefix) 1423 1424 for path in paths: 1425 dir,name = os.path.split(str(path)) 1426 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: 1427 return path
1428
1429 - def ParseConfig(self, command, function=None, unique=1):
1430 """ 1431 Use the specified function to parse the output of the command 1432 in order to modify the current environment. The 'command' can 1433 be a string or a list of strings representing a command and 1434 its arguments. 'Function' is an optional argument that takes 1435 the environment, the output of the command, and the unique flag. 1436 If no function is specified, MergeFlags, which treats the output 1437 as the result of a typical 'X-config' command (i.e. gtk-config), 1438 will merge the output into the appropriate variables. 1439 """ 1440 if function is None: 1441 def parse_conf(env, cmd, unique=unique): 1442 return env.MergeFlags(cmd, unique)
1443 function = parse_conf 1444 if SCons.Util.is_List(command): 1445 command = string.join(command) 1446 command = self.subst(command) 1447 return function(self, self.backtick(command))
1448
1449 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1450 """ 1451 Parse a mkdep-style file for explicit dependencies. This is 1452 completely abusable, and should be unnecessary in the "normal" 1453 case of proper SCons configuration, but it may help make 1454 the transition from a Make hierarchy easier for some people 1455 to swallow. It can also be genuinely useful when using a tool 1456 that can write a .d file, but for which writing a scanner would 1457 be too complicated. 1458 """ 1459 filename = self.subst(filename) 1460 try: 1461 fp = open(filename, 'r') 1462 except IOError: 1463 if must_exist: 1464 raise 1465 return 1466 lines = SCons.Util.LogicalLines(fp).readlines() 1467 lines = filter(lambda l: l[0] != '#', lines) 1468 tdlist = [] 1469 for line in lines: 1470 try: 1471 target, depends = string.split(line, ':', 1) 1472 except (AttributeError, TypeError, ValueError): 1473 # Python 1.5.2 throws TypeError if line isn't a string, 1474 # Python 2.x throws AttributeError because it tries 1475 # to call line.split(). Either can throw ValueError 1476 # if the line doesn't split into two or more elements. 1477 pass 1478 else: 1479 tdlist.append((string.split(target), string.split(depends))) 1480 if only_one: 1481 targets = reduce(lambda x, y: x+y, map(lambda p: p[0], tdlist)) 1482 if len(targets) > 1: 1483 raise SCons.Errors.UserError, "More than one dependency target found in `%s': %s" % (filename, targets) 1484 for target, depends in tdlist: 1485 self.Depends(target, depends)
1486
1487 - def Platform(self, platform):
1488 platform = self.subst(platform) 1489 return SCons.Platform.Platform(platform)(self)
1490
1491 - def Prepend(self, **kw):
1492 """Prepend values to existing construction variables 1493 in an Environment. 1494 """ 1495 kw = copy_non_reserved_keywords(kw) 1496 for key, val in kw.items(): 1497 # It would be easier on the eyes to write this using 1498 # "continue" statements whenever we finish processing an item, 1499 # but Python 1.5.2 apparently doesn't let you use "continue" 1500 # within try:-except: blocks, so we have to nest our code. 1501 try: 1502 orig = self._dict[key] 1503 except KeyError: 1504 # No existing variable in the environment, so just set 1505 # it to the new value. 1506 self._dict[key] = val 1507 else: 1508 try: 1509 # Check if the original looks like a dictionary. 1510 # If it is, we can't just try adding the value because 1511 # dictionaries don't have __add__() methods, and 1512 # things like UserList will incorrectly coerce the 1513 # original dict to a list (which we don't want). 1514 update_dict = orig.update 1515 except AttributeError: 1516 try: 1517 # Most straightforward: just try to add them 1518 # together. This will work in most cases, when the 1519 # original and new values are of compatible types. 1520 self._dict[key] = val + orig 1521 except (KeyError, TypeError): 1522 try: 1523 # Check if the added value is a list. 1524 add_to_val = val.append 1525 except AttributeError: 1526 # The added value isn't a list, but the 1527 # original is (by process of elimination), 1528 # so insert the the new value in the original 1529 # (if there's one to insert). 1530 if val: 1531 orig.insert(0, val) 1532 else: 1533 # The added value is a list, so append 1534 # the original to it (if there's a value 1535 # to append). 1536 if orig: 1537 add_to_val(orig) 1538 self._dict[key] = val 1539 else: 1540 # The original looks like a dictionary, so update it 1541 # based on what we think the value looks like. 1542 if SCons.Util.is_List(val): 1543 for v in val: 1544 orig[v] = None 1545 else: 1546 try: 1547 update_dict(val) 1548 except (AttributeError, TypeError, ValueError): 1549 if SCons.Util.is_Dict(val): 1550 for k, v in val.items(): 1551 orig[k] = v 1552 else: 1553 orig[val] = None 1554 self.scanner_map_delete(kw)
1555
1556 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, 1557 delete_existing=1):
1558 """Prepend path elements to the path 'name' in the 'ENV' 1559 dictionary for this environment. Will only add any particular 1560 path once, and will normpath and normcase all paths to help 1561 assure this. This can also handle the case where the env 1562 variable is a list instead of a string. 1563 1564 If delete_existing is 0, a newpath which is already in the path 1565 will not be moved to the front (it will be left where it is). 1566 """ 1567 1568 orig = '' 1569 if self._dict.has_key(envname) and self._dict[envname].has_key(name): 1570 orig = self._dict[envname][name] 1571 1572 nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing) 1573 1574 if not self._dict.has_key(envname): 1575 self._dict[envname] = {} 1576 1577 self._dict[envname][name] = nv
1578
1579 - def PrependUnique(self, delete_existing=0, **kw):
1580 """Prepend values to existing construction variables 1581 in an Environment, if they're not already there. 1582 If delete_existing is 1, removes existing values first, so 1583 values move to front. 1584 """ 1585 kw = copy_non_reserved_keywords(kw) 1586 for key, val in kw.items(): 1587 if SCons.Util.is_List(val): 1588 val = _delete_duplicates(val, not delete_existing) 1589 if not self._dict.has_key(key) or self._dict[key] in ('', None): 1590 self._dict[key] = val 1591 elif SCons.Util.is_Dict(self._dict[key]) and \ 1592 SCons.Util.is_Dict(val): 1593 self._dict[key].update(val) 1594 elif SCons.Util.is_List(val): 1595 dk = self._dict[key] 1596 if not SCons.Util.is_List(dk): 1597 dk = [dk] 1598 if delete_existing: 1599 dk = filter(lambda x, val=val: x not in val, dk) 1600 else: 1601 val = filter(lambda x, dk=dk: x not in dk, val) 1602 self._dict[key] = val + dk 1603 else: 1604 dk = self._dict[key] 1605 if SCons.Util.is_List(dk): 1606 # By elimination, val is not a list. Since dk is a 1607 # list, wrap val in a list first. 1608 if delete_existing: 1609 dk = filter(lambda x, val=val: x not in val, dk) 1610 self._dict[key] = [val] + dk 1611 else: 1612 if not val in dk: 1613 self._dict[key] = [val] + dk 1614 else: 1615 if delete_existing: 1616 dk = filter(lambda x, val=val: x not in val, dk) 1617 self._dict[key] = val + dk 1618 self.scanner_map_delete(kw)
1619
1620 - def Replace(self, **kw):
1621 """Replace existing construction variables in an Environment 1622 with new construction variables and/or values. 1623 """ 1624 try: 1625 kwbd = kw['BUILDERS'] 1626 except KeyError: 1627 pass 1628 else: 1629 kwbd = semi_deepcopy(kwbd) 1630 del kw['BUILDERS'] 1631 self.__setitem__('BUILDERS', kwbd) 1632 kw = copy_non_reserved_keywords(kw) 1633 self._update(semi_deepcopy(kw)) 1634 self.scanner_map_delete(kw)
1635
1636 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1637 """ 1638 Replace old_prefix with new_prefix and old_suffix with new_suffix. 1639 1640 env - Environment used to interpolate variables. 1641 path - the path that will be modified. 1642 old_prefix - construction variable for the old prefix. 1643 old_suffix - construction variable for the old suffix. 1644 new_prefix - construction variable for the new prefix. 1645 new_suffix - construction variable for the new suffix. 1646 """ 1647 old_prefix = self.subst('$'+old_prefix) 1648 old_suffix = self.subst('$'+old_suffix) 1649 1650 new_prefix = self.subst('$'+new_prefix) 1651 new_suffix = self.subst('$'+new_suffix) 1652 1653 dir,name = os.path.split(str(path)) 1654 if name[:len(old_prefix)] == old_prefix: 1655 name = name[len(old_prefix):] 1656 if name[-len(old_suffix):] == old_suffix: 1657 name = name[:-len(old_suffix)] 1658 return os.path.join(dir, new_prefix+name+new_suffix)
1659
1660 - def SetDefault(self, **kw):
1661 for k in kw.keys(): 1662 if self._dict.has_key(k): 1663 del kw[k] 1664 apply(self.Replace, (), kw)
1665
1666 - def _find_toolpath_dir(self, tp):
1667 return self.fs.Dir(self.subst(tp)).srcnode().abspath
1668
1669 - def Tool(self, tool, toolpath=None, **kw):
1670 if SCons.Util.is_String(tool): 1671 tool = self.subst(tool) 1672 if toolpath is None: 1673 toolpath = self.get('toolpath', []) 1674 toolpath = map(self._find_toolpath_dir, toolpath) 1675 tool = apply(SCons.Tool.Tool, (tool, toolpath), kw) 1676 tool(self)
1677
1678 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1679 """Find prog in the path. 1680 """ 1681 if path is None: 1682 try: 1683 path = self['ENV']['PATH'] 1684 except KeyError: 1685 pass 1686 elif SCons.Util.is_String(path): 1687 path = self.subst(path) 1688 if pathext is None: 1689 try: 1690 pathext = self['ENV']['PATHEXT'] 1691 except KeyError: 1692 pass 1693 elif SCons.Util.is_String(pathext): 1694 pathext = self.subst(pathext) 1695 prog = self.subst(prog) 1696 path = SCons.Util.WhereIs(prog, path, pathext, reject) 1697 if path: return path 1698 return None
1699 1700 ####################################################################### 1701 # Public methods for doing real "SCons stuff" (manipulating 1702 # dependencies, setting attributes on targets, etc.). These begin 1703 # with upper-case letters. The essential characteristic of methods 1704 # in this section is that they all *should* have corresponding 1705 # same-named global functions. 1706 ####################################################################### 1707
1708 - def Action(self, *args, **kw):
1709 def subst_string(a, self=self): 1710 if SCons.Util.is_String(a): 1711 a = self.subst(a) 1712 return a
1713 nargs = map(subst_string, args) 1714 nkw = self.subst_kw(kw) 1715 return apply(SCons.Action.Action, nargs, nkw) 1716
1717 - def AddPreAction(self, files, action):
1718 nodes = self.arg2nodes(files, self.fs.Entry) 1719 action = SCons.Action.Action(action) 1720 uniq = {} 1721 for executor in map(lambda n: n.get_executor(), nodes): 1722 uniq[executor] = 1 1723 for executor in uniq.keys(): 1724 executor.add_pre_action(action) 1725 return nodes
1726
1727 - def AddPostAction(self, files, action):
1728 nodes = self.arg2nodes(files, self.fs.Entry) 1729 action = SCons.Action.Action(action) 1730 uniq = {} 1731 for executor in map(lambda n: n.get_executor(), nodes): 1732 uniq[executor] = 1 1733 for executor in uniq.keys(): 1734 executor.add_post_action(action) 1735 return nodes
1736
1737 - def Alias(self, target, source=[], action=None, **kw):
1738 tlist = self.arg2nodes(target, self.ans.Alias) 1739 if not SCons.Util.is_List(source): 1740 source = [source] 1741 source = filter(None, source) 1742 1743 if not action: 1744 if not source: 1745 # There are no source files and no action, so just 1746 # return a target list of classic Alias Nodes, without 1747 # any builder. The externally visible effect is that 1748 # this will make the wrapping Script.BuildTask class 1749 # say that there's "Nothing to be done" for this Alias, 1750 # instead of that it's "up to date." 1751 return tlist 1752 1753 # No action, but there are sources. Re-call all the target 1754 # builders to add the sources to each target. 1755 result = [] 1756 for t in tlist: 1757 bld = t.get_builder(AliasBuilder) 1758 result.extend(bld(self, t, source)) 1759 return result 1760 1761 nkw = self.subst_kw(kw) 1762 nkw.update({ 1763 'action' : SCons.Action.Action(action), 1764 'source_factory' : self.fs.Entry, 1765 'multi' : 1, 1766 'is_explicit' : None, 1767 }) 1768 bld = apply(SCons.Builder.Builder, (), nkw) 1769 1770 # Apply the Builder separately to each target so that the Aliases 1771 # stay separate. If we did one "normal" Builder call with the 1772 # whole target list, then all of the target Aliases would be 1773 # associated under a single Executor. 1774 result = [] 1775 for t in tlist: 1776 # Calling the convert() method will cause a new Executor to be 1777 # created from scratch, so we have to explicitly initialize 1778 # it with the target's existing sources, plus our new ones, 1779 # so nothing gets lost. 1780 b = t.get_builder() 1781 if b is None or b is AliasBuilder: 1782 b = bld 1783 else: 1784 nkw['action'] = b.action + action 1785 b = apply(SCons.Builder.Builder, (), nkw) 1786 t.convert() 1787 result.extend(b(self, t, t.sources + source)) 1788 return result
1789
1790 - def AlwaysBuild(self, *targets):
1791 tlist = [] 1792 for t in targets: 1793 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 1794 for t in tlist: 1795 t.set_always_build() 1796 return tlist
1797
1798 - def BuildDir(self, *args, **kw):
1799 if kw.has_key('build_dir'): 1800 kw['variant_dir'] = kw['build_dir'] 1801 del kw['build_dir'] 1802 return apply(self.VariantDir, args, kw)
1803
1804 - def Builder(self, **kw):
1805 nkw = self.subst_kw(kw) 1806 return apply(SCons.Builder.Builder, [], nkw)
1807
1808 - def CacheDir(self, path):
1809 import SCons.CacheDir 1810 if not path is None: 1811 path = self.subst(path) 1812 self._CacheDir_path = path
1813
1814 - def Clean(self, targets, files):
1815 global CleanTargets 1816 tlist = self.arg2nodes(targets, self.fs.Entry) 1817 flist = self.arg2nodes(files, self.fs.Entry) 1818 for t in tlist: 1819 try: 1820 CleanTargets[t].extend(flist) 1821 except KeyError: 1822 CleanTargets[t] = flist
1823
1824 - def Configure(self, *args, **kw):
1825 nargs = [self] 1826 if args: 1827 nargs = nargs + self.subst_list(args)[0] 1828 nkw = self.subst_kw(kw) 1829 nkw['_depth'] = kw.get('_depth', 0) + 1 1830 try: 1831 nkw['custom_tests'] = self.subst_kw(nkw['custom_tests']) 1832 except KeyError: 1833 pass 1834 return apply(SCons.SConf.SConf, nargs, nkw)
1835
1836 - def Command(self, target, source, action, **kw):
1837 """Builds the supplied target files from the supplied 1838 source files using the supplied action. Action may 1839 be any type that the Builder constructor will accept 1840 for an action.""" 1841 bkw = { 1842 'action' : action, 1843 'target_factory' : self.fs.Entry, 1844 'source_factory' : self.fs.Entry, 1845 } 1846 try: bkw['source_scanner'] = kw['source_scanner'] 1847 except KeyError: pass 1848 else: del kw['source_scanner'] 1849 bld = apply(SCons.Builder.Builder, (), bkw) 1850 return apply(bld, (self, target, source), kw)
1851
1852 - def Depends(self, target, dependency):
1853 """Explicity specify that 'target's depend on 'dependency'.""" 1854 tlist = self.arg2nodes(target, self.fs.Entry) 1855 dlist = self.arg2nodes(dependency, self.fs.Entry) 1856 for t in tlist: 1857 t.add_dependency(dlist) 1858 return tlist
1859
1860 - def Dir(self, name, *args, **kw):
1861 """ 1862 """ 1863 s = self.subst(name) 1864 if SCons.Util.is_Sequence(s): 1865 result=[] 1866 for e in s: 1867 result.append(apply(self.fs.Dir, (e,) + args, kw)) 1868 return result 1869 return apply(self.fs.Dir, (s,) + args, kw)
1870
1871 - def NoClean(self, *targets):
1872 """Tags a target so that it will not be cleaned by -c""" 1873 tlist = [] 1874 for t in targets: 1875 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 1876 for t in tlist: 1877 t.set_noclean() 1878 return tlist
1879
1880 - def NoCache(self, *targets):
1881 """Tags a target so that it will not be cached""" 1882 tlist = [] 1883 for t in targets: 1884 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 1885 for t in tlist: 1886 t.set_nocache() 1887 return tlist
1888
1889 - def Entry(self, name, *args, **kw):
1890 """ 1891 """ 1892 s = self.subst(name) 1893 if SCons.Util.is_Sequence(s): 1894 result=[] 1895 for e in s: 1896 result.append(apply(self.fs.Entry, (e,) + args, kw)) 1897 return result 1898 return apply(self.fs.Entry, (s,) + args, kw)
1899
1900 - def Environment(self, **kw):
1901 return apply(SCons.Environment.Environment, [], self.subst_kw(kw))
1902
1903 - def Execute(self, action, *args, **kw):
1904 """Directly execute an action through an Environment 1905 """ 1906 action = apply(self.Action, (action,) + args, kw) 1907 result = action([], [], self) 1908 if isinstance(result, SCons.Errors.BuildError): 1909 errstr = result.errstr 1910 if result.filename: 1911 errstr = result.filename + ': ' + errstr 1912 sys.stderr.write("scons: *** %s\n" % errstr) 1913 return result.status 1914 else: 1915 return result
1916
1917 - def File(self, name, *args, **kw):
1918 """ 1919 """ 1920 s = self.subst(name) 1921 if SCons.Util.is_Sequence(s): 1922 result=[] 1923 for e in s: 1924 result.append(apply(self.fs.File, (e,) + args, kw)) 1925 return result 1926 return apply(self.fs.File, (s,) + args, kw)
1927
1928 - def FindFile(self, file, dirs):
1929 file = self.subst(file) 1930 nodes = self.arg2nodes(dirs, self.fs.Dir) 1931 return SCons.Node.FS.find_file(file, tuple(nodes))
1932
1933 - def Flatten(self, sequence):
1934 return SCons.Util.flatten(sequence)
1935
1936 - def GetBuildPath(self, files):
1937 result = map(str, self.arg2nodes(files, self.fs.Entry)) 1938 if SCons.Util.is_List(files): 1939 return result 1940 else: 1941 return result[0]
1942
1943 - def Glob(self, pattern, ondisk=True, source=False, strings=False):
1944 return self.fs.Glob(self.subst(pattern), ondisk, source, strings)
1945
1946 - def Ignore(self, target, dependency):
1947 """Ignore a dependency.""" 1948 tlist = self.arg2nodes(target, self.fs.Entry) 1949 dlist = self.arg2nodes(dependency, self.fs.Entry) 1950 for t in tlist: 1951 t.add_ignore(dlist) 1952 return tlist
1953
1954 - def Literal(self, string):
1955 return SCons.Subst.Literal(string)
1956
1957 - def Local(self, *targets):
1958 ret = [] 1959 for targ in targets: 1960 if isinstance(targ, SCons.Node.Node): 1961 targ.set_local() 1962 ret.append(targ) 1963 else: 1964 for t in self.arg2nodes(targ, self.fs.Entry): 1965 t.set_local() 1966 ret.append(t) 1967 return ret
1968
1969 - def Precious(self, *targets):
1970 tlist = [] 1971 for t in targets: 1972 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 1973 for t in tlist: 1974 t.set_precious() 1975 return tlist
1976
1977 - def Repository(self, *dirs, **kw):
1978 dirs = self.arg2nodes(list(dirs), self.fs.Dir) 1979 apply(self.fs.Repository, dirs, kw)
1980
1981 - def Requires(self, target, prerequisite):
1982 """Specify that 'prerequisite' must be built before 'target', 1983 (but 'target' does not actually depend on 'prerequisite' 1984 and need not be rebuilt if it changes).""" 1985 tlist = self.arg2nodes(target, self.fs.Entry) 1986 plist = self.arg2nodes(prerequisite, self.fs.Entry) 1987 for t in tlist: 1988 t.add_prerequisite(plist) 1989 return tlist
1990
1991 - def Scanner(self, *args, **kw):
1992 nargs = [] 1993 for arg in args: 1994 if SCons.Util.is_String(arg): 1995 arg = self.subst(arg) 1996 nargs.append(arg) 1997 nkw = self.subst_kw(kw) 1998 return apply(SCons.Scanner.Base, nargs, nkw)
1999
2000 - def SConsignFile(self, name=".sconsign", dbm_module=None):
2001 if not name is None: 2002 name = self.subst(name) 2003 if not os.path.isabs(name): 2004 name = os.path.join(str(self.fs.SConstruct_dir), name) 2005 if name: 2006 name = os.path.normpath(name) 2007 sconsign_dir = os.path.dirname(name) 2008 if sconsign_dir and not os.path.exists(sconsign_dir): 2009 self.Execute(SCons.Defaults.Mkdir(sconsign_dir)) 2010 SCons.SConsign.File(name, dbm_module)
2011
2012 - def SideEffect(self, side_effect, target):
2013 """Tell scons that side_effects are built as side 2014 effects of building targets.""" 2015 side_effects = self.arg2nodes(side_effect, self.fs.Entry) 2016 targets = self.arg2nodes(target, self.fs.Entry) 2017 2018 for side_effect in side_effects: 2019 if side_effect.multiple_side_effect_has_builder(): 2020 raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect) 2021 side_effect.add_source(targets) 2022 side_effect.side_effect = 1 2023 self.Precious(side_effect) 2024 for target in targets: 2025 target.side_effects.append(side_effect) 2026 return side_effects
2027
2028 - def SourceCode(self, entry, builder):
2029 """Arrange for a source code builder for (part of) a tree.""" 2030 entries = self.arg2nodes(entry, self.fs.Entry) 2031 for entry in entries: 2032 entry.set_src_builder(builder) 2033 return entries
2034
2035 - def SourceSignatures(self, type):
2036 global _warn_source_signatures_deprecated 2037 if _warn_source_signatures_deprecated: 2038 msg = "The env.SourceSignatures() method is deprecated;\n" + \ 2039 "\tconvert your build to use the env.Decider() method instead." 2040 SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceSignaturesWarning, msg) 2041 _warn_source_signatures_deprecated = False 2042 type = self.subst(type) 2043 self.src_sig_type = type 2044 if type == 'MD5': 2045 if not SCons.Util.md5: 2046 raise UserError, "MD5 signatures are not available in this version of Python." 2047 self.decide_source = self._changed_content 2048 elif type == 'timestamp': 2049 self.decide_source = self._changed_timestamp_match 2050 else: 2051 raise UserError, "Unknown source signature type '%s'" % type
2052
2053 - def Split(self, arg):
2054 """This function converts a string or list into a list of strings 2055 or Nodes. This makes things easier for users by allowing files to 2056 be specified as a white-space separated list to be split. 2057 The input rules are: 2058 - A single string containing names separated by spaces. These will be 2059 split apart at the spaces. 2060 - A single Node instance 2061 - A list containing either strings or Node instances. Any strings 2062 in the list are not split at spaces. 2063 In all cases, the function returns a list of Nodes and strings.""" 2064 if SCons.Util.is_List(arg): 2065 return map(self.subst, arg) 2066 elif SCons.Util.is_String(arg): 2067 return string.split(self.subst(arg)) 2068 else: 2069 return [self.subst(arg)]
2070
2071 - def TargetSignatures(self, type):
2072 global _warn_target_signatures_deprecated 2073 if _warn_target_signatures_deprecated: 2074 msg = "The env.TargetSignatures() method is deprecated;\n" + \ 2075 "\tconvert your build to use the env.Decider() method instead." 2076 SCons.Warnings.warn(SCons.Warnings.DeprecatedTargetSignaturesWarning, msg) 2077 _warn_target_signatures_deprecated = False 2078 type = self.subst(type) 2079 self.tgt_sig_type = type 2080 if type in ('MD5', 'content'): 2081 if not SCons.Util.md5: 2082 raise UserError, "MD5 signatures are not available in this version of Python." 2083 self.decide_target = self._changed_content 2084 elif type == 'timestamp': 2085 self.decide_target = self._changed_timestamp_match 2086 elif type == 'build': 2087 self.decide_target = self._changed_build 2088 elif type == 'source': 2089 self.decide_target = self._changed_source 2090 else: 2091 raise UserError, "Unknown target signature type '%s'"%type
2092
2093 - def Value(self, value, built_value=None):
2094 """ 2095 """ 2096 return SCons.Node.Python.Value(value, built_value)
2097
2098 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
2099 variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0] 2100 src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0] 2101 self.fs.VariantDir(variant_dir, src_dir, duplicate)
2102
2103 - def FindSourceFiles(self, node='.'):
2104 """ returns a list of all source files. 2105 """ 2106 node = self.arg2nodes(node, self.fs.Entry)[0] 2107 2108 sources = [] 2109 # Uncomment this and get rid of the global definition when we 2110 # drop support for pre-2.2 Python versions. 2111 #def build_source(ss, result): 2112 # for s in ss: 2113 # if isinstance(s, SCons.Node.FS.Dir): 2114 # build_source(s.all_children(), result) 2115 # elif s.has_builder(): 2116 # build_source(s.sources, result) 2117 # elif isinstance(s.disambiguate(), SCons.Node.FS.File): 2118 # result.append(s) 2119 build_source(node.all_children(), sources) 2120 2121 # now strip the build_node from the sources by calling the srcnode 2122 # function 2123 def get_final_srcnode(file): 2124 srcnode = file.srcnode() 2125 while srcnode != file.srcnode(): 2126 srcnode = file.srcnode() 2127 return srcnode
2128 2129 # get the final srcnode for all nodes, this means stripping any 2130 # attached build node. 2131 map( get_final_srcnode, sources ) 2132 2133 # remove duplicates 2134 return list(set(sources)) 2135
2136 - def FindInstalledFiles(self):
2137 """ returns the list of all targets of the Install and InstallAs Builder. 2138 """ 2139 from SCons.Tool import install 2140 if install._UNIQUE_INSTALLED_FILES is None: 2141 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES) 2142 return install._UNIQUE_INSTALLED_FILES
2143
2144 -class OverrideEnvironment(Base):
2145 """A proxy that overrides variables in a wrapped construction 2146 environment by returning values from an overrides dictionary in 2147 preference to values from the underlying subject environment. 2148 2149 This is a lightweight (I hope) proxy that passes through most use of 2150 attributes to the underlying Environment.Base class, but has just 2151 enough additional methods defined to act like a real construction 2152 environment with overridden values. It can wrap either a Base 2153 construction environment, or another OverrideEnvironment, which 2154 can in turn nest arbitrary OverrideEnvironments... 2155 2156 Note that we do *not* call the underlying base class 2157 (SubsitutionEnvironment) initialization, because we get most of those 2158 from proxying the attributes of the subject construction environment. 2159 But because we subclass SubstitutionEnvironment, this class also 2160 has inherited arg2nodes() and subst*() methods; those methods can't 2161 be proxied because they need *this* object's methods to fetch the 2162 values from the overrides dictionary. 2163 """ 2164 2165 if SCons.Memoize.use_memoizer: 2166 __metaclass__ = SCons.Memoize.Memoized_Metaclass 2167
2168 - def __init__(self, subject, overrides={}):
2169 if __debug__: logInstanceCreation(self, 'Environment.OverrideEnvironment') 2170 self.__dict__['__subject'] = subject 2171 self.__dict__['overrides'] = overrides
2172 2173 # Methods that make this class act like a proxy.
2174 - def __getattr__(self, name):
2175 return getattr(self.__dict__['__subject'], name)
2176 - def __setattr__(self, name, value):
2177 setattr(self.__dict__['__subject'], name, value)
2178 2179 # Methods that make this class act like a dictionary.
2180 - def __getitem__(self, key):
2181 try: 2182 return self.__dict__['overrides'][key] 2183 except KeyError: 2184 return self.__dict__['__subject'].__getitem__(key)
2185 - def __setitem__(self, key, value):
2186 if not is_valid_construction_var(key): 2187 raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key 2188 self.__dict__['overrides'][key] = value
2189 - def __delitem__(self, key):
2190 try: 2191 del self.__dict__['overrides'][key] 2192 except KeyError: 2193 deleted = 0 2194 else: 2195 deleted = 1 2196 try: 2197 result = self.__dict__['__subject'].__delitem__(key) 2198 except KeyError: 2199 if not deleted: 2200 raise 2201 result = None 2202 return result
2203 - def get(self, key, default=None):
2204 """Emulates the get() method of dictionaries.""" 2205 try: 2206 return self.__dict__['overrides'][key] 2207 except KeyError: 2208 return self.__dict__['__subject'].get(key, default)
2209 - def has_key(self, key):
2210 try: 2211 self.__dict__['overrides'][key] 2212 return 1 2213 except KeyError: 2214 return self.__dict__['__subject'].has_key(key)
2215 - def __contains__(self, key):
2216 if self.__dict__['overrides'].__contains__(key): 2217 return 1 2218 return self.__dict__['__subject'].__contains__(key)
2219 - def Dictionary(self):
2220 """Emulates the items() method of dictionaries.""" 2221 d = self.__dict__['__subject'].Dictionary().copy() 2222 d.update(self.__dict__['overrides']) 2223 return d
2224 - def items(self):
2225 """Emulates the items() method of dictionaries.""" 2226 return self.Dictionary().items()
2227 2228 # Overridden private construction environment methods.
2229 - def _update(self, dict):
2230 """Update an environment's values directly, bypassing the normal 2231 checks that occur when users try to set items. 2232 """ 2233 self.__dict__['overrides'].update(dict)
2234
2235 - def gvars(self):
2236 return self.__dict__['__subject'].gvars()
2237
2238 - def lvars(self):
2239 lvars = self.__dict__['__subject'].lvars() 2240 lvars.update(self.__dict__['overrides']) 2241 return lvars
2242 2243 # Overridden public construction environment methods.
2244 - def Replace(self, **kw):
2245 kw = copy_non_reserved_keywords(kw) 2246 self.__dict__['overrides'].update(semi_deepcopy(kw))
2247 2248 # The entry point that will be used by the external world 2249 # to refer to a construction environment. This allows the wrapper 2250 # interface to extend a construction environment for its own purposes 2251 # by subclassing SCons.Environment.Base and then assigning the 2252 # class to SCons.Environment.Environment. 2253 2254 Environment = Base 2255 2256 # An entry point for returning a proxy subclass instance that overrides 2257 # the subst*() methods so they don't actually perform construction 2258 # variable substitution. This is specifically intended to be the shim 2259 # layer in between global function calls (which don't want construction 2260 # variable substitution) and the DefaultEnvironment() (which would 2261 # substitute variables if left to its own devices).""" 2262 # 2263 # We have to wrap this in a function that allows us to delay definition of 2264 # the class until it's necessary, so that when it subclasses Environment 2265 # it will pick up whatever Environment subclass the wrapper interface 2266 # might have assigned to SCons.Environment.Environment. 2267
2268 -def NoSubstitutionProxy(subject):
2269 class _NoSubstitutionProxy(Environment): 2270 def __init__(self, subject): 2271 self.__dict__['__subject'] = subject
2272 def __getattr__(self, name): 2273 return getattr(self.__dict__['__subject'], name) 2274 def __setattr__(self, name, value): 2275 return setattr(self.__dict__['__subject'], name, value) 2276 def raw_to_mode(self, dict): 2277 try: 2278 raw = dict['raw'] 2279 except KeyError: 2280 pass 2281 else: 2282 del dict['raw'] 2283 dict['mode'] = raw 2284 def subst(self, string, *args, **kwargs): 2285 return string 2286 def subst_kw(self, kw, *args, **kwargs): 2287 return kw 2288 def subst_list(self, string, *args, **kwargs): 2289 nargs = (string, self,) + args 2290 nkw = kwargs.copy() 2291 nkw['gvars'] = {} 2292 self.raw_to_mode(nkw) 2293 return apply(SCons.Subst.scons_subst_list, nargs, nkw) 2294 def subst_target_source(self, string, *args, **kwargs): 2295 nargs = (string, self,) + args 2296 nkw = kwargs.copy() 2297 nkw['gvars'] = {} 2298 self.raw_to_mode(nkw) 2299 return apply(SCons.Subst.scons_subst, nargs, nkw) 2300 return _NoSubstitutionProxy(subject) 2301