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