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 from __future__ import print_function
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 __revision__ = "src/engine/SCons/Node/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
47
48 import os
49 import collections
50 import copy
51 from itertools import chain
52
53 try:
54 from itertools import zip_longest
55 except ImportError:
56 from itertools import izip_longest as zip_longest
57
58 import SCons.Debug
59 from SCons.Debug import logInstanceCreation
60 import SCons.Executor
61 import SCons.Memoize
62 import SCons.Util
63
64 from SCons.Debug import Trace
65
66 from SCons.compat import with_metaclass, NoSlotsPyPy
67
68 print_duplicate = 0
71 return str(obj.__class__).split('.')[-1]
72
73
74
75 do_store_info = True
76
77
78
79
80
81
82
83
84 no_state = 0
85 pending = 1
86 executing = 2
87 up_to_date = 3
88 executed = 4
89 failed = 5
90
91 StateString = {
92 0 : "no_state",
93 1 : "pending",
94 2 : "executing",
95 3 : "up_to_date",
96 4 : "executed",
97 5 : "failed",
98 }
99
100
101 implicit_cache = 0
102
103
104 implicit_deps_unchanged = 0
105
106
107 implicit_deps_changed = 0
112
113 Annotate = do_nothing_node
114
115
116
117
118 interactive = False
121 raise NotImplementedError
122
124 """
125 Returns true if this node is derived (i.e. built).
126 """
127 return node.has_builder() or node.side_effect
128
129 _is_derived_map = {0 : is_derived_none,
130 1 : is_derived_node}
133 raise NotImplementedError
134
137
139 return node.stat() is not None
140
141 -def exists_entry(node):
142 """Return if the Entry exists. Check the file system to see
143 what we should turn into first. Assume a file if there's no
144 directory."""
145 node.disambiguate()
146 return _exists_map[node._func_exists](node)
147
172
173 _exists_map = {0 : exists_none,
174 1 : exists_always,
175 2 : exists_base,
176 3 : exists_entry,
177 4 : exists_file}
181 raise NotImplementedError
182
185
188
189 _rexists_map = {0 : rexists_none,
190 1 : rexists_node,
191 2 : rexists_base}
192
193 -def get_contents_none(node):
194 raise NotImplementedError
195
197 """Fetch the contents of the entry. Returns the exact binary
198 contents of the file."""
199 try:
200 node = node.disambiguate(must_exist=1)
201 except SCons.Errors.UserError:
202
203
204
205
206
207 return ''
208 else:
209 return _get_contents_map[node._func_get_contents](node)
210
212 """Return content signatures and names of all our children
213 separated by new-lines. Ensure that the nodes are sorted."""
214 contents = []
215 for n in sorted(node.children(), key=lambda t: t.name):
216 contents.append('%s %s\n' % (n.get_csig(), n.name))
217 return ''.join(contents)
218
220 if not node.rexists():
221 return b''
222 fname = node.rfile().get_abspath()
223 try:
224 with open(fname, "rb") as fp:
225 contents = fp.read()
226 except EnvironmentError as e:
227 if not e.filename:
228 e.filename = fname
229 raise
230 return contents
231
232 _get_contents_map = {0 : get_contents_none,
233 1 : get_contents_entry,
234 2 : get_contents_dir,
235 3 : get_contents_file}
238 raise NotImplementedError
239
242
243 _target_from_source_map = {0 : target_from_source_none,
244 1 : target_from_source_base}
260 """
261
262 Must be overridden in a specific subclass to return True if this
263 Node (a dependency) has changed since the last time it was used
264 to build the specified target. prev_ni is this Node's state (for
265 example, its file timestamp, length, maybe content signature)
266 as of the last time the target was built.
267
268 Note that this method is called through the dependency, not the
269 target, because a dependency Node must be able to use its own
270 logic to decide if it changed. For example, File Nodes need to
271 obey if we're configured to use timestamps, but Python Value Nodes
272 never use timestamps and always use the content. If this method
273 were called through the target, then each Node's implementation
274 of this method would have to have more complicated logic to
275 handle all the different Node types on which it might depend.
276 """
277 raise NotImplementedError
278
281 cur_csig = node.get_csig()
282 try:
283 return cur_csig != prev_ni.csig
284 except AttributeError:
285 return 1
286
287
288 -def changed_since_last_build_entry(node, target, prev_ni, repo_node=None):
289 node.disambiguate()
290 return _decider_map[node.changed_since_last_build](node, target, prev_ni, repo_node)
291
295
298 return target.get_build_env().decide_source(node, target, prev_ni, repo_node)
299
302 return target.get_build_env().decide_target(node, target, prev_ni, repo_node)
303
306 cur_csig = node.get_csig()
307 try:
308 return cur_csig != prev_ni.csig
309 except AttributeError:
310 return 1
311
312
313
314
315
316 _decider_map = {0 : changed_since_last_build_node,
317 1 : changed_since_last_build_alias,
318 2 : changed_since_last_build_entry,
319 3 : changed_since_last_build_state_changed,
320 4 : decide_source,
321 5 : decide_target,
322 6 : changed_since_last_build_python}
323
324 do_store_info = True
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340 -def store_info_pass(node):
342
350
351
352 store_info_map = {0 : store_info_pass,
353 1 : store_info_file}
358 """
359 The generic base class for signature information for a Node.
360
361 Node subclasses should subclass NodeInfoBase to provide their own
362 logic for dealing with their own Node-specific signature information.
363 """
364 __slots__ = ('__weakref__',)
365 current_version_id = 2
366
368 try:
369 field_list = self.field_list
370 except AttributeError:
371 return
372 for f in field_list:
373 try:
374 delattr(self, f)
375 except AttributeError:
376 pass
377 try:
378 func = getattr(node, 'get_' + f)
379 except AttributeError:
380 pass
381 else:
382 setattr(self, f, func())
383
386
388 """
389 Merge the fields of another object into this object. Already existing
390 information is overwritten by the other instance's data.
391 WARNING: If a '__dict__' slot is added, it should be updated instead of
392 replaced.
393 """
394 state = other.__getstate__()
395 self.__setstate__(state)
396
419
421 """
422 Return all fields that shall be pickled. Walk the slots in the class
423 hierarchy and add those to the state dictionary. If a '__dict__' slot is
424 available, copy all entries to the dictionary. Also include the version
425 id, which is fixed for all instances of a class.
426 """
427 state = getattr(self, '__dict__', {}).copy()
428 for obj in type(self).mro():
429 for name in getattr(obj,'__slots__',()):
430 if hasattr(self, name):
431 state[name] = getattr(self, name)
432
433 state['_version_id'] = self.current_version_id
434 try:
435 del state['__weakref__']
436 except KeyError:
437 pass
438 return state
439
441 """
442 Restore the attributes from a pickled state. The version is discarded.
443 """
444
445 del state['_version_id']
446
447 for key, value in state.items():
448 if key not in ('__weakref__',):
449 setattr(self, key, value)
450
453 """
454 The generic base class for build information for a Node.
455
456 This is what gets stored in a .sconsign file for each target file.
457 It contains a NodeInfo instance for this node (signature information
458 that's specific to the type of Node) and direct attributes for the
459 generic build stuff we have to track: sources, explicit dependencies,
460 implicit dependencies, and action information.
461 """
462 __slots__ = ("bsourcesigs", "bdependsigs", "bimplicitsigs", "bactsig",
463 "bsources", "bdepends", "bact", "bimplicit", "__weakref__")
464 current_version_id = 2
465
473
475 """
476 Merge the fields of another object into this object. Already existing
477 information is overwritten by the other instance's data.
478 WARNING: If a '__dict__' slot is added, it should be updated instead of
479 replaced.
480 """
481 state = other.__getstate__()
482 self.__setstate__(state)
483
485 """
486 Return all fields that shall be pickled. Walk the slots in the class
487 hierarchy and add those to the state dictionary. If a '__dict__' slot is
488 available, copy all entries to the dictionary. Also include the version
489 id, which is fixed for all instances of a class.
490 """
491 state = getattr(self, '__dict__', {}).copy()
492 for obj in type(self).mro():
493 for name in getattr(obj,'__slots__',()):
494 if hasattr(self, name):
495 state[name] = getattr(self, name)
496
497 state['_version_id'] = self.current_version_id
498 try:
499 del state['__weakref__']
500 except KeyError:
501 pass
502 return state
503
505 """
506 Restore the attributes from a pickled state.
507 """
508
509 del state['_version_id']
510 for key, value in state.items():
511 if key not in ('__weakref__',):
512 setattr(self, key, value)
513
514
515 -class Node(object, with_metaclass(NoSlotsPyPy)):
516 """The base Node class, for entities that we know how to
517 build, or use to build other Nodes.
518 """
519
520 __slots__ = ['sources',
521 'sources_set',
522 'target_peers',
523 '_specific_sources',
524 'depends',
525 'depends_set',
526 'ignore',
527 'ignore_set',
528 'prerequisites',
529 'implicit',
530 'waiting_parents',
531 'waiting_s_e',
532 'ref_count',
533 'wkids',
534 'env',
535 'state',
536 'precious',
537 'noclean',
538 'nocache',
539 'cached',
540 'always_build',
541 'includes',
542 'attributes',
543 'side_effect',
544 'side_effects',
545 'linked',
546 '_memo',
547 'executor',
548 'binfo',
549 'ninfo',
550 'builder',
551 'is_explicit',
552 'implicit_set',
553 'changed_since_last_build',
554 'store_info',
555 'pseudo',
556 '_tags',
557 '_func_is_derived',
558 '_func_exists',
559 '_func_rexists',
560 '_func_get_contents',
561 '_func_target_from_source']
562
564 __slots__ = ('shared', '__dict__')
565
566
624
627
630
631 @SCons.Memoize.CountMethodCall
642
646
650
671
681
683 """Remove cached executor; forces recompute when needed."""
684 try:
685 delattr(self, 'executor')
686 except AttributeError:
687 pass
688
690 """Try to push a node into a cache
691 """
692 pass
693
695 """Try to retrieve the node's content from a cache
696
697 This method is called from multiple threads in a parallel build,
698 so only do thread safe stuff here. Do thread unsafe stuff in
699 built().
700
701 Returns true if the node was successfully retrieved.
702 """
703 return 0
704
705
706
707
708
710 """Get a Node ready for evaluation.
711
712 This is called before the Taskmaster decides if the Node is
713 up-to-date or not. Overriding this method allows for a Node
714 subclass to be disambiguated if necessary, or for an implicit
715 source builder to be attached.
716 """
717 pass
718
720 """Prepare for this Node to be built.
721
722 This is called after the Taskmaster has decided that the Node
723 is out-of-date and must be rebuilt, but before actually calling
724 the method to build the Node.
725
726 This default implementation checks that explicit or implicit
727 dependencies either exist or are derived, and initializes the
728 BuildInfo structure that will hold the information about how
729 this node is, uh, built.
730
731 (The existence of source files is checked separately by the
732 Executor, which aggregates checks for all of the targets built
733 by a specific action.)
734
735 Overriding this method allows for for a Node subclass to remove
736 the underlying file from the file system. Note that subclass
737 methods should call this base class method to get the child
738 check and the BuildInfo structure.
739 """
740 if self.depends is not None:
741 for d in self.depends:
742 if d.missing():
743 msg = "Explicit dependency `%s' not found, needed by target `%s'."
744 raise SCons.Errors.StopError(msg % (d, self))
745 if self.implicit is not None:
746 for i in self.implicit:
747 if i.missing():
748 msg = "Implicit dependency `%s' not found, needed by target `%s'."
749 raise SCons.Errors.StopError(msg % (i, self))
750 self.binfo = self.get_binfo()
751
753 """Actually build the node.
754
755 This is called by the Taskmaster after it's decided that the
756 Node is out-of-date and must be rebuilt, and after the prepare()
757 method has gotten everything, uh, prepared.
758
759 This method is called from multiple threads in a parallel build,
760 so only do thread safe stuff here. Do thread unsafe stuff
761 in built().
762
763 """
764 try:
765 self.get_executor()(self, **kw)
766 except SCons.Errors.BuildError as e:
767 e.node = self
768 raise
769
807
820
822 """Called just after this node has been marked
823 up-to-date or was built completely.
824
825 This is where we try to release as many target node infos
826 as possible for clean builds and update runs, in order
827 to minimize the overall memory consumption.
828
829 By purging attributes that aren't needed any longer after
830 a Node (=File) got built, we don't have to care that much how
831 many KBytes a Node actually requires...as long as we free
832 the memory shortly afterwards.
833
834 @see: built() and File.release_target_info()
835 """
836 pass
837
838
839
840
841
844
846 """
847 Returns the number of nodes added to our waiting parents list:
848 1 if we add a unique waiting parent, 0 if not. (Note that the
849 returned values are intended to be used to increment a reference
850 count, so don't think you can "clean up" this function by using
851 True and False instead...)
852 """
853 wp = self.waiting_parents
854 if node in wp:
855 return 0
856 wp.add(node)
857 return 1
858
859 - def postprocess(self):
860 """Clean up anything we don't need to hang onto after we've
861 been built."""
862 self.executor_cleanup()
863 self.waiting_parents = set()
864
866 """Completely clear a Node of all its cached state (so that it
867 can be re-evaluated by interfaces that do continuous integration
868 builds).
869 """
870
871
872
873 self.del_binfo()
874 self.clear_memoized_values()
875 self.ninfo = self.new_ninfo()
876 self.executor_cleanup()
877 try:
878 delattr(self, '_calculated_sig')
879 except AttributeError:
880 pass
881 self.includes = None
882
885
892
894 """Return whether this Node has a builder or not.
895
896 In Boolean tests, this turns out to be a *lot* more efficient
897 than simply examining the builder attribute directly ("if
898 node.builder: ..."). When the builder attribute is examined
899 directly, it ends up calling __getattr__ for both the __len__
900 and __nonzero__ attributes on instances of our Builder Proxy
901 class(es), generating a bazillion extra calls and slowing
902 things down immensely.
903 """
904 try:
905 b = self.builder
906 except AttributeError:
907
908
909 b = self.builder = None
910 return b is not None
911
914
916 """Return whether this Node has an explicit builder
917
918 This allows an internal Builder created by SCons to be marked
919 non-explicit, so that it can be overridden by an explicit
920 builder that the user supplies (the canonical example being
921 directories)."""
922 try:
923 return self.is_explicit
924 except AttributeError:
925 self.is_explicit = None
926 return self.is_explicit
927
929 """Return the set builder, or a specified default value"""
930 try:
931 return self.builder
932 except AttributeError:
933 return default_builder
934
935 multiple_side_effect_has_builder = has_builder
936
938 """
939 Returns true if this node is derived (i.e. built).
940
941 This should return true only for nodes whose path should be in
942 the variant directory when duplicate=0 and should contribute their build
943 signatures when they are used as source files to other derived files. For
944 example: source with source builders are not derived in this sense,
945 and hence should not return true.
946 """
947 return _is_derived_map[self._func_is_derived](self)
948
950 """Return a list of alternate targets for this Node.
951 """
952 return [], None
953
955 """Return the scanned include lines (implicit dependencies)
956 found in this node.
957
958 The default is no implicit dependencies. We expect this method
959 to be overridden by any subclass that can be scanned for
960 implicit dependencies.
961 """
962 return []
963
965 """Return a list of implicit dependencies for this node.
966
967 This method exists to handle recursive invocation of the scanner
968 on the implicit dependencies returned by the scanner, if the
969 scanner's recursive flag says that we should.
970 """
971 nodes = [self]
972 seen = set(nodes)
973 dependencies = []
974 path_memo = {}
975
976 root_node_scanner = self._get_scanner(env, initial_scanner, None, kw)
977
978 while nodes:
979 node = nodes.pop(0)
980
981 scanner = node._get_scanner(env, initial_scanner, root_node_scanner, kw)
982 if not scanner:
983 continue
984
985 try:
986 path = path_memo[scanner]
987 except KeyError:
988 path = path_func(scanner)
989 path_memo[scanner] = path
990
991 included_deps = [x for x in node.get_found_includes(env, scanner, path) if x not in seen]
992 if included_deps:
993 dependencies.extend(included_deps)
994 seen.update(included_deps)
995 nodes.extend(scanner.recurse_nodes(included_deps))
996
997 return dependencies
998
999 - def _get_scanner(self, env, initial_scanner, root_node_scanner, kw):
1000 if initial_scanner:
1001
1002 scanner = initial_scanner.select(self)
1003 else:
1004
1005 scanner = self.get_env_scanner(env, kw)
1006 if scanner:
1007 scanner = scanner.select(self)
1008
1009 if not scanner:
1010
1011
1012 scanner = root_node_scanner
1013
1014 return scanner
1015
1018
1020 return self.builder.target_scanner
1021
1023 """Fetch the source scanner for the specified node
1024
1025 NOTE: "self" is the target being built, "node" is
1026 the source file for which we want to fetch the scanner.
1027
1028 Implies self.has_builder() is true; again, expect to only be
1029 called from locations where this is already verified.
1030
1031 This function may be called very often; it attempts to cache
1032 the scanner found to improve performance.
1033 """
1034 scanner = None
1035 try:
1036 scanner = self.builder.source_scanner
1037 except AttributeError:
1038 pass
1039 if not scanner:
1040
1041
1042
1043 scanner = self.get_env_scanner(self.get_build_env())
1044 if scanner:
1045 scanner = scanner.select(node)
1046 return scanner
1047
1054
1103
1106
1108 """Selects a scanner for this Node.
1109
1110 This is a separate method so it can be overridden by Node
1111 subclasses (specifically, Node.FS.Dir) that *must* use their
1112 own Scanner and don't select one the Scanner.Selector that's
1113 configured for the target.
1114 """
1115 return scanner.select(self)
1116
1118 if safe and self.env:
1119 return
1120 self.env = env
1121
1122
1123
1124
1125
1126 NodeInfo = NodeInfoBase
1127 BuildInfo = BuildInfoBase
1128
1132
1139
1143
1195
1197 """Delete the build info from this node."""
1198 try:
1199 delattr(self, 'binfo')
1200 except AttributeError:
1201 pass
1202
1210
1213
1216
1218 """Fetch the stored implicit dependencies"""
1219 return None
1220
1221
1222
1223
1224
1228
1230 """Set the Node's precious value."""
1231 self.pseudo = pseudo
1232
1234 """Set the Node's noclean value."""
1235
1236
1237 self.noclean = noclean and 1 or 0
1238
1240 """Set the Node's nocache value."""
1241
1242
1243 self.nocache = nocache and 1 or 0
1244
1248
1252
1257
1258 - def get_contents(self):
1259 """Fetch the contents of the entry."""
1260 return _get_contents_map[self._func_get_contents](self)
1261
1266
1268 """Remove this Node: no-op by default."""
1269 return None
1270
1272 """Adds dependencies."""
1273 try:
1274 self._add_child(self.depends, self.depends_set, depend)
1275 except TypeError as e:
1276 e = e.args[0]
1277 if SCons.Util.is_List(e):
1278 s = list(map(str, e))
1279 else:
1280 s = str(e)
1281 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)))
1282
1289
1291 """Adds dependencies to ignore."""
1292 try:
1293 self._add_child(self.ignore, self.ignore_set, depend)
1294 except TypeError as e:
1295 e = e.args[0]
1296 if SCons.Util.is_List(e):
1297 s = list(map(str, e))
1298 else:
1299 s = str(e)
1300 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)))
1301
1315
1317 """Adds 'child' to 'collection', first checking 'set' to see if it's
1318 already present."""
1319 added = None
1320 for c in child:
1321 if c not in set:
1322 set.add(c)
1323 collection.append(c)
1324 added = 1
1325 if added:
1326 self._children_reset()
1327
1331
1333 """Add a node to the list of kids waiting to be evaluated"""
1334 if self.wkids is not None:
1335 self.wkids.append(wkid)
1336
1342
1343 @SCons.Memoize.CountMethodCall
1379
1381 """Return a list of all the node's direct children."""
1382 if scan:
1383 self.scan()
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402 return list(chain.from_iterable([_f for _f in [self.sources, self.depends, self.implicit] if _f]))
1403
1405 """Return a list of the node's direct children, minus those
1406 that are ignored by this node."""
1407 if scan:
1408 self.scan()
1409 return self._children_get()
1410
1413
1416
1423
1434
1435 - def Tag(self, key, value):
1436 """ Add a user-defined tag. """
1437 if not self._tags:
1438 self._tags = {}
1439 self._tags[key] = value
1440
1442 """ Return a user-defined tag. """
1443 if not self._tags:
1444 return None
1445 return self._tags.get(key, None)
1446
1447 - def changed(self, node=None, allowcache=False):
1448 """
1449 Returns if the node is up-to-date with respect to the BuildInfo
1450 stored last time it was built. The default behavior is to compare
1451 it against our own previously stored BuildInfo, but the stored
1452 BuildInfo from another Node (typically one in a Repository)
1453 can be used instead.
1454
1455 Note that we now *always* check every dependency. We used to
1456 short-circuit the check by returning as soon as we detected
1457 any difference, but we now rely on checking every dependency
1458 to make sure that any necessary Node information (for example,
1459 the content signature of an #included .h file) is updated.
1460
1461 The allowcache option was added for supporting the early
1462 release of the executor/builder structures, right after
1463 a File target was built. When set to true, the return
1464 value of this changed method gets cached for File nodes.
1465 Like this, the executor isn't needed any longer for subsequent
1466 calls to changed().
1467
1468 @see: FS.File.changed(), FS.File.release_target_info()
1469 """
1470 t = 0
1471 if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node))
1472 if node is None:
1473 node = self
1474
1475 result = False
1476
1477 bi = node.get_stored_info().binfo
1478 then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs
1479 children = self.children()
1480
1481 diff = len(children) - len(then)
1482 if diff:
1483
1484
1485
1486
1487
1488 then.extend([None] * diff)
1489 if t: Trace(': old %s new %s' % (len(then), len(children)))
1490 result = True
1491
1492 for child, prev_ni in zip(children, then):
1493 if _decider_map[child.changed_since_last_build](child, self, prev_ni, node):
1494 if t: Trace(': %s changed' % child)
1495 result = True
1496
1497 if self.has_builder():
1498 contents = self.get_executor().get_contents()
1499 newsig = SCons.Util.MD5signature(contents)
1500 if bi.bactsig != newsig:
1501 if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
1502 result = True
1503
1504 if not result:
1505 if t: Trace(': up to date')
1506
1507 if t: Trace('\n')
1508
1509 return result
1510
1512 """Default check for whether the Node is current: unknown Node
1513 subtypes are always out of date, so they will always get built."""
1514 return None
1515
1517 """Alternate check for whether the Node is current: If all of
1518 our children were up-to-date, then this Node was up-to-date, too.
1519
1520 The SCons.Node.Alias and SCons.Node.Python.Value subclasses
1521 rebind their current() method to this method."""
1522
1523 self.binfo = self.get_binfo()
1524 if self.always_build:
1525 return None
1526 state = 0
1527 for kid in self.children(None):
1528 s = kid.get_state()
1529 if s and (not state or s > state):
1530 state = s
1531 return (state == 0 or state == SCons.Node.up_to_date)
1532
1534 """Always pass the string representation of a Node to
1535 the command interpreter literally."""
1536 return 1
1537
1554 return SCons.Util.render_tree(s, f, 1)
1555 else:
1556 return None
1557
1559 """
1560 Return an absolute path to the Node. This will return simply
1561 str(Node) by default, but for Node types that have a concept of
1562 relative path, this might return something different.
1563 """
1564 return str(self)
1565
1567 """
1568 Return a string representation of the Node that will always
1569 be the same for this particular Node, no matter what. This
1570 is by contrast to the __str__() method, which might, for
1571 instance, return a relative path for a file Node. The purpose
1572 of this method is to generate a value to be used in signature
1573 calculation for the command line used to build a target, and
1574 we use this method instead of str() to avoid unnecessary
1575 rebuilds. This method does not need to return something that
1576 would actually work in a command line; it can return any kind of
1577 nonsense, so long as it does not change.
1578 """
1579 return str(self)
1580
1582 """This is a convenience function designed primarily to be
1583 used in command generators (i.e., CommandGeneratorActions or
1584 Environment variables that are callable), which are called
1585 with a for_signature argument that is nonzero if the command
1586 generator is being called to generate a signature for the
1587 command line, which determines if we should rebuild or not.
1588
1589 Such command generators should use this method in preference
1590 to str(Node) when converting a Node to a string, passing
1591 in the for_signature parameter, such that we will call
1592 Node.for_signature() or str(Node) properly, depending on whether
1593 we are calculating a signature or actually constructing a
1594 command line."""
1595 if for_signature:
1596 return self.for_signature()
1597 return str(self)
1598
1600 """
1601 This method is expected to return an object that will function
1602 exactly like this Node, except that it implements any additional
1603 special features that we would like to be in effect for
1604 Environment variable substitution. The principle use is that
1605 some Nodes would like to implement a __getattr__() method,
1606 but putting that in the Node type itself has a tendency to kill
1607 performance. We instead put it in a proxy and return it from
1608 this method. It is legal for this method to return self
1609 if no new functionality is needed for Environment substitution.
1610 """
1611 return self
1612
1614 if not self.exists():
1615 return "building `%s' because it doesn't exist\n" % self
1616
1617 if self.always_build:
1618 return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
1619
1620 old = self.get_stored_info()
1621 if old is None:
1622 return None
1623
1624 old = old.binfo
1625 old.prepare_dependencies()
1626
1627 try:
1628 old_bkids = old.bsources + old.bdepends + old.bimplicit
1629 old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs
1630 except AttributeError:
1631 return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
1632
1633 new = self.get_binfo()
1634
1635 new_bkids = new.bsources + new.bdepends + new.bimplicit
1636 new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
1637
1638 osig = dict(list(zip(old_bkids, old_bkidsigs)))
1639 nsig = dict(list(zip(new_bkids, new_bkidsigs)))
1640
1641
1642
1643
1644
1645
1646
1647 def stringify( s, E=self.dir.Entry):
1648 if hasattr( s, 'dir' ) :
1649 return str(E(s))
1650 return str(s)
1651
1652 lines = []
1653
1654 removed = [x for x in old_bkids if x not in new_bkids]
1655 if removed:
1656 removed = [stringify(r) for r in removed]
1657 fmt = "`%s' is no longer a dependency\n"
1658 lines.extend([fmt % s for s in removed])
1659
1660 for k in new_bkids:
1661 if k not in old_bkids:
1662 lines.append("`%s' is a new dependency\n" % stringify(k))
1663 else:
1664 try:
1665 changed = _decider_map[k.changed_since_last_build](k, self, osig[k])
1666 except DeciderNeedsNode as e:
1667 changed = e.decider(self, osig[k], node=self)
1668
1669 if changed:
1670 lines.append("`%s' changed\n" % stringify(k))
1671
1672 if len(lines) == 0 and old_bkids != new_bkids:
1673 lines.append("the dependency order changed:\n")
1674 lines.append("->Sources\n")
1675 for (o,n) in zip_longest(old.bsources, new.bsources, fillvalue=None):
1676 lines.append("Old:%s\tNew:%s\n"%(o,n))
1677 lines.append("->Depends\n")
1678 for (o,n) in zip_longest(old.bdepends, new.bdepends, fillvalue=None):
1679 lines.append("Old:%s\tNew:%s\n"%(o,n))
1680 lines.append("->Implicit\n")
1681 for (o,n) in zip_longest(old.bimplicit, new.bimplicit, fillvalue=None):
1682 lines.append("Old:%s\tNew:%s\n"%(o,n))
1683
1684 if len(lines) == 0:
1685 def fmt_with_title(title, strlines):
1686 lines = strlines.split('\n')
1687 sep = '\n' + ' '*(15 + len(title))
1688 return ' '*15 + title + sep.join(lines) + '\n'
1689 if old.bactsig != new.bactsig:
1690 if old.bact == new.bact:
1691 lines.append("the contents of the build action changed\n" +
1692 fmt_with_title('action: ', new.bact))
1693
1694
1695
1696 else:
1697 lines.append("the build action changed:\n" +
1698 fmt_with_title('old: ', old.bact) +
1699 fmt_with_title('new: ', new.bact))
1700
1701 if len(lines) == 0:
1702 return "rebuilding `%s' for unknown reasons\n" % self
1703
1704 preamble = "rebuilding `%s' because" % self
1705 if len(lines) == 1:
1706 return "%s %s" % (preamble, lines[0])
1707 else:
1708 lines = ["%s:\n" % preamble] + lines
1709 return ( ' '*11).join(lines)
1710
1713 return str(list(map(str, self.data)))
1714
1718
1720 """An iterator for walking a Node tree.
1721
1722 This is depth-first, children are visited before the parent.
1723 The Walker object can be initialized with any node, and
1724 returns the next node on the descent with each get_next() call.
1725 get the children of a node instead of calling 'children'.
1726 'cycle_func' is an optional function that will be called
1727 when a cycle is detected.
1728
1729 This class does not get caught in node cycles caused, for example,
1730 by C header file include loops.
1731 """
1732 - def __init__(self, node, kids_func=get_children,
1733 cycle_func=ignore_cycle,
1734 eval_func=do_nothing):
1735 self.kids_func = kids_func
1736 self.cycle_func = cycle_func
1737 self.eval_func = eval_func
1738 node.wkids = copy.copy(kids_func(node, None))
1739 self.stack = [node]
1740 self.history = {}
1741 self.history[node] = None
1742
1744 """Return the next node for this walk of the tree.
1745
1746 This function is intentionally iterative, not recursive,
1747 to sidestep any issues of stack size limitations.
1748 """
1749
1750 while self.stack:
1751 if self.stack[-1].wkids:
1752 node = self.stack[-1].wkids.pop(0)
1753 if not self.stack[-1].wkids:
1754 self.stack[-1].wkids = None
1755 if node in self.history:
1756 self.cycle_func(node, self.stack)
1757 else:
1758 node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
1759 self.stack.append(node)
1760 self.history[node] = None
1761 else:
1762 node = self.stack.pop()
1763 del self.history[node]
1764 if node:
1765 if self.stack:
1766 parent = self.stack[-1]
1767 else:
1768 parent = None
1769 self.eval_func(node, parent)
1770 return node
1771 return None
1772
1774 return not self.stack
1775
1776
1777 arg2nodes_lookups = []
1778
1779
1780
1781
1782
1783
1784