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