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