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.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 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 nodes = [self]
927 seen = set(nodes)
928 dependencies = []
929 path_memo = {}
930
931 root_node_scanner = self._get_scanner(env, initial_scanner, None, kw)
932
933 while nodes:
934 node = nodes.pop(0)
935
936 scanner = node._get_scanner(env, initial_scanner, root_node_scanner, kw)
937 if not scanner:
938 continue
939
940 try:
941 path = path_memo[scanner]
942 except KeyError:
943 path = path_func(scanner)
944 path_memo[scanner] = path
945
946 included_deps = [x for x in node.get_found_includes(env, scanner, path) if x not in seen]
947 if included_deps:
948 dependencies.extend(included_deps)
949 seen.update(included_deps)
950 nodes.extend(scanner.recurse_nodes(included_deps))
951
952 return dependencies
953
954 - def _get_scanner(self, env, initial_scanner, root_node_scanner, kw):
955 if initial_scanner:
956
957 scanner = initial_scanner.select(self)
958 else:
959
960 scanner = self.get_env_scanner(env, kw)
961 if scanner:
962 scanner = scanner.select(self)
963
964 if not scanner:
965
966
967 scanner = root_node_scanner
968
969 return scanner
970
973
975 return self.builder.target_scanner
976
978 """Fetch the source scanner for the specified node
979
980 NOTE: "self" is the target being built, "node" is
981 the source file for which we want to fetch the scanner.
982
983 Implies self.has_builder() is true; again, expect to only be
984 called from locations where this is already verified.
985
986 This function may be called very often; it attempts to cache
987 the scanner found to improve performance.
988 """
989 scanner = None
990 try:
991 scanner = self.builder.source_scanner
992 except AttributeError:
993 pass
994 if not scanner:
995
996
997
998 scanner = self.get_env_scanner(self.get_build_env())
999 if scanner:
1000 scanner = scanner.select(node)
1001 return scanner
1002
1009
1058
1061
1063 """Selects a scanner for this Node.
1064
1065 This is a separate method so it can be overridden by Node
1066 subclasses (specifically, Node.FS.Dir) that *must* use their
1067 own Scanner and don't select one the Scanner.Selector that's
1068 configured for the target.
1069 """
1070 return scanner.select(self)
1071
1073 if safe and self.env:
1074 return
1075 self.env = env
1076
1077
1078
1079
1080
1081 NodeInfo = NodeInfoBase
1082 BuildInfo = BuildInfoBase
1083
1087
1094
1098
1162
1164 """Delete the build info from this node."""
1165 try:
1166 delattr(self, 'binfo')
1167 except AttributeError:
1168 pass
1169
1177
1180
1183
1185 """Fetch the stored implicit dependencies"""
1186 return None
1187
1188
1189
1190
1191
1195
1197 """Set the Node's precious value."""
1198 self.pseudo = pseudo
1199
1201 """Set the Node's noclean value."""
1202
1203
1204 self.noclean = noclean and 1 or 0
1205
1207 """Set the Node's nocache value."""
1208
1209
1210 self.nocache = nocache and 1 or 0
1211
1215
1219
1224
1225 - def get_contents(self):
1226 """Fetch the contents of the entry."""
1227 return _get_contents_map[self._func_get_contents](self)
1228
1233
1235 """Remove this Node: no-op by default."""
1236 return None
1237
1239 """Adds dependencies."""
1240 try:
1241 self._add_child(self.depends, self.depends_set, depend)
1242 except TypeError, e:
1243 e = e.args[0]
1244 if SCons.Util.is_List(e):
1245 s = list(map(str, e))
1246 else:
1247 s = str(e)
1248 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)))
1249
1256
1258 """Adds dependencies to ignore."""
1259 try:
1260 self._add_child(self.ignore, self.ignore_set, depend)
1261 except TypeError, e:
1262 e = e.args[0]
1263 if SCons.Util.is_List(e):
1264 s = list(map(str, e))
1265 else:
1266 s = str(e)
1267 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)))
1268
1282
1284 """Adds 'child' to 'collection', first checking 'set' to see if it's
1285 already present."""
1286 added = None
1287 for c in child:
1288 if c not in set:
1289 set.add(c)
1290 collection.append(c)
1291 added = 1
1292 if added:
1293 self._children_reset()
1294
1298
1300 """Add a node to the list of kids waiting to be evaluated"""
1301 if self.wkids is not None:
1302 self.wkids.append(wkid)
1303
1309
1310 @SCons.Memoize.CountMethodCall
1346
1348 """Return a list of all the node's direct children."""
1349 if scan:
1350 self.scan()
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369 return list(chain.from_iterable(filter(None, [self.sources, self.depends, self.implicit])))
1370
1372 """Return a list of the node's direct children, minus those
1373 that are ignored by this node."""
1374 if scan:
1375 self.scan()
1376 return self._children_get()
1377
1380
1383
1390
1401
1402 - def Tag(self, key, value):
1403 """ Add a user-defined tag. """
1404 if not self._tags:
1405 self._tags = {}
1406 self._tags[key] = value
1407
1409 """ Return a user-defined tag. """
1410 if not self._tags:
1411 return None
1412 return self._tags.get(key, None)
1413
1414 - def changed(self, node=None, allowcache=False):
1415 """
1416 Returns if the node is up-to-date with respect to the BuildInfo
1417 stored last time it was built. The default behavior is to compare
1418 it against our own previously stored BuildInfo, but the stored
1419 BuildInfo from another Node (typically one in a Repository)
1420 can be used instead.
1421
1422 Note that we now *always* check every dependency. We used to
1423 short-circuit the check by returning as soon as we detected
1424 any difference, but we now rely on checking every dependency
1425 to make sure that any necessary Node information (for example,
1426 the content signature of an #included .h file) is updated.
1427
1428 The allowcache option was added for supporting the early
1429 release of the executor/builder structures, right after
1430 a File target was built. When set to true, the return
1431 value of this changed method gets cached for File nodes.
1432 Like this, the executor isn't needed any longer for subsequent
1433 calls to changed().
1434
1435 @see: FS.File.changed(), FS.File.release_target_info()
1436 """
1437 t = 0
1438 if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node))
1439 if node is None:
1440 node = self
1441
1442 result = False
1443
1444 bi = node.get_stored_info().binfo
1445 then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs
1446 children = self.children()
1447
1448 diff = len(children) - len(then)
1449 if diff:
1450
1451
1452
1453
1454
1455 then.extend([None] * diff)
1456 if t: Trace(': old %s new %s' % (len(then), len(children)))
1457 result = True
1458
1459 for child, prev_ni in zip(children, then):
1460 if _decider_map[child.changed_since_last_build](child, self, prev_ni):
1461 if t: Trace(': %s changed' % child)
1462 result = True
1463
1464 contents = self.get_executor().get_contents()
1465 if self.has_builder():
1466 import SCons.Util
1467 newsig = SCons.Util.MD5signature(contents)
1468 if bi.bactsig != newsig:
1469 if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
1470 result = True
1471
1472 if not result:
1473 if t: Trace(': up to date')
1474
1475 if t: Trace('\n')
1476
1477 return result
1478
1480 """Default check for whether the Node is current: unknown Node
1481 subtypes are always out of date, so they will always get built."""
1482 return None
1483
1485 """Alternate check for whether the Node is current: If all of
1486 our children were up-to-date, then this Node was up-to-date, too.
1487
1488 The SCons.Node.Alias and SCons.Node.Python.Value subclasses
1489 rebind their current() method to this method."""
1490
1491 self.binfo = self.get_binfo()
1492 if self.always_build:
1493 return None
1494 state = 0
1495 for kid in self.children(None):
1496 s = kid.get_state()
1497 if s and (not state or s > state):
1498 state = s
1499 return (state == 0 or state == SCons.Node.up_to_date)
1500
1502 """Always pass the string representation of a Node to
1503 the command interpreter literally."""
1504 return 1
1505
1522 return SCons.Util.render_tree(s, f, 1)
1523 else:
1524 return None
1525
1527 """
1528 Return an absolute path to the Node. This will return simply
1529 str(Node) by default, but for Node types that have a concept of
1530 relative path, this might return something different.
1531 """
1532 return str(self)
1533
1535 """
1536 Return a string representation of the Node that will always
1537 be the same for this particular Node, no matter what. This
1538 is by contrast to the __str__() method, which might, for
1539 instance, return a relative path for a file Node. The purpose
1540 of this method is to generate a value to be used in signature
1541 calculation for the command line used to build a target, and
1542 we use this method instead of str() to avoid unnecessary
1543 rebuilds. This method does not need to return something that
1544 would actually work in a command line; it can return any kind of
1545 nonsense, so long as it does not change.
1546 """
1547 return str(self)
1548
1550 """This is a convenience function designed primarily to be
1551 used in command generators (i.e., CommandGeneratorActions or
1552 Environment variables that are callable), which are called
1553 with a for_signature argument that is nonzero if the command
1554 generator is being called to generate a signature for the
1555 command line, which determines if we should rebuild or not.
1556
1557 Such command generators should use this method in preference
1558 to str(Node) when converting a Node to a string, passing
1559 in the for_signature parameter, such that we will call
1560 Node.for_signature() or str(Node) properly, depending on whether
1561 we are calculating a signature or actually constructing a
1562 command line."""
1563 if for_signature:
1564 return self.for_signature()
1565 return str(self)
1566
1568 """
1569 This method is expected to return an object that will function
1570 exactly like this Node, except that it implements any additional
1571 special features that we would like to be in effect for
1572 Environment variable substitution. The principle use is that
1573 some Nodes would like to implement a __getattr__() method,
1574 but putting that in the Node type itself has a tendency to kill
1575 performance. We instead put it in a proxy and return it from
1576 this method. It is legal for this method to return self
1577 if no new functionality is needed for Environment substitution.
1578 """
1579 return self
1580
1582 if not self.exists():
1583 return "building `%s' because it doesn't exist\n" % self
1584
1585 if self.always_build:
1586 return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
1587
1588 old = self.get_stored_info()
1589 if old is None:
1590 return None
1591
1592 old = old.binfo
1593 old.prepare_dependencies()
1594
1595 try:
1596 old_bkids = old.bsources + old.bdepends + old.bimplicit
1597 old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs
1598 except AttributeError:
1599 return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
1600
1601 new = self.get_binfo()
1602
1603 new_bkids = new.bsources + new.bdepends + new.bimplicit
1604 new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
1605
1606 osig = dict(zip(old_bkids, old_bkidsigs))
1607 nsig = dict(zip(new_bkids, new_bkidsigs))
1608
1609
1610
1611
1612
1613
1614
1615 def stringify( s, E=self.dir.Entry ) :
1616 if hasattr( s, 'dir' ) :
1617 return str(E(s))
1618 return str(s)
1619
1620 lines = []
1621
1622 removed = [x for x in old_bkids if not x in new_bkids]
1623 if removed:
1624 removed = list(map(stringify, removed))
1625 fmt = "`%s' is no longer a dependency\n"
1626 lines.extend([fmt % s for s in removed])
1627
1628 for k in new_bkids:
1629 if not k in old_bkids:
1630 lines.append("`%s' is a new dependency\n" % stringify(k))
1631 elif _decider_map[k.changed_since_last_build](k, self, osig[k]):
1632 lines.append("`%s' changed\n" % stringify(k))
1633
1634 if len(lines) == 0 and old_bkids != new_bkids:
1635 lines.append("the dependency order changed:\n" +
1636 "%sold: %s\n" % (' '*15, list(map(stringify, old_bkids))) +
1637 "%snew: %s\n" % (' '*15, list(map(stringify, new_bkids))))
1638
1639 if len(lines) == 0:
1640 def fmt_with_title(title, strlines):
1641 lines = strlines.split('\n')
1642 sep = '\n' + ' '*(15 + len(title))
1643 return ' '*15 + title + sep.join(lines) + '\n'
1644 if old.bactsig != new.bactsig:
1645 if old.bact == new.bact:
1646 lines.append("the contents of the build action changed\n" +
1647 fmt_with_title('action: ', new.bact))
1648 else:
1649 lines.append("the build action changed:\n" +
1650 fmt_with_title('old: ', old.bact) +
1651 fmt_with_title('new: ', new.bact))
1652
1653 if len(lines) == 0:
1654 return "rebuilding `%s' for unknown reasons\n" % self
1655
1656 preamble = "rebuilding `%s' because" % self
1657 if len(lines) == 1:
1658 return "%s %s" % (preamble, lines[0])
1659 else:
1660 lines = ["%s:\n" % preamble] + lines
1661 return ( ' '*11).join(lines)
1662
1665 return str(list(map(str, self.data)))
1666
1670
1672 """An iterator for walking a Node tree.
1673
1674 This is depth-first, children are visited before the parent.
1675 The Walker object can be initialized with any node, and
1676 returns the next node on the descent with each get_next() call.
1677 'kids_func' is an optional function that will be called to
1678 get the children of a node instead of calling 'children'.
1679 'cycle_func' is an optional function that will be called
1680 when a cycle is detected.
1681
1682 This class does not get caught in node cycles caused, for example,
1683 by C header file include loops.
1684 """
1685 - def __init__(self, node, kids_func=get_children,
1686 cycle_func=ignore_cycle,
1687 eval_func=do_nothing):
1688 self.kids_func = kids_func
1689 self.cycle_func = cycle_func
1690 self.eval_func = eval_func
1691 node.wkids = copy.copy(kids_func(node, None))
1692 self.stack = [node]
1693 self.history = {}
1694 self.history[node] = None
1695
1697 """Return the next node for this walk of the tree.
1698
1699 This function is intentionally iterative, not recursive,
1700 to sidestep any issues of stack size limitations.
1701 """
1702
1703 while self.stack:
1704 if self.stack[-1].wkids:
1705 node = self.stack[-1].wkids.pop(0)
1706 if not self.stack[-1].wkids:
1707 self.stack[-1].wkids = None
1708 if node in self.history:
1709 self.cycle_func(node, self.stack)
1710 else:
1711 node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
1712 self.stack.append(node)
1713 self.history[node] = None
1714 else:
1715 node = self.stack.pop()
1716 del self.history[node]
1717 if node:
1718 if self.stack:
1719 parent = self.stack[-1]
1720 else:
1721 parent = None
1722 self.eval_func(node, parent)
1723 return node
1724 return None
1725
1727 return not self.stack
1728
1729
1730 arg2nodes_lookups = []
1731
1732
1733
1734
1735
1736
1737