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 bee7caf9defd6e108fc2998a2520ddb36a967691 2019-12-17 02:07:09 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
625
628
631
632 @SCons.Memoize.CountMethodCall
643
647
651
672
682
684 """Remove cached executor; forces recompute when needed."""
685 try:
686 delattr(self, 'executor')
687 except AttributeError:
688 pass
689
691 """Try to push a node into a cache
692 """
693 pass
694
696 """Try to retrieve the node's content from a cache
697
698 This method is called from multiple threads in a parallel build,
699 so only do thread safe stuff here. Do thread unsafe stuff in
700 built().
701
702 Returns true if the node was successfully retrieved.
703 """
704 return 0
705
706
707
708
709
711 """Get a Node ready for evaluation.
712
713 This is called before the Taskmaster decides if the Node is
714 up-to-date or not. Overriding this method allows for a Node
715 subclass to be disambiguated if necessary, or for an implicit
716 source builder to be attached.
717 """
718 pass
719
721 """Prepare for this Node to be built.
722
723 This is called after the Taskmaster has decided that the Node
724 is out-of-date and must be rebuilt, but before actually calling
725 the method to build the Node.
726
727 This default implementation checks that explicit or implicit
728 dependencies either exist or are derived, and initializes the
729 BuildInfo structure that will hold the information about how
730 this node is, uh, built.
731
732 (The existence of source files is checked separately by the
733 Executor, which aggregates checks for all of the targets built
734 by a specific action.)
735
736 Overriding this method allows for for a Node subclass to remove
737 the underlying file from the file system. Note that subclass
738 methods should call this base class method to get the child
739 check and the BuildInfo structure.
740 """
741 if self.depends is not None:
742 for d in self.depends:
743 if d.missing():
744 msg = "Explicit dependency `%s' not found, needed by target `%s'."
745 raise SCons.Errors.StopError(msg % (d, self))
746 if self.implicit is not None:
747 for i in self.implicit:
748 if i.missing():
749 msg = "Implicit dependency `%s' not found, needed by target `%s'."
750 raise SCons.Errors.StopError(msg % (i, self))
751 self.binfo = self.get_binfo()
752
754 """Actually build the node.
755
756 This is called by the Taskmaster after it's decided that the
757 Node is out-of-date and must be rebuilt, and after the prepare()
758 method has gotten everything, uh, prepared.
759
760 This method is called from multiple threads in a parallel build,
761 so only do thread safe stuff here. Do thread unsafe stuff
762 in built().
763
764 """
765 try:
766 self.get_executor()(self, **kw)
767 except SCons.Errors.BuildError as e:
768 e.node = self
769 raise
770
808
821
823 """Called just after this node has been marked
824 up-to-date or was built completely.
825
826 This is where we try to release as many target node infos
827 as possible for clean builds and update runs, in order
828 to minimize the overall memory consumption.
829
830 By purging attributes that aren't needed any longer after
831 a Node (=File) got built, we don't have to care that much how
832 many KBytes a Node actually requires...as long as we free
833 the memory shortly afterwards.
834
835 @see: built() and File.release_target_info()
836 """
837 pass
838
839
840
841
842
845
847 """
848 Returns the number of nodes added to our waiting parents list:
849 1 if we add a unique waiting parent, 0 if not. (Note that the
850 returned values are intended to be used to increment a reference
851 count, so don't think you can "clean up" this function by using
852 True and False instead...)
853 """
854 wp = self.waiting_parents
855 if node in wp:
856 return 0
857 wp.add(node)
858 return 1
859
860 - def postprocess(self):
861 """Clean up anything we don't need to hang onto after we've
862 been built."""
863 self.executor_cleanup()
864 self.waiting_parents = set()
865
867 """Completely clear a Node of all its cached state (so that it
868 can be re-evaluated by interfaces that do continuous integration
869 builds).
870 """
871
872
873
874 self.del_binfo()
875 self.clear_memoized_values()
876 self.ninfo = self.new_ninfo()
877 self.executor_cleanup()
878 try:
879 delattr(self, '_calculated_sig')
880 except AttributeError:
881 pass
882 self.includes = None
883
886
893
895 """Return whether this Node has a builder or not.
896
897 In Boolean tests, this turns out to be a *lot* more efficient
898 than simply examining the builder attribute directly ("if
899 node.builder: ..."). When the builder attribute is examined
900 directly, it ends up calling __getattr__ for both the __len__
901 and __nonzero__ attributes on instances of our Builder Proxy
902 class(es), generating a bazillion extra calls and slowing
903 things down immensely.
904 """
905 try:
906 b = self.builder
907 except AttributeError:
908
909
910 b = self.builder = None
911 return b is not None
912
915
917 """Return whether this Node has an explicit builder
918
919 This allows an internal Builder created by SCons to be marked
920 non-explicit, so that it can be overridden by an explicit
921 builder that the user supplies (the canonical example being
922 directories)."""
923 try:
924 return self.is_explicit
925 except AttributeError:
926 self.is_explicit = None
927 return self.is_explicit
928
930 """Return the set builder, or a specified default value"""
931 try:
932 return self.builder
933 except AttributeError:
934 return default_builder
935
936 multiple_side_effect_has_builder = has_builder
937
939 """
940 Returns true if this node is derived (i.e. built).
941
942 This should return true only for nodes whose path should be in
943 the variant directory when duplicate=0 and should contribute their build
944 signatures when they are used as source files to other derived files. For
945 example: source with source builders are not derived in this sense,
946 and hence should not return true.
947 """
948 return _is_derived_map[self._func_is_derived](self)
949
951 """Return a list of alternate targets for this Node.
952 """
953 return [], None
954
956 """Return the scanned include lines (implicit dependencies)
957 found in this node.
958
959 The default is no implicit dependencies. We expect this method
960 to be overridden by any subclass that can be scanned for
961 implicit dependencies.
962 """
963 return []
964
966 """Return a list of implicit dependencies for this node.
967
968 This method exists to handle recursive invocation of the scanner
969 on the implicit dependencies returned by the scanner, if the
970 scanner's recursive flag says that we should.
971 """
972 nodes = [self]
973 seen = set(nodes)
974 dependencies = []
975 path_memo = {}
976
977 root_node_scanner = self._get_scanner(env, initial_scanner, None, kw)
978
979 while nodes:
980 node = nodes.pop(0)
981
982 scanner = node._get_scanner(env, initial_scanner, root_node_scanner, kw)
983 if not scanner:
984 continue
985
986 try:
987 path = path_memo[scanner]
988 except KeyError:
989 path = path_func(scanner)
990 path_memo[scanner] = path
991
992 included_deps = [x for x in node.get_found_includes(env, scanner, path) if x not in seen]
993 if included_deps:
994 dependencies.extend(included_deps)
995 seen.update(included_deps)
996 nodes.extend(scanner.recurse_nodes(included_deps))
997
998 return dependencies
999
1000 - def _get_scanner(self, env, initial_scanner, root_node_scanner, kw):
1001 if initial_scanner:
1002
1003 scanner = initial_scanner.select(self)
1004 else:
1005
1006 scanner = self.get_env_scanner(env, kw)
1007 if scanner:
1008 scanner = scanner.select(self)
1009
1010 if not scanner:
1011
1012
1013 scanner = root_node_scanner
1014
1015 return scanner
1016
1019
1021 return self.builder.target_scanner
1022
1024 """Fetch the source scanner for the specified node
1025
1026 NOTE: "self" is the target being built, "node" is
1027 the source file for which we want to fetch the scanner.
1028
1029 Implies self.has_builder() is true; again, expect to only be
1030 called from locations where this is already verified.
1031
1032 This function may be called very often; it attempts to cache
1033 the scanner found to improve performance.
1034 """
1035 scanner = None
1036 try:
1037 scanner = self.builder.source_scanner
1038 except AttributeError:
1039 pass
1040 if not scanner:
1041
1042
1043
1044 scanner = self.get_env_scanner(self.get_build_env())
1045 if scanner:
1046 scanner = scanner.select(node)
1047 return scanner
1048
1055
1104
1107
1109 """Selects a scanner for this Node.
1110
1111 This is a separate method so it can be overridden by Node
1112 subclasses (specifically, Node.FS.Dir) that *must* use their
1113 own Scanner and don't select one the Scanner.Selector that's
1114 configured for the target.
1115 """
1116 return scanner.select(self)
1117
1119 if safe and self.env:
1120 return
1121 self.env = env
1122
1123
1124
1125
1126
1127 NodeInfo = NodeInfoBase
1128 BuildInfo = BuildInfoBase
1129
1133
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 changed = _decider_map[k.changed_since_last_build](k, self, osig[k])
1665
1666 if changed:
1667 lines.append("`%s' changed\n" % stringify(k))
1668
1669 if len(lines) == 0 and old_bkids != new_bkids:
1670 lines.append("the dependency order changed:\n")
1671 lines.append("->Sources\n")
1672 for (o,n) in zip_longest(old.bsources, new.bsources, fillvalue=None):
1673 lines.append("Old:%s\tNew:%s\n"%(o,n))
1674 lines.append("->Depends\n")
1675 for (o,n) in zip_longest(old.bdepends, new.bdepends, fillvalue=None):
1676 lines.append("Old:%s\tNew:%s\n"%(o,n))
1677 lines.append("->Implicit\n")
1678 for (o,n) in zip_longest(old.bimplicit, new.bimplicit, fillvalue=None):
1679 lines.append("Old:%s\tNew:%s\n"%(o,n))
1680
1681 if len(lines) == 0:
1682 def fmt_with_title(title, strlines):
1683 lines = strlines.split('\n')
1684 sep = '\n' + ' '*(15 + len(title))
1685 return ' '*15 + title + sep.join(lines) + '\n'
1686 if old.bactsig != new.bactsig:
1687 if old.bact == new.bact:
1688 lines.append("the contents of the build action changed\n" +
1689 fmt_with_title('action: ', new.bact))
1690
1691
1692
1693 else:
1694 lines.append("the build action changed:\n" +
1695 fmt_with_title('old: ', old.bact) +
1696 fmt_with_title('new: ', new.bact))
1697
1698 if len(lines) == 0:
1699 return "rebuilding `%s' for unknown reasons\n" % self
1700
1701 preamble = "rebuilding `%s' because" % self
1702 if len(lines) == 1:
1703 return "%s %s" % (preamble, lines[0])
1704 else:
1705 lines = ["%s:\n" % preamble] + lines
1706 return ( ' '*11).join(lines)
1707
1710 return str(list(map(str, self.data)))
1711
1715
1717 """An iterator for walking a Node tree.
1718
1719 This is depth-first, children are visited before the parent.
1720 The Walker object can be initialized with any node, and
1721 returns the next node on the descent with each get_next() call.
1722 get the children of a node instead of calling 'children'.
1723 'cycle_func' is an optional function that will be called
1724 when a cycle is detected.
1725
1726 This class does not get caught in node cycles caused, for example,
1727 by C header file include loops.
1728 """
1729 - def __init__(self, node, kids_func=get_children,
1730 cycle_func=ignore_cycle,
1731 eval_func=do_nothing):
1732 self.kids_func = kids_func
1733 self.cycle_func = cycle_func
1734 self.eval_func = eval_func
1735 node.wkids = copy.copy(kids_func(node, None))
1736 self.stack = [node]
1737 self.history = {}
1738 self.history[node] = None
1739
1741 """Return the next node for this walk of the tree.
1742
1743 This function is intentionally iterative, not recursive,
1744 to sidestep any issues of stack size limitations.
1745 """
1746
1747 while self.stack:
1748 if self.stack[-1].wkids:
1749 node = self.stack[-1].wkids.pop(0)
1750 if not self.stack[-1].wkids:
1751 self.stack[-1].wkids = None
1752 if node in self.history:
1753 self.cycle_func(node, self.stack)
1754 else:
1755 node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
1756 self.stack.append(node)
1757 self.history[node] = None
1758 else:
1759 node = self.stack.pop()
1760 del self.history[node]
1761 if node:
1762 if self.stack:
1763 parent = self.stack[-1]
1764 else:
1765 parent = None
1766 self.eval_func(node, parent)
1767 return node
1768 return None
1769
1771 return not self.stack
1772
1773
1774 arg2nodes_lookups = []
1775
1776
1777
1778
1779
1780
1781