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 - 2014 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  2014/09/27 12:51:43 garyo" 
  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 == '-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', '-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 memoizer_counters = [] 903 904 ####################################################################### 905 # This is THE class for interacting with the SCons build engine, 906 # and it contains a lot of stuff, so we're going to try to keep this 907 # a little organized by grouping the methods. 908 ####################################################################### 909 910 ####################################################################### 911 # Methods that make an Environment act like a dictionary. These have 912 # the expected standard names for Python mapping objects. Note that 913 # we don't actually make an Environment a subclass of UserDict for 914 # performance reasons. Note also that we only supply methods for 915 # dictionary functionality that we actually need and use. 916 ####################################################################### 917
918 - def __init__(self, 919 platform=None, 920 tools=None, 921 toolpath=None, 922 variables=None, 923 parse_flags = None, 924 **kw):
925 """ 926 Initialization of a basic SCons construction environment, 927 including setting up special construction variables like BUILDER, 928 PLATFORM, etc., and searching for and applying available Tools. 929 930 Note that we do *not* call the underlying base class 931 (SubsitutionEnvironment) initialization, because we need to 932 initialize things in a very specific order that doesn't work 933 with the much simpler base class initialization. 934 """ 935 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.Base') 936 self._memo = {} 937 self.fs = SCons.Node.FS.get_default_fs() 938 self.ans = SCons.Node.Alias.default_ans 939 self.lookup_list = SCons.Node.arg2nodes_lookups 940 self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment) 941 self._init_special() 942 self.added_methods = [] 943 944 # We don't use AddMethod, or define these as methods in this 945 # class, because we *don't* want these functions to be bound 946 # methods. They need to operate independently so that the 947 # settings will work properly regardless of whether a given 948 # target ends up being built with a Base environment or an 949 # OverrideEnvironment or what have you. 950 self.decide_target = default_decide_target 951 self.decide_source = default_decide_source 952 953 self.copy_from_cache = default_copy_from_cache 954 955 self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self) 956 957 if platform is None: 958 platform = self._dict.get('PLATFORM', None) 959 if platform is None: 960 platform = SCons.Platform.Platform() 961 if SCons.Util.is_String(platform): 962 platform = SCons.Platform.Platform(platform) 963 self._dict['PLATFORM'] = str(platform) 964 platform(self) 965 966 self._dict['HOST_OS'] = self._dict.get('HOST_OS',None) 967 self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None) 968 969 # Now set defaults for TARGET_{OS|ARCH} 970 self._dict['TARGET_OS'] = self._dict.get('TARGET_OS',None) 971 self._dict['TARGET_ARCH'] = self._dict.get('TARGET_ARCH',None) 972 973 974 # Apply the passed-in and customizable variables to the 975 # environment before calling the tools, because they may use 976 # some of them during initialization. 977 if 'options' in kw: 978 # Backwards compatibility: they may stll be using the 979 # old "options" keyword. 980 variables = kw['options'] 981 del kw['options'] 982 self.Replace(**kw) 983 keys = list(kw.keys()) 984 if variables: 985 keys = keys + list(variables.keys()) 986 variables.Update(self) 987 988 save = {} 989 for k in keys: 990 try: 991 save[k] = self._dict[k] 992 except KeyError: 993 # No value may have been set if they tried to pass in a 994 # reserved variable name like TARGETS. 995 pass 996 997 SCons.Tool.Initializers(self) 998 999 if tools is None: 1000 tools = self._dict.get('TOOLS', None) 1001 if tools is None: 1002 tools = ['default'] 1003 apply_tools(self, tools, toolpath) 1004 1005 # Now restore the passed-in and customized variables 1006 # to the environment, since the values the user set explicitly 1007 # should override any values set by the tools. 1008 for key, val in save.items(): 1009 self._dict[key] = val 1010 1011 # Finally, apply any flags to be merged in 1012 if parse_flags: self.MergeFlags(parse_flags)
1013 1014 ####################################################################### 1015 # Utility methods that are primarily for internal use by SCons. 1016 # These begin with lower-case letters. 1017 ####################################################################### 1018
1019 - def get_builder(self, name):
1020 """Fetch the builder with the specified name from the environment. 1021 """ 1022 try: 1023 return self._dict['BUILDERS'][name] 1024 except KeyError: 1025 return None
1026
1027 - def get_CacheDir(self):
1028 try: 1029 path = self._CacheDir_path 1030 except AttributeError: 1031 path = SCons.Defaults.DefaultEnvironment()._CacheDir_path 1032 try: 1033 if path == self._last_CacheDir_path: 1034 return self._last_CacheDir 1035 except AttributeError: 1036 pass 1037 cd = SCons.CacheDir.CacheDir(path) 1038 self._last_CacheDir_path = path 1039 self._last_CacheDir = cd 1040 return cd
1041
1042 - def get_factory(self, factory, default='File'):
1043 """Return a factory function for creating Nodes for this 1044 construction environment. 1045 """ 1046 name = default 1047 try: 1048 is_node = issubclass(factory, SCons.Node.FS.Base) 1049 except TypeError: 1050 # The specified factory isn't a Node itself--it's 1051 # most likely None, or possibly a callable. 1052 pass 1053 else: 1054 if is_node: 1055 # The specified factory is a Node (sub)class. Try to 1056 # return the FS method that corresponds to the Node's 1057 # name--that is, we return self.fs.Dir if they want a Dir, 1058 # self.fs.File for a File, etc. 1059 try: name = factory.__name__ 1060 except AttributeError: pass 1061 else: factory = None 1062 if not factory: 1063 # They passed us None, or we picked up a name from a specified 1064 # class, so return the FS method. (Note that we *don't* 1065 # use our own self.{Dir,File} methods because that would 1066 # cause env.subst() to be called twice on the file name, 1067 # interfering with files that have $$ in them.) 1068 factory = getattr(self.fs, name) 1069 return factory
1070 1071 memoizer_counters.append(SCons.Memoize.CountValue('_gsm')) 1072
1073 - def _gsm(self):
1074 try: 1075 return self._memo['_gsm'] 1076 except KeyError: 1077 pass 1078 1079 result = {} 1080 1081 try: 1082 scanners = self._dict['SCANNERS'] 1083 except KeyError: 1084 pass 1085 else: 1086 # Reverse the scanner list so that, if multiple scanners 1087 # claim they can scan the same suffix, earlier scanners 1088 # in the list will overwrite later scanners, so that 1089 # the result looks like a "first match" to the user. 1090 if not SCons.Util.is_List(scanners): 1091 scanners = [scanners] 1092 else: 1093 scanners = scanners[:] # copy so reverse() doesn't mod original 1094 scanners.reverse() 1095 for scanner in scanners: 1096 for k in scanner.get_skeys(self): 1097 if k and self['PLATFORM'] == 'win32': 1098 k = k.lower() 1099 result[k] = scanner 1100 1101 self._memo['_gsm'] = result 1102 1103 return result
1104
1105 - def get_scanner(self, skey):
1106 """Find the appropriate scanner given a key (usually a file suffix). 1107 """ 1108 if skey and self['PLATFORM'] == 'win32': 1109 skey = skey.lower() 1110 return self._gsm().get(skey)
1111
1112 - def scanner_map_delete(self, kw=None):
1113 """Delete the cached scanner map (if we need to). 1114 """ 1115 try: 1116 del self._memo['_gsm'] 1117 except KeyError: 1118 pass
1119
1120 - def _update(self, dict):
1121 """Update an environment's values directly, bypassing the normal 1122 checks that occur when users try to set items. 1123 """ 1124 self._dict.update(dict)
1125
1126 - def get_src_sig_type(self):
1127 try: 1128 return self.src_sig_type 1129 except AttributeError: 1130 t = SCons.Defaults.DefaultEnvironment().src_sig_type 1131 self.src_sig_type = t 1132 return t
1133
1134 - def get_tgt_sig_type(self):
1135 try: 1136 return self.tgt_sig_type 1137 except AttributeError: 1138 t = SCons.Defaults.DefaultEnvironment().tgt_sig_type 1139 self.tgt_sig_type = t 1140 return t
1141 1142 ####################################################################### 1143 # Public methods for manipulating an Environment. These begin with 1144 # upper-case letters. The essential characteristic of methods in 1145 # this section is that they do *not* have corresponding same-named 1146 # global functions. For example, a stand-alone Append() function 1147 # makes no sense, because Append() is all about appending values to 1148 # an Environment's construction variables. 1149 ####################################################################### 1150
1151 - def Append(self, **kw):
1152 """Append values to existing construction variables 1153 in an Environment. 1154 """ 1155 kw = copy_non_reserved_keywords(kw) 1156 for key, val in kw.items(): 1157 # It would be easier on the eyes to write this using 1158 # "continue" statements whenever we finish processing an item, 1159 # but Python 1.5.2 apparently doesn't let you use "continue" 1160 # within try:-except: blocks, so we have to nest our code. 1161 try: 1162 if key == 'CPPDEFINES' and SCons.Util.is_String(self._dict[key]): 1163 self._dict[key] = [self._dict[key]] 1164 orig = self._dict[key] 1165 except KeyError: 1166 # No existing variable in the environment, so just set 1167 # it to the new value. 1168 if key == 'CPPDEFINES' and SCons.Util.is_String(val): 1169 self._dict[key] = [val] 1170 else: 1171 self._dict[key] = val 1172 else: 1173 try: 1174 # Check if the original looks like a dictionary. 1175 # If it is, we can't just try adding the value because 1176 # dictionaries don't have __add__() methods, and 1177 # things like UserList will incorrectly coerce the 1178 # original dict to a list (which we don't want). 1179 update_dict = orig.update 1180 except AttributeError: 1181 try: 1182 # Most straightforward: just try to add them 1183 # together. This will work in most cases, when the 1184 # original and new values are of compatible types. 1185 self._dict[key] = orig + val 1186 except (KeyError, TypeError): 1187 try: 1188 # Check if the original is a list. 1189 add_to_orig = orig.append 1190 except AttributeError: 1191 # The original isn't a list, but the new 1192 # value is (by process of elimination), 1193 # so insert the original in the new value 1194 # (if there's one to insert) and replace 1195 # the variable with it. 1196 if orig: 1197 val.insert(0, orig) 1198 self._dict[key] = val 1199 else: 1200 # The original is a list, so append the new 1201 # value to it (if there's a value to append). 1202 if val: 1203 add_to_orig(val) 1204 else: 1205 # The original looks like a dictionary, so update it 1206 # based on what we think the value looks like. 1207 if SCons.Util.is_List(val): 1208 if key == 'CPPDEFINES': 1209 tmp = [] 1210 for (k, v) in orig.iteritems(): 1211 if v is not None: 1212 tmp.append((k, v)) 1213 else: 1214 tmp.append((k,)) 1215 orig = tmp 1216 orig += val 1217 self._dict[key] = orig 1218 else: 1219 for v in val: 1220 orig[v] = None 1221 else: 1222 try: 1223 update_dict(val) 1224 except (AttributeError, TypeError, ValueError): 1225 if SCons.Util.is_Dict(val): 1226 for k, v in val.items(): 1227 orig[k] = v 1228 else: 1229 orig[val] = None 1230 self.scanner_map_delete(kw)
1231 1232 # allow Dirs and strings beginning with # for top-relative 1233 # Note this uses the current env's fs (in self).
1234 - def _canonicalize(self, path):
1235 if not SCons.Util.is_String(path): # typically a Dir 1236 path = str(path) 1237 if path and path[0] == '#': 1238 path = str(self.fs.Dir(path)) 1239 return path
1240
1241 - def AppendENVPath(self, name, newpath, envname = 'ENV', 1242 sep = os.pathsep, delete_existing=1):
1243 """Append path elements to the path 'name' in the 'ENV' 1244 dictionary for this environment. Will only add any particular 1245 path once, and will normpath and normcase all paths to help 1246 assure this. This can also handle the case where the env 1247 variable is a list instead of a string. 1248 1249 If delete_existing is 0, a newpath which is already in the path 1250 will not be moved to the end (it will be left where it is). 1251 """ 1252 1253 orig = '' 1254 if envname in self._dict and name in self._dict[envname]: 1255 orig = self._dict[envname][name] 1256 1257 nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing, 1258 canonicalize=self._canonicalize) 1259 1260 if envname not in self._dict: 1261 self._dict[envname] = {} 1262 1263 self._dict[envname][name] = nv
1264
1265 - def AppendUnique(self, delete_existing=0, **kw):
1266 """Append values to existing construction variables 1267 in an Environment, if they're not already there. 1268 If delete_existing is 1, removes existing values first, so 1269 values move to end. 1270 """ 1271 kw = copy_non_reserved_keywords(kw) 1272 for key, val in kw.items(): 1273 if SCons.Util.is_List(val): 1274 val = _delete_duplicates(val, delete_existing) 1275 if key not in self._dict or self._dict[key] in ('', None): 1276 self._dict[key] = val 1277 elif SCons.Util.is_Dict(self._dict[key]) and \ 1278 SCons.Util.is_Dict(val): 1279 self._dict[key].update(val) 1280 elif SCons.Util.is_List(val): 1281 dk = self._dict[key] 1282 if key == 'CPPDEFINES': 1283 tmp = [] 1284 for i in val: 1285 if SCons.Util.is_List(i): 1286 if len(i) >= 2: 1287 tmp.append((i[0], i[1])) 1288 else: 1289 tmp.append((i[0],)) 1290 elif SCons.Util.is_Tuple(i): 1291 tmp.append(i) 1292 else: 1293 tmp.append((i,)) 1294 val = tmp 1295 # Construct a list of (key, value) tuples. 1296 if SCons.Util.is_Dict(dk): 1297 tmp = [] 1298 for (k, v) in dk.iteritems(): 1299 if v is not None: 1300 tmp.append((k, v)) 1301 else: 1302 tmp.append((k,)) 1303 dk = tmp 1304 elif SCons.Util.is_String(dk): 1305 dk = [(dk,)] 1306 else: 1307 tmp = [] 1308 for i in dk: 1309 if SCons.Util.is_List(i): 1310 if len(i) >= 2: 1311 tmp.append((i[0], i[1])) 1312 else: 1313 tmp.append((i[0],)) 1314 elif SCons.Util.is_Tuple(i): 1315 tmp.append(i) 1316 else: 1317 tmp.append((i,)) 1318 dk = tmp 1319 else: 1320 if not SCons.Util.is_List(dk): 1321 dk = [dk] 1322 if delete_existing: 1323 dk = [x for x in dk if x not in val] 1324 else: 1325 val = [x for x in val if x not in dk] 1326 self._dict[key] = dk + val 1327 else: 1328 dk = self._dict[key] 1329 if SCons.Util.is_List(dk): 1330 if key == 'CPPDEFINES': 1331 tmp = [] 1332 for i in dk: 1333 if SCons.Util.is_List(i): 1334 if len(i) >= 2: 1335 tmp.append((i[0], i[1])) 1336 else: 1337 tmp.append((i[0],)) 1338 elif SCons.Util.is_Tuple(i): 1339 tmp.append(i) 1340 else: 1341 tmp.append((i,)) 1342 dk = tmp 1343 # Construct a list of (key, value) tuples. 1344 if SCons.Util.is_Dict(val): 1345 tmp = [] 1346 for (k, v) in val.iteritems(): 1347 if v is not None: 1348 tmp.append((k, v)) 1349 else: 1350 tmp.append((k,)) 1351 val = tmp 1352 elif SCons.Util.is_String(val): 1353 val = [(val,)] 1354 if delete_existing: 1355 dk = filter(lambda x, val=val: x not in val, dk) 1356 self._dict[key] = dk + val 1357 else: 1358 dk = [x for x in dk if x not in val] 1359 self._dict[key] = dk + val 1360 else: 1361 # By elimination, val is not a list. Since dk is a 1362 # list, wrap val in a list first. 1363 if delete_existing: 1364 dk = filter(lambda x, val=val: x not in val, dk) 1365 self._dict[key] = dk + [val] 1366 else: 1367 if not val in dk: 1368 self._dict[key] = dk + [val] 1369 else: 1370 if key == 'CPPDEFINES': 1371 if SCons.Util.is_String(dk): 1372 dk = [dk] 1373 elif SCons.Util.is_Dict(dk): 1374 tmp = [] 1375 for (k, v) in dk.iteritems(): 1376 if v is not None: 1377 tmp.append((k, v)) 1378 else: 1379 tmp.append((k,)) 1380 dk = tmp 1381 if SCons.Util.is_String(val): 1382 if val in dk: 1383 val = [] 1384 else: 1385 val = [val] 1386 elif SCons.Util.is_Dict(val): 1387 tmp = [] 1388 for i,j in val.iteritems(): 1389 if j is not None: 1390 tmp.append((i,j)) 1391 else: 1392 tmp.append(i) 1393 val = tmp 1394 if delete_existing: 1395 dk = [x for x in dk if x not in val] 1396 self._dict[key] = dk + val 1397 self.scanner_map_delete(kw)
1398
1399 - def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
1400 """Return a copy of a construction Environment. The 1401 copy is like a Python "deep copy"--that is, independent 1402 copies are made recursively of each objects--except that 1403 a reference is copied when an object is not deep-copyable 1404 (like a function). There are no references to any mutable 1405 objects in the original Environment. 1406 """ 1407 1408 builders = self._dict.get('BUILDERS', {}) 1409 1410 clone = copy.copy(self) 1411 # BUILDERS is not safe to do a simple copy 1412 clone._dict = semi_deepcopy_dict(self._dict, ['BUILDERS']) 1413 clone._dict['BUILDERS'] = BuilderDict(builders, clone) 1414 1415 # Check the methods added via AddMethod() and re-bind them to 1416 # the cloned environment. Only do this if the attribute hasn't 1417 # been overwritten by the user explicitly and still points to 1418 # the added method. 1419 clone.added_methods = [] 1420 for mw in self.added_methods: 1421 if mw == getattr(self, mw.name): 1422 clone.added_methods.append(mw.clone(clone)) 1423 1424 clone._memo = {} 1425 1426 # Apply passed-in variables before the tools 1427 # so the tools can use the new variables 1428 kw = copy_non_reserved_keywords(kw) 1429 new = {} 1430 for key, value in kw.items(): 1431 new[key] = SCons.Subst.scons_subst_once(value, self, key) 1432 clone.Replace(**new) 1433 1434 apply_tools(clone, tools, toolpath) 1435 1436 # apply them again in case the tools overwrote them 1437 clone.Replace(**new) 1438 1439 # Finally, apply any flags to be merged in 1440 if parse_flags: clone.MergeFlags(parse_flags) 1441 1442 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.EnvironmentClone') 1443 return clone
1444
1445 - def Copy(self, *args, **kw):
1446 global _warn_copy_deprecated 1447 if _warn_copy_deprecated: 1448 msg = "The env.Copy() method is deprecated; use the env.Clone() method instead." 1449 SCons.Warnings.warn(SCons.Warnings.DeprecatedCopyWarning, msg) 1450 _warn_copy_deprecated = False 1451 return self.Clone(*args, **kw)
1452
1453 - def _changed_build(self, dependency, target, prev_ni):
1454 if dependency.changed_state(target, prev_ni): 1455 return 1 1456 return self.decide_source(dependency, target, prev_ni)
1457
1458 - def _changed_content(self, dependency, target, prev_ni):
1459 return dependency.changed_content(target, prev_ni)
1460
1461 - def _changed_source(self, dependency, target, prev_ni):
1462 target_env = dependency.get_build_env() 1463 type = target_env.get_tgt_sig_type() 1464 if type == 'source': 1465 return target_env.decide_source(dependency, target, prev_ni) 1466 else: 1467 return target_env.decide_target(dependency, target, prev_ni)
1468
1469 - def _changed_timestamp_then_content(self, dependency, target, prev_ni):
1470 return dependency.changed_timestamp_then_content(target, prev_ni)
1471
1472 - def _changed_timestamp_newer(self, dependency, target, prev_ni):
1473 return dependency.changed_timestamp_newer(target, prev_ni)
1474
1475 - def _changed_timestamp_match(self, dependency, target, prev_ni):
1476 return dependency.changed_timestamp_match(target, prev_ni)
1477
1478 - def _copy_from_cache(self, src, dst):
1479 return self.fs.copy(src, dst)
1480
1481 - def _copy2_from_cache(self, src, dst):
1482 return self.fs.copy2(src, dst)
1483
1484 - def Decider(self, function):
1485 copy_function = self._copy2_from_cache 1486 if function in ('MD5', 'content'): 1487 if not SCons.Util.md5: 1488 raise UserError("MD5 signatures are not available in this version of Python.") 1489 function = self._changed_content 1490 elif function == 'MD5-timestamp': 1491 function = self._changed_timestamp_then_content 1492 elif function in ('timestamp-newer', 'make'): 1493 function = self._changed_timestamp_newer 1494 copy_function = self._copy_from_cache 1495 elif function == 'timestamp-match': 1496 function = self._changed_timestamp_match 1497 elif not callable(function): 1498 raise UserError("Unknown Decider value %s" % repr(function)) 1499 1500 # We don't use AddMethod because we don't want to turn the 1501 # function, which only expects three arguments, into a bound 1502 # method, which would add self as an initial, fourth argument. 1503 self.decide_target = function 1504 self.decide_source = function 1505 1506 self.copy_from_cache = copy_function
1507
1508 - def Detect(self, progs):
1509 """Return the first available program in progs. 1510 """ 1511 if not SCons.Util.is_List(progs): 1512 progs = [ progs ] 1513 for prog in progs: 1514 path = self.WhereIs(prog) 1515 if path: return prog 1516 return None
1517
1518 - def Dictionary(self, *args):
1519 if not args: 1520 return self._dict 1521 dlist = [self._dict[x] for x in args] 1522 if len(dlist) == 1: 1523 dlist = dlist[0] 1524 return dlist
1525
1526 - def Dump(self, key = None):
1527 """ 1528 Using the standard Python pretty printer, dump the contents of the 1529 scons build environment to stdout. 1530 1531 If the key passed in is anything other than None, then that will 1532 be used as an index into the build environment dictionary and 1533 whatever is found there will be fed into the pretty printer. Note 1534 that this key is case sensitive. 1535 """ 1536 import pprint 1537 pp = pprint.PrettyPrinter(indent=2) 1538 if key: 1539 dict = self.Dictionary(key) 1540 else: 1541 dict = self.Dictionary() 1542 return pp.pformat(dict)
1543
1544 - def FindIxes(self, paths, prefix, suffix):
1545 """ 1546 Search a list of paths for something that matches the prefix and suffix. 1547 1548 paths - the list of paths or nodes. 1549 prefix - construction variable for the prefix. 1550 suffix - construction variable for the suffix. 1551 """ 1552 1553 suffix = self.subst('$'+suffix) 1554 prefix = self.subst('$'+prefix) 1555 1556 for path in paths: 1557 dir,name = os.path.split(str(path)) 1558 if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: 1559 return path
1560
1561 - def ParseConfig(self, command, function=None, unique=1):
1562 """ 1563 Use the specified function to parse the output of the command 1564 in order to modify the current environment. The 'command' can 1565 be a string or a list of strings representing a command and 1566 its arguments. 'Function' is an optional argument that takes 1567 the environment, the output of the command, and the unique flag. 1568 If no function is specified, MergeFlags, which treats the output 1569 as the result of a typical 'X-config' command (i.e. gtk-config), 1570 will merge the output into the appropriate variables. 1571 """ 1572 if function is None: 1573 def parse_conf(env, cmd, unique=unique): 1574 return env.MergeFlags(cmd, unique)
1575 function = parse_conf 1576 if SCons.Util.is_List(command): 1577 command = ' '.join(command) 1578 command = self.subst(command) 1579 return function(self, self.backtick(command))
1580
1581 - def ParseDepends(self, filename, must_exist=None, only_one=0):
1582 """ 1583 Parse a mkdep-style file for explicit dependencies. This is 1584 completely abusable, and should be unnecessary in the "normal" 1585 case of proper SCons configuration, but it may help make 1586 the transition from a Make hierarchy easier for some people 1587 to swallow. It can also be genuinely useful when using a tool 1588 that can write a .d file, but for which writing a scanner would 1589 be too complicated. 1590 """ 1591 filename = self.subst(filename) 1592 try: 1593 fp = open(filename, 'r') 1594 except IOError: 1595 if must_exist: 1596 raise 1597 return 1598 lines = SCons.Util.LogicalLines(fp).readlines() 1599 lines = [l for l in lines if l[0] != '#'] 1600 tdlist = [] 1601 for line in lines: 1602 try: 1603 target, depends = line.split(':', 1) 1604 except (AttributeError, ValueError): 1605 # Throws AttributeError if line isn't a string. Can throw 1606 # ValueError if line doesn't split into two or more elements. 1607 pass 1608 else: 1609 tdlist.append((target.split(), depends.split())) 1610 if only_one: 1611 targets = [] 1612 for td in tdlist: 1613 targets.extend(td[0]) 1614 if len(targets) > 1: 1615 raise SCons.Errors.UserError( 1616 "More than one dependency target found in `%s': %s" 1617 % (filename, targets)) 1618 for target, depends in tdlist: 1619 self.Depends(target, depends)
1620
1621 - def Platform(self, platform):
1622 platform = self.subst(platform) 1623 return SCons.Platform.Platform(platform)(self)
1624
1625 - def Prepend(self, **kw):
1626 """Prepend values to existing construction variables 1627 in an Environment. 1628 """ 1629 kw = copy_non_reserved_keywords(kw) 1630 for key, val in kw.items(): 1631 # It would be easier on the eyes to write this using 1632 # "continue" statements whenever we finish processing an item, 1633 # but Python 1.5.2 apparently doesn't let you use "continue" 1634 # within try:-except: blocks, so we have to nest our code. 1635 try: 1636 orig = self._dict[key] 1637 except KeyError: 1638 # No existing variable in the environment, so just set 1639 # it to the new value. 1640 self._dict[key] = val 1641 else: 1642 try: 1643 # Check if the original looks like a dictionary. 1644 # If it is, we can't just try adding the value because 1645 # dictionaries don't have __add__() methods, and 1646 # things like UserList will incorrectly coerce the 1647 # original dict to a list (which we don't want). 1648 update_dict = orig.update 1649 except AttributeError: 1650 try: 1651 # Most straightforward: just try to add them 1652 # together. This will work in most cases, when the 1653 # original and new values are of compatible types. 1654 self._dict[key] = val + orig 1655 except (KeyError, TypeError): 1656 try: 1657 # Check if the added value is a list. 1658 add_to_val = val.append 1659 except AttributeError: 1660 # The added value isn't a list, but the 1661 # original is (by process of elimination), 1662 # so insert the the new value in the original 1663 # (if there's one to insert). 1664 if val: 1665 orig.insert(0, val) 1666 else: 1667 # The added value is a list, so append 1668 # the original to it (if there's a value 1669 # to append). 1670 if orig: 1671 add_to_val(orig) 1672 self._dict[key] = val 1673 else: 1674 # The original looks like a dictionary, so update it 1675 # based on what we think the value looks like. 1676 if SCons.Util.is_List(val): 1677 for v in val: 1678 orig[v] = None 1679 else: 1680 try: 1681 update_dict(val) 1682 except (AttributeError, TypeError, ValueError): 1683 if SCons.Util.is_Dict(val): 1684 for k, v in val.items(): 1685 orig[k] = v 1686 else: 1687 orig[val] = None 1688 self.scanner_map_delete(kw)
1689
1690 - def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, 1691 delete_existing=1):
1692 """Prepend path elements to the path 'name' in the 'ENV' 1693 dictionary for this environment. Will only add any particular 1694 path once, and will normpath and normcase all paths to help 1695 assure this. This can also handle the case where the env 1696 variable is a list instead of a string. 1697 1698 If delete_existing is 0, a newpath which is already in the path 1699 will not be moved to the front (it will be left where it is). 1700 """ 1701 1702 orig = '' 1703 if envname in self._dict and name in self._dict[envname]: 1704 orig = self._dict[envname][name] 1705 1706 nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing, 1707 canonicalize=self._canonicalize) 1708 1709 if envname not in self._dict: 1710 self._dict[envname] = {} 1711 1712 self._dict[envname][name] = nv
1713
1714 - def PrependUnique(self, delete_existing=0, **kw):
1715 """Prepend values to existing construction variables 1716 in an Environment, if they're not already there. 1717 If delete_existing is 1, removes existing values first, so 1718 values move to front. 1719 """ 1720 kw = copy_non_reserved_keywords(kw) 1721 for key, val in kw.items(): 1722 if SCons.Util.is_List(val): 1723 val = _delete_duplicates(val, not delete_existing) 1724 if key not in self._dict or self._dict[key] in ('', None): 1725 self._dict[key] = val 1726 elif SCons.Util.is_Dict(self._dict[key]) and \ 1727 SCons.Util.is_Dict(val): 1728 self._dict[key].update(val) 1729 elif SCons.Util.is_List(val): 1730 dk = self._dict[key] 1731 if not SCons.Util.is_List(dk): 1732 dk = [dk] 1733 if delete_existing: 1734 dk = [x for x in dk if x not in val] 1735 else: 1736 val = [x for x in val if x not in dk] 1737 self._dict[key] = val + dk 1738 else: 1739 dk = self._dict[key] 1740 if SCons.Util.is_List(dk): 1741 # By elimination, val is not a list. Since dk is a 1742 # list, wrap val in a list first. 1743 if delete_existing: 1744 dk = [x for x in dk if x not in val] 1745 self._dict[key] = [val] + dk 1746 else: 1747 if not val in dk: 1748 self._dict[key] = [val] + dk 1749 else: 1750 if delete_existing: 1751 dk = [x for x in dk if x not in val] 1752 self._dict[key] = val + dk 1753 self.scanner_map_delete(kw)
1754
1755 - def Replace(self, **kw):
1756 """Replace existing construction variables in an Environment 1757 with new construction variables and/or values. 1758 """ 1759 try: 1760 kwbd = kw['BUILDERS'] 1761 except KeyError: 1762 pass 1763 else: 1764 kwbd = BuilderDict(kwbd,self) 1765 del kw['BUILDERS'] 1766 self.__setitem__('BUILDERS', kwbd) 1767 kw = copy_non_reserved_keywords(kw) 1768 self._update(semi_deepcopy(kw)) 1769 self.scanner_map_delete(kw)
1770
1771 - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
1772 """ 1773 Replace old_prefix with new_prefix and old_suffix with new_suffix. 1774 1775 env - Environment used to interpolate variables. 1776 path - the path that will be modified. 1777 old_prefix - construction variable for the old prefix. 1778 old_suffix - construction variable for the old suffix. 1779 new_prefix - construction variable for the new prefix. 1780 new_suffix - construction variable for the new suffix. 1781 """ 1782 old_prefix = self.subst('$'+old_prefix) 1783 old_suffix = self.subst('$'+old_suffix) 1784 1785 new_prefix = self.subst('$'+new_prefix) 1786 new_suffix = self.subst('$'+new_suffix) 1787 1788 dir,name = os.path.split(str(path)) 1789 if name[:len(old_prefix)] == old_prefix: 1790 name = name[len(old_prefix):] 1791 if name[-len(old_suffix):] == old_suffix: 1792 name = name[:-len(old_suffix)] 1793 return os.path.join(dir, new_prefix+name+new_suffix)
1794
1795 - def SetDefault(self, **kw):
1796 for k in kw.keys(): 1797 if k in self._dict: 1798 del kw[k] 1799 self.Replace(**kw)
1800
1801 - def _find_toolpath_dir(self, tp):
1802 return self.fs.Dir(self.subst(tp)).srcnode().abspath
1803
1804 - def Tool(self, tool, toolpath=None, **kw):
1805 if SCons.Util.is_String(tool): 1806 tool = self.subst(tool) 1807 if toolpath is None: 1808 toolpath = self.get('toolpath', []) 1809 toolpath = list(map(self._find_toolpath_dir, toolpath)) 1810 tool = SCons.Tool.Tool(tool, toolpath, **kw) 1811 tool(self)
1812
1813 - def WhereIs(self, prog, path=None, pathext=None, reject=[]):
1814 """Find prog in the path. 1815 """ 1816 if path is None: 1817 try: 1818 path = self['ENV']['PATH'] 1819 except KeyError: 1820 pass 1821 elif SCons.Util.is_String(path): 1822 path = self.subst(path) 1823 if pathext is None: 1824 try: 1825 pathext = self['ENV']['PATHEXT'] 1826 except KeyError: 1827 pass 1828 elif SCons.Util.is_String(pathext): 1829 pathext = self.subst(pathext) 1830 prog = SCons.Util.CLVar(self.subst(prog)) # support "program --with-args" 1831 path = SCons.Util.WhereIs(prog[0], path, pathext, reject) 1832 if path: return path 1833 return None
1834 1835 ####################################################################### 1836 # Public methods for doing real "SCons stuff" (manipulating 1837 # dependencies, setting attributes on targets, etc.). These begin 1838 # with upper-case letters. The essential characteristic of methods 1839 # in this section is that they all *should* have corresponding 1840 # same-named global functions. 1841 ####################################################################### 1842
1843 - def Action(self, *args, **kw):
1844 def subst_string(a, self=self): 1845 if SCons.Util.is_String(a): 1846 a = self.subst(a) 1847 return a
1848 nargs = list(map(subst_string, args)) 1849 nkw = self.subst_kw(kw) 1850 return SCons.Action.Action(*nargs, **nkw) 1851
1852 - def AddPreAction(self, files, action):
1853 nodes = self.arg2nodes(files, self.fs.Entry) 1854 action = SCons.Action.Action(action) 1855 uniq = {} 1856 for executor in [n.get_executor() for n in nodes]: 1857 uniq[executor] = 1 1858 for executor in uniq.keys(): 1859 executor.add_pre_action(action) 1860 return nodes
1861
1862 - def AddPostAction(self, files, action):
1863 nodes = self.arg2nodes(files, self.fs.Entry) 1864 action = SCons.Action.Action(action) 1865 uniq = {} 1866 for executor in [n.get_executor() for n in nodes]: 1867 uniq[executor] = 1 1868 for executor in uniq.keys(): 1869 executor.add_post_action(action) 1870 return nodes
1871
1872 - def Alias(self, target, source=[], action=None, **kw):
1873 tlist = self.arg2nodes(target, self.ans.Alias) 1874 if not SCons.Util.is_List(source): 1875 source = [source] 1876 source = [_f for _f in source if _f] 1877 1878 if not action: 1879 if not source: 1880 # There are no source files and no action, so just 1881 # return a target list of classic Alias Nodes, without 1882 # any builder. The externally visible effect is that 1883 # this will make the wrapping Script.BuildTask class 1884 # say that there's "Nothing to be done" for this Alias, 1885 # instead of that it's "up to date." 1886 return tlist 1887 1888 # No action, but there are sources. Re-call all the target 1889 # builders to add the sources to each target. 1890 result = [] 1891 for t in tlist: 1892 bld = t.get_builder(AliasBuilder) 1893 result.extend(bld(self, t, source)) 1894 return result 1895 1896 nkw = self.subst_kw(kw) 1897 nkw.update({ 1898 'action' : SCons.Action.Action(action), 1899 'source_factory' : self.fs.Entry, 1900 'multi' : 1, 1901 'is_explicit' : None, 1902 }) 1903 bld = SCons.Builder.Builder(**nkw) 1904 1905 # Apply the Builder separately to each target so that the Aliases 1906 # stay separate. If we did one "normal" Builder call with the 1907 # whole target list, then all of the target Aliases would be 1908 # associated under a single Executor. 1909 result = [] 1910 for t in tlist: 1911 # Calling the convert() method will cause a new Executor to be 1912 # created from scratch, so we have to explicitly initialize 1913 # it with the target's existing sources, plus our new ones, 1914 # so nothing gets lost. 1915 b = t.get_builder() 1916 if b is None or b is AliasBuilder: 1917 b = bld 1918 else: 1919 nkw['action'] = b.action + action 1920 b = SCons.Builder.Builder(**nkw) 1921 t.convert() 1922 result.extend(b(self, t, t.sources + source)) 1923 return result
1924
1925 - def AlwaysBuild(self, *targets):
1926 tlist = [] 1927 for t in targets: 1928 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 1929 for t in tlist: 1930 t.set_always_build() 1931 return tlist
1932
1933 - def BuildDir(self, *args, **kw):
1934 msg = """BuildDir() and the build_dir keyword have been deprecated;\n\tuse VariantDir() and the variant_dir keyword instead.""" 1935 SCons.Warnings.warn(SCons.Warnings.DeprecatedBuildDirWarning, msg) 1936 if 'build_dir' in kw: 1937 kw['variant_dir'] = kw['build_dir'] 1938 del kw['build_dir'] 1939 return self.VariantDir(*args, **kw)
1940
1941 - def Builder(self, **kw):
1942 nkw = self.subst_kw(kw) 1943 return SCons.Builder.Builder(**nkw)
1944
1945 - def CacheDir(self, path):
1946 import SCons.CacheDir 1947 if path is not None: 1948 path = self.subst(path) 1949 self._CacheDir_path = path
1950
1951 - def Clean(self, targets, files):
1952 global CleanTargets 1953 tlist = self.arg2nodes(targets, self.fs.Entry) 1954 flist = self.arg2nodes(files, self.fs.Entry) 1955 for t in tlist: 1956 try: 1957 CleanTargets[t].extend(flist) 1958 except KeyError: 1959 CleanTargets[t] = flist
1960
1961 - def Configure(self, *args, **kw):
1962 nargs = [self] 1963 if args: 1964 nargs = nargs + self.subst_list(args)[0] 1965 nkw = self.subst_kw(kw) 1966 nkw['_depth'] = kw.get('_depth', 0) + 1 1967 try: 1968 nkw['custom_tests'] = self.subst_kw(nkw['custom_tests']) 1969 except KeyError: 1970 pass 1971 return SCons.SConf.SConf(*nargs, **nkw)
1972
1973 - def Command(self, target, source, action, **kw):
1974 """Builds the supplied target files from the supplied 1975 source files using the supplied action. Action may 1976 be any type that the Builder constructor will accept 1977 for an action.""" 1978 bkw = { 1979 'action' : action, 1980 'target_factory' : self.fs.Entry, 1981 'source_factory' : self.fs.Entry, 1982 } 1983 try: bkw['source_scanner'] = kw['source_scanner'] 1984 except KeyError: pass 1985 else: del kw['source_scanner'] 1986 bld = SCons.Builder.Builder(**bkw) 1987 return bld(self, target, source, **kw)
1988
1989 - def Depends(self, target, dependency):
1990 """Explicity specify that 'target's depend on 'dependency'.""" 1991 tlist = self.arg2nodes(target, self.fs.Entry) 1992 dlist = self.arg2nodes(dependency, self.fs.Entry) 1993 for t in tlist: 1994 t.add_dependency(dlist) 1995 return tlist
1996
1997 - def Dir(self, name, *args, **kw):
1998 """ 1999 """ 2000 s = self.subst(name) 2001 if SCons.Util.is_Sequence(s): 2002 result=[] 2003 for e in s: 2004 result.append(self.fs.Dir(e, *args, **kw)) 2005 return result 2006 return self.fs.Dir(s, *args, **kw)
2007
2008 - def NoClean(self, *targets):
2009 """Tags a target so that it will not be cleaned by -c""" 2010 tlist = [] 2011 for t in targets: 2012 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 2013 for t in tlist: 2014 t.set_noclean() 2015 return tlist
2016
2017 - def NoCache(self, *targets):
2018 """Tags a target so that it will not be cached""" 2019 tlist = [] 2020 for t in targets: 2021 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 2022 for t in tlist: 2023 t.set_nocache() 2024 return tlist
2025
2026 - def Entry(self, name, *args, **kw):
2027 """ 2028 """ 2029 s = self.subst(name) 2030 if SCons.Util.is_Sequence(s): 2031 result=[] 2032 for e in s: 2033 result.append(self.fs.Entry(e, *args, **kw)) 2034 return result 2035 return self.fs.Entry(s, *args, **kw)
2036
2037 - def Environment(self, **kw):
2038 return SCons.Environment.Environment(**self.subst_kw(kw))
2039
2040 - def Execute(self, action, *args, **kw):
2041 """Directly execute an action through an Environment 2042 """ 2043 action = self.Action(action, *args, **kw) 2044 result = action([], [], self) 2045 if isinstance(result, SCons.Errors.BuildError): 2046 errstr = result.errstr 2047 if result.filename: 2048 errstr = result.filename + ': ' + errstr 2049 sys.stderr.write("scons: *** %s\n" % errstr) 2050 return result.status 2051 else: 2052 return result
2053
2054 - def File(self, name, *args, **kw):
2055 """ 2056 """ 2057 s = self.subst(name) 2058 if SCons.Util.is_Sequence(s): 2059 result=[] 2060 for e in s: 2061 result.append(self.fs.File(e, *args, **kw)) 2062 return result 2063 return self.fs.File(s, *args, **kw)
2064
2065 - def FindFile(self, file, dirs):
2066 file = self.subst(file) 2067 nodes = self.arg2nodes(dirs, self.fs.Dir) 2068 return SCons.Node.FS.find_file(file, tuple(nodes))
2069
2070 - def Flatten(self, sequence):
2071 return SCons.Util.flatten(sequence)
2072
2073 - def GetBuildPath(self, files):
2074 result = list(map(str, self.arg2nodes(files, self.fs.Entry))) 2075 if SCons.Util.is_List(files): 2076 return result 2077 else: 2078 return result[0]
2079
2080 - def Glob(self, pattern, ondisk=True, source=False, strings=False):
2081 return self.fs.Glob(self.subst(pattern), ondisk, source, strings)
2082
2083 - def Ignore(self, target, dependency):
2084 """Ignore a dependency.""" 2085 tlist = self.arg2nodes(target, self.fs.Entry) 2086 dlist = self.arg2nodes(dependency, self.fs.Entry) 2087 for t in tlist: 2088 t.add_ignore(dlist) 2089 return tlist
2090
2091 - def Literal(self, string):
2092 return SCons.Subst.Literal(string)
2093
2094 - def Local(self, *targets):
2095 ret = [] 2096 for targ in targets: 2097 if isinstance(targ, SCons.Node.Node): 2098 targ.set_local() 2099 ret.append(targ) 2100 else: 2101 for t in self.arg2nodes(targ, self.fs.Entry): 2102 t.set_local() 2103 ret.append(t) 2104 return ret
2105
2106 - def Precious(self, *targets):
2107 tlist = [] 2108 for t in targets: 2109 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 2110 for t in tlist: 2111 t.set_precious() 2112 return tlist
2113
2114 - def Pseudo(self, *targets):
2115 tlist = [] 2116 for t in targets: 2117 tlist.extend(self.arg2nodes(t, self.fs.Entry)) 2118 for t in tlist: 2119 t.set_pseudo() 2120 return tlist
2121
2122 - def Repository(self, *dirs, **kw):
2123 dirs = self.arg2nodes(list(dirs), self.fs.Dir) 2124 self.fs.Repository(*dirs, **kw)
2125
2126 - def Requires(self, target, prerequisite):
2127 """Specify that 'prerequisite' must be built before 'target', 2128 (but 'target' does not actually depend on 'prerequisite' 2129 and need not be rebuilt if it changes).""" 2130 tlist = self.arg2nodes(target, self.fs.Entry) 2131 plist = self.arg2nodes(prerequisite, self.fs.Entry) 2132 for t in tlist: 2133 t.add_prerequisite(plist) 2134 return tlist
2135
2136 - def Scanner(self, *args, **kw):
2137 nargs = [] 2138 for arg in args: 2139 if SCons.Util.is_String(arg): 2140 arg = self.subst(arg) 2141 nargs.append(arg) 2142 nkw = self.subst_kw(kw) 2143 return SCons.Scanner.Base(*nargs, **nkw)
2144
2145 - def SConsignFile(self, name=".sconsign", dbm_module=None):
2146 if name is not None: 2147 name = self.subst(name) 2148 if not os.path.isabs(name): 2149 name = os.path.join(str(self.fs.SConstruct_dir), name) 2150 if name: 2151 name = os.path.normpath(name) 2152 sconsign_dir = os.path.dirname(name) 2153 if sconsign_dir and not os.path.exists(sconsign_dir): 2154 self.Execute(SCons.Defaults.Mkdir(sconsign_dir)) 2155 SCons.SConsign.File(name, dbm_module)
2156
2157 - def SideEffect(self, side_effect, target):
2158 """Tell scons that side_effects are built as side 2159 effects of building targets.""" 2160 side_effects = self.arg2nodes(side_effect, self.fs.Entry) 2161 targets = self.arg2nodes(target, self.fs.Entry) 2162 2163 for side_effect in side_effects: 2164 if side_effect.multiple_side_effect_has_builder(): 2165 raise SCons.Errors.UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect)) 2166 side_effect.add_source(targets) 2167 side_effect.side_effect = 1 2168 self.Precious(side_effect) 2169 for target in targets: 2170 target.side_effects.append(side_effect) 2171 return side_effects
2172
2173 - def SourceCode(self, entry, builder):
2174 """Arrange for a source code builder for (part of) a tree.""" 2175 msg = """SourceCode() has been deprecated and there is no replacement. 2176 \tIf you need this function, please contact scons-dev@scons.org""" 2177 SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceCodeWarning, msg) 2178 entries = self.arg2nodes(entry, self.fs.Entry) 2179 for entry in entries: 2180 entry.set_src_builder(builder) 2181 return entries
2182
2183 - def SourceSignatures(self, type):
2184 global _warn_source_signatures_deprecated 2185 if _warn_source_signatures_deprecated: 2186 msg = "The env.SourceSignatures() method is deprecated;\n" + \ 2187 "\tconvert your build to use the env.Decider() method instead." 2188 SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceSignaturesWarning, msg) 2189 _warn_source_signatures_deprecated = False 2190 type = self.subst(type) 2191 self.src_sig_type = type 2192 if type == 'MD5': 2193 if not SCons.Util.md5: 2194 raise UserError("MD5 signatures are not available in this version of Python.") 2195 self.decide_source = self._changed_content 2196 elif type == 'timestamp': 2197 self.decide_source = self._changed_timestamp_match 2198 else: 2199 raise UserError("Unknown source signature type '%s'" % type)
2200
2201 - def Split(self, arg):
2202 """This function converts a string or list into a list of strings 2203 or Nodes. This makes things easier for users by allowing files to 2204 be specified as a white-space separated list to be split. 2205 The input rules are: 2206 - A single string containing names separated by spaces. These will be 2207 split apart at the spaces. 2208 - A single Node instance 2209 - A list containing either strings or Node instances. Any strings 2210 in the list are not split at spaces. 2211 In all cases, the function returns a list of Nodes and strings.""" 2212 if SCons.Util.is_List(arg): 2213 return list(map(self.subst, arg)) 2214 elif SCons.Util.is_String(arg): 2215 return self.subst(arg).split() 2216 else: 2217 return [self.subst(arg)]
2218
2219 - def TargetSignatures(self, type):
2220 global _warn_target_signatures_deprecated 2221 if _warn_target_signatures_deprecated: 2222 msg = "The env.TargetSignatures() method is deprecated;\n" + \ 2223 "\tconvert your build to use the env.Decider() method instead." 2224 SCons.Warnings.warn(SCons.Warnings.DeprecatedTargetSignaturesWarning, msg) 2225 _warn_target_signatures_deprecated = False 2226 type = self.subst(type) 2227 self.tgt_sig_type = type 2228 if type in ('MD5', 'content'): 2229 if not SCons.Util.md5: 2230 raise UserError("MD5 signatures are not available in this version of Python.") 2231 self.decide_target = self._changed_content 2232 elif type == 'timestamp': 2233 self.decide_target = self._changed_timestamp_match 2234 elif type == 'build': 2235 self.decide_target = self._changed_build 2236 elif type == 'source': 2237 self.decide_target = self._changed_source 2238 else: 2239 raise UserError("Unknown target signature type '%s'"%type)
2240
2241 - def Value(self, value, built_value=None):
2242 """ 2243 """ 2244 return SCons.Node.Python.Value(value, built_value)
2245
2246 - def VariantDir(self, variant_dir, src_dir, duplicate=1):
2247 variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0] 2248 src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0] 2249 self.fs.VariantDir(variant_dir, src_dir, duplicate)
2250
2251 - def FindSourceFiles(self, node='.'):
2252 """ returns a list of all source files. 2253 """ 2254 node = self.arg2nodes(node, self.fs.Entry)[0] 2255 2256 sources = [] 2257 def build_source(ss): 2258 for s in ss: 2259 if isinstance(s, SCons.Node.FS.Dir): 2260 build_source(s.all_children()) 2261 elif s.has_builder(): 2262 build_source(s.sources) 2263 elif isinstance(s.disambiguate(), SCons.Node.FS.File): 2264 sources.append(s)
2265 build_source(node.all_children()) 2266 2267 def final_source(node): 2268 while (node != node.srcnode()): 2269 node = node.srcnode() 2270 return node 2271 sources = map( final_source, sources ); 2272 # remove duplicates 2273 return list(set(sources)) 2274
2275 - def FindInstalledFiles(self):
2276 """ returns the list of all targets of the Install and InstallAs Builder. 2277 """ 2278 from SCons.Tool import install 2279 if install._UNIQUE_INSTALLED_FILES is None: 2280 install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES) 2281 return install._UNIQUE_INSTALLED_FILES
2282 2283
2284 -class OverrideEnvironment(Base):
2285 """A proxy that overrides variables in a wrapped construction 2286 environment by returning values from an overrides dictionary in 2287 preference to values from the underlying subject environment. 2288 2289 This is a lightweight (I hope) proxy that passes through most use of 2290 attributes to the underlying Environment.Base class, but has just 2291 enough additional methods defined to act like a real construction 2292 environment with overridden values. It can wrap either a Base 2293 construction environment, or another OverrideEnvironment, which 2294 can in turn nest arbitrary OverrideEnvironments... 2295 2296 Note that we do *not* call the underlying base class 2297 (SubsitutionEnvironment) initialization, because we get most of those 2298 from proxying the attributes of the subject construction environment. 2299 But because we subclass SubstitutionEnvironment, this class also 2300 has inherited arg2nodes() and subst*() methods; those methods can't 2301 be proxied because they need *this* object's methods to fetch the 2302 values from the overrides dictionary. 2303 """ 2304
2305 - def __init__(self, subject, overrides={}):
2306 if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.OverrideEnvironment') 2307 self.__dict__['__subject'] = subject 2308 self.__dict__['overrides'] = overrides
2309 2310 # Methods that make this class act like a proxy.
2311 - def __getattr__(self, name):
2312 return getattr(self.__dict__['__subject'], name)
2313 - def __setattr__(self, name, value):
2314 setattr(self.__dict__['__subject'], name, value)
2315 2316 # Methods that make this class act like a dictionary.
2317 - def __getitem__(self, key):
2318 try: 2319 return self.__dict__['overrides'][key] 2320 except KeyError: 2321 return self.__dict__['__subject'].__getitem__(key)
2322 - def __setitem__(self, key, value):
2323 if not is_valid_construction_var(key): 2324 raise SCons.Errors.UserError("Illegal construction variable `%s'" % key) 2325 self.__dict__['overrides'][key] = value
2326 - def __delitem__(self, key):
2327 try: 2328 del self.__dict__['overrides'][key] 2329 except KeyError: 2330 deleted = 0 2331 else: 2332 deleted = 1 2333 try: 2334 result = self.__dict__['__subject'].__delitem__(key) 2335 except KeyError: 2336 if not deleted: 2337 raise 2338 result = None 2339 return result
2340 - def get(self, key, default=None):
2341 """Emulates the get() method of dictionaries.""" 2342 try: 2343 return self.__dict__['overrides'][key] 2344 except KeyError: 2345 return self.__dict__['__subject'].get(key, default)
2346 - def has_key(self, key):
2347 try: 2348 self.__dict__['overrides'][key] 2349 return 1 2350 except KeyError: 2351 return key in self.__dict__['__subject']
2352 - def __contains__(self, key):
2353 if self.__dict__['overrides'].__contains__(key): 2354 return 1 2355 return self.__dict__['__subject'].__contains__(key)
2356 - def Dictionary(self):
2357 """Emulates the items() method of dictionaries.""" 2358 d = self.__dict__['__subject'].Dictionary().copy() 2359 d.update(self.__dict__['overrides']) 2360 return d
2361 - def items(self):
2362 """Emulates the items() method of dictionaries.""" 2363 return list(self.Dictionary().items())
2364 2365 # Overridden private construction environment methods.
2366 - def _update(self, dict):
2367 """Update an environment's values directly, bypassing the normal 2368 checks that occur when users try to set items. 2369 """ 2370 self.__dict__['overrides'].update(dict)
2371
2372 - def gvars(self):
2373 return self.__dict__['__subject'].gvars()
2374
2375 - def lvars(self):
2376 lvars = self.__dict__['__subject'].lvars() 2377 lvars.update(self.__dict__['overrides']) 2378 return lvars
2379 2380 # Overridden public construction environment methods.
2381 - def Replace(self, **kw):
2382 kw = copy_non_reserved_keywords(kw) 2383 self.__dict__['overrides'].update(semi_deepcopy(kw))
2384 2385 # The entry point that will be used by the external world 2386 # to refer to a construction environment. This allows the wrapper 2387 # interface to extend a construction environment for its own purposes 2388 # by subclassing SCons.Environment.Base and then assigning the 2389 # class to SCons.Environment.Environment. 2390 2391 Environment = Base 2392 2393 # An entry point for returning a proxy subclass instance that overrides 2394 # the subst*() methods so they don't actually perform construction 2395 # variable substitution. This is specifically intended to be the shim 2396 # layer in between global function calls (which don't want construction 2397 # variable substitution) and the DefaultEnvironment() (which would 2398 # substitute variables if left to its own devices).""" 2399 # 2400 # We have to wrap this in a function that allows us to delay definition of 2401 # the class until it's necessary, so that when it subclasses Environment 2402 # it will pick up whatever Environment subclass the wrapper interface 2403 # might have assigned to SCons.Environment.Environment. 2404
2405 -def NoSubstitutionProxy(subject):
2406 class _NoSubstitutionProxy(Environment): 2407 def __init__(self, subject): 2408 self.__dict__['__subject'] = subject
2409 def __getattr__(self, name): 2410 return getattr(self.__dict__['__subject'], name) 2411 def __setattr__(self, name, value): 2412 return setattr(self.__dict__['__subject'], name, value) 2413 def executor_to_lvars(self, kwdict): 2414 if kwdict.has_key('executor'): 2415 kwdict['lvars'] = kwdict['executor'].get_lvars() 2416 del kwdict['executor'] 2417 else: 2418 kwdict['lvars'] = {} 2419 def raw_to_mode(self, dict): 2420 try: 2421 raw = dict['raw'] 2422 except KeyError: 2423 pass 2424 else: 2425 del dict['raw'] 2426 dict['mode'] = raw 2427 def subst(self, string, *args, **kwargs): 2428 return string 2429 def subst_kw(self, kw, *args, **kwargs): 2430 return kw 2431 def subst_list(self, string, *args, **kwargs): 2432 nargs = (string, self,) + args 2433 nkw = kwargs.copy() 2434 nkw['gvars'] = {} 2435 self.executor_to_lvars(nkw) 2436 self.raw_to_mode(nkw) 2437 return SCons.Subst.scons_subst_list(*nargs, **nkw) 2438 def subst_target_source(self, string, *args, **kwargs): 2439 nargs = (string, self,) + args 2440 nkw = kwargs.copy() 2441 nkw['gvars'] = {} 2442 self.executor_to_lvars(nkw) 2443 self.raw_to_mode(nkw) 2444 return SCons.Subst.scons_subst(*nargs, **nkw) 2445 return _NoSubstitutionProxy(subject) 2446 2447 # Local Variables: 2448 # tab-width:4 2449 # indent-tabs-mode:nil 2450 # End: 2451 # vim: set expandtab tabstop=4 shiftwidth=4: 2452