1 """SCons.Executor
2
3 A module for executing actions with specific lists of target and source
4 Nodes.
5
6 """
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 from __future__ import print_function
30
31 __revision__ = "src/engine/SCons/Executor.py 3a41ed6b288cee8d085373ad7fa02894e1903864 2019-01-23 17:30:35 bdeegan"
32
33 import collections
34
35 import SCons.Debug
36 from SCons.Debug import logInstanceCreation
37 import SCons.Errors
38 import SCons.Memoize
39 from SCons.compat import with_metaclass, NoSlotsPyPy
42 """Remembers exact association between targets
43 and sources of executor."""
44
45 __slots__ = ('targets',
46 'sources')
47
48 - def __init__(self, targets=[], sources=[]):
51
52
53
54 -class TSList(collections.UserList):
55 """A class that implements $TARGETS or $SOURCES expansions by wrapping
56 an executor Method. This class is used in the Executor.lvars()
57 to delay creation of NodeList objects until they're needed.
58
59 Note that we subclass collections.UserList purely so that the
60 is_Sequence() function will identify an object of this class as
61 a list during variable expansion. We're not really using any
62 collections.UserList methods in practice.
63 """
67 nl = self.func()
68 return getattr(nl, attr)
70 nl = self.func()
71 return nl[i]
73 nl = self.func()
74 i = max(i, 0); j = max(j, 0)
75 return nl[i:j]
77 nl = self.func()
78 return str(nl)
80 nl = self.func()
81 return repr(nl)
82
84 """A class that implements $TARGET or $SOURCE expansions by wrapping
85 an Executor method.
86 """
90 n = self.func()
91 return getattr(n, attr)
93 n = self.func()
94 if n:
95 return str(n)
96 return ''
98 n = self.func()
99 if n:
100 return repr(n)
101 return ''
102
104 """
105 A function to return the results of a Node's rfile() method,
106 if it exists, and the Node itself otherwise (if it's a Value
107 Node, e.g.).
108 """
109 try:
110 rfile = node.rfile
111 except AttributeError:
112 return node
113 else:
114 return rfile()
115
119
139
140 _do_execute_map = {0 : execute_nothing,
141 1 : execute_action_list}
150
153
154 _execute_str_map = {0 : execute_null_str,
155 1 : execute_actions_str}
156
157
158 -class Executor(object, with_metaclass(NoSlotsPyPy)):
159 """A class for controlling instances of executing an action.
160
161 This largely exists to hold a single association of an action,
162 environment, list of environment override dictionaries, targets
163 and sources for later processing as needed.
164 """
165
166 __slots__ = ('pre_actions',
167 'post_actions',
168 'env',
169 'overridelist',
170 'batches',
171 'builder_kw',
172 '_memo',
173 'lvars',
174 '_changed_sources_list',
175 '_changed_targets_list',
176 '_unchanged_sources_list',
177 '_unchanged_targets_list',
178 'action_list',
179 '_do_execute',
180 '_execute_str')
181
182 - def __init__(self, action, env=None, overridelist=[{}],
183 targets=[], sources=[], builder_kw={}):
198
214
233
240
247
250
253
256
259
266
273
275 if not self.action_list:
276 return []
277 targets_string = self.action_list[0].get_targets(self.env, self)
278 if targets_string[0] == '$':
279 targets_string = targets_string[1:]
280 return self.get_lvars()[targets_string]
281
290
295
302
309
311 """Returns all unique children (dependencies) for all batches
312 of this Executor.
313
314 The Taskmaster can recognize when it's already evaluated a
315 Node, so we don't have to make this list unique for its intended
316 canonical use case, but we expect there to be a lot of redundancy
317 (long lists of batched .cc files #including the same .h files
318 over and over), so removing the duplicates once up front should
319 save the Taskmaster a lot of work.
320 """
321 result = SCons.Util.UniqueList([])
322 for target in self.get_all_targets():
323 result.extend(target.children())
324 return result
325
335
345
346 @SCons.Memoize.CountMethodCall
348 """Fetch or create the appropriate build Environment
349 for this Executor.
350 """
351 try:
352 return self._memo['get_build_env']
353 except KeyError:
354 pass
355
356
357
358
359
360
361 overrides = {}
362 for odict in self.overridelist:
363 overrides.update(odict)
364
365 import SCons.Defaults
366 env = self.env or SCons.Defaults.DefaultEnvironment()
367 build_env = env.Override(overrides)
368
369 self._memo['get_build_env'] = build_env
370
371 return build_env
372
384
390
391
392
393
394
397
400
402 """Add source files to this Executor's list. This is necessary
403 for "multi" Builders that can be called repeatedly to build up
404 a source file list for a given target."""
405
406 assert (len(self.batches) == 1)
407
408 sources = [x for x in sources if x not in self.batches[0].sources]
409 self.batches[0].sources.extend(sources)
410
413
415 """Add pair of associated target and source to this Executor's list.
416 This is necessary for "batch" Builders that can be called repeatedly
417 to build up a list of matching target and source files that will be
418 used in order to update multiple target files at once from multiple
419 corresponding source files, for tools like MSVC that support it."""
420 self.batches.append(Batch(targets, sources))
421
423 """
424 Preparatory checks for whether this Executor can go ahead
425 and (try to) build its targets.
426 """
427 for s in self.get_all_sources():
428 if s.missing():
429 msg = "Source `%s' not found, needed by target `%s'."
430 raise SCons.Errors.StopError(msg % (s, self.batches[0].targets[0]))
431
434
435 - def add_post_action(self, action):
436 self.post_actions.append(action)
437
438
439
442
447
448 @SCons.Memoize.CountMethodCall
449 - def get_contents(self):
450 """Fetch the signature contents. This is the main reason this
451 class exists, so we can compute this once and cache it regardless
452 of how many target or source Nodes there are.
453
454 Returns bytes
455 """
456 try:
457 return self._memo['get_contents']
458 except KeyError:
459 pass
460 env = self.get_build_env()
461
462 action_list = self.get_action_list()
463 all_targets = self.get_all_targets()
464 all_sources = self.get_all_sources()
465
466 result = bytearray("",'utf-8').join([action.get_contents(all_targets,
467 all_sources,
468 env)
469 for action in action_list])
470
471 self._memo['get_contents'] = result
472 return result
473
475 """Fetch a time stamp for this Executor. We don't have one, of
476 course (only files do), but this is the interface used by the
477 timestamp module.
478 """
479 return 0
480
484
489
490 - def scan(self, scanner, node_list):
511
513 return (node,) + tuple(ignore)
514
515 @SCons.Memoize.CountDictCall(_get_unignored_sources_key)
517 key = (node,) + tuple(ignore)
518 try:
519 memo_dict = self._memo['get_unignored_sources']
520 except KeyError:
521 memo_dict = {}
522 self._memo['get_unignored_sources'] = memo_dict
523 else:
524 try:
525 return memo_dict[key]
526 except KeyError:
527 pass
528
529 if node:
530
531
532 sourcelist = []
533 for b in self.batches:
534 if node in b.targets:
535 sourcelist = b.sources
536 break
537 else:
538 sourcelist = self.get_all_sources()
539 if ignore:
540 idict = {}
541 for i in ignore:
542 idict[i] = 1
543 sourcelist = [s for s in sourcelist if s not in idict]
544
545 memo_dict[key] = sourcelist
546
547 return sourcelist
548
560
561
562
563 _batch_executors = {}
567
571
572 nullenv = None
573
574
575 import SCons.Util
582
591
592 -class Null(object, with_metaclass(NoSlotsPyPy)):
593 """A null Executor, with a null build Environment, that does
594 nothing when the rest of the methods call it.
595
596 This might be able to disappear when we refactor things to
597 disassociate Builders from Nodes entirely, so we're not
598 going to worry about unit tests for this--at least for now.
599 """
600
601 __slots__ = ('pre_actions',
602 'post_actions',
603 'env',
604 'overridelist',
605 'batches',
606 'builder_kw',
607 '_memo',
608 'lvars',
609 '_changed_sources_list',
610 '_changed_targets_list',
611 '_unchanged_sources_list',
612 '_unchanged_targets_list',
613 'action_list',
614 '_do_execute',
615 '_execute_str')
616
646 - def get_contents(self):
654
655
656
657
661 - def add_post_action(self, action):
662 self._morph()
663 self.add_post_action(action)
667
668
669
670
671
672
673