Package SCons :: Package Node
[hide private]
[frames] | no frames]

Source Code for Package SCons.Node

   1  """SCons.Node 
   2   
   3  The Node package for the SCons software construction utility. 
   4   
   5  This is, in many ways, the heart of SCons. 
   6   
   7  A Node is where we encapsulate all of the dependency information about 
   8  any thing that SCons can build, or about any thing which SCons can use 
   9  to build some other thing.  The canonical "thing," of course, is a file, 
  10  but a Node can also represent something remote (like a web page) or 
  11  something completely abstract (like an Alias). 
  12   
  13  Each specific type of "thing" is specifically represented by a subclass 
  14  of the Node base class:  Node.FS.File for files, Node.Alias for aliases, 
  15  etc.  Dependency information is kept here in the base class, and 
  16  information specific to files/aliases/etc. is in the subclass.  The 
  17  goal, if we've done this correctly, is that any type of "thing" should 
  18  be able to depend on any other type of "thing." 
  19   
  20  """ 
  21   
  22  # 
  23  # Copyright (c) 2001 - 2014 The SCons Foundation 
  24  # 
  25  # Permission is hereby granted, free of charge, to any person obtaining 
  26  # a copy of this software and associated documentation files (the 
  27  # "Software"), to deal in the Software without restriction, including 
  28  # without limitation the rights to use, copy, modify, merge, publish, 
  29  # distribute, sublicense, and/or sell copies of the Software, and to 
  30  # permit persons to whom the Software is furnished to do so, subject to 
  31  # the following conditions: 
  32  # 
  33  # The above copyright notice and this permission notice shall be included 
  34  # in all copies or substantial portions of the Software. 
  35  # 
  36  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
  37  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
  38  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  39  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
  40  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
  41  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
  42  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  43   
  44  __revision__ = "src/engine/SCons/Node/__init__.py  2014/09/27 12:51:43 garyo" 
  45   
  46  import collections 
  47  import copy 
  48  from itertools import chain 
  49   
  50  import SCons.Debug 
  51  from SCons.Debug import logInstanceCreation 
  52  import SCons.Executor 
  53  import SCons.Memoize 
  54  import SCons.Util 
  55   
  56  from SCons.Debug import Trace 
  57   
