summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Taskmaster.py
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-07-04 21:44:00 (GMT)
committerSteven Knight <knight@baldmt.com>2002-07-04 21:44:00 (GMT)
commitf4115620c39f65724c5ef38e386c61141a71e9eb (patch)
treed0ff010898f5a406c6d5ff6127230bc1024340ee /src/engine/SCons/Taskmaster.py
parent946b8e61e1cea21a700a9646c561e4b871f2caba (diff)
downloadSCons-f4115620c39f65724c5ef38e386c61141a71e9eb.zip
SCons-f4115620c39f65724c5ef38e386c61141a71e9eb.tar.gz
SCons-f4115620c39f65724c5ef38e386c61141a71e9eb.tar.bz2
Add support for side effect targets. (Anthony Roach)
Diffstat (limited to 'src/engine/SCons/Taskmaster.py')
-rw-r--r--src/engine/SCons/Taskmaster.py62
1 files changed, 39 insertions, 23 deletions
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index 3fe96da..3e4dbbc 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -39,7 +39,7 @@ import copy
class Task:
"""Default SCons build engine task.
-
+
This controls the interaction of the actual building of node
and the rest of the engine.
@@ -50,7 +50,7 @@ class Task:
needs to customze something by sub-classing Taskmaster (or
some other build engine class), we should first try to migrate
that functionality into this class.
-
+
Note that it's generally a good idea for sub-classes to call
these methods explicitly to update state, etc., rather than
roll their own interaction with Taskmaster from scratch."""
@@ -73,11 +73,6 @@ class Task:
"""
return self.node
- def set_tstates(self, state):
- """Set all of the target nodes's states."""
- for t in self.targets:
- t.set_state(state)
-
def executed(self):
"""Called when the task has been successfully executed.
@@ -88,8 +83,10 @@ class Task:
back on the pending list."""
if self.targets[0].get_state() == SCons.Node.executing:
- self.set_tstates(SCons.Node.executed)
for t in self.targets:
+ for side_effect in t.side_effects:
+ side_effect.set_state(None)
+ t.set_state(SCons.Node.executed)
t.built()
self.tm.executed(self.node)
@@ -100,7 +97,8 @@ class Task:
def fail_stop(self):
"""Explicit stop-the-build failure."""
- self.set_tstates(SCons.Node.failed)
+ for t in self.targets:
+ t.set_state(SCons.Node.failed)
self.tm.stop()
def fail_continue(self):
@@ -116,7 +114,7 @@ class Task:
n = walker.next()
while n:
n = walker.next()
-
+
self.tm.executed(self.node)
def make_ready(self):
@@ -126,7 +124,11 @@ class Task:
bsig = self.tm.calc.bsig(t)
if not self.tm.calc.current(t, bsig):
state = SCons.Node.executing
- self.set_tstates(state)
+ for t in self.targets:
+ if state == SCons.Node.executing:
+ for side_effect in t.side_effects:
+ side_effect.set_state(state)
+ t.set_state(state)
class Calc:
def bsig(self, node):
@@ -136,7 +138,7 @@ class Calc:
def current(self, node, sig):
"""Default SCons build engine is-it-current function.
-
+
This returns "always out of date," so every node is always
built/visited.
"""
@@ -146,7 +148,7 @@ class Taskmaster:
"""A generic Taskmaster for handling a bunch of targets.
Classes that override methods of this class should call
- the base class method, so this class can do its thing.
+ the base class method, so this class can do its thing.
"""
def __init__(self, targets=[], tasker=Task, calc=Calc()):
@@ -164,11 +166,11 @@ class Taskmaster:
if self.ready:
return
-
+
while self.candidates:
node = self.candidates[-1]
state = node.get_state()
-
+
# Skip nodes that have already been executed:
if state != None and state != SCons.Node.stack:
self.candidates.pop()
@@ -191,13 +193,24 @@ class Taskmaster:
# Add non-derived files that have not been built
# to the candidates list:
def derived(node):
- return node.builder and node.get_state() == None
+ return (node.builder or node.side_effect) and node.get_state() == None
derived = filter(derived, children)
if derived:
derived.reverse()
self.candidates.extend(derived)
continue
+ # Skip nodes whose side-effects are currently being built:
+ cont = 0
+ for side_effect in node.side_effects:
+ if side_effect.get_state() == SCons.Node.executing:
+ self.pending.append(node)
+ node.set_state(SCons.Node.pending)
+ self.candidates.pop()
+ cont = 1
+ break
+ if cont: continue
+
# Skip nodes that are pending on a currently executing node:
if node.depends_on(self.executing) or node.depends_on(self.pending):
self.pending.append(node)
@@ -211,25 +224,26 @@ class Taskmaster:
def next_task(self):
"""Return the next task to be executed."""
-
+
self._find_next_ready_node()
node = self.ready
-
+
if node is None:
return None
-
+
self.executing.append(node)
+ self.executing.extend(node.side_effects)
try:
tlist = node.builder.targets(node)
except AttributeError:
tlist = [node]
- task = self.tasker(self, tlist, node in self.targets, node)
+ task = self.tasker(self, tlist, node in self.targets, node)
task.make_ready()
self.ready = None
-
+
return task
-
+
def is_blocked(self):
self._find_next_ready_node()
@@ -243,7 +257,9 @@ class Taskmaster:
def executed(self, node):
self.executing.remove(node)
-
+ for side_effect in node.side_effects:
+ self.executing.remove(side_effect)
+
# move the current pending nodes to the candidates list:
# (they may not all be ready to build, but _find_next_ready_node()
# will figure out which ones are really ready)