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