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 3363 2008/09/06 07:34:10 scons"
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 """
165 Preparatory checks for whether this Executor can go ahead
166 and (try to) build its targets.
167 """
168 for s in self.get_sources():
169 if s.missing():
170 msg = "Source `%s' not found, needed by target `%s'."
171 raise SCons.Errors.StopError, msg % (s, self.targets[0])
172
174 self.pre_actions.append(action)
175
176 - def add_post_action(self, action):
177 self.post_actions.append(action)
178
179
180
186
187
190
195
196 memoizer_counters.append(SCons.Memoize.CountValue('get_contents'))
197
198 - def get_contents(self):
199 """Fetch the signature contents. This is the main reason this
200 class exists, so we can compute this once and cache it regardless
201 of how many target or source Nodes there are.
202 """
203 try:
204 return self._memo['get_contents']
205 except KeyError:
206 pass
207 env = self.get_build_env()
208 get = lambda action, t=self.targets, s=self.get_sources(), e=env: \
209 action.get_contents(t, s, e)
210 result = string.join(map(get, self.get_action_list()), "")
211 self._memo['get_contents'] = result
212 return result
213
215 """Fetch a time stamp for this Executor. We don't have one, of
216 course (only files do), but this is the interface used by the
217 timestamp module.
218 """
219 return 0
220
222 self.scan(scanner, self.targets)
223
227
228 - def scan(self, scanner, node_list):
262
265
266 memoizer_counters.append(SCons.Memoize.CountDict('get_unignored_sources', _get_unignored_sources_key))
267
269 ignore = tuple(ignore)
270 try:
271 memo_dict = self._memo['get_unignored_sources']
272 except KeyError:
273 memo_dict = {}
274 self._memo['get_unignored_sources'] = memo_dict
275 else:
276 try:
277 return memo_dict[ignore]
278 except KeyError:
279 pass
280
281 sourcelist = self.get_sources()
282 if ignore:
283 idict = {}
284 for i in ignore:
285 idict[i] = 1
286 sourcelist = filter(lambda s, i=idict: not i.has_key(s), sourcelist)
287
288 memo_dict[ignore] = sourcelist
289
290 return sourcelist
291
293 return (func, tuple(ignore))
294
295 memoizer_counters.append(SCons.Memoize.CountDict('process_sources', _process_sources_key))
296
298 memo_key = (func, tuple(ignore))
299 try:
300 memo_dict = self._memo['process_sources']
301 except KeyError:
302 memo_dict = {}
303 self._memo['process_sources'] = memo_dict
304 else:
305 try:
306 return memo_dict[memo_key]
307 except KeyError:
308 pass
309
310 result = map(func, self.get_unignored_sources(ignore))
311
312 memo_dict[memo_key] = result
313
314 return result
315
324
325
326 _Executor = Executor
327
328 -class Null(_Executor):
329 """A null Executor, with a null build Environment, that does
330 nothing when the rest of the methods call it.
331
332 This might be able to disapper when we refactor things to
333 disassociate Builders from Nodes entirely, so we're not
334 going to worry about unit tests for this--at least for now.
335 """
341 import SCons.Util
342 class NullEnvironment(SCons.Util.Null):
343 import SCons.CacheDir
344 _CacheDir_path = None
345 _CacheDir = SCons.CacheDir.CacheDir(None)
346 def get_CacheDir(self):
347 return self._CacheDir
348 return NullEnvironment()
355