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