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