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 5110 2010/07/25 16:14:38 bdeegan"
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 push a node into a cache
302 """
303 pass
304
306 """Try to retrieve the node's content from a cache
307
308 This method is called from multiple threads in a parallel build,
309 so only do thread safe stuff here. Do thread unsafe stuff in
310 built().
311
312 Returns true iff the node was successfully retrieved.
313 """
314 return 0
315
316
317
318
319
321 """Get a Node ready for evaluation.
322
323 This is called before the Taskmaster decides if the Node is
324 up-to-date or not. Overriding this method allows for a Node
325 subclass to be disambiguated if necessary, or for an implicit
326 source builder to be attached.
327 """
328 pass
329
331 """Prepare for this Node to be built.
332
333 This is called after the Taskmaster has decided that the Node
334 is out-of-date and must be rebuilt, but before actually calling
335 the method to build the Node.
336
337 This default implementation checks that explicit or implicit
338 dependencies either exist or are derived, and initializes the
339 BuildInfo structure that will hold the information about how
340 this node is, uh, built.
341
342 (The existence of source files is checked separately by the
343 Executor, which aggregates checks for all of the targets built
344 by a specific action.)
345
346 Overriding this method allows for for a Node subclass to remove
347 the underlying file from the file system. Note that subclass
348 methods should call this base class method to get the child
349 check and the BuildInfo structure.
350 """
351 for d in self.depends:
352 if d.missing():
353 msg = "Explicit dependency `%s' not found, needed by target `%s'."
354 raise SCons.Errors.StopError, msg % (d, self)
355 if self.implicit is not None:
356 for i in self.implicit:
357 if i.missing():
358 msg = "Implicit dependency `%s' not found, needed by target `%s'."
359 raise SCons.Errors.StopError, msg % (i, self)
360 self.binfo = self.get_binfo()
361
363 """Actually build the node.
364
365 This is called by the Taskmaster after it's decided that the
366 Node is out-of-date and must be rebuilt, and after the prepare()
367 method has gotten everything, uh, prepared.
368
369 This method is called from multiple threads in a parallel build,
370 so only do thread safe stuff here. Do thread unsafe stuff
371 in built().
372
373 """
374 try:
375 apply(self.get_executor(), (self,), kw)
376 except SCons.Errors.BuildError, e:
377 e.node = self
378 raise
379
381 """Called just after this node is successfully built."""
382
383
384
385 for parent in self.waiting_parents:
386 parent.implicit = None
387
388 self.clear()
389
390 self.ninfo.update(self)
391
393 """Called just after this node has been visited (with or
394 without a build)."""
395 try:
396 binfo = self.binfo
397 except AttributeError:
398
399
400 pass
401 else:
402 self.ninfo.update(self)
403 self.store_info()
404
405
406
407
408
410 self.waiting_s_e.add(node)
411
413 """
414 Returns the number of nodes added to our waiting parents list:
415 1 if we add a unique waiting parent, 0 if not. (Note that the
416 returned values are intended to be used to increment a reference
417 count, so don't think you can "clean up" this function by using
418 True and False instead...)
419 """
420 wp = self.waiting_parents
421 if node in wp:
422 return 0
423 wp.add(node)
424 return 1
425
426 - def postprocess(self):
427 """Clean up anything we don't need to hang onto after we've
428 been built."""
429 self.executor_cleanup()
430 self.waiting_parents = set()
431
433 """Completely clear a Node of all its cached state (so that it
434 can be re-evaluated by interfaces that do continuous integration
435 builds).
436 """
437
438
439
440 self.del_binfo()
441 self.clear_memoized_values()
442 self.ninfo = self.new_ninfo()
443 self.executor_cleanup()
444 try:
445 delattr(self, '_calculated_sig')
446 except AttributeError:
447 pass
448 self.includes = None
449
452
454 self.builder = builder
455 try:
456 del self.executor
457 except AttributeError:
458 pass
459
461 """Return whether this Node has a builder or not.
462
463 In Boolean tests, this turns out to be a *lot* more efficient
464 than simply examining the builder attribute directly ("if
465 node.builder: ..."). When the builder attribute is examined
466 directly, it ends up calling __getattr__ for both the __len__
467 and __nonzero__ attributes on instances of our Builder Proxy
468 class(es), generating a bazillion extra calls and slowing
469 things down immensely.
470 """
471 try:
472 b = self.builder
473 except AttributeError:
474
475
476 b = self.builder = None
477 return b is not None
478
480 self.is_explicit = is_explicit
481
483 """Return whether this Node has an explicit builder
484
485 This allows an internal Builder created by SCons to be marked
486 non-explicit, so that it can be overridden by an explicit
487 builder that the user supplies (the canonical example being
488 directories)."""
489 try:
490 return self.is_explicit
491 except AttributeError:
492 self.is_explicit = None
493 return self.is_explicit
494
496 """Return the set builder, or a specified default value"""
497 try:
498 return self.builder
499 except AttributeError:
500 return default_builder
501
502 multiple_side_effect_has_builder = has_builder
503
505 """
506 Returns true iff this node is derived (i.e. built).
507
508 This should return true only for nodes whose path should be in
509 the variant directory when duplicate=0 and should contribute their build
510 signatures when they are used as source files to other derived files. For
511 example: source with source builders are not derived in this sense,
512 and hence should not return true.
513 """
514 return self.has_builder() or self.side_effect
515
517 """Return a list of alternate targets for this Node.
518 """
519 return [], None
520
522 """Return the scanned include lines (implicit dependencies)
523 found in this node.
524
525 The default is no implicit dependencies. We expect this method
526 to be overridden by any subclass that can be scanned for
527 implicit dependencies.
528 """
529 return []
530
532 """Return a list of implicit dependencies for this node.
533
534 This method exists to handle recursive invocation of the scanner
535 on the implicit dependencies returned by the scanner, if the
536 scanner's recursive flag says that we should.
537 """
538 if not scanner:
539 return []
540
541
542
543
544
545 nodes = [self]
546 seen = {}
547 seen[self] = 1
548 deps = []
549 while nodes:
550 n = nodes.pop(0)
551 d = filter(lambda x, seen=seen: not seen.has_key(x),
552 n.get_found_includes(env, scanner, path))
553 if d:
554 deps.extend(d)
555 for n in d:
556 seen[n] = 1
557 nodes.extend(scanner.recurse_nodes(d))
558
559 return deps
560
563
565 return self.builder.target_scanner
566
568 """Fetch the source scanner for the specified node
569
570 NOTE: "self" is the target being built, "node" is
571 the source file for which we want to fetch the scanner.
572
573 Implies self.has_builder() is true; again, expect to only be
574 called from locations where this is already verified.
575
576 This function may be called very often; it attempts to cache
577 the scanner found to improve performance.
578 """
579 scanner = None
580 try:
581 scanner = self.builder.source_scanner
582 except AttributeError:
583 pass
584 if not scanner:
585
586
587
588 scanner = self.get_env_scanner(self.get_build_env())
589 if scanner:
590 scanner = scanner.select(node)
591 return scanner
592
594 if not hasattr(self, 'implicit') or self.implicit is None:
595 self.implicit = []
596 self.implicit_set = set()
597 self._children_reset()
598 self._add_child(self.implicit, self.implicit_set, deps)
599
647
650
652 """Selects a scanner for this Node.
653
654 This is a separate method so it can be overridden by Node
655 subclasses (specifically, Node.FS.Dir) that *must* use their
656 own Scanner and don't select one the Scanner.Selector that's
657 configured for the target.
658 """
659 return scanner.select(self)
660
662 if safe and self.env:
663 return
664 self.env = env
665
666
667
668
669
670 NodeInfo = NodeInfoBase
671 BuildInfo = BuildInfoBase
672
674 ninfo = self.NodeInfo(self)
675 return ninfo
676
678 try:
679 return self.ninfo
680 except AttributeError:
681 self.ninfo = self.new_ninfo()
682 return self.ninfo
683
685 binfo = self.BuildInfo(self)
686 return binfo
687
689 """
690 Fetch a node's build information.
691
692 node - the node whose sources will be collected
693 cache - alternate node to use for the signature cache
694 returns - the build signature
695
696 This no longer handles the recursive descent of the
697 node's children's signatures. We expect that they're
698 already built and updated by someone else, if that's
699 what's wanted.
700 """
701 try:
702 return self.binfo
703 except AttributeError:
704 pass
705
706 binfo = self.new_binfo()
707 self.binfo = binfo
708
709 executor = self.get_executor()
710 ignore_set = self.ignore_set
711
712 if self.has_builder():
713 binfo.bact = str(executor)
714 binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
715
716 if self._specific_sources:
717 sources = []
718 for s in self.sources:
719 if s not in ignore_set:
720 sources.append(s)
721 else:
722 sources = executor.get_unignored_sources(self, self.ignore)
723 seen = set()
724 bsources = []
725 bsourcesigs = []
726 for s in sources:
727 if not s in seen:
728 seen.add(s)
729 bsources.append(s)
730 bsourcesigs.append(s.get_ninfo())
731 binfo.bsources = bsources
732 binfo.bsourcesigs = bsourcesigs
733
734 depends = self.depends
735 dependsigs = []
736 for d in depends:
737 if d not in ignore_set:
738 dependsigs.append(d.get_ninfo())
739 binfo.bdepends = depends
740 binfo.bdependsigs = dependsigs
741
742 implicit = self.implicit or []
743 implicitsigs = []
744 for i in implicit:
745 if i not in ignore_set:
746 implicitsigs.append(i.get_ninfo())
747 binfo.bimplicit = implicit
748 binfo.bimplicitsigs = implicitsigs
749
750 return binfo
751
753 """Delete the build info from this node."""
754 try:
755 delattr(self, 'binfo')
756 except AttributeError:
757 pass
758
760 try:
761 return self.ninfo.csig
762 except AttributeError:
763 ninfo = self.get_ninfo()
764 ninfo.csig = SCons.Util.MD5signature(self.get_contents())
765 return self.ninfo.csig
766
769
771 """Make the build signature permanent (that is, store it in the
772 .sconsign file or equivalent)."""
773 pass
774
777
780
782 """Fetch the stored implicit dependencies"""
783 return None
784
785
786
787
788
790 """Set the Node's precious value."""
791 self.precious = precious
792
794 """Set the Node's noclean value."""
795
796
797 self.noclean = noclean and 1 or 0
798
800 """Set the Node's nocache value."""
801
802
803 self.nocache = nocache and 1 or 0
804
806 """Set the Node's always_build value."""
807 self.always_build = always_build
808
810 """Does this node exists?"""
811
812 return 1
813
815 """Does this node exist locally or in a repositiory?"""
816
817 return self.exists()
818
820 return not self.is_derived() and \
821 not self.linked and \
822 not self.rexists()
823
825 """Remove this Node: no-op by default."""
826 return None
827
829 """Adds dependencies."""
830 try:
831 self._add_child(self.depends, self.depends_set, depend)
832 except TypeError, e:
833 e = e.args[0]
834 if SCons.Util.is_List(e):
835 s = map(str, e)
836 else:
837 s = str(e)
838 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)))
839
844
846 """Adds dependencies to ignore."""
847 try:
848 self._add_child(self.ignore, self.ignore_set, depend)
849 except TypeError, e:
850 e = e.args[0]
851 if SCons.Util.is_List(e):
852 s = map(str, e)
853 else:
854 s = str(e)
855 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)))
856
858 """Adds sources."""
859 if self._specific_sources:
860 return
861 try:
862 self._add_child(self.sources, self.sources_set, source)
863 except TypeError, e:
864 e = e.args[0]
865 if SCons.Util.is_List(e):
866 s = map(str, e)
867 else:
868 s = str(e)
869 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)))
870
872 """Adds 'child' to 'collection', first checking 'set' to see if it's
873 already present."""
874
875
876
877
878
879 added = None
880 for c in child:
881 if c not in set:
882 set.add(c)
883 collection.append(c)
884 added = 1
885 if added:
886 self._children_reset()
887
891
893 """Add a node to the list of kids waiting to be evaluated"""
894 if self.wkids is not None:
895 self.wkids.append(wkid)
896
902
903 memoizer_counters.append(SCons.Memoize.CountValue('_children_get'))
904
906 try:
907 return self._memo['children_get']
908 except KeyError:
909 pass
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928 if self.ignore_set:
929 if self.implicit is None:
930 iter = chain(self.sources,self.depends)
931 else:
932 iter = chain(self.sources, self.depends, self.implicit)
933
934 children = []
935 for i in iter:
936 if i not in self.ignore_set:
937 children.append(i)
938 else:
939 if self.implicit is None:
940 children = self.sources + self.depends
941 else:
942 children = self.sources + self.depends + self.implicit
943
944 self._memo['children_get'] = children
945 return children
946
948 """Return a list of all the node's direct children."""
949 if scan:
950 self.scan()
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969 if self.implicit is None:
970 return self.sources + self.depends
971 else:
972 return self.sources + self.depends + self.implicit
973
975 """Return a list of the node's direct children, minus those
976 that are ignored by this node."""
977 if scan:
978 self.scan()
979 return self._children_get()
980
983
986
989
996
998 """
999
1000 Must be overridden in a specific subclass to return True if this
1001 Node (a dependency) has changed since the last time it was used
1002 to build the specified target. prev_ni is this Node's state (for
1003 example, its file timestamp, length, maybe content signature)
1004 as of the last time the target was built.
1005
1006 Note that this method is called through the dependency, not the
1007 target, because a dependency Node must be able to use its own
1008 logic to decide if it changed. For example, File Nodes need to
1009 obey if we're configured to use timestamps, but Python Value Nodes
1010 never use timestamps and always use the content. If this method
1011 were called through the target, then each Node's implementation
1012 of this method would have to have more complicated logic to
1013 handle all the different Node types on which it might depend.
1014 """
1015 raise NotImplementedError
1016
1019
1021 """
1022 Returns if the node is up-to-date with respect to the BuildInfo
1023 stored last time it was built. The default behavior is to compare
1024 it against our own previously stored BuildInfo, but the stored
1025 BuildInfo from another Node (typically one in a Repository)
1026 can be used instead.
1027
1028 Note that we now *always* check every dependency. We used to
1029 short-circuit the check by returning as soon as we detected
1030 any difference, but we now rely on checking every dependency
1031 to make sure that any necessary Node information (for example,
1032 the content signature of an #included .h file) is updated.
1033 """
1034 t = 0
1035 if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node))
1036 if node is None:
1037 node = self
1038
1039 result = False
1040
1041 bi = node.get_stored_info().binfo
1042 then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs
1043 children = self.children()
1044
1045 diff = len(children) - len(then)
1046 if diff:
1047
1048
1049
1050
1051
1052 then.extend([None] * diff)
1053 if t: Trace(': old %s new %s' % (len(then), len(children)))
1054 result = True
1055
1056 for child, prev_ni in izip(children, then):
1057 if child.changed_since_last_build(self, prev_ni):
1058 if t: Trace(': %s changed' % child)
1059 result = True
1060
1061 contents = self.get_executor().get_contents()
1062 if self.has_builder():
1063 import SCons.Util
1064 newsig = SCons.Util.MD5signature(contents)
1065 if bi.bactsig != newsig:
1066 if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
1067 result = True
1068
1069 if not result:
1070 if t: Trace(': up to date')
1071
1072 if t: Trace('\n')
1073
1074 return result
1075
1077 """Default check for whether the Node is current: unknown Node
1078 subtypes are always out of date, so they will always get built."""
1079 return None
1080
1082 """Alternate check for whether the Node is current: If all of
1083 our children were up-to-date, then this Node was up-to-date, too.
1084
1085 The SCons.Node.Alias and SCons.Node.Python.Value subclasses
1086 rebind their current() method to this method."""
1087
1088 self.binfo = self.get_binfo()
1089 if self.always_build:
1090 return None
1091 state = 0
1092 for kid in self.children(None):
1093 s = kid.get_state()
1094 if s and (not state or s > state):
1095 state = s
1096 return (state == 0 or state == SCons.Node.up_to_date)
1097
1099 """Always pass the string representation of a Node to
1100 the command interpreter literally."""
1101 return 1
1102
1104 """
1105 Return a text representation, suitable for displaying to the
1106 user, of the include tree for the sources of this node.
1107 """
1108 if self.is_derived() and self.env:
1109 env = self.get_build_env()
1110 for s in self.sources:
1111 scanner = self.get_source_scanner(s)
1112 if scanner:
1113 path = self.get_build_scanner_path(scanner)
1114 else:
1115 path = None
1116 def f(node, env=env, scanner=scanner, path=path):
1117 return node.get_found_includes(env, scanner, path)
1118 return SCons.Util.render_tree(s, f, 1)
1119 else:
1120 return None
1121
1123 """
1124 Return an absolute path to the Node. This will return simply
1125 str(Node) by default, but for Node types that have a concept of
1126 relative path, this might return something different.
1127 """
1128 return str(self)
1129
1131 """
1132 Return a string representation of the Node that will always
1133 be the same for this particular Node, no matter what. This
1134 is by contrast to the __str__() method, which might, for
1135 instance, return a relative path for a file Node. The purpose
1136 of this method is to generate a value to be used in signature
1137 calculation for the command line used to build a target, and
1138 we use this method instead of str() to avoid unnecessary
1139 rebuilds. This method does not need to return something that
1140 would actually work in a command line; it can return any kind of
1141 nonsense, so long as it does not change.
1142 """
1143 return str(self)
1144
1146 """This is a convenience function designed primarily to be
1147 used in command generators (i.e., CommandGeneratorActions or
1148 Environment variables that are callable), which are called
1149 with a for_signature argument that is nonzero if the command
1150 generator is being called to generate a signature for the
1151 command line, which determines if we should rebuild or not.
1152
1153 Such command generators should use this method in preference
1154 to str(Node) when converting a Node to a string, passing
1155 in the for_signature parameter, such that we will call
1156 Node.for_signature() or str(Node) properly, depending on whether
1157 we are calculating a signature or actually constructing a
1158 command line."""
1159 if for_signature:
1160 return self.for_signature()
1161 return str(self)
1162
1164 """
1165 This method is expected to return an object that will function
1166 exactly like this Node, except that it implements any additional
1167 special features that we would like to be in effect for
1168 Environment variable substitution. The principle use is that
1169 some Nodes would like to implement a __getattr__() method,
1170 but putting that in the Node type itself has a tendency to kill
1171 performance. We instead put it in a proxy and return it from
1172 this method. It is legal for this method to return self
1173 if no new functionality is needed for Environment substitution.
1174 """
1175 return self
1176
1178 if not self.exists():
1179 return "building `%s' because it doesn't exist\n" % self
1180
1181 if self.always_build:
1182 return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
1183
1184 old = self.get_stored_info()
1185 if old is None:
1186 return None
1187
1188 old = old.binfo
1189 old.prepare_dependencies()
1190
1191 try:
1192 old_bkids = old.bsources + old.bdepends + old.bimplicit
1193 old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs
1194 except AttributeError:
1195 return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
1196
1197 new = self.get_binfo()
1198
1199 new_bkids = new.bsources + new.bdepends + new.bimplicit
1200 new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
1201
1202 osig = dict(izip(old_bkids, old_bkidsigs))
1203 nsig = dict(izip(new_bkids, new_bkidsigs))
1204
1205
1206
1207
1208
1209
1210
1211 def stringify( s, E=self.dir.Entry ) :
1212 if hasattr( s, 'dir' ) :
1213 return str(E(s))
1214 return str(s)
1215
1216 lines = []
1217
1218 removed = filter(lambda x, nk=new_bkids: not x in nk, old_bkids)
1219 if removed:
1220 removed = map(stringify, removed)
1221 fmt = "`%s' is no longer a dependency\n"
1222 lines.extend(map(lambda s, fmt=fmt: fmt % s, removed))
1223
1224 for k in new_bkids:
1225 if not k in old_bkids:
1226 lines.append("`%s' is a new dependency\n" % stringify(k))
1227 elif k.changed_since_last_build(self, osig[k]):
1228 lines.append("`%s' changed\n" % stringify(k))
1229
1230 if len(lines) == 0 and old_bkids != new_bkids:
1231 lines.append("the dependency order changed:\n" +
1232 "%sold: %s\n" % (' '*15, map(stringify, old_bkids)) +
1233 "%snew: %s\n" % (' '*15, map(stringify, new_bkids)))
1234
1235 if len(lines) == 0:
1236 def fmt_with_title(title, strlines):
1237 lines = string.split(strlines, '\n')
1238 sep = '\n' + ' '*(15 + len(title))
1239 return ' '*15 + title + string.join(lines, sep) + '\n'
1240 if old.bactsig != new.bactsig:
1241 if old.bact == new.bact:
1242 lines.append("the contents of the build action changed\n" +
1243 fmt_with_title('action: ', new.bact))
1244 else:
1245 lines.append("the build action changed:\n" +
1246 fmt_with_title('old: ', old.bact) +
1247 fmt_with_title('new: ', new.bact))
1248
1249 if len(lines) == 0:
1250 return "rebuilding `%s' for unknown reasons\n" % self
1251
1252 preamble = "rebuilding `%s' because" % self
1253 if len(lines) == 1:
1254 return "%s %s" % (preamble, lines[0])
1255 else:
1256 lines = ["%s:\n" % preamble] + lines
1257 return string.join(lines, ' '*11)
1258
1259 try:
1260 [].extend(UserList.UserList([]))
1261 except TypeError:
1262
1263
1264
1267 else:
1270 return str(map(str, self.data))
1271
1275
1277 """An iterator for walking a Node tree.
1278
1279 This is depth-first, children are visited before the parent.
1280 The Walker object can be initialized with any node, and
1281 returns the next node on the descent with each next() call.
1282 'kids_func' is an optional function that will be called to
1283 get the children of a node instead of calling 'children'.
1284 'cycle_func' is an optional function that will be called
1285 when a cycle is detected.
1286
1287 This class does not get caught in node cycles caused, for example,
1288 by C header file include loops.
1289 """
1290 - def __init__(self, node, kids_func=get_children,
1291 cycle_func=ignore_cycle,
1292 eval_func=do_nothing):
1293 self.kids_func = kids_func
1294 self.cycle_func = cycle_func
1295 self.eval_func = eval_func
1296 node.wkids = copy.copy(kids_func(node, None))
1297 self.stack = [node]
1298 self.history = {}
1299 self.history[node] = None
1300
1302 """Return the next node for this walk of the tree.
1303
1304 This function is intentionally iterative, not recursive,
1305 to sidestep any issues of stack size limitations.
1306 """
1307
1308 while self.stack:
1309 if self.stack[-1].wkids:
1310 node = self.stack[-1].wkids.pop(0)
1311 if not self.stack[-1].wkids:
1312 self.stack[-1].wkids = None
1313 if self.history.has_key(node):
1314 self.cycle_func(node, self.stack)
1315 else:
1316 node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
1317 self.stack.append(node)
1318 self.history[node] = None
1319 else:
1320 node = self.stack.pop()
1321 del self.history[node]
1322 if node:
1323 if self.stack:
1324 parent = self.stack[-1]
1325 else:
1326 parent = None
1327 self.eval_func(node, parent)
1328 return node
1329 return None
1330
1332 return not self.stack
1333
1334
1335 arg2nodes_lookups = []
1336
1337
1338
1339
1340
1341
1342