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