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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 __revision__ = "src/engine/SCons/Node/__init__.py 3842 2008/12/20 22:59:52 scons"
46
47 import copy
48 from itertools import chain, izip
49 import string
50 import UserList
51
52 from SCons.Debug import logInstanceCreation
53 import SCons.Executor
54 import SCons.Memoize
55 import SCons.Util
56
57 from SCons.Debug import Trace
58
61
62
63
64
65
66
67
68
69 no_state = 0
70 pending = 1
71 executing = 2
72 up_to_date = 3
73 executed = 4
74 failed = 5
75
76 StateString = {
77 0 : "no_state",
78 1 : "pending",
79 2 : "executing",
80 3 : "up_to_date",
81 4 : "executed",
82 5 : "failed",
83 }
84
85
86 implicit_cache = 0
87
88
89 implicit_deps_unchanged = 0
90
91
92 implicit_deps_changed = 0
93
94
95
97
98 Annotate = do_nothing
99
100
101
103 """
104 The generic base class for signature information for a Node.
105
106 Node subclasses should subclass NodeInfoBase to provide their own
107 logic for dealing with their own Node-specific signature information.
108 """
109 current_version_id = 1
115 try:
116 field_list = self.field_list
117 except AttributeError:
118 return
119 for f in field_list:
120 try:
121 delattr(self, f)
122 except AttributeError:
123 pass
124 try:
125 func = getattr(node, 'get_' + f)
126 except AttributeError:
127 pass
128 else:
129 setattr(self, f, func())
133 self.__dict__.update(other.__dict__)
152
154 """
155 The generic base class for build information for a Node.
156
157 This is what gets stored in a .sconsign file for each target file.
158 It contains a NodeInfo instance for this node (signature information
159 that's specific to the type of Node) and direct attributes for the
160 generic build stuff we have to track: sources, explicit dependencies,
161 implicit dependencies, and action information.
162 """
163 current_version_id = 1
165
166
167 self._version_id = self.current_version_id
168 self.bsourcesigs = []
169 self.bdependsigs = []
170 self.bimplicitsigs = []
171 self.bactsig = None
173 self.__dict__.update(other.__dict__)
174
176 """The base Node class, for entities that we know how to
177 build, or use to build other Nodes.
178 """
179
180 if SCons.Memoize.use_memoizer:
181 __metaclass__ = SCons.Memoize.Memoized_Metaclass
182
183 memoizer_counters = []
184
187
189 if __debug__: logInstanceCreation(self, 'Node.Node')
190
191
192
193
194
195
196
197
198
199
200
201
202
203 self.sources = []
204 self.sources_set = set()
205 self._specific_sources = False
206 self.depends = []
207 self.depends_set = set()
208 self.ignore = []
209 self.ignore_set = set()
210 self.prerequisites = SCons.Util.UniqueList()
211 self.implicit = None
212 self.waiting_parents = set()
213 self.waiting_s_e = set()
214 self.ref_count = 0
215 self.wkids = None
216
217 self.env = None
218 self.state = no_state
219 self.precious = None
220 self.noclean = 0
221 self.nocache = 0
222 self.always_build = None
223 self.includes = None
224 self.attributes = self.Attrs()
225 self.side_effect = 0
226 self.side_effects = []
227 self.linked = 0
228
229 self.clear_memoized_values()
230
231
232
233
234 Annotate(self)
235
238
241
242 memoizer_counters.append(SCons.Memoize.CountValue('get_build_env'))
243
245 """Fetch the appropriate Environment to build this node.
246 """
247 try:
248 return self._memo['get_build_env']
249 except KeyError:
250 pass
251 result = self.get_executor().get_build_env()
252 self._memo['get_build_env'] = result
253 return result
254
258
260 """Set the action executor for this node."""
261 self.executor = executor
262
264 """Fetch the action executor for this node. Create one if
265 there isn't already one, and requested to do so."""
266 try:
267 executor = self.executor
268 except AttributeError:
269 if not create:
270 raise
271 try:
272 act = self.builder.action
273 except AttributeError:
274 executor = SCons.Executor.Null(targets=[self])
275 else:
276 executor = SCons.Executor.Executor(act,
277 self.env or self.builder.env,
278 [self.builder.overrides],
279 [self],
280 self.sources)
281 self.executor = executor
282 return executor
283
285 """Let the executor clean up any cached information."""
286 try:
287 executor = self.get_executor(create=None)
288 except AttributeError:
289 pass
290 else:
291 executor.cleanup()
292
294 "Remove cached executor; forces recompute when needed."
295 try:
296 delattr(self, 'executor')
297 except AttributeError:
298 pass
299
301 """Try to retrieve the node's content from a cache
302
303 This method is called from multiple threads in a parallel build,
304 so only do thread safe stuff here. Do thread unsafe stuff in
305 built().
306
307 Returns true iff the node was successfully retrieved.
308 """
309 return 0
310
311
312
313
314
316 """Get a Node ready for evaluation.
317
318 This is called before the Taskmaster decides if the Node is
319 up-to-date or not. Overriding this method allows for a Node
320 subclass to be disambiguated if necessary, or for an implicit
321 source builder to be attached.
322 """
323 pass
324
326 """Prepare for this Node to be built.
327
328 This is called after the Taskmaster has decided that the Node
329 is out-of-date and must be rebuilt, but before actually calling
330 the method to build the Node.
331
332 This default implementation checks that explicit or implicit
333 dependencies either exist or are derived, and initializes the
334 BuildInfo structure that will hold the information about how
335 this node is, uh, built.
336
337 (The existence of source files is checked separately by the
338 Executor, which aggregates checks for all of the targets built
339 by a specific action.)
340
341 Overriding this method allows for for a Node subclass to remove
342 the underlying file from the file system. Note that subclass
343 methods should call this base class method to get the child
344 check and the BuildInfo structure.
345 """
346 for d in self.depends:
347 if d.missing():
348 msg = "Explicit dependency `%s' not found, needed by target `%s'."
349 raise SCons.Errors.StopError, msg % (d, self)
350 if not self.implicit is None:
351 for i in self.implicit:
352 if i.missing():
353 msg = "Implicit dependency `%s' not found, needed by target `%s'."
354 raise SCons.Errors.StopError, msg % (i, self)
355 self.binfo = self.get_binfo()
356
358 """Actually build the node.
359
360 This is called by the Taskmaster after it's decided that the
361 Node is out-of-date and must be rebuilt, and after the prepare()
362 method has gotten everything, uh, prepared.
363
364 This method is called from multiple threads in a parallel build,
365 so only do thread safe stuff here. Do thread unsafe stuff
366 in built().
367
368 """
369 try:
370 apply(self.get_executor(), (self,), kw)
371 except SCons.Errors.BuildError, e:
372 e.node = self
373 raise
374
376 """Called just after this node is successfully built."""
377
378
379
380 for parent in self.waiting_parents:
381 parent.implicit = None
382
383 self.clear()
384
385 self.ninfo.update(self)
386
388 """Called just after this node has been visited (with or
389 without a build)."""
390 try:
391 binfo = self.binfo
392 except AttributeError:
393
394
395 pass
396 else:
397 self.ninfo.update(self)
398 self.store_info()
399
400
401
402
403
405 self.waiting_s_e.add(node)
406
408 """
409 Returns the number of nodes added to our waiting parents list:
410 1 if we add a unique waiting parent, 0 if not. (Note that the
411 returned values are intended to be used to increment a reference
412 count, so don't think you can "clean up" this function by using
413 True and False instead...)
414 """
415 wp = self.waiting_parents
416 if node in wp:
417 return 0
418 wp.add(node)
419 return 1
420
421 - def postprocess(self):
422 """Clean up anything we don't need to hang onto after we've
423 been built."""
424 self.executor_cleanup()
425 self.waiting_parents = set()
426
428 """Completely clear a Node of all its cached state (so that it
429 can be re-evaluated by interfaces that do continuous integration
430 builds).
431 """
432
433
434
435 self.del_binfo()
436 self.clear_memoized_values()
437 self.ninfo = self.new_ninfo()
438 self.executor_cleanup()
439 try:
440 delattr(self, '_calculated_sig')
441 except AttributeError:
442 pass
443 self.includes = None
444
447
449 self.builder = builder
450 try:
451 del self.executor
452 except AttributeError:
453 pass
454
456 """Return whether this Node has a builder or not.
457
458 In Boolean tests, this turns out to be a *lot* more efficient
459 than simply examining the builder attribute directly ("if
460 node.builder: ..."). When the builder attribute is examined
461 directly, it ends up calling __getattr__ for both the __len__
462 and __nonzero__ attributes on instances of our Builder Proxy
463 class(es), generating a bazillion extra calls and slowing
464 things down immensely.
465 """
466 try:
467 b = self.builder
468 except AttributeError:
469
470
471 b = self.builder = None
472 return not b is None
473
475 self.is_explicit = is_explicit
476
478 """Return whether this Node has an explicit builder
479
480 This allows an internal Builder created by SCons to be marked
481 non-explicit, so that it can be overridden by an explicit
482 builder that the user supplies (the canonical example being
483 directories)."""
484 try:
485 return self.is_explicit
486 except AttributeError:
487 self.is_explicit = None
488 return self.is_explicit
489
491 """Return the set builder, or a specified default value"""
492 try:
493 return self.builder
494 except AttributeError:
495 return default_builder
496
497 multiple_side_effect_has_builder = has_builder
498
500 """
501 Returns true iff this node is derived (i.e. built).
502
503 This should return true only for nodes whose path should be in
504 the variant directory when duplicate=0 and should contribute their build
505 signatures when they are used as source files to other derived files. For
506 example: source with source builders are not derived in this sense,
507 and hence should not return true.
508 """
509 return self.has_builder() or self.side_effect
510
512 """Return a list of alternate targets for this Node.
513 """
514 return [], None
515
517 """Return the scanned include lines (implicit dependencies)
518 found in this node.
519
520 The default is no implicit dependencies. We expect this method
521 to be overridden by any subclass that can be scanned for
522 implicit dependencies.
523 """
524 return []
525
527 """Return a list of implicit dependencies for this node.
528
529 This method exists to handle recursive invocation of the scanner
530 on the implicit dependencies returned by the scanner, if the
531 scanner's recursive flag says that we should.
532 """
533 if not scanner:
534 return []
535
536
537
538
539
540 nodes = [self]
541 seen = {}
542 seen[self] = 1
543 deps = []
544 while nodes:
545 n = nodes.pop(0)
546 d = filter(lambda x, seen=seen: not seen.has_key(x),
547 n.get_found_includes(env, scanner, path))
548 if d:
549 deps.extend(d)
550 for n in d:
551 seen[n] = 1
552 nodes.extend(scanner.recurse_nodes(d))
553
554 return deps
555
558
560 return self.builder.target_scanner
561
563 """Fetch the source scanner for the specified node
564
565 NOTE: "self" is the target being built, "node" is
566 the source file for which we want to fetch the scanner.
567
568 Implies self.has_builder() is true; again, expect to only be
569 called from locations where this is already verified.
570
571 This function may be called very often; it attempts to cache
572 the scanner found to improve performance.
573 """
574 scanner = None
575 try:
576 scanner = self.builder.source_scanner
577 except AttributeError:
578 pass
579 if not scanner:
580
581
582
583 scanner = self.get_env_scanner(self.get_build_env())
584 if scanner:
585 scanner = scanner.select(node)
586 return scanner
587
589 if not hasattr(self, 'implicit') or self.implicit is None:
590 self.implicit = []
591 self.implicit_set = set()
592 self._children_reset()
593 self._add_child(self.implicit, self.implicit_set, deps)
594
642
645
647 """Selects a scanner for this Node.
648
649 This is a separate method so it can be overridden by Node
650 subclasses (specifically, Node.FS.Dir) that *must* use their
651 own Scanner and don't select one the Scanner.Selector that's
652 configured for the target.
653 """
654 return scanner.select(self)
655
657 if safe and self.env:
658 return
659 self.env = env
660
661
662
663
664
665 NodeInfo = NodeInfoBase
666 BuildInfo = BuildInfoBase
667
669 ninfo = self.NodeInfo(self)
670 return ninfo
671
673 try:
674 return self.ninfo
675 except AttributeError:
676 self.ninfo = self.new_ninfo()
677 return self.ninfo
678
680 binfo = self.BuildInfo(self)
681 return binfo
682
684 """
685 Fetch a node's build information.
686
687 node - the node whose sources will be collected
688 cache - alternate node to use for the signature cache
689 returns - the build signature
690
691 This no longer handles the recursive descent of the
692 node's children's signatures. We expect that they're
693 already built and updated by someone else, if that's
694 what's wanted.
695 """
696 try:
697 return self.binfo
698 except AttributeError:
699 pass
700
701 binfo = self.new_binfo()
702 self.binfo = binfo
703
704 executor = self.get_executor()
705 ignore_set = self.ignore_set
706
707 if self.has_builder():
708 binfo.bact = str(executor)
709 binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
710
711 if self._specific_sources:
712 sources = []
713 for s in self.sources:
714 if s not in ignore_set:
715 sources.append(s)
716 else:
717 sources = executor.get_unignored_sources(self.ignore)
718 seen = set()
719 bsources = []
720 bsourcesigs = []
721 for s in sources:
722 if not s in seen:
723 seen.add(s)
724 bsources.append(s)
725 bsourcesigs.append(s.get_ninfo())
726 binfo.bsources = bsources
727 binfo.bsourcesigs = bsourcesigs
728
729 depends = self.depends
730 dependsigs = []
731 for d in depends:
732 if d not in ignore_set:
733 dependsigs.append(d.get_ninfo())
734 binfo.bdepends = depends
735 binfo.bdependsigs = dependsigs
736
737 implicit = self.implicit or []
738 implicitsigs = []
739 for i in implicit:
740 if i not in ignore_set:
741 implicitsigs.append(i.get_ninfo())
742 binfo.bimplicit = implicit
743 binfo.bimplicitsigs = implicitsigs
744
745 return binfo
746
748 """Delete the build info from this node."""
749 try:
750 delattr(self, 'binfo')
751 except AttributeError:
752 pass
753
755 try:
756 return self.ninfo.csig
757 except AttributeError:
758 ninfo = self.get_ninfo()
759 ninfo.csig = SCons.Util.MD5signature(self.get_contents())
760 return self.ninfo.csig
761
764
766 """Make the build signature permanent (that is, store it in the
767 .sconsign file or equivalent)."""
768 pass
769
772
775
777 """Fetch the stored implicit dependencies"""
778 return None
779
780
781
782
783
785 """Set the Node's precious value."""
786 self.precious = precious
787
789 """Set the Node's noclean value."""
790
791
792 self.noclean = noclean and 1 or 0
793
795 """Set the Node's nocache value."""
796
797
798 self.nocache = nocache and 1 or 0
799
801 """Set the Node's always_build value."""
802 self.always_build = always_build
803
805 """Does this node exists?"""
806
807 return 1
808
810 """Does this node exist locally or in a repositiory?"""
811
812 return self.exists()
813
815 return not self.is_derived() and \
816 not self.linked and \
817 not self.rexists()
818
820 """Remove this Node: no-op by default."""
821 return None
822
824 """Adds dependencies."""
825 try:
826 self._add_child(self.depends, self.depends_set, depend)
827 except TypeError, e:
828 e = e.args[0]
829 if SCons.Util.is_List(e):
830 s = map(str, e)
831 else:
832 s = str(e)
833 raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
834
839
841 """Adds dependencies to ignore."""
842 try:
843 self._add_child(self.ignore, self.ignore_set, depend)
844 except TypeError, e:
845 e = e.args[0]
846 if SCons.Util.is_List(e):
847 s = map(str, e)
848 else:
849 s = str(e)
850 raise SCons.Errors.UserError("attempted to ignore a non-Node dependency of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
851
853 """Adds sources."""
854 if self._specific_sources:
855 return
856 try:
857 self._add_child(self.sources, self.sources_set, source)
858 except TypeError, e:
859 e = e.args[0]
860 if SCons.Util.is_List(e):
861 s = map(str, e)
862 else:
863 s = str(e)
864 raise SCons.Errors.UserError("attempted to add a non-Node as source of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
865
867 """Adds 'child' to 'collection', first checking 'set' to see if it's
868 already present."""
869
870
871
872
873
874 added = None
875 for c in child:
876 if c not in set:
877 set.add(c)
878 collection.append(c)
879 added = 1
880 if added:
881 self._children_reset()
882
886
888 """Add a node to the list of kids waiting to be evaluated"""
889 if self.wkids != None:
890 self.wkids.append(wkid)
891
897
898 memoizer_counters.append(SCons.Memoize.CountValue('_children_get'))
899
901 try:
902 return self._memo['children_get']
903 except KeyError:
904 pass
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923 if self.ignore_set:
924 if self.implicit is None:
925 iter = chain(self.sources,self.depends)
926 else:
927 iter = chain(self.sources, self.depends, self.implicit)
928
929 children = []
930 for i in iter:
931 if i not in self.ignore_set:
932 children.append(i)
933 else:
934 if self.implicit is None:
935 children = self.sources + self.depends
936 else:
937 children = self.sources + self.depends + self.implicit
938
939 self._memo['children_get'] = children
940 return children
941
943 """Return a list of all the node's direct children."""
944 if scan:
945 self.scan()
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964 if self.implicit is None:
965 return self.sources + self.depends
966 else:
967 return self.sources + self.depends + self.implicit
968
970 """Return a list of the node's direct children, minus those
971 that are ignored by this node."""
972 if scan:
973 self.scan()
974 return self._children_get()
975
978
981
984
991
993 """
994
995 Must be overridden in a specific subclass to return True if this
996 Node (a dependency) has changed since the last time it was used
997 to build the specified target. prev_ni is this Node's state (for
998 example, its file timestamp, length, maybe content signature)
999 as of the last time the target was built.
1000
1001 Note that this method is called through the dependency, not the
1002 target, because a dependency Node must be able to use its own
1003 logic to decide if it changed. For example, File Nodes need to
1004 obey if we're configured to use timestamps, but Python Value Nodes
1005 never use timestamps and always use the content. If this method
1006 were called through the target, then each Node's implementation
1007 of this method would have to have more complicated logic to
1008 handle all the different Node types on which it might depend.
1009 """
1010 raise NotImplementedError
1011
1014
1016 """
1017 Returns if the node is up-to-date with respect to the BuildInfo
1018 stored last time it was built. The default behavior is to compare
1019 it against our own previously stored BuildInfo, but the stored
1020 BuildInfo from another Node (typically one in a Repository)
1021 can be used instead.
1022
1023 Note that we now *always* check every dependency. We used to
1024 short-circuit the check by returning as soon as we detected
1025 any difference, but we now rely on checking every dependency
1026 to make sure that any necessary Node information (for example,
1027 the content signature of an #included .h file) is updated.
1028 """
1029 t = 0
1030 if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node))
1031 if node is None:
1032 node = self
1033
1034 result = False
1035
1036 bi = node.get_stored_info().binfo
1037 then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs
1038 children = self.children()
1039
1040 diff = len(children) - len(then)
1041 if diff:
1042
1043
1044
1045
1046
1047 then.extend([None] * diff)
1048 if t: Trace(': old %s new %s' % (len(then), len(children)))
1049 result = True
1050
1051 for child, prev_ni in izip(children, then):
1052 if child.changed_since_last_build(self, prev_ni):
1053 if t: Trace(': %s changed' % child)
1054 result = True
1055
1056 contents = self.get_executor().get_contents()
1057 if self.has_builder():
1058 import SCons.Util
1059 newsig = SCons.Util.MD5signature(contents)
1060 if bi.bactsig != newsig:
1061 if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
1062 result = True
1063
1064 if not result:
1065 if t: Trace(': up to date')
1066
1067 if t: Trace('\n')
1068
1069 return result
1070
1072 """Default check for whether the Node is current: unknown Node
1073 subtypes are always out of date, so they will always get built."""
1074 return None
1075
1077 """Alternate check for whether the Node is current: If all of
1078 our children were up-to-date, then this Node was up-to-date, too.
1079
1080 The SCons.Node.Alias and SCons.Node.Python.Value subclasses
1081 rebind their current() method to this method."""
1082
1083 self.binfo = self.get_binfo()
1084 if self.always_build:
1085 return None
1086 state = 0
1087 for kid in self.children(None):
1088 s = kid.get_state()
1089 if s and (not state or s > state):
1090 state = s
1091 return (state == 0 or state == SCons.Node.up_to_date)
1092
1094 """Always pass the string representation of a Node to
1095 the command interpreter literally."""
1096 return 1
1097
1099 """
1100 Return a text representation, suitable for displaying to the
1101 user, of the include tree for the sources of this node.
1102 """
1103 if self.is_derived() and self.env:
1104 env = self.get_build_env()
1105 for s in self.sources:
1106 scanner = self.get_source_scanner(s)
1107 if scanner:
1108 path = self.get_build_scanner_path(scanner)
1109 else:
1110 path = None
1111 def f(node, env=env, scanner=scanner, path=path):
1112 return node.get_found_includes(env, scanner, path)
1113 return SCons.Util.render_tree(s, f, 1)
1114 else:
1115 return None
1116
1118 """
1119 Return an absolute path to the Node. This will return simply
1120 str(Node) by default, but for Node types that have a concept of
1121 relative path, this might return something different.
1122 """
1123 return str(self)
1124
1126 """
1127 Return a string representation of the Node that will always
1128 be the same for this particular Node, no matter what. This
1129 is by contrast to the __str__() method, which might, for
1130 instance, return a relative path for a file Node. The purpose
1131 of this method is to generate a value to be used in signature
1132 calculation for the command line used to build a target, and
1133 we use this method instead of str() to avoid unnecessary
1134 rebuilds. This method does not need to return something that
1135 would actually work in a command line; it can return any kind of
1136 nonsense, so long as it does not change.
1137 """
1138 return str(self)
1139
1141 """This is a convenience function designed primarily to be
1142 used in command generators (i.e., CommandGeneratorActions or
1143 Environment variables that are callable), which are called
1144 with a for_signature argument that is nonzero if the command
1145 generator is being called to generate a signature for the
1146 command line, which determines if we should rebuild or not.
1147
1148 Such command generators should use this method in preference
1149 to str(Node) when converting a Node to a string, passing
1150 in the for_signature parameter, such that we will call
1151 Node.for_signature() or str(Node) properly, depending on whether
1152 we are calculating a signature or actually constructing a
1153 command line."""
1154 if for_signature:
1155 return self.for_signature()
1156 return str(self)
1157
1159 """
1160 This method is expected to return an object that will function
1161 exactly like this Node, except that it implements any additional
1162 special features that we would like to be in effect for
1163 Environment variable substitution. The principle use is that
1164 some Nodes would like to implement a __getattr__() method,
1165 but putting that in the Node type itself has a tendency to kill
1166 performance. We instead put it in a proxy and return it from
1167 this method. It is legal for this method to return self
1168 if no new functionality is needed for Environment substitution.
1169 """
1170 return self
1171
1173 if not self.exists():
1174 return "building `%s' because it doesn't exist\n" % self
1175
1176 if self.always_build:
1177 return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
1178
1179 old = self.get_stored_info()
1180 if old is None:
1181 return None
1182
1183 old = old.binfo
1184 old.prepare_dependencies()
1185
1186 try:
1187 old_bkids = old.bsources + old.bdepends + old.bimplicit
1188 old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs
1189 except AttributeError:
1190 return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
1191
1192 new = self.get_binfo()
1193
1194 new_bkids = new.bsources + new.bdepends + new.bimplicit
1195 new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
1196
1197 osig = dict(izip(old_bkids, old_bkidsigs))
1198 nsig = dict(izip(new_bkids, new_bkidsigs))
1199
1200
1201
1202
1203
1204
1205
1206 def stringify( s, E=self.dir.Entry ) :
1207 if hasattr( s, 'dir' ) :
1208 return str(E(s))
1209 return str(s)
1210
1211 lines = []
1212
1213 removed = filter(lambda x, nk=new_bkids: not x in nk, old_bkids)
1214 if removed:
1215 removed = map(stringify, removed)
1216 fmt = "`%s' is no longer a dependency\n"
1217 lines.extend(map(lambda s, fmt=fmt: fmt % s, removed))
1218
1219 for k in new_bkids:
1220 if not k in old_bkids:
1221 lines.append("`%s' is a new dependency\n" % stringify(k))
1222 elif k.changed_since_last_build(self, osig[k]):
1223 lines.append("`%s' changed\n" % stringify(k))
1224
1225 if len(lines) == 0 and old_bkids != new_bkids:
1226 lines.append("the dependency order changed:\n" +
1227 "%sold: %s\n" % (' '*15, map(stringify, old_bkids)) +
1228 "%snew: %s\n" % (' '*15, map(stringify, new_bkids)))
1229
1230 if len(lines) == 0:
1231 def fmt_with_title(title, strlines):
1232 lines = string.split(strlines, '\n')
1233 sep = '\n' + ' '*(15 + len(title))
1234 return ' '*15 + title + string.join(lines, sep) + '\n'
1235 if old.bactsig != new.bactsig:
1236 if old.bact == new.bact:
1237 lines.append("the contents of the build action changed\n" +
1238 fmt_with_title('action: ', new.bact))
1239 else:
1240 lines.append("the build action changed:\n" +
1241 fmt_with_title('old: ', old.bact) +
1242 fmt_with_title('new: ', new.bact))
1243
1244 if len(lines) == 0:
1245 return "rebuilding `%s' for unknown reasons\n" % self
1246
1247 preamble = "rebuilding `%s' because" % self
1248 if len(lines) == 1:
1249 return "%s %s" % (preamble, lines[0])
1250 else:
1251 lines = ["%s:\n" % preamble] + lines
1252 return string.join(lines, ' '*11)
1253
1254 try:
1255 [].extend(UserList.UserList([]))
1256 except TypeError:
1257
1258
1259
1262 else:
1265 return str(map(str, self.data))
1266
1270
1272 """An iterator for walking a Node tree.
1273
1274 This is depth-first, children are visited before the parent.
1275 The Walker object can be initialized with any node, and
1276 returns the next node on the descent with each next() call.
1277 'kids_func' is an optional function that will be called to
1278 get the children of a node instead of calling 'children'.
1279 'cycle_func' is an optional function that will be called
1280 when a cycle is detected.
1281
1282 This class does not get caught in node cycles caused, for example,
1283 by C header file include loops.
1284 """
1285 - def __init__(self, node, kids_func=get_children,
1286 cycle_func=ignore_cycle,
1287 eval_func=do_nothing):
1288 self.kids_func = kids_func
1289 self.cycle_func = cycle_func
1290 self.eval_func = eval_func
1291 node.wkids = copy.copy(kids_func(node, None))
1292 self.stack = [node]
1293 self.history = {}
1294 self.history[node] = None
1295
1297 """Return the next node for this walk of the tree.
1298
1299 This function is intentionally iterative, not recursive,
1300 to sidestep any issues of stack size limitations.
1301 """
1302
1303 while self.stack:
1304 if self.stack[-1].wkids:
1305 node = self.stack[-1].wkids.pop(0)
1306 if not self.stack[-1].wkids:
1307 self.stack[-1].wkids = None
1308 if self.history.has_key(node):
1309 self.cycle_func(node, self.stack)
1310 else:
1311 node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
1312 self.stack.append(node)
1313 self.history[node] = None
1314 else:
1315 node = self.stack.pop()
1316 del self.history[node]
1317 if node:
1318 if self.stack:
1319 parent = self.stack[-1]
1320 else:
1321 parent = None
1322 self.eval_func(node, parent)
1323 return node
1324 return None
1325
1327 return not self.stack
1328
1329
1330 arg2nodes_lookups = []
1331