summaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/SCons/Node/FS.py33
-rw-r--r--src/engine/SCons/Node/FSTests.py15
-rw-r--r--src/engine/SCons/Node/NodeTests.py8
-rw-r--r--src/engine/SCons/Node/__init__.py5
-rw-r--r--src/engine/SCons/Script/__init__.py3
-rw-r--r--src/engine/SCons/Taskmaster.py49
-rw-r--r--src/engine/SCons/TaskmasterTests.py16
7 files changed, 117 insertions, 12 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 57fd1c2..d6b7b53 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -197,6 +197,7 @@ class ParentOfRoot:
self.name=''
self.duplicate=0
self.srcdir=None
+ self.build_dirs=[]
def is_under(self, dir):
return 0
@@ -714,6 +715,24 @@ class FS:
def CacheDir(self, path):
self.CachePath = path
+ def build_dir_target_climb(self, dir, tail):
+ """Create targets in corresponding build directories
+
+ Climb the directory tree, and look up path names
+ relative to any linked build directories we find.
+ """
+ targets = []
+ message = None
+ while dir:
+ for bd in dir.build_dirs:
+ p = apply(os.path.join, [bd.path] + tail)
+ targets.append(self.Entry(p))
+ tail = [dir.name] + tail
+ dir = dir.up()
+ if targets:
+ message = "building associated BuildDir targets: %s" % string.join(map(str, targets))
+ return targets, message
+
# XXX TODO?
# Annotate with the creator
# rel_path
@@ -749,6 +768,7 @@ class Dir(Entry):
self.cwd = self
self.builder = 1
self._sconsign = None
+ self.build_dirs = []
def __clearRepositoryCache(self, duplicate=None):
"""Called when we change the repository(ies) for a directory.
@@ -801,6 +821,7 @@ class Dir(Entry):
self.srcdir = srcdir
self.duplicate = duplicate
self.__clearRepositoryCache(duplicate)
+ srcdir.build_dirs.append(self)
def getRepositories(self):
"""Returns a list of repositories for this directory."""
@@ -850,6 +871,11 @@ class Dir(Entry):
"""A null "builder" for directories."""
pass
+ def alter_targets(self):
+ """Return any corresponding targets in a build directory.
+ """
+ return self.fs.build_dir_target_climb(self, [])
+
def calc_signature(self, calc):
"""A directory has no signature."""
return None
@@ -1160,6 +1186,13 @@ class File(Entry):
"""
return self.has_builder() or self.side_effect or self.has_src_builder()
+ def alter_targets(self):
+ """Return any corresponding targets in a build directory.
+ """
+ if self.has_builder():
+ return [], None
+ return self.fs.build_dir_target_climb(self.dir, [self.name])
+
def prepare(self):
"""Prepare for this file to be created."""
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index d460c1e..11146eb 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -282,6 +282,21 @@ class BuildDirTestCase(unittest.TestCase):
assert f10.exists()
assert f10.get_contents() == 'stuff', f10.get_contents()
+ f11 = fs.File('src/file11')
+ t, m = f11.alter_targets()
+ bdt = map(lambda n: n.path, t)
+ assert bdt == ['build/var1/file11', 'build/var2/file11'], bdt
+
+ f12 = fs.File('src/file12')
+ f12.builder = 1
+ bdt, m = f12.alter_targets()
+ assert bdt == [], map(lambda n: n.path, bdt)
+
+ d13 = fs.Dir('src/new_dir')
+ t, m = d13.alter_targets()
+ bdt = map(lambda n: n.path, t)
+ assert bdt == ['build/var1/new_dir', 'build/var2/new_dir'], bdt
+
save_Mkdir = SCons.Node.FS.Mkdir
dir_made = []
def mkdir_func(target, source, env, dir_made=dir_made):
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index 91b35d0..f282860 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -277,6 +277,14 @@ class NodeTestCase(unittest.TestCase):
assert n2.is_derived() == 1
assert n3.is_derived() == 1
+ def test_alter_targets(self):
+ """Test the alter_targets() method
+ """
+ n = SCons.Node.Node()
+ t, m = n.alter_targets()
+ assert t == [], t
+ assert m == None, m
+
def test_builder_sig_adapter(self):
"""Test the node's adapter for builder signatures
"""
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 326aee3..222cd1f 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -231,6 +231,11 @@ class Node:
def is_derived(self):
return self.has_builder() or self.side_effect
+ def alter_targets(self):
+ """Return a list of alternate targets for this Node.
+ """
+ return [], None
+
def builder_sig_adapter(self):
"""Create an adapter for calculating a builder's signature.
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 60d299d..d2c60aa 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -73,6 +73,9 @@ import SCons.Warnings
#
class BuildTask(SCons.Taskmaster.Task):
"""An SCons build task."""
+ def display(self, message):
+ display('scons: ' + message)
+
def execute(self):
target = self.targets[0]
if target.get_state() == SCons.Node.up_to_date:
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index 93df569..bc53024 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -58,6 +58,11 @@ class Task:
self.top = top
self.node = node
+ def display(self, message):
+ """Allow the calling interface to display a message
+ """
+ pass
+
def prepare(self):
"""Called just before the task is executed.
@@ -69,6 +74,10 @@ class Task:
# this task.
self.tm.exception_raise()
+ if self.tm.message:
+ self.display(self.tm.message)
+ self.tm.message = None
+
if self.targets[0].get_state() != SCons.Node.up_to_date:
for t in self.targets:
t.prepare()
@@ -197,6 +206,7 @@ class Taskmaster:
self.calc = calc
self.order = order
self.exception_set(None, None)
+ self.message = None
def _find_next_ready_node(self):
"""Find the next node that is ready to be built"""
@@ -243,24 +253,39 @@ class Taskmaster:
desc = "Dependency cycle: " + string.join(map(str, nodes), " -> ")
raise SCons.Errors.UserError, desc
- # Add derived files that have not been built
- # to the candidates list:
- def derived(node):
- return node.is_derived() and node.get_state() == None
+ # Find all of the derived dependencies (that is,
+ # children who have builders or are side effects):
try:
- derived = filter(derived, children)
+ def derived_nodes(node): return node.is_derived()
+ derived = filter(derived_nodes, children)
except:
- # We had a problem just trying to figure out the
- # children (like a child couldn't be linked in to a
- # BuildDir, or a Scanner threw something). Arrange to
- # raise the exception when the Task is "executed."
+ # We had a problem just trying to figure out if any of
+ # the kids are derived (like a child couldn't be linked
+ # from a repository). Arrange to raise the exception
+ # when the Task is "executed."
self.exception_set(sys.exc_type, sys.exc_value)
self.candidates.pop()
self.ready = node
break
- if derived:
- derived.reverse()
- self.candidates.extend(self.order(derived))
+
+ # If there aren't any children with builders and this
+ # was a top-level argument, then see if we can find any
+ # corresponding targets in linked build directories:
+ if not derived and node in self.targets:
+ alt, message = node.alter_targets()
+ if alt:
+ self.message = message
+ self.candidates.pop()
+ self.candidates.extend(alt)
+ continue
+
+ # Add derived files that have not been built
+ # to the candidates list:
+ def unbuilt_nodes(node): return node.get_state() == None
+ not_built = filter(unbuilt_nodes, derived)
+ if not_built:
+ not_built.reverse()
+ self.candidates.extend(self.order(not_built))
continue
# Skip this node if it has side-effects that are
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index c6543e3..89c53c7 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -50,6 +50,7 @@ class Node:
self.parents = []
self.side_effect = 0
self.side_effects = []
+ self.alttargets = []
for kid in kids:
kid.parents.append(self)
@@ -64,6 +65,9 @@ class Node:
def is_derived(self):
return self.has_builder or self.side_effect
+ def alter_targets(self):
+ return self.alttargets, None
+
def built(self):
global built_text
built_text = built_text + " really"
@@ -376,6 +380,18 @@ class TaskmasterTestCase(unittest.TestCase):
assert t.get_target() == n4, t.get_target()
t.executed()
+ n5 = Node("n5")
+ n6 = Node("n6")
+ n7 = Node("n7")
+ n6.alttargets = [n7]
+ tm = SCons.Taskmaster.Taskmaster([n5])
+ t = tm.next_task()
+ assert t.get_target() == n5
+ t.executed()
+ tm = SCons.Taskmaster.Taskmaster([n6])
+ t = tm.next_task()
+ assert t.get_target() == n7
+ t.executed()
def test_make_ready_exception(self):