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 rel_2.4.0:3365:9259ea1c13d7 2015/09/21 14:03:43 bdbaddog"
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
58 print_duplicate = 0
61 return str(obj.__class__).split('.')[-1]
62
63
64
65 do_store_info = True
66
67
68
69
70
71
72
73
74 no_state = 0
75 pending = 1
76 executing = 2
77 up_to_date = 3
78 executed = 4
79 failed = 5
80
81 StateString = {
82 0 : "no_state",
83 1 : "pending",
84 2 : "executing",
85 3 : "up_to_date",
86 4 : "executed",
87 5 : "failed",
88 }
89
90
91 implicit_cache = 0
92
93
94 implicit_deps_unchanged = 0
95
96
97 implicit_deps_changed = 0
102
103 Annotate = do_nothing
104
105
106
107
108 interactive = False
111 raise NotImplementedError
112
114 """
115 Returns true if this node is derived (i.e. built).
116 """
117 return node.has_builder() or node.side_effect
118
119 _is_derived_map = {0 : is_derived_none,
120 1 : is_derived_node}
123 raise NotImplementedError
124
127
129 return node.stat() is not None
130
131 -def exists_entry(node):
132 """Return if the Entry exists. Check the file system to see
133 what we should turn into first. Assume a file if there's no
134 directory."""
135 node.disambiguate()
136 return _exists_map[node._func_exists](node)
137
161
162 _exists_map = {0 : exists_none,
163 1 : exists_always,
164 2 : exists_base,
165 3 : exists_entry,
166 4 : exists_file}
170 raise NotImplementedError
171
174
177
178 _rexists_map = {0 : rexists_none,
179 1 : rexists_node,
180 2 : rexists_base}
181
182 -def get_contents_none(node):
183 raise NotImplementedError
184
186 """Fetch the contents of the entry. Returns the exact binary
187 contents of the file."""
188 try:
189 node = node.disambiguate(must_exist=1)
190 except SCons.Errors.UserError:
191
192
193
194
195
196 return ''
197 else:
198 return _get_contents_map[node._func_get_contents](node)
199
201 """Return content signatures and names of all our children
202 separated by new-lines. Ensure that the nodes are sorted."""
203 contents = []
204 for n in sorted(node.children(), key=lambda t: t.name):
205 contents.append('%s %s\n' % (n.get_csig(), n.name))
206 return ''.join(contents)
207
209 if not node.rexists():
210 return ''
211 fname = node.rfile().get_abspath()
212 try:
213 contents = open(fname, "rb").read()
214 except EnvironmentError, e:
215 if not e.filename:
216 e.filename = fname
217 raise
218 return contents
219
220 _get_contents_map = {0 : get_contents_none,
221 1 : get_contents_entry,
222 2 : get_contents_dir,
223 3 : get_contents_file}
226 raise NotImplementedError
227
230
231 _target_from_source_map = {0 : target_from_source_none,
232 1 : target_from_source_base}
248 """
249
250 Must be overridden in a specific subclass to return True if this
251 Node (a dependency) has changed since the last time it was used
252 to build the specified target. prev_ni is this Node's state (for
253 example, its file timestamp, length, maybe content signature)
254 as of the last time the target was built.
255
256 Note that this method is called through the dependency, not the
257 target, because a dependency Node must be able to use its own
258 logic to decide if it changed. For example, File Nodes need to
259 obey if we're configured to use timestamps, but Python Value Nodes
260 never use timestamps and always use the content. If this method
261 were called through the target, then each Node's implementation
262 of this method would have to have more complicated logic to
263 handle all the different Node types on which it might depend.
264 """
265 raise NotImplementedError
266
268 cur_csig = node.get_csig()
269 try:
270 return cur_csig != prev_ni.csig
271 except AttributeError:
272 return 1
273
274 -def changed_since_last_build_entry(node, target, prev_ni):
275 node.disambiguate()
276 return _decider_map[node.changed_since_last_build](node, target, prev_ni)
277
280
282 return target.get_build_env().decide_source(node, target, prev_ni)
283
285 return target.get_build_env().decide_target(node, target, prev_ni)
286
288 cur_csig = node.get_csig()
289 try:
290 return cur_csig != prev_ni.csig
291 except AttributeError:
292 return 1
293
294
295
296
297
298 _decider_map = {0 : changed_since_last_build_node,
299 1 : changed_since_last_build_alias,
300 2 : changed_since_last_build_entry,
301 3 : changed_since_last_build_state_changed,
302 4 : decide_source,
303 5 : decide_target,
304 6 : changed_since_last_build_python}
305
306 do_store_info = True
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 -def store_info_pass(node):
324
332
333
334 store_info_map = {0 : store_info_pass,
335 1 : store_info_file}
340 """
341 The generic base class for signature information for a Node.
342
343 Node subclasses should subclass NodeInfoBase to provide their own
344 logic for dealing with their own Node-specific signature information.
345 """
346 __slots__ = ('__weakref__',)
347 current_version_id = 2
349 try:
350 field_list = self.field_list
351 except AttributeError:
352 return
353 for f in field_list:
354 try:
355 delattr(self, f)
356 except AttributeError:
357 pass
358 try:
359 func = getattr(node, 'get_' + f)
360 except AttributeError:
361 pass
362 else:
363 setattr(self, f, func())
367 """
368 Merge the fields of another object into this object. Already existing
369 information is overwritten by the other instance's data.
370 WARNING: If a '__dict__' slot is added, it should be updated instead of
371 replaced.
372 """
373 state = other.__getstate__()
374 self.__setstate__(state)
397
399 """
400 Return all fields that shall be pickled. Walk the slots in the class
401 hierarchy and add those to the state dictionary. If a '__dict__' slot is
402 available, copy all entries to the dictionary. Also include the version
403 id, which is fixed for all instances of a class.
404 """
405 state = getattr(self, '__dict__', {}).copy()
406 for obj in type(self).mro():
407 for name in getattr(obj,'__slots__',()):
408 if hasattr(self, name):
409 state[name] = getattr(self, name)
410
411 state['_version_id'] = self.current_version_id
412 try:
413 del state['__weakref__']
414 except KeyError:
415 pass
416 return state
417
419 """
420 Restore the attributes from a pickled state. The version is discarded.
421 """
422
423 del state['_version_id']
424
425 for key, value in state.items():
426 if key not in ('__weakref__',):
427 setattr(self, key, value)
428
431 """
432 The generic base class for build information for a Node.
433
434 This is what gets stored in a .sconsign file for each target file.
435 It contains a NodeInfo instance for this node (signature information
436 that's specific to the type of Node) and direct attributes for the
437 generic build stuff we have to track: sources, explicit dependencies,
438 implicit dependencies, and action information.
439 """
440 __slots__ = ("bsourcesigs", "bdependsigs", "bimplicitsigs", "bactsig",
441 "bsources", "bdepends", "bact", "bimplicit", "__weakref__")
442 current_version_id = 2
451 """
452 Merge the fields of another object into this object. Already existing
453 information is overwritten by the other instance's data.
454 WARNING: If a '__dict__' slot is added, it should be updated instead of
455 replaced.
456 """
457 state = other.__getstate__()
458 self.__setstate__(state)
459
461 """
462 Return all fields that shall be pickled. Walk the slots in the class
463 hierarchy and add those to the state dictionary. If a '__dict__' slot is
464 available, copy all entries to the dictionary. Also include the version
465 id, which is fixed for all instances of a class.
466 """
467 state = getattr(self, '__dict__', {}).copy()
468 for obj in type(self).mro():
469 for name in getattr(obj,'__slots__',()):
470 if hasattr(self, name):
471 state[name] = getattr(self, name)
472
473 state['_version_id'] = self.current_version_id
474 try:
475 del state['__weakref__']
476 except KeyError:
477 pass
478 return state
479
481 """
482 Restore the attributes from a pickled state.
483 """
484
485 del state['_version_id']
486 for key, value in state.items():
487 if key not in ('__weakref__',):
488 setattr(self, key, value)
489
491 """The base Node class, for entities that we know how to
492 build, or use to build other Nodes.
493 """
494
495 __slots__ = ['sources',
496 'sources_set',
497 '_specific_sources',
498 'depends',
499 'depends_set',
500 'ignore',
501 'ignore_set',
502 'prerequisites',
503 'implicit',
504 'waiting_parents',
505 'waiting_s_e',
506 'ref_count',
507 'wkids',
508 'env',
509 'state',
510 'precious',
511 'noclean',
512 'nocache',
513 'cached',
514 'always_build',
515 'includes',
516 'attributes',
517 'side_effect',
518 'side_effects',
519 'linked',
520 '_memo',
521 'executor',
522 'binfo',
523 'ninfo',
524 'builder',
525 'is_explicit',
526 'implicit_set',
527 'changed_since_last_build',
528 'store_info',
529 'pseudo',
530 '_tags',
531 '_func_is_derived',
532 '_func_exists',
533 '_func_rexists',
534 '_func_get_contents',
535 '_func_target_from_source']
536
538 __slots__ = ('shared', '__dict__')
539
540
598
601
604
605 @SCons.Memoize.CountMethodCall
616
620
624
645
655
657 "Remove cached executor; forces recompute when needed."
658 try:
659 delattr(self, 'executor')
660 except AttributeError:
661 pass
662
664 """Try to push a node into a cache
665 """
666 pass
667
669 """Try to retrieve the node's content from a cache
670
671 This method is called from multiple threads in a parallel build,
672 so only do thread safe stuff here. Do thread unsafe stuff in
673 built().
674
675 Returns true if the node was successfully retrieved.
676 """
677 return 0
678
679
680
681
682
684 """Get a Node ready for evaluation.
685
686 This is called before the Taskmaster decides if the Node is
687 up-to-date or not. Overriding this method allows for a Node
688 subclass to be disambiguated if necessary, or for an implicit
689 source builder to be attached.
690 """
691 pass
692
694 """Prepare for this Node to be built.
695
696 This is called after the Taskmaster has decided that the Node
697 is out-of-date and must be rebuilt, but before actually calling
698 the method to build the Node.
699
700 This default implementation checks that explicit or implicit
701 dependencies either exist or are derived, and initializes the
702 BuildInfo structure that will hold the information about how
703 this node is, uh, built.
704
705 (The existence of source files is checked separately by the
706 Executor, which aggregates checks for all of the targets built
707 by a specific action.)
708
709 Overriding this method allows for for a Node subclass to remove
710 the underlying file from the file system. Note that subclass
711 methods should call this base class method to get the child
712 check and the BuildInfo structure.
713 """
714 if self.depends is not None:
715 for d in self.depends:
716 if d.missing():
717 msg = "Explicit dependency `%s' not found, needed by target `%s'."
718 raise SCons.Errors.StopError(msg % (d, self))
719 if self.implicit is not None:
720 for i in self.implicit:
721 if i.missing():
722 msg = "Implicit dependency `%s' not found, needed by target `%s'."
723 raise SCons.Errors.StopError(msg % (i, self))
724 self.binfo = self.get_binfo()
725
727 """Actually build the node.
728
729 This is called by the Taskmaster after it's decided that the
730 Node is out-of-date and must be rebuilt, and after the prepare()
731 method has gotten everything, uh, prepared.
732
733 This method is called from multiple threads in a parallel build,
734 so only do thread safe stuff here. Do thread unsafe stuff
735 in built().
736
737 """
738 try:
739 self.get_executor()(self, **kw)
740 except SCons.Errors.BuildError, e:
741 e.node = self
742 raise
743
762
775
777 """Called just after this node has been marked
778 up-to-date or was built completely.
779
780 This is where we try to release as many target node infos
781 as possible for clean builds and update runs, in order
782 to minimize the overall memory consumption.
783
784 By purging attributes that aren't needed any longer after
785 a Node (=File) got built, we don't have to care that much how
786 many KBytes a Node actually requires...as long as we free
787 the memory shortly afterwards.
788
789 @see: built() and File.release_target_info()
790 """
791 pass
792
793
794
795
796
799
801 """
802 Returns the number of nodes added to our waiting parents list:
803 1 if we add a unique waiting parent, 0 if not. (Note that the
804 returned values are intended to be used to increment a reference
805 count, so don't think you can "clean up" this function by using
806 True and False instead...)
807 """
808 wp = self.waiting_parents
809 if node in wp:
810 return 0
811 wp.add(node)
812 return 1
813
814 - def postprocess(self):
815 """Clean up anything we don't need to hang onto after we've
816 been built."""
817 self.executor_cleanup()
818 self.waiting_parents = set()
819
821 """Completely clear a Node of all its cached state (so that it
822 can be re-evaluated by interfaces that do continuous integration
823 builds).
824 """
825
826
827
828 self.del_binfo()
829 self.clear_memoized_values()
830 self.ninfo = self.new_ninfo()
831 self.executor_cleanup()
832 try:
833 delattr(self, '_calculated_sig')
834 except AttributeError:
835 pass
836 self.includes = None
837
840
847
849 """Return whether this Node has a builder or not.
850
851 In Boolean tests, this turns out to be a *lot* more efficient
852 than simply examining the builder attribute directly ("if
853 node.builder: ..."). When the builder attribute is examined
854 directly, it ends up calling __getattr__ for both the __len__
855 and __nonzero__ attributes on instances of our Builder Proxy
856 class(es), generating a bazillion extra calls and slowing
857 things down immensely.
858 """
859 try:
860 b = self.builder
861 except AttributeError:
862
863
864 b = self.builder = None
865 return b is not None
866
869
871 """Return whether this Node has an explicit builder
872
873 This allows an internal Builder created by SCons to be marked
874 non-explicit, so that it can be overridden by an explicit
875 builder that the user supplies (the canonical example being
876 directories)."""
877 try:
878 return self.is_explicit
879 except AttributeError:
880 self.is_explicit = None
881 return self.is_explicit
882
884 """Return the set builder, or a specified default value"""
885 try:
886 return self.builder
887 except AttributeError:
888 return default_builder
889
890 multiple_side_effect_has_builder = has_builder
891
893 """
894 Returns true if this node is derived (i.e. built).
895
896 This should return true only for nodes whose path should be in
897 the variant directory when duplicate=0 and should contribute their build
898 signatures when they are used as source files to other derived files. For
899 example: source with source builders are not derived in this sense,
900 and hence should not return true.
901 """
902 return _is_derived_map[self._func_is_derived](self)
903
905 """Return a list of alternate targets for this Node.
906 """
907 return [], None
908
910 """Return the scanned include lines (implicit dependencies)
911 found in this node.
912
913 The default is no implicit dependencies. We expect this method
914 to be overridden by any subclass that can be scanned for
915 implicit dependencies.
916 """
917 return []
918
920 """Return a list of implicit dependencies for this node.
921
922 This method exists to handle recursive invocation of the scanner
923 on the implicit dependencies returned by the scanner, if the
924 scanner's recursive flag says that we should.
925 """
926 if not scanner:
927 return []
928
929
930
931
932
933 nodes = [self]
934 seen = {}
935 seen[self] = 1
936 deps = []
937 while nodes:
938 n = nodes.pop(0)
939 d = [x for x in n.get_found_includes(env, scanner, path) if x not in seen]
940 if d:
941 deps.extend(d)
942 for n in d:
943 seen[n] = 1
944 nodes.extend(scanner.recurse_nodes(d))
945
946 return deps
947
950
952 return self.builder.target_scanner
953
955 """Fetch the source scanner for the specified node
956
957 NOTE: "self" is the target being built, "node" is
958 the source file for which we want to fetch the scanner.
959
960 Implies self.has_builder() is true; again, expect to only be
961 called from locations where this is already verified.
962
963 This function may be called very often; it attempts to cache
964 the scanner found to improve performance.
965 """
966 scanner = None
967 try:
968 scanner = self.builder.source_scanner
969 except AttributeError:
970 pass
971 if not scanner:
972
973
974
975 scanner = self.get_env_scanner(self.get_build_env())
976 if scanner:
977 scanner = scanner.select(node)
978 return scanner
979
986
1035
1038
1040 """Selects a scanner for this Node.
1041
1042 This is a separate method so it can be overridden by Node
1043 subclasses (specifically, Node.FS.Dir) that *must* use their
1044 own Scanner and don't select one the Scanner.Selector that's
1045 configured for the target.
1046 """
1047 return scanner.select(self)
1048
1050 if safe and self.env:
1051 return
1052 self.env = env
1053
1054
1055
1056
1057
1058 NodeInfo = NodeInfoBase
1059 BuildInfo = BuildInfoBase
1060
1064
1071
1075
1139
1141 """Delete the build info from this node."""
1142 try:
1143 delattr(self, 'binfo')
1144 except AttributeError:
1145 pass
1146
1154
1157
1160
1162 """Fetch the stored implicit dependencies"""
1163 return None
1164
1165
1166
1167
1168
1172
1174 """Set the Node's precious value."""
1175 self.pseudo = pseudo
1176
1178 """Set the Node's noclean value."""
1179
1180
1181 self.noclean = noclean and 1 or 0
1182
1184 """Set the Node's nocache value."""
1185
1186
1187 self.nocache = nocache and 1 or 0
1188
1192
1196
1201
1202 - def get_contents(self):
1203 """Fetch the contents of the entry."""
1204 return _get_contents_map[self._func_get_contents](self)
1205
1210
1212 """Remove this Node: no-op by default."""
1213 return None
1214
1216 """Adds dependencies."""
1217 try:
1218 self._add_child(self.depends, self.depends_set, depend)
1219 except TypeError, e:
1220 e = e.args[0]
1221 if SCons.Util.is_List(e):
1222 s = list(map(str, e))
1223 else:
1224 s = str(e)
1225 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)))
1226
1233
1235 """Adds dependencies to ignore."""
1236 try:
1237 self._add_child(self.ignore, self.ignore_set, depend)
1238 except TypeError, e:
1239 e = e.args[0]
1240 if SCons.Util.is_List(e):
1241 s = list(map(str, e))
1242 else:
1243 s = str(e)
1244 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)))
1245
1259
1261 """Adds 'child' to 'collection', first checking 'set' to see if it's
1262 already present."""
1263
1264
1265
1266
1267
1268 added = None
1269 for c in child:
1270 if c not in set:
1271 set.add(c)
1272 collection.append(c)
1273 added = 1
1274 if added:
1275 self._children_reset()
1276
1280
1282 """Add a node to the list of kids waiting to be evaluated"""
1283 if self.wkids is not None:
1284 self.wkids.append(wkid)
1285
1291
1292 @SCons.Memoize.CountMethodCall
1328
1330 """Return a list of all the node's direct children."""
1331 if scan:
1332 self.scan()
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351 return list(chain.from_iterable(filter(None, [self.sources, self.depends, self.implicit])))
1352
1354 """Return a list of the node's direct children, minus those
1355 that are ignored by this node."""
1356 if scan:
1357 self.scan()
1358 return self._children_get()
1359
1362
1365
1372
1383
1384 - def Tag(self, key, value):
1385 """ Add a user-defined tag. """
1386 if not self._tags:
1387 self._tags = {}
1388 self._tags[key] = value
1389
1391 """ Return a user-defined tag. """
1392 if not self._tags:
1393 return None
1394 return self._tags.get(key, None)
1395
1396 - def changed(self, node=None, allowcache=False):
1397 """
1398 Returns if the node is up-to-date with respect to the BuildInfo
1399 stored last time it was built. The default behavior is to compare
1400 it against our own previously stored BuildInfo, but the stored
1401 BuildInfo from another Node (typically one in a Repository)
1402 can be used instead.
1403
1404 Note that we now *always* check every dependency. We used to
1405 short-circuit the check by returning as soon as we detected
1406 any difference, but we now rely on checking every dependency
1407 to make sure that any necessary Node information (for example,
1408 the content signature of an #included .h file) is updated.
1409
1410 The allowcache option was added for supporting the early
1411 release of the executor/builder structures, right after
1412 a File target was built. When set to true, the return
1413 value of this changed method gets cached for File nodes.
1414 Like this, the executor isn't needed any longer for subsequent
1415 calls to changed().
1416
1417 @see: FS.File.changed(), FS.File.release_target_info()
1418 """
1419 t = 0
1420 if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node))
1421 if node is None:
1422 node = self
1423
1424 result = False
1425
1426 bi = node.get_stored_info().binfo
1427 then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs
1428 children = self.children()
1429
1430 diff = len(children) - len(then)
1431 if diff:
1432
1433
1434
1435
1436
1437 then.extend([None] * diff)
1438 if t: Trace(': old %s new %s' % (len(then), len(children)))
1439 result = True
1440
1441 for child, prev_ni in zip(children, then):
1442 if _decider_map[child.changed_since_last_build](child, self, prev_ni):
1443 if t: Trace(': %s changed' % child)
1444 result = True
1445
1446 contents = self.get_executor().get_contents()
1447 if self.has_builder():
1448 import SCons.Util
1449 newsig = SCons.Util.MD5signature(contents)
1450 if bi.bactsig != newsig:
1451 if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
1452 result = True
1453
1454 if not result:
1455 if t: Trace(': up to date')
1456
1457 if t: Trace('\n')
1458
1459 return result
1460
1462 """Default check for whether the Node is current: unknown Node
1463 subtypes are always out of date, so they will always get built."""
1464 return None
1465
1467 """Alternate check for whether the Node is current: If all of
1468 our children were up-to-date, then this Node was up-to-date, too.
1469
1470 The SCons.Node.Alias and SCons.Node.Python.Value subclasses
1471 rebind their current() method to this method."""
1472
1473 self.binfo = self.get_binfo()
1474 if self.always_build:
1475 return None
1476 state = 0
1477 for kid in self.children(None):
1478 s = kid.get_state()
1479 if s and (not state or s > state):
1480 state = s
1481 return (state == 0 or state == SCons.Node.up_to_date)
1482
1484 """Always pass the string representation of a Node to
1485 the command interpreter literally."""
1486 return 1
1487
1504 return SCons.Util.render_tree(s, f, 1)
1505 else:
1506 return None
1507
1509 """
1510 Return an absolute path to the Node. This will return simply
1511 str(Node) by default, but for Node types that have a concept of
1512 relative path, this might return something different.
1513 """
1514 return str(self)
1515
1517 """
1518 Return a string representation of the Node that will always
1519 be the same for this particular Node, no matter what. This
1520 is by contrast to the __str__() method, which might, for
1521 instance, return a relative path for a file Node. The purpose
1522 of this method is to generate a value to be used in signature
1523 calculation for the command line used to build a target, and
1524 we use this method instead of str() to avoid unnecessary
1525 rebuilds. This method does not need to return something that
1526 would actually work in a command line; it can return any kind of
1527 nonsense, so long as it does not change.
1528 """
1529 return str(self)
1530
1532 """This is a convenience function designed primarily to be
1533 used in command generators (i.e., CommandGeneratorActions or
1534 Environment variables that are callable), which are called
1535 with a for_signature argument that is nonzero if the command
1536 generator is being called to generate a signature for the
1537 command line, which determines if we should rebuild or not.
1538
1539 Such command generators should use this method in preference
1540 to str(Node) when converting a Node to a string, passing
1541 in the for_signature parameter, such that we will call
1542 Node.for_signature() or str(Node) properly, depending on whether
1543 we are calculating a signature or actually constructing a
1544 command line."""
1545 if for_signature:
1546 return self.for_signature()
1547 return str(self)
1548
1550 """
1551 This method is expected to return an object that will function
1552 exactly like this Node, except that it implements any additional
1553 special features that we would like to be in effect for
1554 Environment variable substitution. The principle use is that
1555 some Nodes would like to implement a __getattr__() method,
1556 but putting that in the Node type itself has a tendency to kill
1557 performance. We instead put it in a proxy and return it from
1558 this method. It is legal for this method to return self
1559 if no new functionality is needed for Environment substitution.
1560 """
1561 return self
1562
1564 if not self.exists():
1565 return "building `%s' because it doesn't exist\n" % self
1566
1567 if self.always_build:
1568 return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
1569
1570 old = self.get_stored_info()
1571 if old is None:
1572 return None
1573
1574 old = old.binfo
1575 old.prepare_dependencies()
1576
1577 try:
1578 old_bkids = old.bsources + old.bdepends + old.bimplicit
1579 old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs
1580 except AttributeError:
1581 return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
1582
1583 new = self.get_binfo()
1584
1585 new_bkids = new.bsources + new.bdepends + new.bimplicit
1586 new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
1587
1588 osig = dict(zip(old_bkids, old_bkidsigs))
1589 nsig = dict(zip(new_bkids, new_bkidsigs))
1590
1591
1592
1593
1594
1595
1596
1597 def stringify( s, E=self.dir.Entry ) :
1598 if hasattr( s, 'dir' ) :
1599 return str(E(s))
1600 return str(s)
1601
1602 lines = []
1603
1604 removed = [x for x in old_bkids if not x in new_bkids]
1605 if removed:
1606 removed = list(map(stringify, removed))
1607 fmt = "`%s' is no longer a dependency\n"
1608 lines.extend([fmt % s for s in removed])
1609
1610 for k in new_bkids:
1611 if not k in old_bkids:
1612 lines.append("`%s' is a new dependency\n" % stringify(k))
1613 elif _decider_map[k.changed_since_last_build](k, self, osig[k]):
1614 lines.append("`%s' changed\n" % stringify(k))
1615
1616 if len(lines) == 0 and old_bkids != new_bkids:
1617 lines.append("the dependency order changed:\n" +
1618 "%sold: %s\n" % (' '*15, list(map(stringify, old_bkids))) +
1619 "%snew: %s\n" % (' '*15, list(map(stringify, new_bkids))))
1620
1621 if len(lines) == 0:
1622 def fmt_with_title(title, strlines):
1623 lines = strlines.split('\n')
1624 sep = '\n' + ' '*(15 + len(title))
1625 return ' '*15 + title + sep.join(lines) + '\n'
1626 if old.bactsig != new.bactsig:
1627 if old.bact == new.bact:
1628 lines.append("the contents of the build action changed\n" +
1629 fmt_with_title('action: ', new.bact))
1630 else:
1631 lines.append("the build action changed:\n" +
1632 fmt_with_title('old: ', old.bact) +
1633 fmt_with_title('new: ', new.bact))
1634
1635 if len(lines) == 0:
1636 return "rebuilding `%s' for unknown reasons\n" % self
1637
1638 preamble = "rebuilding `%s' because" % self
1639 if len(lines) == 1:
1640 return "%s %s" % (preamble, lines[0])
1641 else:
1642 lines = ["%s:\n" % preamble] + lines
1643 return ( ' '*11).join(lines)
1644
1647 return str(list(map(str, self.data)))
1648
1652
1654 """An iterator for walking a Node tree.
1655
1656 This is depth-first, children are visited before the parent.
1657 The Walker object can be initialized with any node, and
1658 returns the next node on the descent with each get_next() call.
1659 'kids_func' is an optional function that will be called to
1660 get the children of a node instead of calling 'children'.
1661 'cycle_func' is an optional function that will be called
1662 when a cycle is detected.
1663
1664 This class does not get caught in node cycles caused, for example,
1665 by C header file include loops.
1666 """
1667 - def __init__(self, node, kids_func=get_children,
1668 cycle_func=ignore_cycle,
1669 eval_func=do_nothing):
1670 self.kids_func = kids_func
1671 self.cycle_func = cycle_func
1672 self.eval_func = eval_func
1673 node.wkids = copy.copy(kids_func(node, None))
1674 self.stack = [node]
1675 self.history = {}
1676 self.history[node] = None
1677
1679 """Return the next node for this walk of the tree.
1680
1681 This function is intentionally iterative, not recursive,
1682 to sidestep any issues of stack size limitations.
1683 """
1684
1685 while self.stack:
1686 if self.stack[-1].wkids:
1687 node = self.stack[-1].wkids.pop(0)
1688 if not self.stack[-1].wkids:
1689 self.stack[-1].wkids = None
1690 if node in self.history:
1691 self.cycle_func(node, self.stack)
1692 else:
1693 node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
1694 self.stack.append(node)
1695 self.history[node] = None
1696 else:
1697 node = self.stack.pop()
1698 del self.history[node]
1699 if node:
1700 if self.stack:
1701 parent = self.stack[-1]
1702 else:
1703 parent = None
1704 self.eval_func(node, parent)
1705 return node
1706 return None
1707
1709 return not self.stack
1710
1711
1712 arg2nodes_lookups = []
1713
1714
1715
1716
1717
1718
1719