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
30
31 __revision__ = "src/engine/SCons/Executor.py 2725 2008/03/31 12:52:02 knight"
32
33 import string
34
35 from SCons.Debug import logInstanceCreation
36 import SCons.Errors
37 import SCons.Memoize
38
39
41 """A class for controlling instances of executing an action.
42
43 This largely exists to hold a single association of an action,
44 environment, list of environment override dictionaries, targets
45 and sources for later processing as needed.
46 """
47
48 if SCons.Memoize.use_memoizer:
49 __metaclass__ = SCons.Memoize.Memoized_Metaclass
50
51 memoizer_counters = []
52
53 - def __init__(self, action, env=None, overridelist=[{}],
54 targets=[], sources=[], builder_kw={}):
55 if __debug__: logInstanceCreation(self, 'Executor.Executor')
56 self.set_action_list(action)
57 self.pre_actions = []
58 self.post_actions = []
59 self.env = env
60 self.overridelist = overridelist
61 self.targets = targets
62 self.sources = sources[:]
63 self.sources_need_sorting = False
64 self.builder_kw = builder_kw
65 self._memo = {}
66
75
77 return self.pre_actions + self.action_list + self.post_actions
78
79 memoizer_counters.append(SCons.Memoize.CountValue('get_build_env'))
80
82 """Fetch or create the appropriate build Environment
83 for this Executor.
84 """
85 try:
86 return self._memo['get_build_env']
87 except KeyError:
88 pass
89
90
91
92
93
94
95 overrides = {}
96 for odict in self.overridelist:
97 overrides.update(odict)
98
99 import SCons.Defaults
100 env = self.env or SCons.Defaults.DefaultEnvironment()
101 build_env = env.Override(overrides)
102
103 self._memo['get_build_env'] = build_env
104
105 return build_env
106
108 """Fetch the scanner path for this executor's targets and sources.
109 """
110 env = self.get_build_env()
111 try:
112 cwd = self.targets[0].cwd
113 except (IndexError, AttributeError):
114 cwd = None
115 return scanner.path(env, cwd, self.targets, self.get_sources())
116
121
124
139
140
141
142
143
146
149
151 """Add source files to this Executor's list. This is necessary
152 for "multi" Builders that can be called repeatedly to build up
153 a source file list for a given target."""
154 self.sources.extend(sources)
155 self.sources_need_sorting = True
156
158 if self.sources_need_sorting:
159 self.sources = SCons.Util.uniquer_hashables(self.sources)
160 self.sources_need_sorting = False
161 return self.sources
162
164 self.pre_actions.append(action)
165
166 - def add_post_action(self, action):
167 self.post_actions.append(action)
168
169
170
176
177
180
185
186 memoizer_counters.append(SCons.Memoize.CountValue('get_contents'))
187
188 - def get_contents(self):
189 """Fetch the signature contents. This is the main reason this
190 class exists, so we can compute this once and cache it regardless
191 of how many target or source Nodes there are.
192 """
193 try:
194 return self._memo['get_contents']
195 except KeyError:
196 pass
197 env = self.get_build_env()
198 get = lambda action, t=self.targets, s=self.get_sources(), e=env: \
199 action.get_contents(t, s, e)
200 result = string.join(map(get, self.get_action_list()), "")
201 self._memo['get_contents'] = result
202 return result
203
205 """Fetch a time stamp for this Executor. We don't have one, of
206 course (only files do), but this is the interface used by the
207 timestamp module.
208 """
209 return 0
210
212 self.scan(scanner, self.targets)
213
217
218 - def scan(self, scanner, node_list):
219 """Scan a list of this Executor's files (targets or sources) for
220 implicit dependencies and update all of the targets with them.
221 This essentially short-circuits an N*M scan of the sources for
222 each individual target, which is a hell of a lot more efficient.
223 """
224 map(lambda N: N.disambiguate(), node_list)
225
226 env = self.get_build_env()
227 select_specific_scanner = lambda t: (t[0], t[1].select(t[0]))
228 remove_null_scanners = lambda t: not t[1] is None
229 add_scanner_path = lambda t, s=self: \
230 (t[0], t[1], s.get_build_scanner_path(t[1]))
231 if scanner:
232 scanner_list = map(lambda n, s=scanner: (n, s), node_list)
233 else:
234 kw = self.get_kw()
235 get_initial_scanners = lambda n, e=env, kw=kw: \
236 (n, n.get_env_scanner(e, kw))
237 scanner_list = map(get_initial_scanners, node_list)
238 scanner_list = filter(remove_null_scanners, scanner_list)
239
240 scanner_list = map(select_specific_scanner, scanner_list)
241 scanner_list = filter(remove_null_scanners, scanner_list)
242 scanner_path_list = map(add_scanner_path, scanner_list)
243
244 deps = []
245 for node, scanner, path in scanner_path_list:
246 deps.extend(node.get_implicit_deps(env, scanner, path))
247
248 deps.extend(self.get_implicit_deps())
249
250 for tgt in self.targets:
251 tgt.add_to_implicit(deps)
252
257
260
261 memoizer_counters.append(SCons.Memoize.CountDict('get_unignored_sources', _get_unignored_sources_key))
262
264 ignore = tuple(ignore)
265 try:
266 memo_dict = self._memo['get_unignored_sources']
267 except KeyError:
268 memo_dict = {}
269 self._memo['get_unignored_sources'] = memo_dict
270 else:
271 try:
272 return memo_dict[ignore]
273 except KeyError:
274 pass
275
276 sourcelist = self.get_sources()
277 if ignore:
278 idict = {}
279 for i in ignore:
280 idict[i] = 1
281 sourcelist = filter(lambda s, i=idict: not i.has_key(s), sourcelist)
282
283 memo_dict[ignore] = sourcelist
284
285 return sourcelist
286
288 return (func, tuple(ignore))
289
290 memoizer_counters.append(SCons.Memoize.CountDict('process_sources', _process_sources_key))
291
293 memo_key = (func, tuple(ignore))
294 try:
295 memo_dict = self._memo['process_sources']
296 except KeyError:
297 memo_dict = {}
298 self._memo['process_sources'] = memo_dict
299 else:
300 try:
301 return memo_dict[memo_key]
302 except KeyError:
303 pass
304
305 result = map(func, self.get_unignored_sources(ignore))
306
307 memo_dict[memo_key] = result
308
309 return result
310
319
320
321 _Executor = Executor
322
323 -class Null(_Executor):
324 """A null Executor, with a null build Environment, that does
325 nothing when the rest of the methods call it.
326
327 This might be able to disapper when we refactor things to
328 disassociate Builders from Nodes entirely, so we're not
329 going to worry about unit tests for this--at least for now.
330 """
336 import SCons.Util
337 class NullEnvironment(SCons.Util.Null):
338 import SCons.CacheDir
339 _CacheDir_path = None
340 _CacheDir = SCons.CacheDir.CacheDir(None)
341 def get_CacheDir(self):
342 return self._CacheDir
343 return NullEnvironment()
348