Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: third_party/scons/scons-local/SCons/Executor.py

Issue 20025: Update SCons to latest checkpoint release, 1.2.0.d20090113.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 """SCons.Executor 1 """SCons.Executor
2 2
3 A module for executing actions with specific lists of target and source 3 A module for executing actions with specific lists of target and source
4 Nodes. 4 Nodes.
5 5
6 """ 6 """
7 7
8 # 8 #
9 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundat ion 9 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons F oundation
10 # 10 #
11 # Permission is hereby granted, free of charge, to any person obtaining 11 # Permission is hereby granted, free of charge, to any person obtaining
12 # a copy of this software and associated documentation files (the 12 # a copy of this software and associated documentation files (the
13 # "Software"), to deal in the Software without restriction, including 13 # "Software"), to deal in the Software without restriction, including
14 # without limitation the rights to use, copy, modify, merge, publish, 14 # without limitation the rights to use, copy, modify, merge, publish,
15 # distribute, sublicense, and/or sell copies of the Software, and to 15 # distribute, sublicense, and/or sell copies of the Software, and to
16 # permit persons to whom the Software is furnished to do so, subject to 16 # permit persons to whom the Software is furnished to do so, subject to
17 # the following conditions: 17 # the following conditions:
18 # 18 #
19 # The above copyright notice and this permission notice shall be included 19 # The above copyright notice and this permission notice shall be included
20 # in all copies or substantial portions of the Software. 20 # in all copies or substantial portions of the Software.
21 # 21 #
22 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 22 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
23 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 23 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
24 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 # 29 #
30 30
31 __revision__ = "src/engine/SCons/Executor.py 3842 2008/12/20 22:59:52 scons" 31 __revision__ = "src/engine/SCons/Executor.py 3897 2009/01/13 06:45:54 scons"
32 32
33 import string 33 import string
34 import UserList
34 35
35 from SCons.Debug import logInstanceCreation 36 from SCons.Debug import logInstanceCreation
36 import SCons.Errors 37 import SCons.Errors
37 import SCons.Memoize 38 import SCons.Memoize
38 39
39 40
41 class Batch:
42 """Remembers exact association between targets
43 and sources of executor."""
44 def __init__(self, targets=[], sources=[]):
45 self.targets = targets
46 self.sources = sources
47
48
49
50 class TSList(UserList.UserList):
51 """A class that implements $TARGETS or $SOURCES expansions by wrapping
52 an executor Method. This class is used in the Executor.lvars()
53 to delay creation of NodeList objects until they're needed.
54
55 Note that we subclass UserList.UserList purely so that the
56 is_Sequence() function will identify an object of this class as
57 a list during variable expansion. We're not really using any
58 UserList.UserList methods in practice.
59 """
60 def __init__(self, func):
61 self.func = func
62 def __getattr__(self, attr):
63 nl = self.func()
64 return getattr(nl, attr)
65 def __getitem__(self, i):
66 nl = self.func()
67 return nl[i]
68 def __getslice__(self, i, j):
69 nl = self.func()
70 i = max(i, 0); j = max(j, 0)
71 return nl[i:j]
72 def __str__(self):
73 nl = self.func()
74 return str(nl)
75 def __repr__(self):
76 nl = self.func()
77 return repr(nl)
78
79 class TSObject:
80 """A class that implements $TARGET or $SOURCE expansions by wrapping
81 an Executor method.
82 """
83 def __init__(self, func):
84 self.func = func
85 def __getattr__(self, attr):
86 n = self.func()
87 return getattr(n, attr)
88 def __str__(self):
89 n = self.func()
90 if n:
91 return str(n)
92 return ''
93 def __repr__(self):
94 n = self.func()
95 if n:
96 return repr(n)
97 return ''
98
99 def rfile(node):
100 """
101 A function to return the results of a Node's rfile() method,
102 if it exists, and the Node itself otherwise (if it's a Value
103 Node, e.g.).
104 """
105 try:
106 rfile = node.rfile
107 except AttributeError:
108 return node
109 else:
110 return rfile()
111
112
40 class Executor: 113 class Executor:
41 """A class for controlling instances of executing an action. 114 """A class for controlling instances of executing an action.
42 115
43 This largely exists to hold a single association of an action, 116 This largely exists to hold a single association of an action,
44 environment, list of environment override dictionaries, targets 117 environment, list of environment override dictionaries, targets
45 and sources for later processing as needed. 118 and sources for later processing as needed.
46 """ 119 """
47 120
48 if SCons.Memoize.use_memoizer: 121 if SCons.Memoize.use_memoizer:
49 __metaclass__ = SCons.Memoize.Memoized_Metaclass 122 __metaclass__ = SCons.Memoize.Memoized_Metaclass
50 123
51 memoizer_counters = [] 124 memoizer_counters = []
52 125
53 def __init__(self, action, env=None, overridelist=[{}], 126 def __init__(self, action, env=None, overridelist=[{}],
54 targets=[], sources=[], builder_kw={}): 127 targets=[], sources=[], builder_kw={}):
55 if __debug__: logInstanceCreation(self, 'Executor.Executor') 128 if __debug__: logInstanceCreation(self, 'Executor.Executor')
56 self.set_action_list(action) 129 self.set_action_list(action)
57 self.pre_actions = [] 130 self.pre_actions = []
58 self.post_actions = [] 131 self.post_actions = []
59 self.env = env 132 self.env = env
60 self.overridelist = overridelist 133 self.overridelist = overridelist
61 self.targets = targets 134 if targets or sources:
62 self.sources = sources[:] 135 self.batches = [Batch(targets[:], sources[:])]
63 self.sources_need_sorting = False 136 else:
137 self.batches = []
64 self.builder_kw = builder_kw 138 self.builder_kw = builder_kw
65 self._memo = {} 139 self._memo = {}
66 140
141 def get_lvars(self):
142 try:
143 return self.lvars
144 except AttributeError:
145 self.lvars = {
146 'CHANGED_SOURCES' : TSList(self._get_changed_sources),
147 'CHANGED_TARGETS' : TSList(self._get_changed_targets),
148 'SOURCE' : TSObject(self._get_source),
149 'SOURCES' : TSList(self._get_sources),
150 'TARGET' : TSObject(self._get_target),
151 'TARGETS' : TSList(self._get_targets),
152 'UNCHANGED_SOURCES' : TSList(self._get_unchanged_sources),
153 'UNCHANGED_TARGETS' : TSList(self._get_unchanged_targets),
154 }
155 return self.lvars
156
157 def _get_changes(self):
158 cs = []
159 ct = []
160 us = []
161 ut = []
162 for b in self.batches:
163 if b.targets[0].changed():
164 cs.extend(map(rfile, b.sources))
165 ct.extend(b.targets)
166 else:
167 us.extend(map(rfile, b.sources))
168 ut.extend(b.targets)
169 self._changed_sources_list = SCons.Util.NodeList(cs)
170 self._changed_targets_list = SCons.Util.NodeList(ct)
171 self._unchanged_sources_list = SCons.Util.NodeList(us)
172 self._unchanged_targets_list = SCons.Util.NodeList(ut)
173
174 def _get_changed_sources(self, *args, **kw):
175 try:
176 return self._changed_sources_list
177 except AttributeError:
178 self._get_changes()
179 return self._changed_sources_list
180
181 def _get_changed_targets(self, *args, **kw):
182 try:
183 return self._changed_targets_list
184 except AttributeError:
185 self._get_changes()
186 return self._changed_targets_list
187
188 def _get_source(self, *args, **kw):
189 #return SCons.Util.NodeList([rfile(self.batches[0].sources[0]).get_subst _proxy()])
190 return rfile(self.batches[0].sources[0]).get_subst_proxy()
191
192 def _get_sources(self, *args, **kw):
193 return SCons.Util.NodeList(map(lambda n: rfile(n).get_subst_proxy(), sel f.get_all_sources()))
194
195 def _get_target(self, *args, **kw):
196 #return SCons.Util.NodeList([self.batches[0].targets[0].get_subst_proxy( )])
197 return self.batches[0].targets[0].get_subst_proxy()
198
199 def _get_targets(self, *args, **kw):
200 return SCons.Util.NodeList(map(lambda n: n.get_subst_proxy(), self.get_a ll_targets()))
201
202 def _get_unchanged_sources(self, *args, **kw):
203 try:
204 return self._unchanged_sources_list
205 except AttributeError:
206 self._get_changes()
207 return self._unchanged_sources_list
208
209 def _get_unchanged_targets(self, *args, **kw):
210 try:
211 return self._unchanged_targets_list
212 except AttributeError:
213 self._get_changes()
214 return self._unchanged_targets_list
215
216 def get_action_targets(self):
217 if not self.action_list:
218 return []
219 targets_string = self.action_list[0].get_targets(self.env, self)
220 if targets_string[0] == '$':
221 targets_string = targets_string[1:]
222 return self.get_lvars()[targets_string]
223
67 def set_action_list(self, action): 224 def set_action_list(self, action):
68 import SCons.Util 225 import SCons.Util
69 if not SCons.Util.is_List(action): 226 if not SCons.Util.is_List(action):
70 if not action: 227 if not action:
71 import SCons.Errors 228 import SCons.Errors
72 raise SCons.Errors.UserError, "Executor must have an action." 229 raise SCons.Errors.UserError, "Executor must have an action."
73 action = [action] 230 action = [action]
74 self.action_list = action 231 self.action_list = action
75 232
76 def get_action_list(self): 233 def get_action_list(self):
77 return self.pre_actions + self.action_list + self.post_actions 234 return self.pre_actions + self.action_list + self.post_actions
78 235
236 def get_all_targets(self):
237 """Returns all targets for all batches of this Executor."""
238 result = []
239 for batch in self.batches:
240 # TODO(1.5): remove the list() cast
241 result.extend(list(batch.targets))
242 return result
243
244 def get_all_sources(self):
245 """Returns all sources for all batches of this Executor."""
246 result = []
247 for batch in self.batches:
248 # TODO(1.5): remove the list() cast
249 result.extend(list(batch.sources))
250 return result
251
252 def get_all_children(self):
253 """Returns all unique children (dependencies) for all batches
254 of this Executor.
255
256 The Taskmaster can recognize when it's already evaluated a
257 Node, so we don't have to make this list unique for its intended
258 canonical use case, but we expect there to be a lot of redundancy
259 (long lists of batched .cc files #including the same .h files
260 over and over), so removing the duplicates once up front should
261 save the Taskmaster a lot of work.
262 """
263 result = SCons.Util.UniqueList([])
264 for target in self.get_all_targets():
265 result.extend(target.children())
266 return result
267
268 def get_all_prerequisites(self):
269 """Returns all unique (order-only) prerequisites for all batches
270 of this Executor.
271 """
272 result = SCons.Util.UniqueList([])
273 for target in self.get_all_targets():
274 # TODO(1.5): remove the list() cast
275 result.extend(list(target.prerequisites))
276 return result
277
278 def get_action_side_effects(self):
279
280 """Returns all side effects for all batches of this
281 Executor used by the underlying Action.
282 """
283 result = SCons.Util.UniqueList([])
284 for target in self.get_action_targets():
285 result.extend(target.side_effects)
286 return result
287
79 memoizer_counters.append(SCons.Memoize.CountValue('get_build_env')) 288 memoizer_counters.append(SCons.Memoize.CountValue('get_build_env'))
80 289
81 def get_build_env(self): 290 def get_build_env(self):
82 """Fetch or create the appropriate build Environment 291 """Fetch or create the appropriate build Environment
83 for this Executor. 292 for this Executor.
84 """ 293 """
85 try: 294 try:
86 return self._memo['get_build_env'] 295 return self._memo['get_build_env']
87 except KeyError: 296 except KeyError:
88 pass 297 pass
(...skipping 13 matching lines...) Expand all
102 311
103 self._memo['get_build_env'] = build_env 312 self._memo['get_build_env'] = build_env
104 313
105 return build_env 314 return build_env
106 315
107 def get_build_scanner_path(self, scanner): 316 def get_build_scanner_path(self, scanner):
108 """Fetch the scanner path for this executor's targets and sources. 317 """Fetch the scanner path for this executor's targets and sources.
109 """ 318 """
110 env = self.get_build_env() 319 env = self.get_build_env()
111 try: 320 try:
112 cwd = self.targets[0].cwd 321 cwd = self.batches[0].targets[0].cwd
113 except (IndexError, AttributeError): 322 except (IndexError, AttributeError):
114 cwd = None 323 cwd = None
115 return scanner.path(env, cwd, self.targets, self.get_sources()) 324 return scanner.path(env, cwd,
325 self.get_all_targets(),
326 self.get_all_sources())
116 327
117 def get_kw(self, kw={}): 328 def get_kw(self, kw={}):
118 result = self.builder_kw.copy() 329 result = self.builder_kw.copy()
119 result.update(kw) 330 result.update(kw)
331 result['executor'] = self
120 return result 332 return result
121 333
122 def do_nothing(self, target, kw): 334 def do_nothing(self, target, kw):
123 return 0 335 return 0
124 336
125 def do_execute(self, target, kw): 337 def do_execute(self, target, kw):
126 """Actually execute the action list.""" 338 """Actually execute the action list."""
127 env = self.get_build_env() 339 env = self.get_build_env()
128 kw = self.get_kw(kw) 340 kw = self.get_kw(kw)
129 status = 0 341 status = 0
130 for act in self.get_action_list(): 342 for act in self.get_action_list():
131 status = apply(act, (self.targets, self.get_sources(), env), kw) 343 #args = (self.get_all_targets(), self.get_all_sources(), env)
344 args = ([], [], env)
345 status = apply(act, args, kw)
132 if isinstance(status, SCons.Errors.BuildError): 346 if isinstance(status, SCons.Errors.BuildError):
133 status.executor = self 347 status.executor = self
134 raise status 348 raise status
135 elif status: 349 elif status:
136 msg = "Error %s" % status 350 msg = "Error %s" % status
137 raise SCons.Errors.BuildError( 351 raise SCons.Errors.BuildError(
138 errstr=msg, 352 errstr=msg,
139 node=self.targets, 353 node=self.batches[0].targets,
140 executor=self, 354 executor=self,
141 action=act) 355 action=act)
142 return status 356 return status
143 357
144 # use extra indirection because with new-style objects (Python 2.2 358 # use extra indirection because with new-style objects (Python 2.2
145 # and above) we can't override special methods, and nullify() needs 359 # and above) we can't override special methods, and nullify() needs
146 # to be able to do this. 360 # to be able to do this.
147 361
148 def __call__(self, target, **kw): 362 def __call__(self, target, **kw):
149 return self.do_execute(target, kw) 363 return self.do_execute(target, kw)
150 364
151 def cleanup(self): 365 def cleanup(self):
152 self._memo = {} 366 self._memo = {}
153 367
154 def add_sources(self, sources): 368 def add_sources(self, sources):
155 """Add source files to this Executor's list. This is necessary 369 """Add source files to this Executor's list. This is necessary
156 for "multi" Builders that can be called repeatedly to build up 370 for "multi" Builders that can be called repeatedly to build up
157 a source file list for a given target.""" 371 a source file list for a given target."""
158 self.sources.extend(sources) 372 # TODO(batch): extend to multiple batches
159 self.sources_need_sorting = True 373 assert (len(self.batches) == 1)
374 # TODO(batch): remove duplicates?
375 sources = filter(lambda x, s=self.batches[0].sources: x not in s, source s)
376 self.batches[0].sources.extend(sources)
160 377
161 def get_sources(self): 378 def get_sources(self):
162 if self.sources_need_sorting: 379 return self.batches[0].sources
163 self.sources = SCons.Util.uniquer_hashables(self.sources) 380
164 self.sources_need_sorting = False 381 def add_batch(self, targets, sources):
165 return self.sources 382 """Add pair of associated target and source to this Executor's list.
383 This is necessary for "batch" Builders that can be called repeatedly
384 to build up a list of matching target and source files that will be
385 used in order to update multiple target files at once from multiple
386 corresponding source files, for tools like MSVC that support it."""
387 self.batches.append(Batch(targets, sources))
166 388
167 def prepare(self): 389 def prepare(self):
168 """ 390 """
169 Preparatory checks for whether this Executor can go ahead 391 Preparatory checks for whether this Executor can go ahead
170 and (try to) build its targets. 392 and (try to) build its targets.
171 """ 393 """
172 for s in self.get_sources(): 394 for s in self.get_all_sources():
173 if s.missing(): 395 if s.missing():
174 msg = "Source `%s' not found, needed by target `%s'." 396 msg = "Source `%s' not found, needed by target `%s'."
175 raise SCons.Errors.StopError, msg % (s, self.targets[0]) 397 raise SCons.Errors.StopError, msg % (s, self.batches[0].targets[ 0])
176 398
177 def add_pre_action(self, action): 399 def add_pre_action(self, action):
178 self.pre_actions.append(action) 400 self.pre_actions.append(action)
179 401
180 def add_post_action(self, action): 402 def add_post_action(self, action):
181 self.post_actions.append(action) 403 self.post_actions.append(action)
182 404
183 # another extra indirection for new-style objects and nullify... 405 # another extra indirection for new-style objects and nullify...
184 406
185 def my_str(self): 407 def my_str(self):
186 env = self.get_build_env() 408 env = self.get_build_env()
187 get = lambda action, t=self.targets, s=self.get_sources(), e=env: \ 409 get = lambda action, t=self.get_all_targets(), s=self.get_all_sources(), e=env: \
188 action.genstring(t, s, e) 410 action.genstring(t, s, e)
189 return string.join(map(get, self.get_action_list()), "\n") 411 return string.join(map(get, self.get_action_list()), "\n")
190 412
191 413
192 def __str__(self): 414 def __str__(self):
193 return self.my_str() 415 return self.my_str()
194 416
195 def nullify(self): 417 def nullify(self):
196 self.cleanup() 418 self.cleanup()
197 self.do_execute = self.do_nothing 419 self.do_execute = self.do_nothing
198 self.my_str = lambda S=self: '' 420 self.my_str = lambda S=self: ''
199 421
200 memoizer_counters.append(SCons.Memoize.CountValue('get_contents')) 422 memoizer_counters.append(SCons.Memoize.CountValue('get_contents'))
201 423
202 def get_contents(self): 424 def get_contents(self):
203 """Fetch the signature contents. This is the main reason this 425 """Fetch the signature contents. This is the main reason this
204 class exists, so we can compute this once and cache it regardless 426 class exists, so we can compute this once and cache it regardless
205 of how many target or source Nodes there are. 427 of how many target or source Nodes there are.
206 """ 428 """
207 try: 429 try:
208 return self._memo['get_contents'] 430 return self._memo['get_contents']
209 except KeyError: 431 except KeyError:
210 pass 432 pass
211 env = self.get_build_env() 433 env = self.get_build_env()
212 get = lambda action, t=self.targets, s=self.get_sources(), e=env: \ 434 get = lambda action, t=self.get_all_targets(), s=self.get_all_sources(), e=env: \
213 action.get_contents(t, s, e) 435 action.get_contents(t, s, e)
214 result = string.join(map(get, self.get_action_list()), "") 436 result = string.join(map(get, self.get_action_list()), "")
215 self._memo['get_contents'] = result 437 self._memo['get_contents'] = result
216 return result 438 return result
217 439
218 def get_timestamp(self): 440 def get_timestamp(self):
219 """Fetch a time stamp for this Executor. We don't have one, of 441 """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 442 course (only files do), but this is the interface used by the
221 timestamp module. 443 timestamp module.
222 """ 444 """
223 return 0 445 return 0
224 446
225 def scan_targets(self, scanner): 447 def scan_targets(self, scanner):
226 self.scan(scanner, self.targets) 448 # TODO(batch): scan by batches
449 self.scan(scanner, self.get_all_targets())
227 450
228 def scan_sources(self, scanner): 451 def scan_sources(self, scanner):
229 if self.sources: 452 # TODO(batch): scan by batches
230 self.scan(scanner, self.get_sources()) 453 if self.batches[0].sources:
454 self.scan(scanner, self.get_all_sources())
231 455
232 def scan(self, scanner, node_list): 456 def scan(self, scanner, node_list):
233 """Scan a list of this Executor's files (targets or sources) for 457 """Scan a list of this Executor's files (targets or sources) for
234 implicit dependencies and update all of the targets with them. 458 implicit dependencies and update all of the targets with them.
235 This essentially short-circuits an N*M scan of the sources for 459 This essentially short-circuits an N*M scan of the sources for
236 each individual target, which is a hell of a lot more efficient. 460 each individual target, which is a hell of a lot more efficient.
237 """ 461 """
238 env = self.get_build_env() 462 env = self.get_build_env()
239 463
464 # TODO(batch): scan by batches)
240 deps = [] 465 deps = []
241 if scanner: 466 if scanner:
242 for node in node_list: 467 for node in node_list:
243 node.disambiguate() 468 node.disambiguate()
244 s = scanner.select(node) 469 s = scanner.select(node)
245 if not s: 470 if not s:
246 continue 471 continue
247 path = self.get_build_scanner_path(s) 472 path = self.get_build_scanner_path(s)
248 deps.extend(node.get_implicit_deps(env, s, path)) 473 deps.extend(node.get_implicit_deps(env, s, path))
249 else: 474 else:
250 kw = self.get_kw() 475 kw = self.get_kw()
251 for node in node_list: 476 for node in node_list:
252 node.disambiguate() 477 node.disambiguate()
253 scanner = node.get_env_scanner(env, kw) 478 scanner = node.get_env_scanner(env, kw)
254 if not scanner: 479 if not scanner:
255 continue 480 continue
256 scanner = scanner.select(node) 481 scanner = scanner.select(node)
257 if not scanner: 482 if not scanner:
258 continue 483 continue
259 path = self.get_build_scanner_path(scanner) 484 path = self.get_build_scanner_path(scanner)
260 deps.extend(node.get_implicit_deps(env, scanner, path)) 485 deps.extend(node.get_implicit_deps(env, scanner, path))
261 486
262 deps.extend(self.get_implicit_deps()) 487 deps.extend(self.get_implicit_deps())
263 488
264 for tgt in self.targets: 489 for tgt in self.get_all_targets():
265 tgt.add_to_implicit(deps) 490 tgt.add_to_implicit(deps)
266 491
267 def _get_unignored_sources_key(self, ignore=()): 492 def _get_unignored_sources_key(self, node, ignore=()):
268 return tuple(ignore) 493 return (node,) + tuple(ignore)
269 494
270 memoizer_counters.append(SCons.Memoize.CountDict('get_unignored_sources', _g et_unignored_sources_key)) 495 memoizer_counters.append(SCons.Memoize.CountDict('get_unignored_sources', _g et_unignored_sources_key))
271 496
272 def get_unignored_sources(self, ignore=()): 497 def get_unignored_sources(self, node, ignore=()):
273 ignore = tuple(ignore) 498 key = (node,) + tuple(ignore)
274 try: 499 try:
275 memo_dict = self._memo['get_unignored_sources'] 500 memo_dict = self._memo['get_unignored_sources']
276 except KeyError: 501 except KeyError:
277 memo_dict = {} 502 memo_dict = {}
278 self._memo['get_unignored_sources'] = memo_dict 503 self._memo['get_unignored_sources'] = memo_dict
279 else: 504 else:
280 try: 505 try:
281 return memo_dict[ignore] 506 return memo_dict[key]
282 except KeyError: 507 except KeyError:
283 pass 508 pass
284 509
285 sourcelist = self.get_sources() 510 if node:
511 # TODO: better way to do this (it's a linear search,
512 # but it may not be critical path)?
513 sourcelist = []
514 for b in self.batches:
515 if node in b.targets:
516 sourcelist = b.sources
517 break
518 else:
519 sourcelist = self.get_all_sources()
286 if ignore: 520 if ignore:
287 idict = {} 521 idict = {}
288 for i in ignore: 522 for i in ignore:
289 idict[i] = 1 523 idict[i] = 1
290 sourcelist = filter(lambda s, i=idict: not i.has_key(s), sourcelist) 524 sourcelist = filter(lambda s, i=idict: not i.has_key(s), sourcelist)
291 525
292 memo_dict[ignore] = sourcelist 526 memo_dict[key] = sourcelist
293 527
294 return sourcelist 528 return sourcelist
295 529
296 def _process_sources_key(self, func, ignore=()):
297 return (func, tuple(ignore))
298
299 memoizer_counters.append(SCons.Memoize.CountDict('process_sources', _process _sources_key))
300
301 def process_sources(self, func, ignore=()):
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
320 def get_implicit_deps(self): 530 def get_implicit_deps(self):
321 """Return the executor's implicit dependencies, i.e. the nodes of 531 """Return the executor's implicit dependencies, i.e. the nodes of
322 the commands to be executed.""" 532 the commands to be executed."""
323 result = [] 533 result = []
324 build_env = self.get_build_env() 534 build_env = self.get_build_env()
325 for act in self.get_action_list(): 535 for act in self.get_action_list():
326 result.extend(act.get_implicit_deps(self.targets, self.get_sources() , build_env)) 536 deps = act.get_implicit_deps(self.get_all_targets(),
537 self.get_all_sources(),
538 build_env)
539 result.extend(deps)
327 return result 540 return result
328 541
542
543
544 _batch_executors = {}
545
546 def GetBatchExecutor(key):
547 return _batch_executors[key]
548
549 def AddBatchExecutor(key, executor):
550 assert not _batch_executors.has_key(key)
551 _batch_executors[key] = executor
552
329 nullenv = None 553 nullenv = None
330 554
555
331 def get_NullEnvironment(): 556 def get_NullEnvironment():
332 """Use singleton pattern for Null Environments.""" 557 """Use singleton pattern for Null Environments."""
333 global nullenv 558 global nullenv
334 559
335 import SCons.Util 560 import SCons.Util
336 class NullEnvironment(SCons.Util.Null): 561 class NullEnvironment(SCons.Util.Null):
337 import SCons.CacheDir 562 import SCons.CacheDir
338 _CacheDir_path = None 563 _CacheDir_path = None
339 _CacheDir = SCons.CacheDir.CacheDir(None) 564 _CacheDir = SCons.CacheDir.CacheDir(None)
340 def get_CacheDir(self): 565 def get_CacheDir(self):
341 return self._CacheDir 566 return self._CacheDir
342 567
343 if not nullenv: 568 if not nullenv:
344 nullenv = NullEnvironment() 569 nullenv = NullEnvironment()
345 return nullenv 570 return nullenv
346 571
347 class Null: 572 class Null:
348 """A null Executor, with a null build Environment, that does 573 """A null Executor, with a null build Environment, that does
349 nothing when the rest of the methods call it. 574 nothing when the rest of the methods call it.
350 575
351 This might be able to disapper when we refactor things to 576 This might be able to disapper when we refactor things to
352 disassociate Builders from Nodes entirely, so we're not 577 disassociate Builders from Nodes entirely, so we're not
353 going to worry about unit tests for this--at least for now. 578 going to worry about unit tests for this--at least for now.
354 """ 579 """
355 def __init__(self, *args, **kw): 580 def __init__(self, *args, **kw):
356 if __debug__: logInstanceCreation(self, 'Executor.Null') 581 if __debug__: logInstanceCreation(self, 'Executor.Null')
357 self.targets = kw['targets'] 582 self.batches = [Batch(kw['targets'][:], [])]
358 def get_build_env(self): 583 def get_build_env(self):
359 return get_NullEnvironment() 584 return get_NullEnvironment()
360 def get_build_scanner_path(self): 585 def get_build_scanner_path(self):
361 return None 586 return None
362 def cleanup(self): 587 def cleanup(self):
363 pass 588 pass
364 def prepare(self): 589 def prepare(self):
365 pass 590 pass
366 def get_unignored_sources(self, *args, **kw): 591 def get_unignored_sources(self, *args, **kw):
367 return tuple(()) 592 return tuple(())
593 def get_action_targets(self):
594 return []
368 def get_action_list(self): 595 def get_action_list(self):
369 return [] 596 return []
597 def get_all_targets(self):
598 return self.batches[0].targets
599 def get_all_sources(self):
600 return self.batches[0].targets[0].sources
601 def get_all_children(self):
602 return self.get_all_sources()
603 def get_all_prerequisites(self):
604 return []
605 def get_action_side_effects(self):
606 return []
370 def __call__(self, *args, **kw): 607 def __call__(self, *args, **kw):
371 return 0 608 return 0
372 def get_contents(self): 609 def get_contents(self):
373 return '' 610 return ''
374
375 def _morph(self): 611 def _morph(self):
376 """Morph this Null executor to a real Executor object.""" 612 """Morph this Null executor to a real Executor object."""
613 batches = self.batches
377 self.__class__ = Executor 614 self.__class__ = Executor
378 self.__init__([], targets=self.targets) 615 self.__init__([])
616 self.batches = batches
379 617
380 # The following methods require morphing this Null Executor to a 618 # The following methods require morphing this Null Executor to a
381 # real Executor object. 619 # real Executor object.
382 620
383 def add_pre_action(self, action): 621 def add_pre_action(self, action):
384 self._morph() 622 self._morph()
385 self.add_pre_action(action) 623 self.add_pre_action(action)
386 def add_post_action(self, action): 624 def add_post_action(self, action):
387 self._morph() 625 self._morph()
388 self.add_post_action(action) 626 self.add_post_action(action)
389 def set_action_list(self, action): 627 def set_action_list(self, action):
390 self._morph() 628 self._morph()
391 self.set_action_list(action) 629 self.set_action_list(action)
392 630
393 631
OLDNEW
« no previous file with comments | « third_party/scons/scons-local/SCons/Errors.py ('k') | third_party/scons/scons-local/SCons/Job.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698