Allow Alias Nodes to have Actions.
[scons.git] / src / engine / SCons / Node / __init__.py
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__
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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
46
47
48
49 import copy
50 import string
51 import UserList
52
53 from SCons.Debug import logInstanceCreation
54 import SCons.SConsign
55 import SCons.Util
56
57 # Node states
58 #
59 # These are in "priority" order, so that the maximum value for any
60 # child/dependency of a node represents the state of that node if
61 # it has no builder of its own.  The canonical example is a file
62 # system directory, which is only up to date if all of its children
63 # were up to date.
64 pending = 1
65 executing = 2
66 up_to_date = 3
67 executed = 4
68 failed = 5
69 stack = 6 # nodes that are in the current Taskmaster execution stack
70
71 # controls whether implicit depedencies are cached:
72 implicit_cache = 0
73
74 # controls whether implicit dep changes are ignored:
75 implicit_deps_unchanged = 0
76
77 # controls whether the cached implicit deps are ignored:
78 implicit_deps_changed = 0
79
80 # A variable that can be set to an interface-specific function be called
81 # to annotate a Node with information about its creation.
82 def do_nothing(node): pass
83
84 Annotate = do_nothing
85
86 class BuildInfo:
87     def __cmp__(self, other):
88         return cmp(self.__dict__, other.__dict__)
89
90 class Node:
91     """The base Node class, for entities that we know how to
92     build, or use to build other Nodes.
93     """
94
95     class Attrs:
96         pass
97
98     def __init__(self):
99         if __debug__: logInstanceCreation(self, 'Node')
100         # Note that we no longer explicitly initialize a self.builder
101         # attribute to None here.  That's because the self.builder
102         # attribute may be created on-the-fly later by a subclass (the
103         # canonical example being a builder to fetch a file from a
104         # source code system like CVS or Subversion).
105
106         # Each list of children that we maintain is accompanied by a
107         # dictionary used to look up quickly whether a node is already
108         # present in the list.  Empirical tests showed that it was
109         # fastest to maintain them as side-by-side Node attributes in
110         # this way, instead of wrapping up each list+dictionary pair in
111         # a class.  (Of course, we could always still do that in the
112         # future if we had a good reason to...).
113         self.sources = []       # source files used to build node
114         self.sources_dict = {}
115         self.depends = []       # explicit dependencies (from Depends)
116         self.depends_dict = {}
117         self.ignore = []        # dependencies to ignore
118         self.ignore_dict = {}
119         self.implicit = None    # implicit (scanned) dependencies (None means not scanned yet)
120         self.waiting_parents = []
121         self.wkids = None       # Kids yet to walk, when it's an array
122         self.target_scanner = None      # explicit scanner from this node's Builder
123         self.source_scanner = None
124         self.backup_source_scanner = None
125
126         self.env = None
127         self.state = None
128         self.precious = None
129         self.always_build = None
130         self.found_includes = {}
131         self.includes = None
132         self.overrides = {}     # construction variable overrides for building this node
133         self.attributes = self.Attrs() # Generic place to stick information about the Node.
134         self.side_effect = 0 # true iff this node is a side effect
135         self.side_effects = [] # the side effects of building this target
136         self.pre_actions = []
137         self.post_actions = []
138         self.linked = 0 # is this node linked to the build directory? 
139
140         # Let the interface in which the build engine is embedded
141         # annotate this Node with its own info (like a description of
142         # what line in what file created the node, for example).
143         Annotate(self)
144
145     def get_suffix(self):
146         return ''
147
148     def generate_build_dict(self):
149         """Return an appropriate dictionary of values for building
150         this Node."""
151         return {}
152
153     def get_build_env(self):
154         """Fetch the appropriate Environment to build this node."""
155         executor = self.get_executor()
156         return executor.get_build_env()
157
158     def set_executor(self, executor):
159         """Set the action executor for this node."""
160         self.executor = executor
161
162     def get_executor(self, create=1):
163         """Fetch the action executor for this node.  Create one if
164         there isn't already one, and requested to do so."""
165         try:
166             executor = self.executor
167         except AttributeError:
168             if not create:
169                 raise
170             import SCons.Executor
171             act = self.builder.action
172             if self.pre_actions:
173                 act = self.pre_actions + act
174             if self.post_actions:
175                 act = act + self.post_actions
176             executor = SCons.Executor.Executor(act,
177                                                self.env or self.builder.env,
178                                                [self.builder.overrides],
179                                                [self],
180                                                self.sources)
181             self.executor = executor
182         return executor
183
184     def reset_executor(self):
185         "Remove cached executor; forces recompute when needed."
186         try:
187             delattr(self, 'executor')
188         except AttributeError:
189             pass
190
191     def retrieve_from_cache(self):
192         """Try to retrieve the node's content from a cache
193
194         This method is called from multiple threads in a parallel build,
195         so only do thread safe stuff here. Do thread unsafe stuff in
196         built().
197
198         Returns true iff the node was successfully retrieved.
199         """
200         return 0
201         
202     def build(self, **kw):
203         """Actually build the node.
204
205         This method is called from multiple threads in a parallel build,
206         so only do thread safe stuff here. Do thread unsafe stuff in
207         built().
208         """
209         if not self.has_builder():
210             return
211         def errfunc(stat, node=self):
212             raise SCons.Errors.BuildError(node=node, errstr="Error %d" % stat)
213         executor = self.get_executor()
214         apply(executor, (self, errfunc), kw)
215
216     def built(self):
217         """Called just after this node is sucessfully built."""
218
219         # Clear the implicit dependency caches of any Nodes
220         # waiting for this Node to be built.
221         for parent in self.waiting_parents:
222             parent.implicit = None
223             parent.del_binfo()
224         
225         try:
226             new_binfo = self.binfo
227         except AttributeError:
228             # Node arrived here without build info; apparently it
229             # doesn't need it, so don't bother calculating or storing
230             # it.
231             new_binfo = None
232
233         # Reset this Node's cached state since it was just built and
234         # various state has changed.
235         save_state = self.get_state()
236         self.clear()
237         self.set_state(save_state)
238
239         # Had build info, so it should be stored in the signature
240         # cache.  However, if the build info included a content
241         # signature then it should be recalculated before being
242         # stored.
243         
244         if new_binfo:
245             if hasattr(new_binfo, 'csig'):
246                 new_binfo = self.gen_binfo()  # sets self.binfo
247             else:
248                 self.binfo = new_binfo
249             self.store_info(new_binfo)
250
251     def add_to_waiting_parents(self, node):
252         self.waiting_parents.append(node)
253
254     def call_for_all_waiting_parents(self, func):
255         func(self)
256         for parent in self.waiting_parents:
257             parent.call_for_all_waiting_parents(func)
258
259     def postprocess(self):
260         """Clean up anything we don't need to hang onto after we've
261         been built."""
262         try:
263             executor = self.get_executor(create=None)
264         except AttributeError:
265             pass
266         else:
267             executor.cleanup()
268
269     def clear(self):
270         """Completely clear a Node of all its cached state (so that it
271         can be re-evaluated by interfaces that do continuous integration
272         builds).
273         """
274         self.set_state(None)
275         self.del_binfo()
276         self.del_cinfo()
277         try:
278             delattr(self, '_calculated_sig')
279         except AttributeError:
280             pass
281         self.includes = None
282         self.found_includes = {}
283         self.implicit = None
284
285         self.waiting_parents = []
286
287     def visited(self):
288         """Called just after this node has been visited
289         without requiring a build.."""
290         pass
291
292     def depends_on(self, nodes):
293         """Does this node depend on any of 'nodes'?"""
294         for node in nodes:
295             if node in self.children():
296                 return 1
297
298         return 0
299
300     def builder_set(self, builder):
301         self.builder = builder
302
303     def has_builder(self):
304         """Return whether this Node has a builder or not.
305
306         In Boolean tests, this turns out to be a *lot* more efficient
307         than simply examining the builder attribute directly ("if
308         node.builder: ..."). When the builder attribute is examined
309         directly, it ends up calling __getattr__ for both the __len__
310         and __nonzero__ attributes on instances of our Builder Proxy
311         class(es), generating a bazillion extra calls and slowing
312         things down immensely.
313         """
314         try:
315             b = self.builder
316         except AttributeError:
317             # There was no explicit builder for this Node, so initialize
318             # the self.builder attribute to None now.
319             self.builder = None
320             b = self.builder
321         return not b is None
322
323     def has_explicit_builder(self):
324         """Return whether this Node has an explicit builder
325
326         This allows an internal Builder created by SCons to be marked
327         non-explicit, so that it can be overridden by an explicit
328         builder that the user supplies (the canonical example being
329         directories)."""
330         return self.has_builder() and self.builder.is_explicit
331
332     def get_builder(self, default_builder=None):
333         """Return the set builder, or a specified default value"""
334         try:
335             return self.builder
336         except AttributeError:
337             return default_builder
338
339     multiple_side_effect_has_builder = has_builder
340
341     def is_derived(self):
342         """
343         Returns true iff this node is derived (i.e. built).
344
345         This should return true only for nodes whose path should be in
346         the build directory when duplicate=0 and should contribute their build
347         signatures when they are used as source files to other derived files. For
348         example: source with source builders are not derived in this sense,
349         and hence should not return true.
350         """
351         return self.has_builder() or self.side_effect
352
353     def is_pseudo_derived(self):
354         """
355         Returns true iff this node is built, but should use a source path
356         when duplicate=0 and should contribute a content signature (i.e.
357         source signature) when used as a source for other derived files.
358         """
359         return 0
360
361     def alter_targets(self):
362         """Return a list of alternate targets for this Node.
363         """
364         return [], None
365
366     def get_found_includes(self, env, scanner, target):
367         """Return the scanned include lines (implicit dependencies)
368         found in this node.
369
370         The default is no implicit dependencies.  We expect this method
371         to be overridden by any subclass that can be scanned for
372         implicit dependencies.
373         """
374         return []
375
376     def get_implicit_deps(self, env, scanner, target):
377         """Return a list of implicit dependencies for this node.
378
379         This method exists to handle recursive invocation of the scanner
380         on the implicit dependencies returned by the scanner, if the
381         scanner's recursive flag says that we should.
382         """
383         if not scanner:
384             return []
385
386         # Give the scanner a chance to select a more specific scanner
387         # for this Node.
388         scanner = scanner.select(self)
389
390         try:
391             recurse = scanner.recursive
392         except AttributeError:
393             recurse = None
394
395         nodes = [self]
396         seen = {}
397         seen[self] = 1
398         deps = []
399         while nodes:
400            n = nodes.pop(0)
401            d = filter(lambda x, seen=seen: not seen.has_key(x),
402                       n.get_found_includes(env, scanner, target))
403            if d:
404                deps.extend(d)
405                for n in d:
406                    seen[n] = 1
407                if recurse:
408                    nodes.extend(d)
409
410         return deps
411
412     # cache used to make implicit_factory fast.
413     implicit_factory_cache = {}
414     
415     def implicit_factory(self, path):
416         """
417         Turn a cache implicit dependency path into a node.
418         This is called so many times that doing caching
419         here is a significant performance boost.
420         """
421         try:
422             return self.implicit_factory_cache[path]
423         except KeyError:
424             n = self.builder.source_factory(path)
425             self.implicit_factory_cache[path] = n
426             return n
427
428     def get_source_scanner(self, node):
429         """Fetch the source scanner for the specified node
430
431         NOTE:  "self" is the target being built, "node" is
432         the source file for which we want to fetch the scanner.
433         """
434         if self.source_scanner:
435             return self.source_scanner
436         try:
437             scanner = self.builder.source_scanner
438             if scanner:
439                 return scanner
440         except AttributeError:
441             pass
442         return node.backup_source_scanner or None
443
444     def scan(self):
445         """Scan this node's dependents for implicit dependencies."""
446         # Don't bother scanning non-derived files, because we don't
447         # care what their dependencies are.
448         # Don't scan again, if we already have scanned.
449         if not self.implicit is None:
450             return
451         self.implicit = []
452         self.implicit_dict = {}
453         self._children_reset()
454         if not self.has_builder():
455             return
456
457         build_env = self.get_build_env()
458
459         # Here's where we implement --implicit-cache.
460         if implicit_cache and not implicit_deps_changed:
461             implicit = self.get_stored_implicit()
462             if implicit is not None:
463                 implicit = map(self.implicit_factory, implicit)
464                 self._add_child(self.implicit, self.implicit_dict, implicit)
465                 calc = build_env.get_calculator()
466                 if implicit_deps_unchanged or self.current(calc, scan=0):
467                     return
468                 else:
469                     # one of this node's sources has changed, so
470                     # we need to recalculate the implicit deps,
471                     # and the bsig:
472                     self.implicit = []
473                     self.implicit_dict = {}
474                     self._children_reset()
475                     self.del_binfo()
476
477         for child in self.children(scan=0):
478             scanner = self.get_source_scanner(child)
479             if scanner:
480                 deps = child.get_implicit_deps(build_env, scanner, self)
481                 self._add_child(self.implicit, self.implicit_dict, deps)
482
483         # scan this node itself for implicit dependencies
484         deps = self.get_implicit_deps(build_env, self.target_scanner, self)
485         self._add_child(self.implicit, self.implicit_dict, deps)
486
487         # XXX See note above re: --implicit-cache.
488         #if implicit_cache:
489         #    self.store_implicit()
490
491     def scanner_key(self):
492         return None
493
494     def env_set(self, env, safe=0):
495         if safe and self.env:
496             return
497         self.env = env
498
499     def calculator(self):
500         import SCons.Defaults
501         
502         env = self.env or SCons.Defaults.DefaultEnvironment()
503         return env.get_calculator()
504
505     def calc_signature(self, calc=None):
506         """
507         Select and calculate the appropriate build signature for a node.
508
509         self - the node
510         calc - the signature calculation module
511         returns - the signature
512         """
513         try:
514             return self._calculated_sig
515         except AttributeError:
516             if self.is_derived():
517                 import SCons.Defaults
518                 
519                 env = self.env or SCons.Defaults.DefaultEnvironment()
520                 if env.use_build_signature():
521                     sig = self.calc_bsig(calc)
522                 else:
523                     sig = self.calc_csig(calc)
524             elif not self.rexists():
525                 sig = None
526             else:
527                 sig = self.calc_csig(calc)
528             self._calculated_sig = sig
529             return sig
530
531     def new_binfo(self):
532         return BuildInfo()
533
534     def del_binfo(self):
535         """Delete the bsig from this node."""
536         try:
537             delattr(self, 'binfo')
538         except AttributeError:
539             pass
540
541     def calc_bsig(self, calc=None):
542         try:
543             return self.binfo.bsig
544         except AttributeError:
545             self.binfo = self.gen_binfo(calc)
546             return self.binfo.bsig
547
548     def gen_binfo(self, calc=None, scan=1):
549         """
550         Generate a node's build signature, the digested signatures
551         of its dependency files and build information.
552
553         node - the node whose sources will be collected
554         cache - alternate node to use for the signature cache
555         returns - the build signature
556
557         This no longer handles the recursive descent of the
558         node's children's signatures.  We expect that they're
559         already built and updated by someone else, if that's
560         what's wanted.
561         """
562
563         if calc is None:
564             calc = self.calculator()
565
566         binfo = self.new_binfo()
567
568         if scan:
569             self.scan()
570
571         sources = self.filter_ignore(self.sources)
572         depends = self.filter_ignore(self.depends)
573         if self.implicit is None:
574             implicit = []
575         else:
576             implicit = self.filter_ignore(self.implicit)
577
578         def calc_signature(node, calc=calc):
579             return node.calc_signature(calc)
580         sourcesigs = map(calc_signature, sources)
581         dependsigs = map(calc_signature, depends)
582         implicitsigs = map(calc_signature, implicit)
583
584         sigs = sourcesigs + dependsigs + implicitsigs
585
586         if self.has_builder():
587             executor = self.get_executor()
588             binfo.bact = str(executor)
589             binfo.bactsig = calc.module.signature(executor)
590             sigs.append(binfo.bactsig)
591
592         binfo.bsources = map(str, sources)
593         binfo.bdepends = map(str, depends)
594         binfo.bimplicit = map(str, implicit)
595
596         binfo.bsourcesigs = sourcesigs
597         binfo.bdependsigs = dependsigs
598         binfo.bimplicitsigs = implicitsigs
599
600         binfo.bsig = calc.module.collect(filter(None, sigs))
601
602         return binfo
603
604     def del_cinfo(self):
605         try:
606             del self.binfo.csig
607         except AttributeError:
608             pass
609
610     def calc_csig(self, calc=None):
611         try:
612             binfo = self.binfo
613         except AttributeError:
614             binfo = self.binfo = self.new_binfo()
615         try:
616             return binfo.csig
617         except AttributeError:
618             if calc is None:
619                 calc = self.calculator()
620             binfo.csig = calc.module.signature(self)
621             self.store_info(binfo)
622             return binfo.csig
623
624     def store_info(self, obj):
625         """Make the build signature permanent (that is, store it in the
626         .sconsign file or equivalent)."""
627         pass
628
629     def get_stored_info(self):
630         return None
631
632     def get_stored_implicit(self):
633         """Fetch the stored implicit dependencies"""
634         return None
635
636     def set_precious(self, precious = 1):
637         """Set the Node's precious value."""
638         self.precious = precious
639
640     def set_always_build(self, always_build = 1):
641         """Set the Node's always_build value."""
642         self.always_build = always_build
643
644     def exists(self):
645         """Does this node exists?"""
646         # All node exist by default:
647         return 1
648     
649     def rexists(self):
650         """Does this node exist locally or in a repositiory?"""
651         # There are no repositories by default:
652         return self.exists()
653     
654     def prepare(self):
655         """Prepare for this Node to be created.
656         The default implemenation checks that all children either exist
657         or are derived.
658         """
659         def missing(node):
660             return not node.is_derived() and \
661                    not node.is_pseudo_derived() and \
662                    not node.linked and \
663                    not node.rexists()
664         missing_sources = filter(missing, self.children())
665         if missing_sources:
666             desc = "Source `%s' not found, needed by target `%s'." % (missing_sources[0], self)
667             raise SCons.Errors.StopError, desc
668
669     def remove(self):
670         """Remove this Node:  no-op by default."""
671         return None
672
673     def add_dependency(self, depend):
674         """Adds dependencies."""
675         try:
676             self._add_child(self.depends, self.depends_dict, depend)
677         except TypeError, e:
678             e = e.args[0]
679             if SCons.Util.is_List(e):
680                 s = map(str, e)
681             else:
682                 s = str(e)
683             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)))
684
685     def add_ignore(self, depend):
686         """Adds dependencies to ignore."""
687         try:
688             self._add_child(self.ignore, self.ignore_dict, depend)
689         except TypeError, e:
690             e = e.args[0]
691             if SCons.Util.is_List(e):
692                 s = map(str, e)
693             else:
694                 s = str(e)
695             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)))
696
697     def add_source(self, source):
698         """Adds sources."""
699         try:
700             self._add_child(self.sources, self.sources_dict, source)
701         except TypeError, e:
702             e = e.args[0]
703             if SCons.Util.is_List(e):
704                 s = map(str, e)
705             else:
706                 s = str(e)
707             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)))
708
709     def _add_child(self, collection, dict, child):
710         """Adds 'child' to 'collection', first checking 'dict' to see
711         if it's already present."""
712         if type(child) is not type([]):
713             child = [child]
714         for c in child:
715             if not isinstance(c, Node):
716                 raise TypeError, c
717         added = None
718         for c in child:
719             if not dict.has_key(c):
720                 collection.append(c)
721                 dict[c] = 1
722                 added = 1
723         if added:
724             self._children_reset()
725
726     def add_wkid(self, wkid):
727         """Add a node to the list of kids waiting to be evaluated"""
728         if self.wkids != None:
729             self.wkids.append(wkid)
730
731     def _children_reset(self):
732         try:
733             delattr(self, '_children')
734         except AttributeError:
735             pass
736
737     def filter_ignore(self, nodelist):
738         ignore = self.ignore
739         result = []
740         for node in nodelist:
741             if node not in ignore:
742                 result.append(node)
743         return result
744
745     def children(self, scan=1):
746         """Return a list of the node's direct children, minus those
747         that are ignored by this node."""
748         if scan:
749             self.scan()
750         try:
751             return self._children
752         except AttributeError:
753             c = self.all_children(scan=0)
754             self._children = self.filter_ignore(c)
755             return self._children
756
757     def all_children(self, scan=1):
758         """Return a list of all the node's direct children."""
759         # The return list may contain duplicate Nodes, especially in
760         # source trees where there are a lot of repeated #includes
761         # of a tangle of .h files.  Profiling shows, however, that
762         # eliminating the duplicates with a brute-force approach that
763         # preserves the order (that is, something like:
764         #
765         #       u = []
766         #       for n in list:
767         #           if n not in u:
768         #               u.append(n)"
769         #
770         # takes more cycles than just letting the underlying methods
771         # hand back cached values if a Node's information is requested
772         # multiple times.  (Other methods of removing duplicates, like
773         # using dictionary keys, lose the order, and the only ordered
774         # dictionary patterns I found all ended up using "not in"
775         # internally anyway...)
776         if scan:
777             self.scan()
778         if self.implicit is None:
779             return self.sources + self.depends
780         else:
781             return self.sources + self.depends + self.implicit
782
783     def set_state(self, state):
784         self.state = state
785
786     def get_state(self):
787         return self.state
788
789     def current(self, calc=None):
790         """Default check for whether the Node is current: unknown Node
791         subtypes are always out of date, so they will always get built."""
792         return None
793
794     def children_are_up_to_date(self, calc=None):
795         """Alternate check for whether the Node is current:  If all of
796         our children were up-to-date, then this Node was up-to-date, too.
797
798         The SCons.Node.Alias and SCons.Node.Python.Value subclasses
799         rebind their current() method to this method."""
800         # Allow the children to calculate their signatures.
801         self.binfo = self.gen_binfo(calc)
802         state = 0
803         for kid in self.children(None):
804             s = kid.get_state()
805             if s and (not state or s > state):
806                 state = s
807         return (state == 0 or state == SCons.Node.up_to_date)
808
809     def is_literal(self):
810         """Always pass the string representation of a Node to
811         the command interpreter literally."""
812         return 1
813
814     def add_pre_action(self, act):
815         """Adds an Action performed on this Node only before
816         building it."""
817         self.pre_actions.append(act)
818         # executor must be recomputed to include new pre-actions
819         self.reset_executor()
820
821     def add_post_action(self, act):
822         """Adds and Action performed on this Node only after
823         building it."""
824         self.post_actions.append(act)
825         # executor must be recomputed to include new pre-actions
826         self.reset_executor()
827
828     def render_include_tree(self):
829         """
830         Return a text representation, suitable for displaying to the
831         user, of the include tree for the sources of this node.
832         """
833         if self.is_derived() and self.env:
834             env = self.get_build_env()
835             for s in self.sources:
836                 scanner = self.get_source_scanner(s)
837                 def f(node, env=env, scanner=scanner, target=self):
838                     return node.get_found_includes(env, scanner, target)
839                 return SCons.Util.render_tree(s, f, 1)
840         else:
841             return None
842
843     def get_abspath(self):
844         """
845         Return an absolute path to the Node.  This will return simply
846         str(Node) by default, but for Node types that have a concept of
847         relative path, this might return something different.
848         """
849         return str(self)
850
851     def for_signature(self):
852         """
853         Return a string representation of the Node that will always
854         be the same for this particular Node, no matter what.  This
855         is by contrast to the __str__() method, which might, for
856         instance, return a relative path for a file Node.  The purpose
857         of this method is to generate a value to be used in signature
858         calculation for the command line used to build a target, and
859         we use this method instead of str() to avoid unnecessary
860         rebuilds.  This method does not need to return something that
861         would actually work in a command line; it can return any kind of
862         nonsense, so long as it does not change.
863         """
864         return str(self)
865
866     def get_string(self, for_signature):
867         """This is a convenience function designed primarily to be
868         used in command generators (i.e., CommandGeneratorActions or
869         Environment variables that are callable), which are called
870         with a for_signature argument that is nonzero if the command
871         generator is being called to generate a signature for the
872         command line, which determines if we should rebuild or not.
873
874         Such command generators should use this method in preference
875         to str(Node) when converting a Node to a string, passing
876         in the for_signature parameter, such that we will call
877         Node.for_signature() or str(Node) properly, depending on whether
878         we are calculating a signature or actually constructing a
879         command line."""
880         if for_signature:
881             return self.for_signature()
882         return str(self)
883
884     def get_subst_proxy(self):
885         """
886         This method is expected to return an object that will function
887         exactly like this Node, except that it implements any additional
888         special features that we would like to be in effect for
889         Environment variable substitution.  The principle use is that
890         some Nodes would like to implement a __getattr__() method,
891         but putting that in the Node type itself has a tendency to kill
892         performance.  We instead put it in a proxy and return it from
893         this method.  It is legal for this method to return self
894         if no new functionality is needed for Environment substitution.
895         """
896         return self
897
898     def explain(self):
899         if not self.exists():
900             return "building `%s' because it doesn't exist\n" % self
901
902         old = self.get_stored_info()
903         if old is None:
904             return None
905
906         def dictify(result, kids, sigs):
907             for k, s in zip(kids, sigs):
908                 result[k] = s
909
910         try:
911             old_bkids = old.bsources + old.bdepends + old.bimplicit
912         except AttributeError:
913             return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
914
915         osig = {}
916         dictify(osig, old.bsources, old.bsourcesigs)
917         dictify(osig, old.bdepends, old.bdependsigs)
918         dictify(osig, old.bimplicit, old.bimplicitsigs)
919
920         new_bsources = map(str, self.binfo.bsources)
921         new_bdepends = map(str, self.binfo.bdepends)
922         new_bimplicit = map(str, self.binfo.bimplicit)
923
924         nsig = {}
925         dictify(nsig, new_bsources, self.binfo.bsourcesigs)
926         dictify(nsig, new_bdepends, self.binfo.bdependsigs)
927         dictify(nsig, new_bimplicit, self.binfo.bimplicitsigs)
928
929         new_bkids = new_bsources + new_bdepends + new_bimplicit
930         lines = map(lambda x: "`%s' is no longer a dependency\n" % x,
931                     filter(lambda x, nk=new_bkids: not x in nk, old_bkids))
932
933         for k in new_bkids:
934             if not k in old_bkids:
935                 lines.append("`%s' is a new dependency\n" % k)
936             elif osig[k] != nsig[k]:
937                 lines.append("`%s' changed\n" % k)
938
939         if len(lines) == 0 and old_bkids != new_bkids:
940             lines.append("the dependency order changed:\n" +
941                          "%sold: %s\n" % (' '*15, old_bkids) +
942                          "%snew: %s\n" % (' '*15, new_bkids))
943
944         if len(lines) == 0:
945             newact, newactsig = self.binfo.bact, self.binfo.bactsig
946             def fmt_with_title(title, strlines):
947                 lines = string.split(strlines, '\n')
948                 sep = '\n' + ' '*(15 + len(title))
949                 return ' '*15 + title + string.join(lines, sep) + '\n'
950             if old.bactsig != newactsig:
951                 if old.bact == newact:
952                     lines.append("the contents of the build action changed\n" +
953                                  fmt_with_title('action: ', newact))
954                 else:
955                     lines.append("the build action changed:\n" +
956                                  fmt_with_title('old: ', old.bact) +
957                                  fmt_with_title('new: ', newact))
958
959         if len(lines) == 0:
960             return "rebuilding `%s' for unknown reasons\n" % self
961
962         preamble = "rebuilding `%s' because" % self
963         if len(lines) == 1:
964             return "%s %s"  % (preamble, lines[0])
965         else:
966             lines = ["%s:\n" % preamble] + lines
967             return string.join(lines, ' '*11)
968
969 l = [1]
970 ul = UserList.UserList([2])
971 try:
972     l.extend(ul)
973 except TypeError:
974     def NodeList(l):
975         return l
976 else:
977     class NodeList(UserList.UserList):
978         def __str__(self):
979             return str(map(str, self.data))
980 del l
981 del ul
982
983 def get_children(node, parent): return node.children()
984 def ignore_cycle(node, stack): pass
985 def do_nothing(node, parent): pass
986
987 class Walker:
988     """An iterator for walking a Node tree.
989
990     This is depth-first, children are visited before the parent.
991     The Walker object can be initialized with any node, and
992     returns the next node on the descent with each next() call.
993     'kids_func' is an optional function that will be called to
994     get the children of a node instead of calling 'children'.
995     'cycle_func' is an optional function that will be called
996     when a cycle is detected.
997
998     This class does not get caught in node cycles caused, for example,
999     by C header file include loops.
1000     """
1001     def __init__(self, node, kids_func=get_children,
1002                              cycle_func=ignore_cycle,
1003                              eval_func=do_nothing):
1004         self.kids_func = kids_func
1005         self.cycle_func = cycle_func
1006         self.eval_func = eval_func
1007         node.wkids = copy.copy(kids_func(node, None))
1008         self.stack = [node]
1009         self.history = {} # used to efficiently detect and avoid cycles
1010         self.history[node] = None
1011
1012     def next(self):
1013         """Return the next node for this walk of the tree.
1014
1015         This function is intentionally iterative, not recursive,
1016         to sidestep any issues of stack size limitations.
1017         """
1018
1019         while self.stack:
1020             if self.stack[-1].wkids:
1021                 node = self.stack[-1].wkids.pop(0)
1022                 if not self.stack[-1].wkids:
1023                     self.stack[-1].wkids = None
1024                 if self.history.has_key(node):
1025                     self.cycle_func(node, self.stack)
1026                 else:
1027                     node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
1028                     self.stack.append(node)
1029                     self.history[node] = None
1030             else:
1031                 node = self.stack.pop()
1032                 del self.history[node]
1033                 if node:
1034                     if self.stack:
1035                         parent = self.stack[-1]
1036                     else:
1037                         parent = None
1038                     self.eval_func(node, parent)
1039                 return node
1040         return None
1041
1042     def is_done(self):
1043         return not self.stack
1044
1045
1046 arg2nodes_lookups = []