58 -def classname(obj):
59 return str(obj.__class__).split('.')[-1]
60 61 # Set to false if we're doing a dry run. There's more than one of these 62 # little treats 63 do_store_info = True 64 65 # Node states 66 # 67 # These are in "priority" order, so that the maximum value for any 68 # child/dependency of a node represents the state of that node if 69 # it has no builder of its own. The canonical example is a file 70 # system directory, which is only up to date if all of its children 71 # were up to date. 72 no_state = 0 73 pending = 1 74 executing = 2 75 up_to_date = 3 76 executed = 4 77 failed = 5 78 79 StateString = { 80 0 : "no_state", 81 1 : "pending", 82 2 : "executing", 83 3 : "up_to_date", 84 4 : "executed", 85 5 : "failed", 86 } 87 88 # controls whether implicit dependencies are cached: 89 implicit_cache = 0 90 91 # controls whether implicit dep changes are ignored: 92 implicit_deps_unchanged = 0 93 94 # controls whether the cached implicit deps are ignored: 95 implicit_deps_changed = 0 96 97 # A variable that can be set to an interface-specific function be called 98 # to annotate a Node with information about its creation.
99 -def do_nothing(node): pass
100 101 Annotate = do_nothing 102 103 # Gets set to 'True' if we're running in interactive mode. Is 104 # currently used to release parts of a target's info during 105 # clean builds and update runs (see release_target_info). 106 interactive = False 107 108 # Classes for signature info for Nodes. 109
110 -class NodeInfoBase(object):
111 """ 112 The generic base class for signature information for a Node. 113 114 Node subclasses should subclass NodeInfoBase to provide their own 115 logic for dealing with their own Node-specific signature information. 116 """ 117 current_version_id = 1
118 - def __init__(self, node=None):
119 # Create an object attribute from the class attribute so it ends up 120 # in the pickled data in the .sconsign file. 121 self._version_id = self.current_version_id
122 - def update(self, node):
123 try: 124 field_list = self.field_list 125 except AttributeError: 126 return 127 for f in field_list: 128 try: 129 delattr(self, f) 130 except AttributeError: 131 pass 132 try: 133 func = getattr(node, 'get_' + f) 134 except AttributeError: 135 pass 136 else: 137 setattr(self, f, func())
138 - def convert(self, node, val):
139 pass
140 - def merge(self, other):
141 self.__dict__.update(other.__dict__)
142 - def format(self, field_list=None, names=0):
143 if field_list is None: 144 try: 145 field_list = self.field_list 146 except AttributeError: 147 field_list = sorted(self.__dict__.keys()) 148 fields = [] 149 for field in field_list: 150 try: 151 f = getattr(self, field) 152 except AttributeError: 153 f = None 154 f = str(f) 155 if names: 156 f = field + ': ' + f 157 fields.append(f) 158 return fields
159
160 -class BuildInfoBase(object):
161 """ 162 The generic base class for build information for a Node. 163 164 This is what gets stored in a .sconsign file for each target file. 165 It contains a NodeInfo instance for this node (signature information 166 that's specific to the type of Node) and direct attributes for the 167 generic build stuff we have to track: sources, explicit dependencies, 168 implicit dependencies, and action information. 169 """ 170 current_version_id = 1
171 - def __init__(self, node=None):
172 # Create an object attribute from the class attribute so it ends up 173 # in the pickled data in the .sconsign file. 174 self._version_id = self.current_version_id 175 self.bsourcesigs = [] 176 self.bdependsigs = [] 177 self.bimplicitsigs = [] 178 self.bactsig = None
179 - def merge(self, other):
180 self.__dict__.update(other.__dict__)
181
182 -class Node(object):
183 """The base Node class, for entities that we know how to 184 build, or use to build other Nodes. 185 """ 186 187 if SCons.Memoize.use_memoizer: 188 __metaclass__ = SCons.Memoize.Memoized_Metaclass 189 190 memoizer_counters = [] 191
192 - class Attrs(object):
193 pass
194
195 - def __init__(self):
196 if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.Node') 197 # Note that we no longer explicitly initialize a self.builder 198 # attribute to None here. That's because the self.builder 199 # attribute may be created on-the-fly later by a subclass (the 200 # canonical example being a builder to fetch a file from a 201 # source code system like CVS or Subversion). 202 203 # Each list of children that we maintain is accompanied by a 204 # dictionary used to look up quickly whether a node is already 205 # present in the list. Empirical tests showed that it was 206 # fastest to maintain them as side-by-side Node attributes in 207 # this way, instead of wrapping up each list+dictionary pair in 208 # a class. (Of course, we could always still do that in the 209 # future if we had a good reason to...). 210 self.sources = [] # source files used to build node 211 self.sources_set = set() 212 self._specific_sources = False 213 self.depends = [] # explicit dependencies (from Depends) 214 self.depends_set = set() 215 self.ignore = [] # dependencies to ignore 216 self.ignore_set = set() 217 self.prerequisites = None 218 self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) 219 self.waiting_parents = set() 220 self.waiting_s_e = set() 221 self.ref_count = 0 222 self.wkids = None # Kids yet to walk, when it's an array 223 224 self.env = None 225 self.state = no_state 226 self.precious = None 227 self.pseudo = False 228 self.noclean = 0 229 self.nocache = 0 230 self.cached = 0 # is this node pulled from cache? 231 self.always_build = None 232 self.includes = None 233 self.attributes = self.Attrs() # Generic place to stick information about the Node. 234 self.side_effect = 0 # true iff this node is a side effect 235 self.side_effects = [] # the side effects of building this target 236 self.linked = 0 # is this node linked to the variant directory? 237 238 self.clear_memoized_values() 239 240 # Let the interface in which the build engine is embedded 241 # annotate this Node with its own info (like a description of 242 # what line in what file created the node, for example). 243 Annotate(self)
244
245 - def disambiguate(self, must_exist=None):
246 return self
247
248 - def get_suffix(self):
249 return ''
250 251 memoizer_counters.append(SCons.Memoize.CountValue('get_build_env')) 252
253 - def get_build_env(self):
254 """Fetch the appropriate Environment to build this node. 255 """ 256 try: 257 return self._memo['get_build_env'] 258 except KeyError: 259 pass 260 result = self.get_executor().get_build_env() 261 self._memo['get_build_env'] = result 262 return result
263
264 - def get_build_scanner_path(self, scanner):
265 """Fetch the appropriate scanner path for this node.""" 266 return self.get_executor().get_build_scanner_path(scanner)
267
268 - def set_executor(self, executor):
269 """Set the action executor for this node.""" 270 self.executor = executor
271
272 - def get_executor(self, create=1):
273 """Fetch the action executor for this node. Create one if 274 there isn't already one, and requested to do so.""" 275 try: 276 executor = self.executor 277 except AttributeError: 278 if not create: 279 raise 280 try: 281 act = self.builder.action 282 except AttributeError: 283 executor = SCons.Executor.Null(targets=[self]) 284 else: 285 executor = SCons.Executor.Executor(act, 286 self.env or self.builder.env, 287 [self.builder.overrides], 288 [self], 289 self.sources) 290 self.executor = executor 291 return executor
292
293 - def executor_cleanup(self):
294 """Let the executor clean up any cached information.""" 295 try: 296 executor = self.get_executor(create=None) 297 except AttributeError: 298 pass 299 else: 300 if executor is not None: 301 executor.cleanup()
302
303 - def reset_executor(self):
304 "Remove cached executor; forces recompute when needed." 305 try: 306 delattr(self, 'executor') 307 except AttributeError: 308 pass
309
310 - def push_to_cache(self):
311 """Try to push a node into a cache 312 """ 313 pass
314
315 - def retrieve_from_cache(self):
316 """Try to retrieve the node's content from a cache 317 318 This method is called from multiple threads in a parallel build, 319 so only do thread safe stuff here. Do thread unsafe stuff in 320 built(). 321 322 Returns true if the node was successfully retrieved. 323 """ 324 return 0
325 326 # 327 # Taskmaster interface subsystem 328 # 329
330 - def make_ready(self):
331 """Get a Node ready for evaluation. 332 333 This is called before the Taskmaster decides if the Node is 334 up-to-date or not. Overriding this method allows for a Node 335 subclass to be disambiguated if necessary, or for an implicit 336 source builder to be attached. 337 """ 338 pass
339
340 - def prepare(self):
341 """Prepare for this Node to be built. 342 343 This is called after the Taskmaster has decided that the Node 344 is out-of-date and must be rebuilt, but before actually calling 345 the method to build the Node. 346 347 This default implementation checks that explicit or implicit 348 dependencies either exist or are derived, and initializes the 349 BuildInfo structure that will hold the information about how 350 this node is, uh, built. 351 352 (The existence of source files is checked separately by the 353 Executor, which aggregates checks for all of the targets built 354 by a specific action.) 355 356 Overriding this method allows for for a Node subclass to remove 357 the underlying file from the file system. Note that subclass 358 methods should call this base class method to get the child 359 check and the BuildInfo structure. 360 """ 361 if self.depends is not None: 362 for d in self.depends: 363 if d.missing(): 364 msg = "Explicit dependency `%s' not found, needed by target `%s'." 365 raise SCons.Errors.StopError(msg % (d, self)) 366 if self.implicit is not None: 367 for i in self.implicit: 368 if i.missing(): 369 msg = "Implicit dependency `%s' not found, needed by target `%s'." 370 raise SCons.Errors.StopError(msg % (i, self)) 371 self.binfo = self.get_binfo()
372
373 - def build(self, **kw):
374 """Actually build the node. 375 376 This is called by the Taskmaster after it's decided that the 377 Node is out-of-date and must be rebuilt, and after the prepare() 378 method has gotten everything, uh, prepared. 379 380 This method is called from multiple threads in a parallel build, 381 so only do thread safe stuff here. Do thread unsafe stuff 382 in built(). 383 384 """ 385 try: 386 self.get_executor()(self, **kw) 387 except SCons.Errors.BuildError, e: 388 e.node = self 389 raise
390
391 - def built(self):
392 """Called just after this node is successfully built.""" 393 394 # Clear the implicit dependency caches of any Nodes 395 # waiting for this Node to be built. 396 for parent in self.waiting_parents: 397 parent.implicit = None 398 399 self.clear() 400 401 if self.pseudo: 402 if self.exists(): 403 raise SCons.Errors.UserError("Pseudo target " + str(self) + " must not exist") 404 else: 405 if not self.exists() and do_store_info: 406 SCons.Warnings.warn(SCons.Warnings.TargetNotBuiltWarning, 407 "Cannot find target " + str(self) + " after building") 408 self.ninfo.update(self)
409
410 - def visited(self):
411 """Called just after this node has been visited (with or 412 without a build).""" 413 try: 414 binfo = self.binfo 415 except AttributeError: 416 # Apparently this node doesn't need build info, so 417 # don't bother calculating or storing it. 418 pass 419 else: 420 self.ninfo.update(self) 421 self.store_info()
422
423 - def release_target_info(self):
424 """Called just after this node has been marked 425 up-to-date or was built completely. 426 427 This is where we try to release as many target node infos 428 as possible for clean builds and update runs, in order 429 to minimize the overall memory consumption. 430 431 By purging attributes that aren't needed any longer after 432 a Node (=File) got built, we don't have to care that much how 433 many KBytes a Node actually requires...as long as we free 434 the memory shortly afterwards. 435 436 @see: built() and File.release_target_info() 437 """ 438 pass
439 440 # 441 # 442 # 443
444 - def add_to_waiting_s_e(self, node):
445 self.waiting_s_e.add(node)
446
447 - def add_to_waiting_parents(self, node):
448 """ 449 Returns the number of nodes added to our waiting parents list: 450 1 if we add a unique waiting parent, 0 if not. (Note that the 451 returned values are intended to be used to increment a reference 452 count, so don't think you can "clean up" this function by using 453 True and False instead...) 454 """ 455 wp = self.waiting_parents 456 if node in wp: 457 return 0 458 wp.add(node) 459 return 1
460
461 - def postprocess(self):
462 """Clean up anything we don't need to hang onto after we've 463 been built.""" 464 self.executor_cleanup() 465 self.waiting_parents = set()
466
467 - def clear(self):
468 """Completely clear a Node of all its cached state (so that it 469 can be re-evaluated by interfaces that do continuous integration 470 builds). 471 """ 472 # The del_binfo() call here isn't necessary for normal execution, 473 # but is for interactive mode, where we might rebuild the same 474 # target and need to start from scratch. 475 self.del_binfo() 476 self.clear_memoized_values() 477 self.ninfo = self.new_ninfo() 478 self.executor_cleanup() 479 try: 480 delattr(self, '_calculated_sig') 481 except AttributeError: 482 pass 483 self.includes = None
484
485 - def clear_memoized_values(self):
486 self._memo = {}
487
488 - def builder_set(self, builder):
489 self.builder = builder 490 try: 491 del self.executor 492 except AttributeError: 493 pass
494
495 - def has_builder(self):
496 """Return whether this Node has a builder or not. 497 498 In Boolean tests, this turns out to be a *lot* more efficient 499 than simply examining the builder attribute directly ("if 500 node.builder: ..."). When the builder attribute is examined 501 directly, it ends up calling __getattr__ for both the __len__ 502 and __nonzero__ attributes on instances of our Builder Proxy 503 class(es), generating a bazillion extra calls and slowing 504 things down immensely. 505 """ 506 try: 507 b = self.builder 508 except AttributeError: 509 # There was no explicit builder for this Node, so initialize 510 # the self.builder attribute to None now. 511 b = self.builder = None 512 return b is not None
513
514 - def set_explicit(self, is_explicit):
515 self.is_explicit = is_explicit
516
517 - def has_explicit_builder(self):
518 """Return whether this Node has an explicit builder 519 520 This allows an internal Builder created by SCons to be marked 521 non-explicit, so that it can be overridden by an explicit 522 builder that the user supplies (the canonical example being 523 directories).""" 524 try: 525 return self.is_explicit 526 except AttributeError: 527 self.is_explicit = None 528 return self.is_explicit
529
530 - def get_builder(self, default_builder=None):
531 """Return the set builder, or a specified default value""" 532 try: 533 return self.builder 534 except AttributeError: 535 return default_builder
536 537 multiple_side_effect_has_builder = has_builder 538
539 - def is_derived(self):
540 """ 541 Returns true if this node is derived (i.e. built). 542 543 This should return true only for nodes whose path should be in 544 the variant directory when duplicate=0 and should contribute their build 545 signatures when they are used as source files to other derived files. For 546 example: source with source builders are not derived in this sense, 547 and hence should not return true. 548 """ 549 return self.has_builder() or self.side_effect
550
551 - def alter_targets(self):
552 """Return a list of alternate targets for this Node. 553 """ 554 return [], None
555
556 - def get_found_includes(self, env, scanner, path):
557 """Return the scanned include lines (implicit dependencies) 558 found in this node. 559 560 The default is no implicit dependencies. We expect this method 561 to be overridden by any subclass that can be scanned for 562 implicit dependencies. 563 """ 564 return []
565
566 - def get_implicit_deps(self, env, scanner, path):
567 """Return a list of implicit dependencies for this node. 568 569 This method exists to handle recursive invocation of the scanner 570 on the implicit dependencies returned by the scanner, if the 571 scanner's recursive flag says that we should. 572 """ 573 if not scanner: 574 return [] 575 576 # Give the scanner a chance to select a more specific scanner 577 # for this Node. 578 #scanner = scanner.select(self) 579 580 nodes = [self] 581 seen = {} 582 seen[self] = 1 583 deps = [] 584 while nodes: 585 n = nodes.pop(0) 586 d = [x for x in n.get_found_includes(env, scanner, path) if x not in seen] 587 if d: 588 deps.extend(d) 589 for n in d: 590 seen[n] = 1 591 nodes.extend(scanner.recurse_nodes(d)) 592 593 return deps
594
595 - def get_env_scanner(self, env, kw={}):
596 return env.get_scanner(self.scanner_key())
597
598 - def get_target_scanner(self):
599 return self.builder.target_scanner
600
601 - def get_source_scanner(self, node):
602 """Fetch the source scanner for the specified node 603 604 NOTE: "self" is the target being built, "node" is 605 the source file for which we want to fetch the scanner. 606 607 Implies self.has_builder() is true; again, expect to only be 608 called from locations where this is already verified. 609 610 This function may be called very often; it attempts to cache 611 the scanner found to improve performance. 612 """ 613 scanner = None 614 try: 615 scanner = self.builder.source_scanner 616 except AttributeError: 617 pass 618 if not scanner: 619 # The builder didn't have an explicit scanner, so go look up 620 # a scanner from env['SCANNERS'] based on the node's scanner 621 # key (usually the file extension). 622 scanner = self.get_env_scanner(self.get_build_env()) 623 if scanner: 624 scanner = scanner.select(node) 625 return scanner
626
627 - def add_to_implicit(self, deps):
628 if not hasattr(self, 'implicit') or self.implicit is None: 629 self.implicit = [] 630 self.implicit_set = set() 631 self._children_reset() 632 self._add_child(self.implicit, self.implicit_set, deps)
633
634 - def scan(self):
635 """Scan this node's dependents for implicit dependencies.""" 636 # Don't bother scanning non-derived files, because we don't 637 # care what their dependencies are. 638 # Don't scan again, if we already have scanned. 639 if self.implicit is not None: 640 return 641 self.implicit = [] 642 self.implicit_set = set() 643 self._children_reset() 644 if not self.has_builder(): 645 return 646 647 build_env = self.get_build_env() 648 executor = self.get_executor() 649 650 # Here's where we implement --implicit-cache. 651 if implicit_cache and not implicit_deps_changed: 652 implicit = self.get_stored_implicit() 653 if implicit is not None: 654 # We now add the implicit dependencies returned from the 655 # stored .sconsign entry to have already been converted 656 # to Nodes for us. (We used to run them through a 657 # source_factory function here.) 658 659 # Update all of the targets with them. This 660 # essentially short-circuits an N*M scan of the 661 # sources for each individual target, which is a hell 662 # of a lot more efficient. 663 for tgt in executor.get_all_targets(): 664 tgt.add_to_implicit(implicit) 665 666 if implicit_deps_unchanged or self.is_up_to_date(): 667 return 668 # one of this node's sources has changed, 669 # so we must recalculate the implicit deps for all targets 670 for tgt in executor.get_all_targets(): 671 tgt.implicit = [] 672 tgt.implicit_set = set() 673 674 # Have the executor scan the sources. 675 executor.scan_sources(self.builder.source_scanner) 676 677 # If there's a target scanner, have the executor scan the target 678 # node itself and associated targets that might be built. 679 scanner = self.get_target_scanner() 680 if scanner: 681 executor.scan_targets(scanner)
682
683 - def scanner_key(self):
684 return None
685
686 - def select_scanner(self, scanner):
687 """Selects a scanner for this Node. 688 689 This is a separate method so it can be overridden by Node 690 subclasses (specifically, Node.FS.Dir) that *must* use their 691 own Scanner and don't select one the Scanner.Selector that's 692 configured for the target. 693 """ 694 return scanner.select(self)
695
696 - def env_set(self, env, safe=0):
697 if safe and self.env: 698 return 699 self.env = env
700 701 # 702 # SIGNATURE SUBSYSTEM 703 # 704 705 NodeInfo = NodeInfoBase 706 BuildInfo = BuildInfoBase 707
708 - def new_ninfo(self):
709 ninfo = self.NodeInfo(self) 710 return ninfo
711
712 - def get_ninfo(self):
713 try: 714 return self.ninfo 715 except AttributeError: 716 self.ninfo = self.new_ninfo() 717 return self.ninfo
718
719 - def new_binfo(self):
720 binfo = self.BuildInfo(self) 721 return binfo
722
723 - def get_binfo(self):
724 """ 725 Fetch a node's build information. 726 727 node - the node whose sources will be collected 728 cache - alternate node to use for the signature cache 729 returns - the build signature 730 731 This no longer handles the recursive descent of the 732 node's children's signatures. We expect that they're 733 already built and updated by someone else, if that's 734 what's wanted. 735 """ 736 try: 737 return self.binfo 738 except AttributeError: 739 pass 740 741 binfo = self.new_binfo() 742 self.binfo = binfo 743 744 executor = self.get_executor() 745 ignore_set = self.ignore_set 746 747 if self.has_builder(): 748 binfo.bact = str(executor) 749 binfo.bactsig = SCons.Util.MD5signature(executor.get_contents()) 750 751 if self._specific_sources: 752 sources = [] 753 for s in self.sources: 754 if s not in ignore_set: 755 sources.append(s) 756 else: 757 sources = executor.get_unignored_sources(self, self.ignore) 758 seen = set() 759 bsources = [] 760 bsourcesigs = [] 761 for s in sources: 762 if not s in seen: 763 seen.add(s) 764 bsources.append(s) 765 bsourcesigs.append(s.get_ninfo()) 766 binfo.bsources = bsources 767 binfo.bsourcesigs = bsourcesigs 768 769 depends = self.depends 770 dependsigs = [] 771 for d in depends: 772 if d not in ignore_set: 773 dependsigs.append(d.get_ninfo()) 774 binfo.bdepends = depends 775 binfo.bdependsigs = dependsigs 776 777 implicit = self.implicit or [] 778 implicitsigs = [] 779 for i in implicit: 780 if i not in ignore_set: 781 implicitsigs.append(i.get_ninfo()) 782 binfo.bimplicit = implicit 783 binfo.bimplicitsigs = implicitsigs 784 785 return binfo
786
787 - def del_binfo(self):
788 """Delete the build info from this node.""" 789 try: 790 delattr(self, 'binfo') 791 except AttributeError: 792 pass
793
794 - def get_csig(self):
795 try: 796 return self.ninfo.csig 797 except AttributeError: 798 ninfo = self.get_ninfo() 799 ninfo.csig = SCons.Util.MD5signature(self.get_contents()) 800 return self.ninfo.csig
801
802 - def get_cachedir_csig(self):
803 return self.get_csig()
804
805 - def store_info(self):
806 """Make the build signature permanent (that is, store it in the 807 .sconsign file or equivalent).""" 808 pass
809
810 - def do_not_store_info(self):
811 pass
812
813 - def get_stored_info(self):
814 return None
815
816 - def get_stored_implicit(self):
817 """Fetch the stored implicit dependencies""" 818 return None
819 820 # 821 # 822 # 823
824 - def set_precious(self, precious = 1):
825 """Set the Node's precious value.""" 826 self.precious = precious
827
828 - def set_pseudo(self, pseudo = True):
829 """Set the Node's precious value.""" 830 self.pseudo = pseudo
831
832 - def set_noclean(self, noclean = 1):
833 """Set the Node's noclean value.""" 834 # Make sure noclean is an integer so the --debug=stree 835 # output in Util.py can use it as an index. 836 self.noclean = noclean and 1 or 0
837
838 - def set_nocache(self, nocache = 1):
839 """Set the Node's nocache value.""" 840 # Make sure nocache is an integer so the --debug=stree 841 # output in Util.py can use it as an index. 842 self.nocache = nocache and 1 or 0
843
844 - def set_always_build(self, always_build = 1):
845 """Set the Node's always_build value.""" 846 self.always_build = always_build
847
848 - def exists(self):
849 """Does this node exists?""" 850 # All node exist by default: 851 return 1
852
853 - def rexists(self):
854 """Does this node exist locally or in a repositiory?""" 855 # There are no repositories by default: 856 return self.exists()
857
858 - def missing(self):
859 return not self.is_derived() and \ 860 not self.linked and \ 861 not self.rexists()
862
863 - def remove(self):
864 """Remove this Node: no-op by default.""" 865 return None
866
867 - def add_dependency(self, depend):
868 """Adds dependencies.""" 869 try: 870 self._add_child(self.depends, self.depends_set, depend) 871 except TypeError, e: 872 e = e.args[0] 873 if SCons.Util.is_List(e): 874 s = list(map(str, e)) 875 else: 876 s = str(e) 877 raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
878
879 - def add_prerequisite(self, prerequisite):
880 """Adds prerequisites""" 881 if self.prerequisites is None: 882 self.prerequisites = SCons.Util.UniqueList() 883 self.prerequisites.extend(prerequisite) 884 self._children_reset()
885
886 - def add_ignore(self, depend):
887 """Adds dependencies to ignore.""" 888 try: 889 self._add_child(self.ignore, self.ignore_set, depend) 890 except TypeError, e: 891 e = e.args[0] 892 if SCons.Util.is_List(e): 893 s = list(map(str, e)) 894 else: 895 s = str(e) 896 raise SCons.Errors.UserError("attempted to ignore a non-Node dependency of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
897
898 - def add_source(self, source):
899 """Adds sources.""" 900 if self._specific_sources: 901 return 902 try: 903 self._add_child(self.sources, self.sources_set, source) 904 except TypeError, e: 905 e = e.args[0] 906 if SCons.Util.is_List(e): 907 s = list(map(str, e)) 908 else: 909 s = str(e) 910 raise SCons.Errors.UserError("attempted to add a non-Node as source of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
911
912 - def _add_child(self, collection, set, child):
913 """Adds 'child' to 'collection', first checking 'set' to see if it's 914 already present.""" 915 #if type(child) is not type([]): 916 # child = [child] 917 #for c in child: 918 # if not isinstance(c, Node): 919 # raise TypeError, c 920 added = None 921 for c in child: 922 if c not in set: 923 set.add(c) 924 collection.append(c) 925 added = 1 926 if added: 927 self._children_reset()
928
929 - def set_specific_source(self, source):
930 self.add_source(source) 931 self._specific_sources = True
932
933 - def add_wkid(self, wkid):
934 """Add a node to the list of kids waiting to be evaluated""" 935 if self.wkids is not None: 936 self.wkids.append(wkid)
937
938 - def _children_reset(self):
939 self.clear_memoized_values() 940 # We need to let the Executor clear out any calculated 941 # build info that it's cached so we can re-calculate it. 942 self.executor_cleanup()
943 944 memoizer_counters.append(SCons.Memoize.CountValue('_children_get')) 945
946 - def _children_get(self):
947 try: 948 return self._memo['children_get'] 949 except KeyError: 950 pass 951 952 # The return list may contain duplicate Nodes, especially in 953 # source trees where there are a lot of repeated #includes 954 # of a tangle of .h files. Profiling shows, however, that 955 # eliminating the duplicates with a brute-force approach that 956 # preserves the order (that is, something like: 957 # 958 # u = [] 959 # for n in list: 960 # if n not in u: 961 # u.append(n)" 962 # 963 # takes more cycles than just letting the underlying methods 964 # hand back cached values if a Node's information is requested 965 # multiple times. (Other methods of removing duplicates, like 966 # using dictionary keys, lose the order, and the only ordered 967 # dictionary patterns I found all ended up using "not in" 968 # internally anyway...) 969 if self.ignore_set: 970 iter = chain.from_iterable(filter(None, [self.sources, self.depends, self.implicit])) 971 972 children = [] 973 for i in iter: 974 if i not in self.ignore_set: 975 children.append(i) 976 else: 977 children = self.all_children(scan=0) 978 979 self._memo['children_get'] = children 980 return children
981
982 - def all_children(self, scan=1):
983 """Return a list of all the node's direct children.""" 984 if scan: 985 self.scan() 986 987 # The return list may contain duplicate Nodes, especially in 988 # source trees where there are a lot of repeated #includes 989 # of a tangle of .h files. Profiling shows, however, that 990 # eliminating the duplicates with a brute-force approach that 991 # preserves the order (that is, something like: 992 # 993 # u = [] 994 # for n in list: 995 # if n not in u: 996 # u.append(n)" 997 # 998 # takes more cycles than just letting the underlying methods 999 # hand back cached values if a Node's information is requested 1000 # multiple times. (Other methods of removing duplicates, like 1001 # using dictionary keys, lose the order, and the only ordered 1002 # dictionary patterns I found all ended up using "not in" 1003 # internally anyway...) 1004 return list(chain.from_iterable(filter(None, [self.sources, self.depends, self.implicit])))
1005
1006 - def children(self, scan=1):
1007 """Return a list of the node's direct children, minus those 1008 that are ignored by this node.""" 1009 if scan: 1010 self.scan() 1011 return self._children_get()
1012
1013 - def set_state(self, state):
1014 self.state = state
1015
1016 - def get_state(self):
1017 return self.state
1018
1019 - def state_has_changed(self, target, prev_ni):
1020 return (self.state != SCons.Node.up_to_date)
1021
1022 - def get_env(self):
1023 env = self.env 1024 if not env: 1025 import SCons.Defaults 1026 env = SCons.Defaults.DefaultEnvironment() 1027 return env
1028
1029 - def changed_since_last_build(self, target, prev_ni):
1030 """ 1031 1032 Must be overridden in a specific subclass to return True if this 1033 Node (a dependency) has changed since the last time it was used 1034 to build the specified target. prev_ni is this Node's state (for 1035 example, its file timestamp, length, maybe content signature) 1036 as of the last time the target was built. 1037 1038 Note that this method is called through the dependency, not the 1039 target, because a dependency Node must be able to use its own 1040 logic to decide if it changed. For example, File Nodes need to 1041 obey if we're configured to use timestamps, but Python Value Nodes 1042 never use timestamps and always use the content. If this method 1043 were called through the target, then each Node's implementation 1044 of this method would have to have more complicated logic to 1045 handle all the different Node types on which it might depend. 1046 """ 1047 raise NotImplementedError
1048
1049 - def Decider(self, function):
1050 SCons.Util.AddMethod(self, function, 'changed_since_last_build')
1051
1052 - def changed(self, node=None, allowcache=False):
1053 """ 1054 Returns if the node is up-to-date with respect to the BuildInfo 1055 stored last time it was built. The default behavior is to compare 1056 it against our own previously stored BuildInfo, but the stored 1057 BuildInfo from another Node (typically one in a Repository) 1058 can be used instead. 1059 1060 Note that we now *always* check every dependency. We used to 1061 short-circuit the check by returning as soon as we detected 1062 any difference, but we now rely on checking every dependency 1063 to make sure that any necessary Node information (for example, 1064 the content signature of an #included .h file) is updated. 1065 1066 The allowcache option was added for supporting the early 1067 release of the executor/builder structures, right after 1068 a File target was built. When set to true, the return 1069 value of this changed method gets cached for File nodes. 1070 Like this, the executor isn't needed any longer for subsequent 1071 calls to changed(). 1072 1073 @see: FS.File.changed(), FS.File.release_target_info() 1074 """ 1075 t = 0 1076 if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node)) 1077 if node is None: 1078 node = self 1079 1080 result = False 1081 1082 bi = node.get_stored_info().binfo 1083 then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs 1084 children = self.children() 1085 1086 diff = len(children) - len(then) 1087 if diff: 1088 # The old and new dependency lists are different lengths. 1089 # This always indicates that the Node must be rebuilt. 1090 # We also extend the old dependency list with enough None 1091 # entries to equal the new dependency list, for the benefit 1092 # of the loop below that updates node information. 1093 then.extend([None] * diff) 1094 if t: Trace(': old %s new %s' % (len(then), len(children))) 1095 result = True 1096 1097 for child, prev_ni in zip(children, then): 1098 if child.changed_since_last_build(self, prev_ni): 1099 if t: Trace(': %s changed' % child) 1100 result = True 1101 1102 contents = self.get_executor().get_contents() 1103 if self.has_builder(): 1104 import SCons.Util 1105 newsig = SCons.Util.MD5signature(contents) 1106 if bi.bactsig != newsig: 1107 if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig)) 1108 result = True 1109 1110 if not result: 1111 if t: Trace(': up to date') 1112 1113 if t: Trace('\n') 1114 1115 return result
1116
1117 - def is_up_to_date(self):
1118 """Default check for whether the Node is current: unknown Node 1119 subtypes are always out of date, so they will always get built.""" 1120 return None
1121
1122 - def children_are_up_to_date(self):
1123 """Alternate check for whether the Node is current: If all of 1124 our children were up-to-date, then this Node was up-to-date, too. 1125 1126 The SCons.Node.Alias and SCons.Node.Python.Value subclasses 1127 rebind their current() method to this method.""" 1128 # Allow the children to calculate their signatures. 1129 self.binfo = self.get_binfo() 1130 if self.always_build: 1131 return None 1132 state = 0 1133 for kid in self.children(None): 1134 s = kid.get_state() 1135 if s and (not state or s > state): 1136 state = s 1137 return (state == 0 or state == SCons.Node.up_to_date)
1138
1139 - def is_literal(self):
1140 """Always pass the string representation of a Node to 1141 the command interpreter literally.""" 1142 return 1
1143
1144 - def render_include_tree(self):
1145 """ 1146 Return a text representation, suitable for displaying to the 1147 user, of the include tree for the sources of this node. 1148 """ 1149 if self.is_derived(): 1150 env = self.get_build_env() 1151 if env: 1152 for s in self.sources: 1153 scanner = self.get_source_scanner(s) 1154 if scanner: 1155 path = self.get_build_scanner_path(scanner) 1156 else: 1157 path = None 1158 def f(node, env=env, scanner=scanner, path=path): 1159 return node.get_found_includes(env, scanner, path)
1160 return SCons.Util.render_tree(s, f, 1) 1161 else: 1162 return None
1163
1164 - def get_abspath(self):
1165 """ 1166 Return an absolute path to the Node. This will return simply 1167 str(Node) by default, but for Node types that have a concept of 1168 relative path, this might return something different. 1169 """ 1170 return str(self)
1171
1172 - def for_signature(self):
1173 """ 1174 Return a string representation of the Node that will always 1175 be the same for this particular Node, no matter what. This 1176 is by contrast to the __str__() method, which might, for 1177 instance, return a relative path for a file Node. The purpose 1178 of this method is to generate a value to be used in signature 1179 calculation for the command line used to build a target, and 1180 we use this method instead of str() to avoid unnecessary 1181 rebuilds. This method does not need to return something that 1182 would actually work in a command line; it can return any kind of 1183 nonsense, so long as it does not change. 1184 """ 1185 return str(self)
1186
1187 - def get_string(self, for_signature):
1188 """This is a convenience function designed primarily to be 1189 used in command generators (i.e., CommandGeneratorActions or 1190 Environment variables that are callable), which are called 1191 with a for_signature argument that is nonzero if the command 1192 generator is being called to generate a signature for the 1193 command line, which determines if we should rebuild or not. 1194 1195 Such command generators should use this method in preference 1196 to str(Node) when converting a Node to a string, passing 1197 in the for_signature parameter, such that we will call 1198 Node.for_signature() or str(Node) properly, depending on whether 1199 we are calculating a signature or actually constructing a 1200 command line.""" 1201 if for_signature: 1202 return self.for_signature() 1203 return str(self)
1204
1205 - def get_subst_proxy(self):
1206 """ 1207 This method is expected to return an object that will function 1208 exactly like this Node, except that it implements any additional 1209 special features that we would like to be in effect for 1210 Environment variable substitution. The principle use is that 1211 some Nodes would like to implement a __getattr__() method, 1212 but putting that in the Node type itself has a tendency to kill 1213 performance. We instead put it in a proxy and return it from 1214 this method. It is legal for this method to return self 1215 if no new functionality is needed for Environment substitution. 1216 """ 1217 return self
1218
1219 - def explain(self):
1220 if not self.exists(): 1221 return "building `%s' because it doesn't exist\n" % self 1222 1223 if self.always_build: 1224 return "rebuilding `%s' because AlwaysBuild() is specified\n" % self 1225 1226 old = self.get_stored_info() 1227 if old is None: 1228 return None 1229 1230 old = old.binfo 1231 old.prepare_dependencies() 1232 1233 try: 1234 old_bkids = old.bsources + old.bdepends + old.bimplicit 1235 old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs 1236 except AttributeError: 1237 return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self 1238 1239 new = self.get_binfo() 1240 1241 new_bkids = new.bsources + new.bdepends + new.bimplicit 1242 new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs 1243 1244 osig = dict(zip(old_bkids, old_bkidsigs)) 1245 nsig = dict(zip(new_bkids, new_bkidsigs)) 1246 1247 # The sources and dependencies we'll want to report are all stored 1248 # as relative paths to this target's directory, but we want to 1249 # report them relative to the top-level SConstruct directory, 1250 # so we only print them after running them through this lambda 1251 # to turn them into the right relative Node and then return 1252 # its string. 1253 def stringify( s, E=self.dir.Entry ) : 1254 if hasattr( s, 'dir' ) : 1255 return str(E(s)) 1256 return str(s)
1257 1258 lines = [] 1259 1260 removed = [x for x in old_bkids if not x in new_bkids] 1261 if removed: 1262 removed = list(map(stringify, removed)) 1263 fmt = "`%s' is no longer a dependency\n" 1264 lines.extend([fmt % s for s in removed]) 1265 1266 for k in new_bkids: 1267 if not k in old_bkids: 1268 lines.append("`%s' is a new dependency\n" % stringify(k)) 1269 elif k.changed_since_last_build(self, osig[k]): 1270 lines.append("`%s' changed\n" % stringify(k)) 1271 1272 if len(lines) == 0 and old_bkids != new_bkids: 1273 lines.append("the dependency order changed:\n" + 1274 "%sold: %s\n" % (' '*15, list(map(stringify, old_bkids))) + 1275 "%snew: %s\n" % (' '*15, list(map(stringify, new_bkids)))) 1276 1277 if len(lines) == 0: 1278 def fmt_with_title(title, strlines): 1279 lines = strlines.split('\n') 1280 sep = '\n' + ' '*(15 + len(title)) 1281 return ' '*15 + title + sep.join(lines) + '\n' 1282 if old.bactsig != new.bactsig: 1283 if old.bact == new.bact: 1284 lines.append("the contents of the build action changed\n" + 1285 fmt_with_title('action: ', new.bact)) 1286 else: 1287 lines.append("the build action changed:\n" + 1288 fmt_with_title('old: ', old.bact) + 1289 fmt_with_title('new: ', new.bact)) 1290 1291 if len(lines) == 0: 1292 return "rebuilding `%s' for unknown reasons\n" % self 1293 1294 preamble = "rebuilding `%s' because" % self 1295 if len(lines) == 1: 1296 return "%s %s" % (preamble, lines[0]) 1297 else: 1298 lines = ["%s:\n" % preamble] + lines 1299 return ( ' '*11).join(lines) 1300
1301 -class NodeList(collections.UserList):
1302 - def __str__(self):
1303 return str(list(map(str, self.data)))
1304
1305 -def get_children(node, parent): return node.children()
1306 -def ignore_cycle(node, stack): pass
1307 -def do_nothing(node, parent): pass
1308
1309 -class Walker(object):
1310 """An iterator for walking a Node tree. 1311 1312 This is depth-first, children are visited before the parent. 1313 The Walker object can be initialized with any node, and 1314 returns the next node on the descent with each get_next() call. 1315 'kids_func' is an optional function that will be called to 1316 get the children of a node instead of calling 'children'. 1317 'cycle_func' is an optional function that will be called 1318 when a cycle is detected. 1319 1320 This class does not get caught in node cycles caused, for example, 1321 by C header file include loops. 1322 """
1323 - def __init__(self, node, kids_func=get_children, 1324 cycle_func=ignore_cycle, 1325 eval_func=do_nothing):
1326 self.kids_func = kids_func 1327 self.cycle_func = cycle_func 1328 self.eval_func = eval_func 1329 node.wkids = copy.copy(kids_func(node, None)) 1330 self.stack = [node] 1331 self.history = {} # used to efficiently detect and avoid cycles 1332 self.history[node] = None
1333
1334 - def get_next(self):
1335 """Return the next node for this walk of the tree. 1336 1337 This function is intentionally iterative, not recursive, 1338 to sidestep any issues of stack size limitations. 1339 """ 1340 1341 while self.stack: 1342 if self.stack[-1].wkids: 1343 node = self.stack[-1].wkids.pop(0) 1344 if not self.stack[-1].wkids: 1345 self.stack[-1].wkids = None 1346 if node in self.history: 1347 self.cycle_func(node, self.stack) 1348 else: 1349 node.wkids = copy.copy(self.kids_func(node, self.stack[-1])) 1350 self.stack.append(node) 1351 self.history[node] = None 1352 else: 1353 node = self.stack.pop() 1354 del self.history[node] 1355 if node: 1356 if self.stack: 1357 parent = self.stack[-1] 1358 else: 1359 parent = None 1360 self.eval_func(node, parent) 1361 return node 1362 return None
1363
1364 - def is_done(self):
1365 return not self.stack
1366 1367 1368 arg2nodes_lookups = [] 1369 1370 # Local Variables: 1371 # tab-width:4 1372 # indent-tabs-mode:nil 1373 # End: 1374 # vim: set expandtab tabstop=4 shiftwidth=4: 1375