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