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