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