3 The Node package for the SCons software construction utility.
5 This is, in many ways, the heart of SCons.
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).
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."
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:
33 # The above copyright notice and this permission notice shall be included
34 # in all copies or substantial portions of the Software.
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.
44 from __future__ import generators ### KEEP FOR COMPATIBILITY FIXERS
46 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
50 from itertools import chain, izip
52 from SCons.Debug import logInstanceCreation
57 from SCons.Debug import Trace
60 return str(obj.__class__).split('.')[-1]
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
85 # controls whether implicit dependencies are cached:
88 # controls whether implicit dep changes are ignored:
89 implicit_deps_unchanged = 0
91 # controls whether the cached implicit deps are ignored:
92 implicit_deps_changed = 0
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
100 # Classes for signature info for Nodes.
104 The generic base class for signature information for a Node.
106 Node subclasses should subclass NodeInfoBase to provide their own
107 logic for dealing with their own Node-specific signature information.
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):
116 field_list = self.field_list
117 except AttributeError:
122 except AttributeError:
125 func = getattr(node, 'get_' + f)
126 except AttributeError:
129 setattr(self, f, func())
130 def convert(self, node, val):
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:
137 field_list = self.field_list
138 except AttributeError:
139 field_list = sorted(self.__dict__.keys())
141 for field in field_list:
143 f = getattr(self, field)
144 except AttributeError:
154 The generic base class for build information for a Node.
156 This is what gets stored in a .sconsign file for each target file.
157 It contains a NodeInfo instance for this node (signature information
158 that's specific to the type of Node) and direct attributes for the
159 generic build stuff we have to track: sources, explicit dependencies,
160 implicit dependencies, and action information.
162 current_version_id = 1
163 def __init__(self, node):
164 # Create an object attribute from the class attribute so it ends up
165 # in the pickled data in the .sconsign file.
166 self._version_id = self.current_version_id
167 self.bsourcesigs = []
168 self.bdependsigs = []
169 self.bimplicitsigs = []
171 def merge(self, other):
172 self.__dict__.update(other.__dict__)
175 """The base Node class, for entities that we know how to
176 build, or use to build other Nodes.
179 if SCons.Memoize.use_memoizer:
180 __metaclass__ = SCons.Memoize.Memoized_Metaclass
182 memoizer_counters = []
188 if __debug__: logInstanceCreation(self, 'Node.Node')
189 # Note that we no longer explicitly initialize a self.builder
190 # attribute to None here. That's because the self.builder
191 # attribute may be created on-the-fly later by a subclass (the
192 # canonical example being a builder to fetch a file from a
193 # source code system like CVS or Subversion).
195 # Each list of children that we maintain is accompanied by a
196 # dictionary used to look up quickly whether a node is already
197 # present in the list. Empirical tests showed that it was
198 # fastest to maintain them as side-by-side Node attributes in
199 # this way, instead of wrapping up each list+dictionary pair in
200 # a class. (Of course, we could always still do that in the
201 # future if we had a good reason to...).
202 self.sources = [] # source files used to build node
203 self.sources_set = set()
204 self._specific_sources = False
205 self.depends = [] # explicit dependencies (from Depends)
206 self.depends_set = set()
207 self.ignore = [] # dependencies to ignore
208 self.ignore_set = set()
209 self.prerequisites = SCons.Util.UniqueList()
210 self.implicit = None # implicit (scanned) dependencies (None means not scanned yet)
211 self.waiting_parents = set()
212 self.waiting_s_e = set()
214 self.wkids = None # Kids yet to walk, when it's an array
217 self.state = no_state
221 self.always_build = None
223 self.attributes = self.Attrs() # Generic place to stick information about the Node.
224 self.side_effect = 0 # true iff this node is a side effect
225 self.side_effects = [] # the side effects of building this target
226 self.linked = 0 # is this node linked to the variant directory?
228 self.clear_memoized_values()
230 # Let the interface in which the build engine is embedded
231 # annotate this Node with its own info (like a description of
232 # what line in what file created the node, for example).
235 def disambiguate(self, must_exist=None):
238 def get_suffix(self):
241 memoizer_counters.append(SCons.Memoize.CountValue('get_build_env'))
243 def get_build_env(self):
244 """Fetch the appropriate Environment to build this node.
247 return self._memo['get_build_env']
250 result = self.get_executor().get_build_env()
251 self._memo['get_build_env'] = result
254 def get_build_scanner_path(self, scanner):
255 """Fetch the appropriate scanner path for this node."""
256 return self.get_executor().get_build_scanner_path(scanner)
258 def set_executor(self, executor):
259 """Set the action executor for this node."""
260 self.executor = executor
262 def get_executor(self, create=1):
263 """Fetch the action executor for this node. Create one if
264 there isn't already one, and requested to do so."""
266 executor = self.executor
267 except AttributeError:
271 act = self.builder.action
272 except AttributeError:
273 executor = SCons.Executor.Null(targets=[self])
275 executor = SCons.Executor.Executor(act,
276 self.env or self.builder.env,
277 [self.builder.overrides],
280 self.executor = executor
283 def executor_cleanup(self):
284 """Let the executor clean up any cached information."""
286 executor = self.get_executor(create=None)
287 except AttributeError:
292 def reset_executor(self):
293 "Remove cached executor; forces recompute when needed."
295 delattr(self, 'executor')
296 except AttributeError:
299 def push_to_cache(self):
300 """Try to push a node into a cache
304 def retrieve_from_cache(self):
305 """Try to retrieve the node's content from a cache
307 This method is called from multiple threads in a parallel build,
308 so only do thread safe stuff here. Do thread unsafe stuff in
311 Returns true iff the node was successfully retrieved.
316 # Taskmaster interface subsystem
319 def make_ready(self):
320 """Get a Node ready for evaluation.
322 This is called before the Taskmaster decides if the Node is
323 up-to-date or not. Overriding this method allows for a Node
324 subclass to be disambiguated if necessary, or for an implicit
325 source builder to be attached.
330 """Prepare for this Node to be built.
332 This is called after the Taskmaster has decided that the Node
333 is out-of-date and must be rebuilt, but before actually calling
334 the method to build the Node.
336 This default implementation checks that explicit or implicit
337 dependencies either exist or are derived, and initializes the
338 BuildInfo structure that will hold the information about how
339 this node is, uh, built.
341 (The existence of source files is checked separately by the
342 Executor, which aggregates checks for all of the targets built
343 by a specific action.)
345 Overriding this method allows for for a Node subclass to remove
346 the underlying file from the file system. Note that subclass
347 methods should call this base class method to get the child
348 check and the BuildInfo structure.
350 for d in self.depends:
352 msg = "Explicit dependency `%s' not found, needed by target `%s'."
353 raise SCons.Errors.StopError, msg % (d, self)
354 if self.implicit is not None:
355 for i in self.implicit:
357 msg = "Implicit dependency `%s' not found, needed by target `%s'."
358 raise SCons.Errors.StopError, msg % (i, self)
359 self.binfo = self.get_binfo()
361 def build(self, **kw):
362 """Actually build the node.
364 This is called by the Taskmaster after it's decided that the
365 Node is out-of-date and must be rebuilt, and after the prepare()
366 method has gotten everything, uh, prepared.
368 This method is called from multiple threads in a parallel build,
369 so only do thread safe stuff here. Do thread unsafe stuff
374 self.get_executor()(self, **kw)
375 except SCons.Errors.BuildError, e:
380 """Called just after this node is successfully built."""
382 # Clear the implicit dependency caches of any Nodes
383 # waiting for this Node to be built.
384 for parent in self.waiting_parents:
385 parent.implicit = None
389 self.ninfo.update(self)
392 """Called just after this node has been visited (with or
396 except AttributeError:
397 # Apparently this node doesn't need build info, so
398 # don't bother calculating or storing it.
401 self.ninfo.update(self)
408 def add_to_waiting_s_e(self, node):
409 self.waiting_s_e.add(node)
411 def add_to_waiting_parents(self, node):
413 Returns the number of nodes added to our waiting parents list:
414 1 if we add a unique waiting parent, 0 if not. (Note that the
415 returned values are intended to be used to increment a reference
416 count, so don't think you can "clean up" this function by using
417 True and False instead...)
419 wp = self.waiting_parents
425 def postprocess(self):
426 """Clean up anything we don't need to hang onto after we've
428 self.executor_cleanup()
429 self.waiting_parents = set()
432 """Completely clear a Node of all its cached state (so that it
433 can be re-evaluated by interfaces that do continuous integration
436 # The del_binfo() call here isn't necessary for normal execution,
437 # but is for interactive mode, where we might rebuild the same
438 # target and need to start from scratch.
440 self.clear_memoized_values()
441 self.ninfo = self.new_ninfo()
442 self.executor_cleanup()
444 delattr(self, '_calculated_sig')
445 except AttributeError:
449 def clear_memoized_values(self):
452 def builder_set(self, builder):
453 self.builder = builder
456 except AttributeError:
459 def has_builder(self):
460 """Return whether this Node has a builder or not.
462 In Boolean tests, this turns out to be a *lot* more efficient
463 than simply examining the builder attribute directly ("if
464 node.builder: ..."). When the builder attribute is examined
465 directly, it ends up calling __getattr__ for both the __len__
466 and __nonzero__ attributes on instances of our Builder Proxy
467 class(es), generating a bazillion extra calls and slowing
468 things down immensely.
472 except AttributeError:
473 # There was no explicit builder for this Node, so initialize
474 # the self.builder attribute to None now.
475 b = self.builder = None
478 def set_explicit(self, is_explicit):
479 self.is_explicit = is_explicit
481 def has_explicit_builder(self):
482 """Return whether this Node has an explicit builder
484 This allows an internal Builder created by SCons to be marked
485 non-explicit, so that it can be overridden by an explicit
486 builder that the user supplies (the canonical example being
489 return self.is_explicit
490 except AttributeError:
491 self.is_explicit = None
492 return self.is_explicit
494 def get_builder(self, default_builder=None):
495 """Return the set builder, or a specified default value"""
498 except AttributeError:
499 return default_builder
501 multiple_side_effect_has_builder = has_builder
503 def is_derived(self):
505 Returns true iff this node is derived (i.e. built).
507 This should return true only for nodes whose path should be in
508 the variant directory when duplicate=0 and should contribute their build
509 signatures when they are used as source files to other derived files. For
510 example: source with source builders are not derived in this sense,
511 and hence should not return true.
513 return self.has_builder() or self.side_effect
515 def alter_targets(self):
516 """Return a list of alternate targets for this Node.
520 def get_found_includes(self, env, scanner, path):
521 """Return the scanned include lines (implicit dependencies)
524 The default is no implicit dependencies. We expect this method
525 to be overridden by any subclass that can be scanned for
526 implicit dependencies.
530 def get_implicit_deps(self, env, scanner, path):
531 """Return a list of implicit dependencies for this node.
533 This method exists to handle recursive invocation of the scanner
534 on the implicit dependencies returned by the scanner, if the
535 scanner's recursive flag says that we should.
540 # Give the scanner a chance to select a more specific scanner
542 #scanner = scanner.select(self)
550 d = [x for x in n.get_found_includes(env, scanner, path) if x not in seen]
555 nodes.extend(scanner.recurse_nodes(d))
559 def get_env_scanner(self, env, kw={}):
560 return env.get_scanner(self.scanner_key())
562 def get_target_scanner(self):
563 return self.builder.target_scanner
565 def get_source_scanner(self, node):
566 """Fetch the source scanner for the specified node
568 NOTE: "self" is the target being built, "node" is
569 the source file for which we want to fetch the scanner.
571 Implies self.has_builder() is true; again, expect to only be
572 called from locations where this is already verified.
574 This function may be called very often; it attempts to cache
575 the scanner found to improve performance.
579 scanner = self.builder.source_scanner
580 except AttributeError:
583 # The builder didn't have an explicit scanner, so go look up
584 # a scanner from env['SCANNERS'] based on the node's scanner
585 # key (usually the file extension).
586 scanner = self.get_env_scanner(self.get_build_env())
588 scanner = scanner.select(node)
591 def add_to_implicit(self, deps):
592 if not hasattr(self, 'implicit') or self.implicit is None:
594 self.implicit_set = set()
595 self._children_reset()
596 self._add_child(self.implicit, self.implicit_set, deps)
599 """Scan this node's dependents for implicit dependencies."""
600 # Don't bother scanning non-derived files, because we don't
601 # care what their dependencies are.
602 # Don't scan again, if we already have scanned.
603 if self.implicit is not None:
606 self.implicit_set = set()
607 self._children_reset()
608 if not self.has_builder():
611 build_env = self.get_build_env()
612 executor = self.get_executor()
614 # Here's where we implement --implicit-cache.
615 if implicit_cache and not implicit_deps_changed:
616 implicit = self.get_stored_implicit()
617 if implicit is not None:
618 # We now add the implicit dependencies returned from the
619 # stored .sconsign entry to have already been converted
620 # to Nodes for us. (We used to run them through a
621 # source_factory function here.)
623 # Update all of the targets with them. This
624 # essentially short-circuits an N*M scan of the
625 # sources for each individual target, which is a hell
626 # of a lot more efficient.
627 for tgt in executor.get_all_targets():
628 tgt.add_to_implicit(implicit)
630 if implicit_deps_unchanged or self.is_up_to_date():
632 # one of this node's sources has changed,
633 # so we must recalculate the implicit deps:
635 self.implicit_set = set()
637 # Have the executor scan the sources.
638 executor.scan_sources(self.builder.source_scanner)
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()
644 executor.scan_targets(scanner)
646 def scanner_key(self):
649 def select_scanner(self, scanner):
650 """Selects a scanner for this Node.
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.
657 return scanner.select(self)
659 def env_set(self, env, safe=0):
660 if safe and self.env:
665 # SIGNATURE SUBSYSTEM
668 NodeInfo = NodeInfoBase
669 BuildInfo = BuildInfoBase
672 ninfo = self.NodeInfo(self)
678 except AttributeError:
679 self.ninfo = self.new_ninfo()
683 binfo = self.BuildInfo(self)
688 Fetch a node's build information.
690 node - the node whose sources will be collected
691 cache - alternate node to use for the signature cache
692 returns - the build signature
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
701 except AttributeError:
704 binfo = self.new_binfo()
707 executor = self.get_executor()
708 ignore_set = self.ignore_set
710 if self.has_builder():
711 binfo.bact = str(executor)
712 binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
714 if self._specific_sources:
716 for s in self.sources:
717 if s not in ignore_set:
720 sources = executor.get_unignored_sources(self, self.ignore)
728 bsourcesigs.append(s.get_ninfo())
729 binfo.bsources = bsources
730 binfo.bsourcesigs = bsourcesigs
732 depends = self.depends
735 if d not in ignore_set:
736 dependsigs.append(d.get_ninfo())
737 binfo.bdepends = depends
738 binfo.bdependsigs = dependsigs
740 implicit = self.implicit or []
743 if i not in ignore_set:
744 implicitsigs.append(i.get_ninfo())
745 binfo.bimplicit = implicit
746 binfo.bimplicitsigs = implicitsigs
751 """Delete the build info from this node."""
753 delattr(self, 'binfo')
754 except AttributeError:
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
765 def get_cachedir_csig(self):
766 return self.get_csig()
768 def store_info(self):
769 """Make the build signature permanent (that is, store it in the
770 .sconsign file or equivalent)."""
773 def do_not_store_info(self):
776 def get_stored_info(self):
779 def get_stored_implicit(self):
780 """Fetch the stored implicit dependencies"""
787 def set_precious(self, precious = 1):
788 """Set the Node's precious value."""
789 self.precious = precious
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
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
803 def set_always_build(self, always_build = 1):
804 """Set the Node's always_build value."""
805 self.always_build = always_build
808 """Does this node exists?"""
809 # All node exist by default:
813 """Does this node exist locally or in a repositiory?"""
814 # There are no repositories by default:
818 return not self.is_derived() and \
819 not self.linked and \
823 """Remove this Node: no-op by default."""
826 def add_dependency(self, depend):
827 """Adds dependencies."""
829 self._add_child(self.depends, self.depends_set, depend)
832 if SCons.Util.is_List(e):
833 s = list(map(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)))
838 def add_prerequisite(self, prerequisite):
839 """Adds prerequisites"""
840 self.prerequisites.extend(prerequisite)
841 self._children_reset()
843 def add_ignore(self, depend):
844 """Adds dependencies to ignore."""
846 self._add_child(self.ignore, self.ignore_set, depend)
849 if SCons.Util.is_List(e):
850 s = list(map(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)))
855 def add_source(self, source):
857 if self._specific_sources:
860 self._add_child(self.sources, self.sources_set, source)
863 if SCons.Util.is_List(e):
864 s = list(map(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)))
869 def _add_child(self, collection, set, child):
870 """Adds 'child' to 'collection', first checking 'set' to see if it's
872 #if type(child) is not type([]):
875 # if not isinstance(c, Node):
884 self._children_reset()
886 def set_specific_source(self, source):
887 self.add_source(source)
888 self._specific_sources = True
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)
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()
901 memoizer_counters.append(SCons.Memoize.CountValue('_children_get'))
903 def _children_get(self):
905 return self._memo['children_get']
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:
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...)
927 if self.implicit is None:
928 iter = chain(self.sources,self.depends)
930 iter = chain(self.sources, self.depends, self.implicit)
934 if i not in self.ignore_set:
937 if self.implicit is None:
938 children = self.sources + self.depends
940 children = self.sources + self.depends + self.implicit
942 self._memo['children_get'] = children
945 def all_children(self, scan=1):
946 """Return a list of all the node's direct children."""
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:
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
970 return self.sources + self.depends + self.implicit
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."""
977 return self._children_get()
979 def set_state(self, state):
985 def state_has_changed(self, target, prev_ni):
986 return (self.state != SCons.Node.up_to_date)
991 import SCons.Defaults
992 env = SCons.Defaults.DefaultEnvironment()
995 def changed_since_last_build(self, target, prev_ni):
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.
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.
1013 raise NotImplementedError
1015 def Decider(self, function):
1016 SCons.Util.AddMethod(self, function, 'changed_since_last_build')
1018 def changed(self, node=None):
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.
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.
1033 if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node))
1039 bi = node.get_stored_info().binfo
1040 then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs
1041 children = self.children()
1043 diff = len(children) - len(then)
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)))
1054 for child, prev_ni in izip(children, then):
1055 if child.changed_since_last_build(self, prev_ni):
1056 if t: Trace(': %s changed' % child)
1059 contents = self.get_executor().get_contents()
1060 if self.has_builder():
1062 newsig = SCons.Util.MD5signature(contents)
1063 if bi.bactsig != newsig:
1064 if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
1068 if t: Trace(': up to date')
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."""
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.
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:
1090 for kid in self.children(None):
1092 if s and (not state or s > state):
1094 return (state == 0 or state == SCons.Node.up_to_date)
1096 def is_literal(self):
1097 """Always pass the string representation of a Node to
1098 the command interpreter literally."""
1101 def render_include_tree(self):
1103 Return a text representation, suitable for displaying to the
1104 user, of the include tree for the sources of this node.
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)
1111 path = self.get_build_scanner_path(scanner)
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)
1120 def get_abspath(self):
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.
1128 def for_signature(self):
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.
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.
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
1158 return self.for_signature()
1161 def get_subst_proxy(self):
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.
1176 if not self.exists():
1177 return "building `%s' because it doesn't exist\n" % self
1179 if self.always_build:
1180 return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
1182 old = self.get_stored_info()
1187 old.prepare_dependencies()
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
1195 new = self.get_binfo()
1197 new_bkids = new.bsources + new.bdepends + new.bimplicit
1198 new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
1200 osig = dict(izip(old_bkids, old_bkidsigs))
1201 nsig = dict(izip(new_bkids, new_bkidsigs))
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
1209 def stringify( s, E=self.dir.Entry ) :
1210 if hasattr( s, 'dir' ) :
1216 removed = [x for x in old_bkids if not x in new_bkids]
1218 removed = list(map(stringify, removed))
1219 fmt = "`%s' is no longer a dependency\n"
1220 lines.extend([fmt % s for s in removed])
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))
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))))
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))
1243 lines.append("the build action changed:\n" +
1244 fmt_with_title('old: ', old.bact) +
1245 fmt_with_title('new: ', new.bact))
1248 return "rebuilding `%s' for unknown reasons\n" % self
1250 preamble = "rebuilding `%s' because" % self
1252 return "%s %s" % (preamble, lines[0])
1254 lines = ["%s:\n" % preamble] + lines
1255 return ( ' '*11).join(lines)
1258 [].extend(collections.UserList([]))
1260 # Python 1.5.2 doesn't allow a list to be extended by list-like
1261 # objects (such as UserList instances), so just punt and use
1266 class NodeList(collections.UserList):
1268 return str(list(map(str, self.data)))
1270 def get_children(node, parent): return node.children()
1271 def ignore_cycle(node, stack): pass
1272 def do_nothing(node, parent): pass
1275 """An iterator for walking a Node tree.
1277 This is depth-first, children are visited before the parent.
1278 The Walker object can be initialized with any node, and
1279 returns the next node on the descent with each get_next() call.
1280 'kids_func' is an optional function that will be called to
1281 get the children of a node instead of calling 'children'.
1282 'cycle_func' is an optional function that will be called
1283 when a cycle is detected.
1285 This class does not get caught in node cycles caused, for example,
1286 by C header file include loops.
1288 def __init__(self, node, kids_func=get_children,
1289 cycle_func=ignore_cycle,
1290 eval_func=do_nothing):
1291 self.kids_func = kids_func
1292 self.cycle_func = cycle_func
1293 self.eval_func = eval_func
1294 node.wkids = copy.copy(kids_func(node, None))
1296 self.history = {} # used to efficiently detect and avoid cycles
1297 self.history[node] = None
1300 """Return the next node for this walk of the tree.
1302 This function is intentionally iterative, not recursive,
1303 to sidestep any issues of stack size limitations.
1307 if self.stack[-1].wkids:
1308 node = self.stack[-1].wkids.pop(0)
1309 if not self.stack[-1].wkids:
1310 self.stack[-1].wkids = None
1311 if node in self.history:
1312 self.cycle_func(node, self.stack)
1314 node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
1315 self.stack.append(node)
1316 self.history[node] = None
1318 node = self.stack.pop()
1319 del self.history[node]
1322 parent = self.stack[-1]
1325 self.eval_func(node, parent)
1330 return not self.stack
1333 arg2nodes_lookups = []
1337 # indent-tabs-mode:nil
1339 # vim: set expandtab tabstop=4 shiftwidth=4: