self.children(),
1)
-def get_children(node): return node.children()
+def get_children(node, parent): return node.children()
def ignore_cycle(node, stack): pass
+def do_nothing(node, parent): pass
class Walker:
"""An iterator for walking a Node tree.
This class does not get caught in node cycles caused, for example,
by C header file include loops.
"""
- def __init__(self, node, kids_func=get_children, cycle_func=ignore_cycle):
+ def __init__(self, node, kids_func=get_children,
+ cycle_func=ignore_cycle,
+ eval_func=do_nothing):
self.kids_func = kids_func
self.cycle_func = cycle_func
- node.wkids = copy.copy(kids_func(node))
+ self.eval_func = eval_func
+ node.wkids = copy.copy(kids_func(node, None))
self.stack = [node]
self.history = {} # used to efficiently detect and avoid cycles
self.history[node] = None
if self.history.has_key(node):
self.cycle_func(node, self.stack)
else:
- node.wkids = copy.copy(self.kids_func(node))
+ node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
self.stack.append(node)
self.history[node] = None
else:
node = self.stack.pop()
del self.history[node]
+ if node:
+ if self.stack:
+ parent = self.stack[-1]
+ else:
+ parent = None
+ self.eval_func(node, parent)
return node
def is_done(self):
"""
nodes = {}
for t in self.targets:
- def get_parents(node): return node.get_parents()
+ def get_parents(node, parent): return node.get_parents()
walker = SCons.Node.Walker(t, get_parents)
while 1:
n = walker.next()
def __init__(self, targets=[], tasker=Task, calc=Calc()):
- def out_of_date(node):
+ def out_of_date(node, parent):
if node.get_state():
# The state is set, so someone has already been here
# (finished or currently executing). Find another one.
desc = "Dependency cycle: " + string.join(map(str, nodes), " -> ")
raise SCons.Errors.UserError, desc
- #XXX In Python 2.2 we can get rid of f1 and f2:
- self.walkers = map(lambda x, f1=out_of_date, f2=cycle_error: SCons.Node.Walker(x, f1, f2),
+ def eval_node(node, parent, self=self):
+ if node.get_state():
+ # The state is set, so someone has already been here
+ # (finished or currently executing). Find another one.
+ return
+ if not node.builder:
+ # It's a source file, we don't need to build it,
+ # but mark it as "up to date" so targets won't
+ # wait for it.
+ node.set_state(SCons.Node.up_to_date)
+ # set the signature for non-derived files
+ # here so they don't get recalculated over
+ # and over again:
+ node.set_csig(self.calc.csig(node))
+ return
+ try:
+ tlist = node.builder.targets(node)
+ except AttributeError:
+ tlist = [ node ]
+ task = self.tasker(self, tlist, self.walkers[0].is_done())
+ if not tlist[0].children_are_executed():
+ for t in tlist:
+ t.set_state(SCons.Node.pending)
+ t.task = task
+ self.pending = self.pending + 1
+ return
+ task.make_ready()
+
+ #XXX In Python 2.2 we can get rid of f1, f2 and f3:
+ self.walkers = map(lambda x, f1=out_of_date,
+ f2=cycle_error,
+ f3=eval_node:
+ SCons.Node.Walker(x, f1, f2, f3),
targets)
self.tasker = tasker
self.calc = calc
if n == None:
self.walkers.pop(0)
continue
- if n.get_state():
- # The state is set, so someone has already been here
- # (finished or currently executing). Find another one.
- continue
- if not n.builder:
- # It's a source file, we don't need to build it,
- # but mark it as "up to date" so targets won't
- # wait for it.
- n.set_state(SCons.Node.up_to_date)
- # set the signature for non-derived files
- # here so they don't get recalculated over
- # and over again:
- n.set_csig(self.calc.csig(n))
- continue
- try:
- tlist = n.builder.targets(n)
- except AttributeError:
- tlist = [ n ]
- task = self.tasker(self, tlist, self.walkers[0].is_done())
- if not tlist[0].children_are_executed():
- for t in tlist:
- t.set_state(SCons.Node.pending)
- t.task = task
- self.pending = self.pending + 1
- continue
- task.make_ready()
- return
+ if self.ready:
+ return
def is_blocked(self):
return not self.ready and self.pending