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