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 3842 2008/12/20 22:59:52 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
126 """Actually execute the action list."""
127 env = self.get_build_env()
128 kw = self.get_kw(kw)
129 status = 0
130 for act in self.get_action_list():
131 status = apply(act, (self.targets, self.get_sources(), env), kw)
132 if isinstance(status, SCons.Errors.BuildError):
133 status.executor = self
134 raise status
135 elif status:
136 msg = "Error %s" % status
137 raise SCons.Errors.BuildError(
138 errstr=msg,
139 node=self.targets,
140 executor=self,
141 action=act)
142 return status
143
144
145
146
147
150
153
155 """Add source files to this Executor's list. This is necessary
156 for "multi" Builders that can be called repeatedly to build up
157 a source file list for a given target."""
158 self.sources.extend(sources)
159 self.sources_need_sorting = True
160
162 if self.sources_need_sorting:
163 self.sources = SCons.Util.uniquer_hashables(self.sources)
164 self.sources_need_sorting = False
165 return self.sources
166
168 """
169 Preparatory checks for whether this Executor can go ahead
170 and (try to) build its targets.
171 """
172 for s in self.get_sources():
173 if s.missing():
174 msg = "Source `%s' not found, needed by target `%s'."
175 raise SCons.Errors.StopError, msg % (s, self.targets[0])
176
178 self.pre_actions.append(action)
179
180 - def add_post_action(self, action):
181 self.post_actions.append(action)
182
183
184
190
191
194
199
200 memoizer_counters.append(SCons.Memoize.CountValue('get_contents'))
201
202 - def get_contents(self):
203 """Fetch the signature contents. This is the main reason this
204 class exists, so we can compute this once and cache it regardless
205 of how many target or source Nodes there are.
206 """
207 try:
208 return self._memo['get_contents']
209 except KeyError:
210 pass
211 env = self.get_build_env()
212 get = lambda action, t=self.targets, s=self.get_sources(), e=env: \
213 action.get_contents(t, s, e)
214 result = string.join(map(get, self.get_action_list()), "")
215 self._memo['get_contents'] = result
216 return result
217
219 """Fetch a time stamp for this Executor. We don't have one, of
220 course (only files do), but this is the interface used by the
221 timestamp module.
222 """
223 return 0
224
226 self.scan(scanner, self.targets)
227
231
232 - def scan(self, scanner, node_list):
266
269
270 memoizer_counters.append(SCons.Memoize.CountDict('get_unignored_sources', _get_unignored_sources_key))
271
273 ignore = tuple(ignore)
274 try:
275 memo_dict = self._memo['get_unignored_sources']
276 except KeyError:
277 memo_dict = {}
278 self._memo['get_unignored_sources'] = memo_dict
279 else:
280 try:
281 return memo_dict[ignore]
282 except KeyError:
283 pass
284
285 sourcelist = self.get_sources()
286 if ignore:
287 idict = {}
288 for i in ignore:
289 idict[i] = 1
290 sourcelist = filter(lambda s, i=idict: not i.has_key(s), sourcelist)
291
292 memo_dict[ignore] = sourcelist
293
294 return sourcelist
295
297 return (func, tuple(ignore))
298
299 memoizer_counters.append(SCons.Memoize.CountDict('process_sources', _process_sources_key))
300
302 memo_key = (func, tuple(ignore))
303 try:
304 memo_dict = self._memo['process_sources']
305 except KeyError:
306 memo_dict = {}
307 self._memo['process_sources'] = memo_dict
308 else:
309 try:
310 return memo_dict[memo_key]
311 except KeyError:
312 pass
313
314 result = map(func, self.get_unignored_sources(ignore))
315
316 memo_dict[memo_key] = result
317
318 return result
319
328
329 nullenv = None
330
332 """Use singleton pattern for Null Environments."""
333 global nullenv
334
335 import SCons.Util
336 class NullEnvironment(SCons.Util.Null):
337 import SCons.CacheDir
338 _CacheDir_path = None
339 _CacheDir = SCons.CacheDir.CacheDir(None)
340 def get_CacheDir(self):
341 return self._CacheDir
342
343 if not nullenv:
344 nullenv = NullEnvironment()
345 return nullenv
346
348 """A null Executor, with a null build Environment, that does
349 nothing when the rest of the methods call it.
350
351 This might be able to disapper when we refactor things to
352 disassociate Builders from Nodes entirely, so we're not
353 going to worry about unit tests for this--at least for now.
354 """
372 - def get_contents(self):
374
376 """Morph this Null executor to a real Executor object."""
377 self.__class__ = Executor
378 self.__init__([], targets=self.targets)
379
380
381
382
386 - def add_post_action(self, action):
387 self._morph()
388 self.add_post_action(action)
392