summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-04-04 09:07:00 (GMT)
committerSteven Knight <knight@baldmt.com>2002-04-04 09:07:00 (GMT)
commit6603cc0d6643e529da45fef6f85fcc1a0fc02ea4 (patch)
tree4a27de7c3fd70e5af0f257ccc73aab38e343f156 /src
parenta7669bc6a02999a3375c7e732a27ded5f9bb9935 (diff)
downloadSCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.zip
SCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.tar.gz
SCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.tar.bz2
Fix --debug=tree for directory targets (Anthony Roach)
Diffstat (limited to 'src')
-rw-r--r--src/CHANGES.txt6
-rw-r--r--src/RELEASE.txt7
-rw-r--r--src/engine/SCons/Builder.py82
-rw-r--r--src/engine/SCons/BuilderTests.py348
-rw-r--r--src/engine/SCons/Node/FS.py71
-rw-r--r--src/engine/SCons/Node/FSTests.py89
-rw-r--r--src/engine/SCons/Node/NodeTests.py363
-rw-r--r--src/engine/SCons/Node/__init__.py130
-rw-r--r--src/engine/SCons/Scanner/C.py57
-rw-r--r--src/engine/SCons/Scanner/CTests.py54
-rw-r--r--src/engine/SCons/Scanner/Prog.py87
-rw-r--r--src/engine/SCons/Scanner/ProgTests.py20
-rw-r--r--src/engine/SCons/Scanner/ScannerTests.py37
-rw-r--r--src/engine/SCons/Scanner/__init__.py20
-rw-r--r--src/engine/SCons/Sig/SigTests.py16
-rw-r--r--src/engine/SCons/Sig/__init__.py32
-rw-r--r--src/engine/SCons/Taskmaster.py229
-rw-r--r--src/engine/SCons/TaskmasterTests.py186
18 files changed, 786 insertions, 1048 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 0fc473c..fee7642 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -14,6 +14,12 @@ RELEASE 0.07 -
- Fix so that -c -n does *not* remove the targets!
+ From Anthony Roach:
+
+ - Fix --debug=tree when used with directory targets.
+
+ - Significant internal restructuring of Scanners and Taskmaster.
+
RELEASE 0.06 - Thu, 28 Mar 2002 01:24:29 -0600
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 9a6a5f8..41cd49b 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -20,15 +20,16 @@ more effectively, please sign up for the scons-users mailing list at:
-RELEASE 0.06 - Thu, 28 Mar 2002 01:24:29 -0600
+RELEASE 0.07 -
- This is the sixth alpha release of SCons. Please consult the
+ This is the seventh alpha release of SCons. Please consult the
CHANGES.txt file for a list of specific changes since last release.
Please note the following important changes since the previous
release:
- - Python functions as Builder actions now take Node objects, not
+ - Scanner functions now take four arguments.
+
strings, as arguments. The string representation of a Node
object is the file name, so you should change your function
actions to use the str() built-in function to fetch the file
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index bc90e19..e7af01c 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -41,7 +41,6 @@ import SCons.Node.FS
import SCons.Util
-
def Builder(**kw):
"""A factory for builder objects."""
@@ -64,77 +63,72 @@ def _init_nodes(builder, env, tlist, slist):
"""Initialize lists of target and source nodes with all of
the proper Builder information.
"""
- src_scanner = None
- if slist:
- src_key = slist[0].scanner_key() # the file suffix
- src_scanner = env.get_scanner(src_key)
- if src_scanner:
- src_scanner = src_scanner.instance(env)
-
+ for s in slist:
+ src_key = slist[0].scanner_key() # the file suffix
+ scanner = env.get_scanner(src_key)
+ if scanner:
+ s.source_scanner = scanner
+
for t in tlist:
- t.cwd = SCons.Node.FS.default_fs.getcwd() # XXX
+ t.cwd = SCons.Node.FS.default_fs.getcwd() # XXX
t.builder_set(builder)
t.env_set(env)
t.add_source(slist)
if builder.scanner:
- t.scanner_set(builder.scanner.instance(env))
- if src_scanner:
- t.src_scanner_set(src_key, src_scanner)
-
-
+ t.target_scanner = builder.scanner
class BuilderBase:
"""Base class for Builders, objects that create output
nodes (files) from input nodes (files).
"""
- def __init__(self, name = None,
- action = None,
- prefix = '',
- suffix = '',
- src_suffix = '',
+ def __init__(self, name = None,
+ action = None,
+ prefix = '',
+ suffix = '',
+ src_suffix = '',
node_factory = SCons.Node.FS.default_fs.File,
target_factory = None,
source_factory = None,
scanner = None):
if name is None:
raise UserError, "You must specify a name for the builder."
- self.name = name
- self.action = SCons.Action.Action(action)
+ self.name = name
+ self.action = SCons.Action.Action(action)
- self.prefix = prefix
- self.suffix = suffix
- self.src_suffix = src_suffix
+ self.prefix = prefix
+ self.suffix = suffix
+ self.src_suffix = src_suffix
self.target_factory = target_factory or node_factory
self.source_factory = source_factory or node_factory
self.scanner = scanner
if self.suffix and self.suffix[0] not in '.$':
- self.suffix = '.' + self.suffix
+ self.suffix = '.' + self.suffix
if self.src_suffix and self.src_suffix[0] not in '.$':
- self.src_suffix = '.' + self.src_suffix
+ self.src_suffix = '.' + self.src_suffix
def __cmp__(self, other):
- return cmp(self.__dict__, other.__dict__)
+ return cmp(self.__dict__, other.__dict__)
def _create_nodes(self, env, target = None, source = None):
"""Create and return lists of target and source nodes.
"""
- def adjustixes(files, pre, suf):
- ret = []
+ def adjustixes(files, pre, suf):
+ ret = []
if SCons.Util.is_String(files):
files = string.split(files)
if not SCons.Util.is_List(files):
- files = [files]
- for f in files:
+ files = [files]
+ for f in files:
if SCons.Util.is_String(f):
- if pre and f[:len(pre)] != pre:
+ if pre and f[:len(pre)] != pre:
path, fn = os.path.split(os.path.normpath(f))
f = os.path.join(path, pre + fn)
- if suf:
- if f[-len(suf):] != suf:
- f = f + suf
- ret.append(f)
- return ret
+ if suf:
+ if f[-len(suf):] != suf:
+ f = f + suf
+ ret.append(f)
+ return ret
tlist = SCons.Node.arg2nodes(adjustixes(target,
env.subst(self.prefix),
@@ -160,9 +154,9 @@ class BuilderBase:
def execute(self, **kw):
- """Execute a builder's action to create an output object.
- """
- return apply(self.action.execute, (), kw)
+ """Execute a builder's action to create an output object.
+ """
+ return apply(self.action.execute, (), kw)
def get_raw_contents(self, **kw):
"""Fetch the "contents" of the builder's action.
@@ -241,10 +235,10 @@ class MultiStepBuilder(BuilderBase):
"""
def __init__(self, src_builder,
name = None,
- action = None,
- prefix = '',
- suffix = '',
- src_suffix = '',
+ action = None,
+ prefix = '',
+ suffix = '',
+ src_suffix = '',
node_factory = SCons.Node.FS.default_fs.File,
target_factory = None,
source_factory = None,
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index 16c87a4..0527fe0 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -65,7 +65,6 @@ outfile = test.workpath('outfile')
outfile2 = test.workpath('outfile2')
show_string = None
-instanced = None
env_scanner = None
count = 0
@@ -88,31 +87,31 @@ env = Environment()
class BuilderTestCase(unittest.TestCase):
def test__call__(self):
- """Test calling a builder to establish source dependencies
- """
- class Node:
- def __init__(self, name):
- self.name = name
- self.sources = []
- self.builder = None
- def __str__(self):
- return self.name
- def builder_set(self, builder):
- self.builder = builder
- def env_set(self, env, safe=0):
- self.env = env
- def add_source(self, source):
- self.sources.extend(source)
+ """Test calling a builder to establish source dependencies
+ """
+ class Node:
+ def __init__(self, name):
+ self.name = name
+ self.sources = []
+ self.builder = None
+ def __str__(self):
+ return self.name
+ def builder_set(self, builder):
+ self.builder = builder
+ def env_set(self, env, safe=0):
+ self.env = env
+ def add_source(self, source):
+ self.sources.extend(source)
def scanner_key(self):
return self.name
builder = SCons.Builder.Builder(name="builder", action="foo", node_factory=Node)
- n1 = Node("n1");
- n2 = Node("n2");
- builder(env, target = n1, source = n2)
- assert n1.env == env
- assert n1.builder == builder
- assert n1.sources == [n2]
+ n1 = Node("n1");
+ n2 = Node("n2");
+ builder(env, target = n1, source = n2)
+ assert n1.env == env
+ assert n1.builder == builder
+ assert n1.sources == [n2]
assert not hasattr(n2, 'env')
target = builder(env, target = 'n3', source = 'n4')
@@ -159,12 +158,12 @@ class BuilderTestCase(unittest.TestCase):
assert 0
def test_action(self):
- """Test Builder creation
+ """Test Builder creation
- Verify that we can retrieve the supplied action attribute.
- """
- builder = SCons.Builder.Builder(name="builder", action="foo")
- assert builder.action.command == "foo"
+ Verify that we can retrieve the supplied action attribute.
+ """
+ builder = SCons.Builder.Builder(name="builder", action="foo")
+ assert builder.action.command == "foo"
def test_generator(self):
"""Test Builder creation given a generator function."""
@@ -176,22 +175,22 @@ class BuilderTestCase(unittest.TestCase):
assert builder.action.generator == generator
def test_cmp(self):
- """Test simple comparisons of Builder objects
- """
- b1 = SCons.Builder.Builder(name="b1", src_suffix = '.o')
- b2 = SCons.Builder.Builder(name="b1", src_suffix = '.o')
- assert b1 == b2
- b3 = SCons.Builder.Builder(name="b3", src_suffix = '.x')
- assert b1 != b3
- assert b2 != b3
+ """Test simple comparisons of Builder objects
+ """
+ b1 = SCons.Builder.Builder(name="b1", src_suffix = '.o')
+ b2 = SCons.Builder.Builder(name="b1", src_suffix = '.o')
+ assert b1 == b2
+ b3 = SCons.Builder.Builder(name="b3", src_suffix = '.x')
+ assert b1 != b3
+ assert b2 != b3
def test_execute(self):
- """Test execution of simple Builder objects
-
- One Builder is a string that executes an external command,
- one is an internal Python function, one is a list
- containing one of each.
- """
+ """Test execution of simple Builder objects
+
+ One Builder is a string that executes an external command,
+ one is an internal Python function, one is a list
+ containing one of each.
+ """
def MyBuilder(**kw):
builder = apply(SCons.Builder.Builder, (), kw)
@@ -200,54 +199,54 @@ class BuilderTestCase(unittest.TestCase):
builder.action.show = no_show
return builder
- python = sys.executable
+ python = sys.executable
- cmd1 = r'%s %s %s xyzzy' % (python, act_py, outfile)
+ cmd1 = r'%s %s %s xyzzy' % (python, act_py, outfile)
builder = MyBuilder(action = cmd1, name = "cmd1")
- r = builder.execute()
- assert r == 0
- c = test.read(outfile, 'r')
+ r = builder.execute()
+ assert r == 0
+ c = test.read(outfile, 'r')
assert c == "act.py: 'xyzzy'\n", c
- cmd2 = r'%s %s %s $TARGET' % (python, act_py, outfile)
+ cmd2 = r'%s %s %s $TARGET' % (python, act_py, outfile)
builder = MyBuilder(action = cmd2, name = "cmd2")
- r = builder.execute(target = 'foo')
- assert r == 0
- c = test.read(outfile, 'r')
+ r = builder.execute(target = 'foo')
+ assert r == 0
+ c = test.read(outfile, 'r')
assert c == "act.py: 'foo'\n", c
- cmd3 = r'%s %s %s ${TARGETS}' % (python, act_py, outfile)
+ cmd3 = r'%s %s %s ${TARGETS}' % (python, act_py, outfile)
builder = MyBuilder(action = cmd3, name = "cmd3")
- r = builder.execute(target = ['aaa', 'bbb'])
- assert r == 0
- c = test.read(outfile, 'r')
+ r = builder.execute(target = ['aaa', 'bbb'])
+ assert r == 0
+ c = test.read(outfile, 'r')
assert c == "act.py: 'aaa' 'bbb'\n", c
- cmd4 = r'%s %s %s $SOURCES' % (python, act_py, outfile)
+ cmd4 = r'%s %s %s $SOURCES' % (python, act_py, outfile)
builder = MyBuilder(action = cmd4, name = "cmd4")
- r = builder.execute(source = ['one', 'two'])
- assert r == 0
- c = test.read(outfile, 'r')
+ r = builder.execute(source = ['one', 'two'])
+ assert r == 0
+ c = test.read(outfile, 'r')
assert c == "act.py: 'one' 'two'\n", c
- cmd4 = r'%s %s %s ${SOURCES[:2]}' % (python, act_py, outfile)
+ cmd4 = r'%s %s %s ${SOURCES[:2]}' % (python, act_py, outfile)
builder = MyBuilder(action = cmd4, name = "cmd4")
- r = builder.execute(source = ['three', 'four', 'five'])
- assert r == 0
- c = test.read(outfile, 'r')
+ r = builder.execute(source = ['three', 'four', 'five'])
+ assert r == 0
+ c = test.read(outfile, 'r')
assert c == "act.py: 'three' 'four'\n", c
- cmd5 = r'%s %s %s $TARGET XYZZY' % (python, act_py, outfile)
+ cmd5 = r'%s %s %s $TARGET XYZZY' % (python, act_py, outfile)
builder = MyBuilder(action = cmd5, name = "cmd5")
- r = builder.execute(target = 'out5', env = {'ENV' : {'XYZZY' : 'xyzzy'}})
- assert r == 0
- c = test.read(outfile, 'r')
+ r = builder.execute(target = 'out5', env = {'ENV' : {'XYZZY' : 'xyzzy'}})
+ assert r == 0
+ c = test.read(outfile, 'r')
assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy'\n", c
class Obj:
@@ -285,16 +284,16 @@ class BuilderTestCase(unittest.TestCase):
global count
count = 0
- def function1(**kw):
+ def function1(**kw):
global count
count = count + 1
if not type(kw['target']) is type([]):
kw['target'] = [ kw['target'] ]
for t in kw['target']:
- open(t, 'w').write("function1\n")
- return 1
+ open(t, 'w').write("function1\n")
+ return 1
- builder = MyBuilder(action = function1, name = "function1")
+ builder = MyBuilder(action = function1, name = "function1")
try:
r = builder.execute(target = [outfile, outfile2])
except SCons.Errors.BuildError:
@@ -302,50 +301,50 @@ class BuilderTestCase(unittest.TestCase):
assert r == 1
assert count == 1
c = test.read(outfile, 'r')
- assert c == "function1\n", c
+ assert c == "function1\n", c
c = test.read(outfile2, 'r')
- assert c == "function1\n", c
-
- class class1a:
- def __init__(self, **kw):
- open(kw['out'], 'w').write("class1a\n")
-
- builder = MyBuilder(action = class1a, name = "class1a")
- r = builder.execute(out = outfile)
- assert r.__class__ == class1a
- c = test.read(outfile, 'r')
- assert c == "class1a\n", c
-
- class class1b:
- def __call__(self, **kw):
- open(kw['out'], 'w').write("class1b\n")
- return 2
-
- builder = MyBuilder(action = class1b(), name = "class1b")
- r = builder.execute(out = outfile)
- assert r == 2
- c = test.read(outfile, 'r')
- assert c == "class1b\n", c
-
- cmd2 = r'%s %s %s syzygy' % (python, act_py, outfile)
-
- def function2(**kw):
- open(kw['out'], 'a').write("function2\n")
- return 0
-
- class class2a:
- def __call__(self, **kw):
- open(kw['out'], 'a').write("class2a\n")
- return 0
-
- class class2b:
- def __init__(self, **kw):
- open(kw['out'], 'a').write("class2b\n")
-
- builder = MyBuilder(action = [cmd2, function2, class2a(), class2b], name = "clist")
- r = builder.execute(out = outfile)
- assert r.__class__ == class2b
- c = test.read(outfile, 'r')
+ assert c == "function1\n", c
+
+ class class1a:
+ def __init__(self, **kw):
+ open(kw['out'], 'w').write("class1a\n")
+
+ builder = MyBuilder(action = class1a, name = "class1a")
+ r = builder.execute(out = outfile)
+ assert r.__class__ == class1a
+ c = test.read(outfile, 'r')
+ assert c == "class1a\n", c
+
+ class class1b:
+ def __call__(self, **kw):
+ open(kw['out'], 'w').write("class1b\n")
+ return 2
+
+ builder = MyBuilder(action = class1b(), name = "class1b")
+ r = builder.execute(out = outfile)
+ assert r == 2
+ c = test.read(outfile, 'r')
+ assert c == "class1b\n", c
+
+ cmd2 = r'%s %s %s syzygy' % (python, act_py, outfile)
+
+ def function2(**kw):
+ open(kw['out'], 'a').write("function2\n")
+ return 0
+
+ class class2a:
+ def __call__(self, **kw):
+ open(kw['out'], 'a').write("class2a\n")
+ return 0
+
+ class class2b:
+ def __init__(self, **kw):
+ open(kw['out'], 'a').write("class2b\n")
+
+ builder = MyBuilder(action = [cmd2, function2, class2a(), class2b], name = "clist")
+ r = builder.execute(out = outfile)
+ assert r.__class__ == class2b
+ c = test.read(outfile, 'r')
assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
if os.name == 'nt':
@@ -390,53 +389,53 @@ class BuilderTestCase(unittest.TestCase):
assert contents == "foo\177\036\000\177\037\000d\000\000Sbar", repr(contents)
def test_node_factory(self):
- """Test a Builder that creates nodes of a specified class
- """
- class Foo:
- pass
- def FooFactory(target):
+ """Test a Builder that creates nodes of a specified class
+ """
+ class Foo:
+ pass
+ def FooFactory(target):
global Foo
- return Foo(target)
- builder = SCons.Builder.Builder(name = "builder", node_factory = FooFactory)
- assert builder.target_factory is FooFactory
- assert builder.source_factory is FooFactory
+ return Foo(target)
+ builder = SCons.Builder.Builder(name = "builder", node_factory = FooFactory)
+ assert builder.target_factory is FooFactory
+ assert builder.source_factory is FooFactory
def test_target_factory(self):
- """Test a Builder that creates target nodes of a specified class
- """
- class Foo:
- pass
- def FooFactory(target):
+ """Test a Builder that creates target nodes of a specified class
+ """
+ class Foo:
+ pass
+ def FooFactory(target):
global Foo
- return Foo(target)
- builder = SCons.Builder.Builder(name = "builder", target_factory = FooFactory)
- assert builder.target_factory is FooFactory
- assert not builder.source_factory is FooFactory
+ return Foo(target)
+ builder = SCons.Builder.Builder(name = "builder", target_factory = FooFactory)
+ assert builder.target_factory is FooFactory
+ assert not builder.source_factory is FooFactory
def test_source_factory(self):
- """Test a Builder that creates source nodes of a specified class
- """
- class Foo:
- pass
- def FooFactory(source):
+ """Test a Builder that creates source nodes of a specified class
+ """
+ class Foo:
+ pass
+ def FooFactory(source):
global Foo
- return Foo(source)
- builder = SCons.Builder.Builder(name = "builder", source_factory = FooFactory)
- assert not builder.target_factory is FooFactory
- assert builder.source_factory is FooFactory
+ return Foo(source)
+ builder = SCons.Builder.Builder(name = "builder", source_factory = FooFactory)
+ assert not builder.target_factory is FooFactory
+ assert builder.source_factory is FooFactory
def test_prefix(self):
- """Test Builder creation with a specified target prefix
-
- Make sure that there is no '.' separator appended.
- """
- builder = SCons.Builder.Builder(name = "builder", prefix = 'lib.')
- assert builder.prefix == 'lib.'
- builder = SCons.Builder.Builder(name = "builder", prefix = 'lib')
- assert builder.prefix == 'lib'
- tgt = builder(env, target = 'tgt1', source = 'src1')
- assert tgt.path == 'libtgt1', \
- "Target has unexpected name: %s" % tgt.path
+ """Test Builder creation with a specified target prefix
+
+ Make sure that there is no '.' separator appended.
+ """
+ builder = SCons.Builder.Builder(name = "builder", prefix = 'lib.')
+ assert builder.prefix == 'lib.'
+ builder = SCons.Builder.Builder(name = "builder", prefix = 'lib')
+ assert builder.prefix == 'lib'
+ tgt = builder(env, target = 'tgt1', source = 'src1')
+ assert tgt.path == 'libtgt1', \
+ "Target has unexpected name: %s" % tgt.path
tgts = builder(env, target = 'tgt2a tgt2b', source = 'src2')
assert tgts[0].path == 'libtgt2a', \
"Target has unexpected name: %s" % tgts[0].path
@@ -482,18 +481,18 @@ class BuilderTestCase(unittest.TestCase):
assert b5.src_suffixes(env) == ['.y'], b5.src_suffixes(env)
def test_suffix(self):
- """Test Builder creation with a specified target suffix
-
- Make sure that the '.' separator is appended to the
- beginning if it isn't already present.
- """
- builder = SCons.Builder.Builder(name = "builder", suffix = '.o')
- assert builder.suffix == '.o'
- builder = SCons.Builder.Builder(name = "builder", suffix = 'o')
- assert builder.suffix == '.o'
- tgt = builder(env, target = 'tgt3', source = 'src3')
- assert tgt.path == 'tgt3.o', \
- "Target has unexpected name: %s" % tgt[0].path
+ """Test Builder creation with a specified target suffix
+
+ Make sure that the '.' separator is appended to the
+ beginning if it isn't already present.
+ """
+ builder = SCons.Builder.Builder(name = "builder", suffix = '.o')
+ assert builder.suffix == '.o'
+ builder = SCons.Builder.Builder(name = "builder", suffix = 'o')
+ assert builder.suffix == '.o'
+ tgt = builder(env, target = 'tgt3', source = 'src3')
+ assert tgt.path == 'tgt3.o', \
+ "Target has unexpected name: %s" % tgt[0].path
tgts = builder(env, target = 'tgt4a tgt4b', source = 'src4')
assert tgts[0].path == 'tgt4a.o', \
"Target has unexpected name: %s" % tgts[0].path
@@ -517,9 +516,9 @@ class BuilderTestCase(unittest.TestCase):
builder = SCons.Builder.Builder(action = function2, name = "function2")
tgts = builder(env, target = [outfile, outfile2], source = 'foo')
- try:
+ try:
r = tgts[0].builder.execute(target = tgts)
- except SCons.Errors.BuildError:
+ except SCons.Errors.BuildError:
pass
c = test.read(outfile, 'r')
assert c == "function2\n", c
@@ -652,17 +651,12 @@ class BuilderTestCase(unittest.TestCase):
"""Testing ability to set a target scanner through a builder."""
global instanced
class TestScanner:
- def instance(self, env):
- global instanced
- instanced = 1
- return self
+ pass
scn = TestScanner()
builder = SCons.Builder.Builder(name = "builder", scanner=scn)
tgt = builder(env, target='foo', source='bar')
- assert tgt.scanner == scn, tgt.scanner
- assert instanced
+ assert tgt.target_scanner == scn, tgt.target_scanner
- instanced = None
builder1 = SCons.Builder.Builder(name = "builder1",
action='foo',
src_suffix='.bar',
@@ -672,8 +666,7 @@ class BuilderTestCase(unittest.TestCase):
src_builder = builder1,
scanner = scn)
tgt = builder2(env, target='baz', source='test.bar test2.foo test3.txt')
- assert tgt.scanner == scn, tgt.scanner
- assert instanced
+ assert tgt.target_scanner == scn, tgt.target_scanner
def test_src_scanner(slf):
"""Testing ability to set a source file scanner through a builder."""
@@ -686,10 +679,11 @@ class BuilderTestCase(unittest.TestCase):
env_scanner = TestScanner()
builder = SCons.Builder.Builder(name = "builder", action='action')
tgt = builder(env, target='foo.x', source='bar')
- assert tgt.scanner != env_scanner, tgt.scanner
- assert tgt.src_scanners[''] == env_scanner, tgt.src_scanners
+ src = tgt.sources[0]
+ assert tgt.target_scanner != env_scanner, tgt.target_scanner
+ assert src.source_scanner == env_scanner
if __name__ == "__main__":
suite = unittest.makeSuite(BuilderTestCase, 'test_')
if not unittest.TextTestRunner().run(suite).wasSuccessful():
- sys.exit(1)
+ sys.exit(1)
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 1be5e81..0f8425f 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -114,7 +114,7 @@ class FS:
def getcwd(self):
self.__setTopLevelDir()
- return self._cwd
+ return self._cwd
def __checkClass(self, node, klass):
if klass == Entry:
@@ -132,9 +132,9 @@ class FS:
"""This method differs from the File and Dir factory methods in
one important way: the meaning of the directory parameter.
In this method, if directory is None or not supplied, the supplied
- name is expected to be an absolute path. If you try to look up a
- relative path with directory=None, then an AssertionError will be
- raised."""
+ name is expected to be an absolute path. If you try to look up a
+ relative path with directory=None, then an AssertionError will be
+ raised."""
if not name:
# This is a stupid hack to compensate for the fact
@@ -280,12 +280,12 @@ class Entry(SCons.Node.Node):
"""
def __init__(self, name, directory):
- """Initialize a generic file system Entry.
-
- Call the superclass initialization, take care of setting up
- our relative and absolute paths, identify our parent
- directory, and indicate that this node should use
- signatures."""
+ """Initialize a generic file system Entry.
+
+ Call the superclass initialization, take care of setting up
+ our relative and absolute paths, identify our parent
+ directory, and indicate that this node should use
+ signatures."""
SCons.Node.Node.__init__(self)
self.name = name
@@ -302,9 +302,10 @@ class Entry(SCons.Node.Node):
self.path_ = self.path
self.abspath_ = self.abspath
self.dir = directory
- self.use_signature = 1
+ self.use_signature = 1
self.__doSrcpath(self.duplicate)
self.srcpath_ = self.srcpath
+ self.cwd = None # will hold the SConscript directory for target nodes
def get_dir(self):
return self.dir
@@ -320,7 +321,7 @@ class Entry(SCons.Node.Node):
self.srcpath = self.dir.srcpath_ + self.name
def __str__(self):
- """A FS node's string representation is its path name."""
+ """A FS node's string representation is its path name."""
if self.duplicate or self.builder:
return self.path
else:
@@ -374,17 +375,17 @@ class Dir(Entry):
def __init__(self, name, directory):
Entry.__init__(self, name, directory)
- self._morph()
+ self._morph()
def _morph(self):
- """Turn a file system node (either a freshly initialized
- directory object or a separate Entry object) into a
- proper directory object.
-
- Modify our paths to add the trailing slash that indicates
- a directory. Set up this directory's entries and hook it
- into the file system tree. Specify that directories (this
- node) don't use signatures for currency calculation."""
+ """Turn a file system node (either a freshly initialized
+ directory object or a separate Entry object) into a
+ proper directory object.
+
+ Modify our paths to add the trailing slash that indicates
+ a directory. Set up this directory's entries and hook it
+ into the file system tree. Specify that directories (this
+ node) don't use signatures for currency calculation."""
self.path_ = self.path + os.sep
self.abspath_ = self.abspath + os.sep
@@ -423,18 +424,18 @@ class Dir(Entry):
else:
return self.entries['..'].root()
- def children(self, scanner):
- #XXX --random: randomize "dependencies?"
- keys = filter(lambda k: k != '.' and k != '..', self.entries.keys())
- kids = map(lambda x, s=self: s.entries[x], keys)
- def c(one, two):
+ def all_children(self, scanner):
+ #XXX --random: randomize "dependencies?"
+ keys = filter(lambda k: k != '.' and k != '..', self.entries.keys())
+ kids = map(lambda x, s=self: s.entries[x], keys)
+ def c(one, two):
if one.abspath < two.abspath:
return -1
if one.abspath > two.abspath:
return 1
return 0
- kids.sort(c)
- return kids
+ kids.sort(c)
+ return kids
def build(self):
"""A null "builder" for directories."""
@@ -529,14 +530,12 @@ class File(Entry):
.sconsign entry."""
return self.dir.sconsign().get(self.name)
- def scan(self, scanner = None):
- if not scanner:
- scanner = self.scanner
- if scanner and not self.scanned.has_key(scanner):
- deps = scanner.scan(self, self.env)
- self.add_implicit(deps, scanner)
- self.scanned[scanner] = 1
-
+ def get_implicit_deps(self, env, scanner, target):
+ if scanner:
+ return scanner.scan(self, env, target)
+ else:
+ return []
+
def exists(self):
if self.duplicate and not self.created:
self.created = 1
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 98abcfc..fe9ea61 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -48,7 +48,7 @@ class Scanner:
global scanner_count
scanner_count = scanner_count + 1
self.hash = scanner_count
- def scan(self, node, env):
+ def scan(self, node, env, target):
return [node]
def __hash__(self):
return self.hash
@@ -191,7 +191,7 @@ class FSTestCase(unittest.TestCase):
up_path = strip_slash(up_path_)
name = string.split(abspath, os.sep)[-1]
- assert dir.name == name, \
+ assert dir.name == name, \
"dir.name %s != expected name %s" % \
(dir.name, name)
assert dir.path == path, \
@@ -230,16 +230,16 @@ class FSTestCase(unittest.TestCase):
try:
f2 = fs.File(string.join(['f1', 'f2'], sep), directory = d1)
except TypeError, x:
- assert str(x) == ("Tried to lookup File '%s' as a Dir." %
- d1_f1), x
+ assert str(x) == ("Tried to lookup File '%s' as a Dir." %
+ d1_f1), x
except:
raise
try:
dir = fs.Dir(string.join(['d1', 'f1'], sep))
except TypeError, x:
- assert str(x) == ("Tried to lookup File '%s' as a Dir." %
- d1_f1), x
+ assert str(x) == ("Tried to lookup File '%s' as a Dir." %
+ d1_f1), x
except:
raise
@@ -249,7 +249,7 @@ class FSTestCase(unittest.TestCase):
assert str(x) == ("Tried to lookup Dir '%s' as a File." %
'd1'), x
except:
- raise
+ raise
# Test Dir.children()
dir = fs.Dir('ddd')
@@ -262,9 +262,9 @@ class FSTestCase(unittest.TestCase):
kids = map(lambda x: x.path, dir.children(None))
kids.sort()
assert kids == [os.path.join('ddd', 'd1'),
- os.path.join('ddd', 'f1'),
- os.path.join('ddd', 'f2'),
- os.path.join('ddd', 'f3')]
+ os.path.join('ddd', 'f1'),
+ os.path.join('ddd', 'f2'),
+ os.path.join('ddd', 'f3')]
kids = map(lambda x: x.path_, dir.children(None))
kids.sort()
assert kids == [os.path.join('ddd', 'd1', ''),
@@ -302,50 +302,50 @@ class FSTestCase(unittest.TestCase):
expect = string.replace(expect, '/', os.sep)
assert path == expect, "path %s != expected %s" % (path, expect)
- e1 = fs.Entry("d1")
- assert e1.__class__.__name__ == 'Dir'
+ e1 = fs.Entry("d1")
+ assert e1.__class__.__name__ == 'Dir'
match(e1.path, "d1")
match(e1.path_, "d1/")
match(e1.dir.path, ".")
- e2 = fs.Entry("d1/f1")
- assert e2.__class__.__name__ == 'File'
+ e2 = fs.Entry("d1/f1")
+ assert e2.__class__.__name__ == 'File'
match(e2.path, "d1/f1")
match(e2.path_, "d1/f1")
match(e2.dir.path, "d1")
- e3 = fs.Entry("e3")
- assert e3.__class__.__name__ == 'Entry'
+ e3 = fs.Entry("e3")
+ assert e3.__class__.__name__ == 'Entry'
match(e3.path, "e3")
match(e3.path_, "e3")
match(e3.dir.path, ".")
- e4 = fs.Entry("d1/e4")
- assert e4.__class__.__name__ == 'Entry'
+ e4 = fs.Entry("d1/e4")
+ assert e4.__class__.__name__ == 'Entry'
match(e4.path, "d1/e4")
match(e4.path_, "d1/e4")
match(e4.dir.path, "d1")
- e5 = fs.Entry("e3/e5")
- assert e3.__class__.__name__ == 'Dir'
+ e5 = fs.Entry("e3/e5")
+ assert e3.__class__.__name__ == 'Dir'
match(e3.path, "e3")
match(e3.path_, "e3/")
match(e3.dir.path, ".")
- assert e5.__class__.__name__ == 'Entry'
+ assert e5.__class__.__name__ == 'Entry'
match(e5.path, "e3/e5")
match(e5.path_, "e3/e5")
match(e5.dir.path, "e3")
- e6 = fs.Dir("d1/e4")
- assert e6 is e4
- assert e4.__class__.__name__ == 'Dir'
+ e6 = fs.Dir("d1/e4")
+ assert e6 is e4
+ assert e4.__class__.__name__ == 'Dir'
match(e4.path, "d1/e4")
match(e4.path_, "d1/e4/")
match(e4.dir.path, "d1")
- e7 = fs.File("e3/e5")
- assert e7 is e5
- assert e5.__class__.__name__ == 'File'
+ e7 = fs.File("e3/e5")
+ assert e7 is e5
+ assert e5.__class__.__name__ == 'File'
match(e5.path, "e3/e5")
match(e5.path_, "e3/e5")
match(e5.dir.path, "e3")
@@ -383,23 +383,12 @@ class FSTestCase(unittest.TestCase):
match(e13.path, "subdir/subdir/e13")
# Test scanning
- scn1 = Scanner()
- f1.scan(scn1)
- assert f1.implicit[scn1][0].path_ == os.path.join("d1", "f1")
- del f1.implicit[scn1]
- f1.scan(scn1)
- assert len(f1.implicit) == 0, f1.implicit
- del f1.scanned[scn1]
- f1.scan(scn1)
- assert f1.implicit[scn1][0].path_ == os.path.join("d1", "f1")
-
- # Test multiple scanners
- scn2 = Scanner()
- f2 = fs.File("f2")
- f2.scan(scn1)
- f2.scan(scn2)
- match(f2.implicit[scn1][0].path_, 'subdir/f2')
- match(f2.implicit[scn2][0].path_, 'subdir/f2')
+ f1.target_scanner = Scanner()
+ f1.scan()
+ assert f1.implicit[0].path_ == os.path.join("d1", "f1")
+ f1.implicit = []
+ f1.scan()
+ assert f1.implicit[0].path_ == os.path.join("d1", "f1")
# Test building a file whose directory is not there yet...
f1 = fs.File(test.workpath("foo/bar/baz/ack"))
@@ -410,13 +399,13 @@ class FSTestCase(unittest.TestCase):
os.chdir('..')
- # Test getcwd()
+ # Test getcwd()
fs = SCons.Node.FS.FS()
- assert str(fs.getcwd()) == ".", str(fs.getcwd())
- fs.chdir(fs.Dir('subdir'))
- assert str(fs.getcwd()) == "subdir", str(fs.getcwd())
- fs.chdir(fs.Dir('../..'))
- assert str(fs.getcwd()) == test.workdir, str(fs.getcwd())
+ assert str(fs.getcwd()) == ".", str(fs.getcwd())
+ fs.chdir(fs.Dir('subdir'))
+ assert str(fs.getcwd()) == "subdir", str(fs.getcwd())
+ fs.chdir(fs.Dir('../..'))
+ assert str(fs.getcwd()) == test.workdir, str(fs.getcwd())
f1 = fs.File(test.workpath("do_i_exist"))
assert not f1.exists()
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index 16c5548..ef98a41 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -41,7 +41,7 @@ cycle_detected = None
class Builder:
def execute(self, **kw):
global built_it, built_target, built_source
- built_it = 1
+ built_it = 1
built_target = kw['target']
built_source = kw['source']
return 0
@@ -87,17 +87,17 @@ class Environment:
class NodeTestCase(unittest.TestCase):
def test_BuildException(self):
- """Test throwing an exception on build failure.
- """
- node = SCons.Node.Node()
- node.builder_set(FailBuilder())
- node.env_set(Environment())
- try:
- node.build()
- except SCons.Errors.BuildError:
- pass
- else:
- raise TestFailed, "did not catch expected BuildError"
+ """Test throwing an exception on build failure.
+ """
+ node = SCons.Node.Node()
+ node.builder_set(FailBuilder())
+ node.env_set(Environment())
+ try:
+ node.build()
+ except SCons.Errors.BuildError:
+ pass
+ else:
+ raise TestFailed, "did not catch expected BuildError"
node = SCons.Node.Node()
node.builder_set(ExceptBuilder())
@@ -126,8 +126,8 @@ class NodeTestCase(unittest.TestCase):
raise TestFailed, "did not catch expected BuildError"
def test_build(self):
- """Test building a node
- """
+ """Test building a node
+ """
global built_it
class MyNode(SCons.Node.Node):
@@ -138,18 +138,18 @@ class NodeTestCase(unittest.TestCase):
return self.path
def prepare(self):
self.prepare_count = self.prepare_count+ 1
- # Make sure it doesn't blow up if no builder is set.
+ # Make sure it doesn't blow up if no builder is set.
node = MyNode()
- node.build()
- assert built_it == None
+ node.build()
+ assert built_it == None
node = MyNode()
- node.builder_set(Builder())
- node.env_set(Environment())
+ node.builder_set(Builder())
+ node.env_set(Environment())
node.path = "xxx"
node.sources = ["yyy", "zzz"]
- node.build()
- assert built_it
+ node.build()
+ assert built_it
assert type(built_target) == type(MyNode()), type(built_target)
assert str(built_target) == "xxx", str(built_target)
assert built_source == ["yyy", "zzz"], built_source
@@ -201,13 +201,19 @@ class NodeTestCase(unittest.TestCase):
assert str(built_target) == "fff", str(built_target)
assert built_source == ["hhh", "iii"], built_source
+ def test_depends_on(self):
+ parent = SCons.Node.Node()
+ child = SCons.Node.Node()
+ parent.add_dependency([child])
+ assert parent.depends_on([child])
+
def test_builder_set(self):
- """Test setting a Node's Builder
- """
- node = SCons.Node.Node()
- b = Builder()
- node.builder_set(b)
- assert node.builder == b
+ """Test setting a Node's Builder
+ """
+ node = SCons.Node.Node()
+ b = Builder()
+ node.builder_set(b)
+ assert node.builder == b
def test_builder_sig_adapter(self):
"""Test the node's adapter for builder signatures
@@ -225,12 +231,12 @@ class NodeTestCase(unittest.TestCase):
assert node.current() is None
def test_env_set(self):
- """Test setting a Node's Environment
- """
- node = SCons.Node.Node()
- e = Environment()
- node.env_set(e)
- assert node.env == e
+ """Test setting a Node's Environment
+ """
+ node = SCons.Node.Node()
+ e = Environment()
+ node.env_set(e)
+ assert node.env == e
def test_set_bsig(self):
"""Test setting a Node's signature
@@ -276,16 +282,16 @@ class NodeTestCase(unittest.TestCase):
assert node.precious == 7
def test_add_dependency(self):
- """Test adding dependencies to a Node's list.
- """
- node = SCons.Node.Node()
- assert node.depends == []
+ """Test adding dependencies to a Node's list.
+ """
+ node = SCons.Node.Node()
+ assert node.depends == []
zero = SCons.Node.Node()
try:
- node.add_dependency(zero)
- except TypeError:
- pass
+ node.add_dependency(zero)
+ except TypeError:
+ pass
else:
assert 0
@@ -309,42 +315,10 @@ class NodeTestCase(unittest.TestCase):
def test_add_source(self):
- """Test adding sources to a Node's list.
- """
- node = SCons.Node.Node()
- assert node.sources == []
-
- zero = SCons.Node.Node()
- try:
- node.add_source(zero)
- except TypeError:
- pass
- else:
- assert 0
-
- one = SCons.Node.Node()
- two = SCons.Node.Node()
- three = SCons.Node.Node()
- four = SCons.Node.Node()
-
- node.add_source([one])
- assert node.sources == [one]
- node.add_source([two, three])
- assert node.sources == [one, two, three]
- node.add_source([three, four, one])
- assert node.sources == [one, two, three, four]
-
- assert zero.get_parents() == []
- assert one.get_parents() == [node]
- assert two.get_parents() == [node]
- assert three.get_parents() == [node]
- assert four.get_parents() == [node]
-
- def test_add_implicit(self):
- """Test adding implicit (scanned) dependencies to a Node's list.
+ """Test adding sources to a Node's list.
"""
node = SCons.Node.Node()
- assert node.implicit == {}
+ assert node.sources == []
zero = SCons.Node.Node()
try:
@@ -359,12 +333,12 @@ class NodeTestCase(unittest.TestCase):
three = SCons.Node.Node()
four = SCons.Node.Node()
- node.add_implicit([one], 1)
- assert node.implicit[1] == [one]
- node.add_implicit([two, three], 1)
- assert node.implicit[1] == [one, two, three]
- node.add_implicit([three, four, one], 1)
- assert node.implicit[1] == [one, two, three, four]
+ node.add_source([one])
+ assert node.sources == [one]
+ node.add_source([two, three])
+ assert node.sources == [one, two, three]
+ node.add_source([three, four, one])
+ assert node.sources == [one, two, three, four]
assert zero.get_parents() == []
assert one.get_parents() == [node]
@@ -372,15 +346,6 @@ class NodeTestCase(unittest.TestCase):
assert three.get_parents() == [node]
assert four.get_parents() == [node]
- node.add_implicit([one], 2)
- node.add_implicit([two, three], 3)
- node.add_implicit([three, four, one], 4)
-
- assert node.implicit[1] == [one, two, three, four]
- assert node.implicit[2] == [one]
- assert node.implicit[3] == [two, three]
- assert node.implicit[4] == [three, four, one]
-
def test_add_ignore(self):
"""Test adding files whose dependencies should be ignored.
"""
@@ -419,42 +384,9 @@ class NodeTestCase(unittest.TestCase):
pass
ds=DummyScanner()
node = SCons.Node.Node()
- assert node.scanner == None, node.scanner
- node.scanner_set(ds)
- assert node.scanner == ds, node.scanner
- node.scan(ds)
- assert node.scanned[ds] == 1, node.scanned
-
- def test_src_scanner_set(self):
- """Test setting source-file Scanners"""
- class DummyScanner:
- pass
- ds1=DummyScanner()
- ds2=DummyScanner()
- node = SCons.Node.Node()
- assert node.src_scanners == {}, node.src_scanners
- node.src_scanner_set('a', ds1)
- assert node.src_scanners['a'] == ds1, node.src_scanners
- node.src_scanner_set('b', ds2)
- assert node.src_scanners['b'] == ds2, node.src_scanners
-
- def test_src_scanner_set(self):
- """Test setting source-file Scanners"""
- class DummyScanner:
- pass
- ds1=DummyScanner()
- ds2=DummyScanner()
- node = SCons.Node.Node()
- node.src_scanner_set('a', ds1)
- node.src_scanner_set('b', ds2)
- s = node.src_scanner_get(None)
- assert s == None, s
- s = node.src_scanner_get('a')
- assert s == ds1, s
- s = node.src_scanner_get('b')
- assert s == ds2, s
- s = node.src_scanner_get('c')
- assert s == None, s
+ assert node.target_scanner == None, node.target_scanner
+ node.target_scanner = ds
+ node.scan()
def test_scanner_key(self):
"""Test that a scanner_key() method exists"""
@@ -463,7 +395,7 @@ class NodeTestCase(unittest.TestCase):
def test_children(self):
"""Test fetching the non-ignored "children" of a Node.
"""
- node = SCons.Node.Node()
+ node = SCons.Node.Node()
n1 = SCons.Node.Node()
n2 = SCons.Node.Node()
n3 = SCons.Node.Node()
@@ -479,28 +411,16 @@ class NodeTestCase(unittest.TestCase):
node.add_source([n1, n2, n3])
node.add_dependency([n4, n5, n6])
- node.add_implicit([n7, n8, n9], 'key1')
- node.add_implicit([n10, n11, n12], 'key2')
+ node._add_child(node.implicit, [n7, n8, n9])
+ node._add_child(node.implicit, [n10, n11, n12])
node.add_ignore([n2, n5, n8, n11])
- kids = node.children(None)
+ kids = node.children()
for kid in [n1, n3, n4, n6, n7, n9, n10, n12]:
assert kid in kids, kid
for kid in [n2, n5, n8, n11]:
assert not kid in kids, kid
- kids = node.children('key1')
- for kid in [n1, n3, n4, n6, n7, n9]:
- assert kid in kids, kid
- for kid in [n2, n5, n8, n10, n11, n12]:
- assert not kid in kids, kid
-
- kids = node.children('key2')
- for kid in [n1, n3, n4, n6, n10, n12]:
- assert kid in kids, kid
- for kid in [n2, n5, n7, n8, n9, n11]:
- assert not kid in kids, kid
-
def test_all_children(self):
"""Test fetching all the "children" of a Node.
"""
@@ -520,29 +440,17 @@ class NodeTestCase(unittest.TestCase):
node.add_source([n1, n2, n3])
node.add_dependency([n4, n5, n6])
- node.add_implicit([n7, n8, n9], 'key1')
- node.add_implicit([n10, n11, n12], 'key2')
+ node._add_child(node.implicit, [n7, n8, n9])
+ node._add_child(node.implicit, [n10, n11, n12])
node.add_ignore([n2, n5, n8, n11])
- kids = node.all_children(None)
+ kids = node.all_children()
for kid in [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12]:
assert kid in kids
- kids = node.all_children('key1')
- for kid in [n1, n2, n3, n4, n5, n6, n7, n8, n9]:
- assert kid in kids
- for kid in [n10, n11, n12]:
- assert not kid in kids
-
- kids = node.all_children('key2')
- for kid in [n1, n2, n3, n4, n5, n6, n10, n11, n12]:
- assert kid in kids
- for kid in [n7, n8, n9]:
- assert not kid in kids
-
def test_state(self):
- """Test setting and getting the state of a node
- """
+ """Test setting and getting the state of a node
+ """
node = SCons.Node.Node()
assert node.get_state() == None
node.set_state(SCons.Node.executing)
@@ -553,51 +461,51 @@ class NodeTestCase(unittest.TestCase):
assert SCons.Node.executed < SCons.Node.failed
def test_walker(self):
- """Test walking a Node tree.
- """
+ """Test walking a Node tree.
+ """
- class MyNode(SCons.Node.Node):
- def __init__(self, name):
- SCons.Node.Node.__init__(self)
- self.name = name
+ class MyNode(SCons.Node.Node):
+ def __init__(self, name):
+ SCons.Node.Node.__init__(self)
+ self.name = name
- n1 = MyNode("n1")
+ n1 = MyNode("n1")
- nw = SCons.Node.Walker(n1)
+ nw = SCons.Node.Walker(n1)
assert not nw.is_done()
- assert nw.next().name == "n1"
+ assert nw.next().name == "n1"
assert nw.is_done()
- assert nw.next() == None
-
- n2 = MyNode("n2")
- n3 = MyNode("n3")
- n1.add_source([n2, n3])
-
- nw = SCons.Node.Walker(n1)
- assert nw.next().name == "n2"
- assert nw.next().name == "n3"
- assert nw.next().name == "n1"
- assert nw.next() == None
-
- n4 = MyNode("n4")
- n5 = MyNode("n5")
- n6 = MyNode("n6")
- n7 = MyNode("n7")
- n2.add_source([n4, n5])
- n3.add_dependency([n6, n7])
-
- nw = SCons.Node.Walker(n1)
- assert nw.next().name == "n4"
- assert nw.next().name == "n5"
+ assert nw.next() == None
+
+ n2 = MyNode("n2")
+ n3 = MyNode("n3")
+ n1.add_source([n2, n3])
+
+ nw = SCons.Node.Walker(n1)
+ assert nw.next().name == "n2"
+ assert nw.next().name == "n3"
+ assert nw.next().name == "n1"
+ assert nw.next() == None
+
+ n4 = MyNode("n4")
+ n5 = MyNode("n5")
+ n6 = MyNode("n6")
+ n7 = MyNode("n7")
+ n2.add_source([n4, n5])
+ n3.add_dependency([n6, n7])
+
+ nw = SCons.Node.Walker(n1)
+ assert nw.next().name == "n4"
+ assert nw.next().name == "n5"
assert nw.history.has_key(n2)
- assert nw.next().name == "n2"
- assert nw.next().name == "n6"
- assert nw.next().name == "n7"
+ assert nw.next().name == "n2"
+ assert nw.next().name == "n6"
+ assert nw.next().name == "n7"
assert nw.history.has_key(n3)
- assert nw.next().name == "n3"
+ assert nw.next().name == "n3"
assert nw.history.has_key(n1)
- assert nw.next().name == "n1"
- assert nw.next() == None
+ assert nw.next().name == "n1"
+ assert nw.next() == None
n8 = MyNode("n8")
n8.add_dependency([n3])
@@ -621,69 +529,6 @@ class NodeTestCase(unittest.TestCase):
n = nw.next()
assert nw.next() == None
- def test_children_are_executed(self):
- n1 = SCons.Node.Node()
- n2 = SCons.Node.Node()
- n3 = SCons.Node.Node()
- n4 = SCons.Node.Node()
-
- n4.add_source([n3])
- n3.add_source([n1, n2])
-
- assert not n4.children_are_executed(None)
- assert not n3.children_are_executed(None)
- assert n2.children_are_executed(None)
- assert n1.children_are_executed(None)
-
- n1.set_state(SCons.Node.executed)
- assert not n4.children_are_executed(None)
- assert not n3.children_are_executed(None)
- assert n2.children_are_executed(None)
- assert n1.children_are_executed(None)
-
- n2.set_state(SCons.Node.executed)
- assert not n4.children_are_executed(None)
- assert n3.children_are_executed(None)
- assert n2.children_are_executed(None)
- assert n1.children_are_executed(None)
-
- n3.set_state(SCons.Node.executed)
- assert n4.children_are_executed(None)
- assert n3.children_are_executed(None)
- assert n2.children_are_executed(None)
- assert n1.children_are_executed(None)
-
- def test_rescan(self):
- """Test that built node implicit dependencies are cleared
- to be rescanned."""
- class DummyScanner:
- pass
-
- class TestNode(SCons.Node.Node):
- def scan(self, scanner):
- if not self.scanned.has_key(scanner):
- n=SCons.Node.Node()
- n.scanner_set(scanner)
- self.add_implicit([ n ], scanner)
- self.scanned[scanner] = 1
- tn=TestNode()
- tn.builder_set(Builder())
- tn.env_set(Environment())
- ds = DummyScanner()
- tn.scan(ds)
- map(lambda x: x.scan(), tn.depends)
- assert tn.scanned[ds]
- assert len(tn.implicit[ds]) == 1, tn.implicit
- tn.scan(ds)
- assert tn.scanned[ds]
- assert len(tn.implicit[ds]) == 1, tn.implicit
- tn.build()
- assert not tn.scanned.has_key(ds)
- assert len(tn.implicit[ds]) == 1, tn.implicit
- tn.scan(ds)
- assert tn.scanned[ds]
- assert len(tn.implicit[ds]) == 2, tn.implicit
-
def test_arg2nodes(self):
"""Test the arg2nodes function."""
dict = {}
@@ -779,4 +624,4 @@ class NodeTestCase(unittest.TestCase):
if __name__ == "__main__":
suite = unittest.makeSuite(NodeTestCase, 'test_')
if not unittest.TextTestRunner().run(suite).wasSuccessful():
- sys.exit(1)
+ sys.exit(1)
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 98b2d50..db11e55 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -51,6 +51,7 @@ executing = 2
up_to_date = 3
executed = 4
failed = 5
+stack = 6 # nodes that are in the current Taskmaster execution stack
class Node:
"""The base Node class, for entities that we know how to
@@ -60,14 +61,13 @@ class Node:
def __init__(self):
self.sources = [] # source files used to build node
self.depends = [] # explicit dependencies (from Depends)
- self.implicit = {} # implicit (scanned) dependencies
- self.ignore = [] # dependencies to ignore
+ self.implicit = [] # implicit (scanned) dependencies
+ self.ignore = [] # dependencies to ignore
self.parents = {}
self.wkids = None # Kids yet to walk, when it's an array
self.builder = None
- self.scanner = None # explicit scanner from this node's Builder
- self.scanned = {} # cached scanned values
- self.src_scanners = {} # scanners for this node's source files
+ self.source_scanner = None # implicit scanner from scanner map
+ self.target_scanner = None # explicit scanner from this node's Builder
self.env = None
self.state = None
self.bsig = None
@@ -75,11 +75,14 @@ class Node:
self.use_signature = 1
self.precious = None
self.found_includes = {}
+ self.includes = None
def build(self):
"""Actually build the node. Return the status from the build."""
- if not self.builder:
- return None
+ # This method is called from multiple threads in a parallel build,
+ # so only do thread safe stuff here. Do thread unsafe stuff in built().
+ if not self.builder:
+ return None
try:
# If this Builder instance has already been called,
# there will already be an associated status.
@@ -103,16 +106,33 @@ class Node:
if stat:
raise BuildError(node = self, errstr = "Error %d" % stat)
- self.found_includes = {}
-
- # If we successfully build a node, then we need to rescan for
- # implicit dependencies, since it might have changed on us.
- self.scanned = {}
-
return stat
+ def built(self):
+ """Called just after this node is sucessfully built."""
+ # Clear out the implicit dependency caches:
+ # XXX this really should somehow be made more general and put
+ # under the control of the scanners.
+ if self.source_scanner:
+ self.found_includes = {}
+ self.includes = None
+
+ def get_parents(node, parent): return node.get_parents()
+ def clear_cache(node, parent):
+ node.implicit = []
+ w = Walker(self, get_parents, ignore_cycle, clear_cache)
+ while w.next(): pass
+
+ def depends_on(self, nodes):
+ """Does this node depend on any of 'nodes'?"""
+ for node in nodes:
+ if node in self.children():
+ return 1
+
+ return 0
+
def builder_set(self, builder):
- self.builder = builder
+ self.builder = builder
def builder_sig_adapter(self):
"""Create an adapter for calculating a builder's signature.
@@ -136,19 +156,21 @@ class Node:
return self.node.builder.get_contents(env = dict)
return Adapter(self)
- def scanner_set(self, scanner):
- self.scanner = scanner
-
- def src_scanner_set(self, key, scanner):
- self.src_scanners[key] = scanner
-
- def src_scanner_get(self, key):
- return self.src_scanners.get(key, None)
-
- def scan(self, scanner = None):
- if not scanner:
- scanner = self.scanner
- self.scanned[scanner] = 1
+ def get_implicit_deps(self, env, scanner, target):
+ """Return a list of implicit dependencies for this node"""
+ return []
+
+ def scan(self):
+ """Scan this node's dependents for implicit dependencies."""
+ # Don't bother scanning non-derived files, because we don't
+ # care what their dependencies are.
+ # Don't scan again, if we already have scanned.
+ if self.builder and not self.implicit:
+ for child in self.children(scan=0):
+ self._add_child(self.implicit, child.get_implicit_deps(self.env, child.source_scanner, self))
+
+ # scan this node itself for implicit dependencies
+ self._add_child(self.implicit, self.get_implicit_deps(self.env, self.target_scanner, self))
def scanner_key(self):
return None
@@ -156,7 +178,7 @@ class Node:
def env_set(self, env, safe=0):
if safe and self.env:
return
- self.env = env
+ self.env = env
def get_bsig(self):
"""Get the node's build signature (based on the signatures
@@ -190,7 +212,7 @@ class Node:
pass
def add_dependency(self, depend):
- """Adds dependencies. The depend argument must be a list."""
+ """Adds dependencies. The depend argument must be a list."""
self._add_child(self.depends, depend)
def add_ignore(self, depend):
@@ -198,23 +220,16 @@ class Node:
self._add_child(self.ignore, depend)
def add_source(self, source):
- """Adds sources. The source argument must be a list."""
+ """Adds sources. The source argument must be a list."""
self._add_child(self.sources, source)
- def add_implicit(self, implicit, key):
- """Adds implicit (scanned) dependencies. The implicit
- argument must be a list."""
- if not self.implicit.has_key(key):
- self.implicit[key] = []
- self._add_child(self.implicit[key], implicit)
-
def _add_child(self, collection, child):
"""Adds 'child' to 'collection'. The 'child' argument must be a list"""
if type(child) is not type([]):
raise TypeError("child must be a list")
- child = filter(lambda x, s=collection: x not in s, child)
- if child:
- collection.extend(child)
+ child = filter(lambda x, s=collection: x not in s, child)
+ if child:
+ collection.extend(child)
for c in child:
c.parents[self] = 1
@@ -224,22 +239,18 @@ class Node:
if self.wkids != None:
self.wkids.append(wkid)
- def children(self, scanner):
+ def children(self, scan=1):
"""Return a list of the node's direct children, minus those
that are ignored by this node."""
return filter(lambda x, i=self.ignore: x not in i,
- self.all_children(scanner))
+ self.all_children(scan))
- def all_children(self, scanner):
+ def all_children(self, scan=1):
"""Return a list of all the node's direct children."""
#XXX Need to remove duplicates from this
- if not self.implicit.has_key(scanner):
- self.scan(scanner)
- if scanner:
- implicit = self.implicit[scanner]
- else:
- implicit = reduce(lambda x, y: x + y, self.implicit.values(), [])
- return self.sources + self.depends + implicit
+ if scan and not self.implicit:
+ self.scan()
+ return self.sources + self.depends + self.implicit
def get_parents(self):
return self.parents.keys()
@@ -253,14 +264,7 @@ class Node:
def current(self):
return None
- def children_are_executed(self, scanner):
- return reduce(lambda x,y: ((y.get_state() == executed
- or y.get_state() == up_to_date)
- and x),
- self.children(scanner),
- 1)
-
-def get_children(node, parent): return node.children(None)
+def get_children(node, parent): return node.children()
def ignore_cycle(node, stack): pass
def do_nothing(node, parent): pass
@@ -290,13 +294,13 @@ class Walker:
self.history[node] = None
def next(self):
- """Return the next node for this walk of the tree.
+ """Return the next node for this walk of the tree.
- This function is intentionally iterative, not recursive,
- to sidestep any issues of stack size limitations.
- """
+ This function is intentionally iterative, not recursive,
+ to sidestep any issues of stack size limitations.
+ """
- while self.stack:
+ while self.stack:
if self.stack[-1].wkids:
node = self.stack[-1].wkids.pop(0)
if not self.stack[-1].wkids:
diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py
index 0a2654e..c81417a 100644
--- a/src/engine/SCons/Scanner/C.py
+++ b/src/engine/SCons/Scanner/C.py
@@ -41,45 +41,16 @@ import SCons.Util
include_re = re.compile('^[ \t]*#[ \t]*include[ \t]+(<|")([\\w./\\\\]+)(>|")', re.M)
-include_cache = {}
-
def CScan(fs = SCons.Node.FS.default_fs):
"""Return a prototype Scanner instance for scanning source files
that use the C pre-processor"""
- cs = CScanner(scan, "CScan", [fs, ()],
- [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
- ".h", ".H", ".hxx", ".hpp", ".hh",
- ".F", ".fpp", ".FPP"])
- cs.fs = fs
+ cs = SCons.Scanner.Recursive(scan, "CScan", fs,
+ [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
+ ".h", ".H", ".hxx", ".hpp", ".hh",
+ ".F", ".fpp", ".FPP"])
return cs
-class CScanner(SCons.Scanner.Recursive):
- def __init__(self, *args, **kw):
- apply(SCons.Scanner.Recursive.__init__, (self,) + args, kw)
- self.hash = None
- self.pathscanners = {}
-
- def instance(self, env):
- """
- Return a unique instance of a C scanner object for a
- given environment.
- """
- try:
- dirs = tuple(SCons.Node.arg2nodes(env.Dictionary('CPPPATH'),
- self.fs.Dir))
- except:
- dirs = ()
- if not self.pathscanners.has_key(dirs):
- clone = copy.copy(self)
- clone.hash = dirs
- clone.argument = [self.fs, dirs] # XXX reaching into object
- self.pathscanners[dirs] = clone
- return self.pathscanners[dirs]
-
- def __hash__(self):
- return hash(self.hash)
-
-def scan(node, env, args = [SCons.Node.FS.default_fs, ()]):
+def scan(node, env, target, fs = SCons.Node.FS.default_fs):
"""
scan(node, Environment) -> [node]
@@ -100,7 +71,21 @@ def scan(node, env, args = [SCons.Node.FS.default_fs, ()]):
dependencies.
"""
- fs, cpppath = args
+ # This function caches various information in node and target:
+ # target.cpppath - env['CPPPATH'] converted to nodes
+ # node.found_includes - include files found by previous call to scan,
+ # keyed on cpppath
+ # node.includes - the result of include_re.findall()
+
+ if not hasattr(target, 'cpppath'):
+ def Dir(x, dir=target.cwd, fs=fs): return fs.Dir(x,dir)
+ try:
+ target.cpppath = tuple(SCons.Node.arg2nodes(env['CPPPATH'],Dir))
+ except KeyError:
+ target.cpppath = ()
+
+ cpppath = target.cpppath
+
nodes = []
try:
@@ -109,7 +94,7 @@ def scan(node, env, args = [SCons.Node.FS.default_fs, ()]):
if node.exists():
# cache the includes list in node so we only scan it once:
- if hasattr(node, 'includes'):
+ if node.includes != None:
includes = node.includes
else:
includes = include_re.findall(node.get_contents())
diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py
index 684df99..f99af18 100644
--- a/src/engine/SCons/Scanner/CTests.py
+++ b/src/engine/SCons/Scanner/CTests.py
@@ -119,6 +119,10 @@ test.write('subdir/include/fb.h', "\n")
# define some helpers:
+class DummyTarget:
+ def __init__(self, cwd=None):
+ self.cwd = cwd
+
class DummyEnvironment:
def __init__(self, listCppPath):
self.path = listCppPath
@@ -131,6 +135,15 @@ class DummyEnvironment:
else:
raise KeyError, "Dummy environment only has CPPPATH attribute."
+ def __getitem__(self,key):
+ return self.Dictionary()[key]
+
+ def __setitem__(self,key,value):
+ self.Dictionary()[key] = value
+
+ def __delitem__(self,key):
+ del self.Dictionary()[key]
+
def deps_match(self, deps, headers):
scanned = map(os.path.normpath, map(str, deps))
expect = map(os.path.normpath, headers)
@@ -145,15 +158,15 @@ class CScannerTestCase1(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f1.cpp'), env)
- headers = ['f1.h', 'f2.h', 'fi.h']
+ deps = s.scan(make_node('f1.cpp'), env, DummyTarget())
+ headers = ['f1.h', 'f2.h', 'fi.h']
deps_match(self, deps, map(test.workpath, headers))
class CScannerTestCase2(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1")])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f1.cpp'), env)
+ deps = s.scan(make_node('f1.cpp'), env, DummyTarget())
headers = ['d1/f2.h', 'f1.h']
deps_match(self, deps, map(test.workpath, headers))
@@ -161,7 +174,7 @@ class CScannerTestCase3(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1")])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f2.cpp'), env)
+ deps = s.scan(make_node('f2.cpp'), env, DummyTarget())
headers = ['d1/d2/f1.h', 'd1/f1.h', 'f1.h']
deps_match(self, deps, map(test.workpath, headers))
@@ -169,7 +182,7 @@ class CScannerTestCase4(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1"), test.workpath("d1/d2")])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f2.cpp'), env)
+ deps = s.scan(make_node('f2.cpp'), env, DummyTarget())
headers = ['d1/d2/f1.h', 'd1/d2/f4.h', 'd1/f1.h', 'f1.h']
deps_match(self, deps, map(test.workpath, headers))
@@ -177,7 +190,7 @@ class CScannerTestCase5(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f3.cpp'), env)
+ deps = s.scan(make_node('f3.cpp'), env, DummyTarget())
# Make sure exists() gets called on the file node being
# scanned, essential for cooperation with BuildDir functionality.
@@ -193,35 +206,23 @@ class CScannerTestCase6(unittest.TestCase):
env2 = DummyEnvironment([test.workpath("d1/d2")])
env3 = DummyEnvironment([test.workpath("d1/../d1")])
s = SCons.Scanner.C.CScan()
- s1 = s.instance(env1)
- s2 = s.instance(env2)
- s3 = s.instance(env3)
- assert not s1 is s2
- assert s1 is s3
- deps1 = s1.scan(make_node('f1.cpp'), None)
- deps2 = s2.scan(make_node('f1.cpp'), None)
+ deps1 = s.scan(make_node('f1.cpp'), env1, DummyTarget())
+ deps2 = s.scan(make_node('f1.cpp'), env2, DummyTarget())
headers1 = ['d1/f2.h', 'f1.h']
headers2 = ['d1/d2/f2.h', 'f1.h']
deps_match(self, deps1, map(test.workpath, headers1))
deps_match(self, deps2, map(test.workpath, headers2))
-class CScannerTestCase7(unittest.TestCase):
- def runTest(self):
- s = SCons.Scanner.C.CScan()
- s1 = s.instance(DummyEnvironment([test.workpath("d1")]))
- s2 = s.instance(DummyEnvironment([test.workpath("d1/../d1")]))
- dict = {}
- dict[s1] = 777
- assert dict[s2] == 777
-
class CScannerTestCase8(unittest.TestCase):
def runTest(self):
fs = SCons.Node.FS.FS(test.workpath(''))
env = DummyEnvironment(["include"])
s = SCons.Scanner.C.CScan(fs = fs)
- deps1 = s.instance(env).scan(fs.File('fa.cpp'), None)
+ deps1 = s.scan(fs.File('fa.cpp'), env, DummyTarget())
fs.chdir(fs.Dir('subdir'))
- deps2 = s.instance(env).scan(fs.File('#fa.cpp'), None)
+ target = DummyTarget(fs.getcwd())
+ fs.chdir(fs.Dir('..'))
+ deps2 = s.scan(fs.File('#fa.cpp'), env, target)
headers1 = ['include/fa.h', 'include/fb.h']
headers2 = ['subdir/include/fa.h', 'subdir/include/fb.h']
deps_match(self, deps1, headers1)
@@ -233,7 +234,7 @@ class CScannerTestCase9(unittest.TestCase):
fs = SCons.Node.FS.FS(test.workpath(''))
s = SCons.Scanner.C.CScan(fs=fs)
env = DummyEnvironment([])
- deps = s.instance(env).scan(fs.File('fa.cpp'), None)
+ deps = s.scan(fs.File('fa.cpp'), env, DummyTarget())
deps_match(self, deps, [ 'fa.h' ])
test.unlink('fa.h')
@@ -244,7 +245,7 @@ class CScannerTestCase10(unittest.TestCase):
s = SCons.Scanner.C.CScan(fs=fs)
env = DummyEnvironment([])
test.write('include/fa.cpp', test.read('fa.cpp'))
- deps = s.instance(env).scan(fs.File('#include/fa.cpp'), None)
+ deps = s.scan(fs.File('#include/fa.cpp'), env, DummyTarget())
deps_match(self, deps, [ 'include/fa.h', 'include/fb.h' ])
test.unlink('include/fa.cpp')
@@ -256,7 +257,6 @@ def suite():
suite.addTest(CScannerTestCase4())
suite.addTest(CScannerTestCase5())
suite.addTest(CScannerTestCase6())
- suite.addTest(CScannerTestCase7())
suite.addTest(CScannerTestCase8())
suite.addTest(CScannerTestCase9())
suite.addTest(CScannerTestCase10())
diff --git a/src/engine/SCons/Scanner/Prog.py b/src/engine/SCons/Scanner/Prog.py
index 9ecc37b..76567ab 100644
--- a/src/engine/SCons/Scanner/Prog.py
+++ b/src/engine/SCons/Scanner/Prog.py
@@ -31,74 +31,49 @@ import SCons.Node.FS
import SCons.Scanner
import SCons.Util
-class NullProgScanner:
- """A do-nothing ProgScanner for Environments that have no LIBS."""
- def scan(node, env, args = []):
- return []
-
-null_scanner = NullProgScanner()
-
def ProgScan(fs = SCons.Node.FS.default_fs):
"""Return a prototype Scanner instance for scanning executable
files for static-lib dependencies"""
- ps = ProgScanner(scan, "ProgScan")
- ps.fs = fs
+ ps = SCons.Scanner.Base(scan, "ProgScan", fs)
return ps
-class ProgScanner(SCons.Scanner.Base):
- def __init__(self, *args, **kw):
- apply(SCons.Scanner.Base.__init__, (self,) + args, kw)
- self.hash = None
- self.pathscanners = {}
-
- def instance(self, env):
- """
- Return a unique instance of a Prog scanner object for a
- given environment.
- """
- try:
- libs = env.Dictionary('LIBS')
- except KeyError:
- # There are no LIBS in this environment, so just return the
- # fake "scanner" instance that always returns a null list.
- return null_scanner
- if SCons.Util.is_String(libs):
- libs = string.split(libs)
+def scan(node, env, target, fs):
+ """
+ This scanner scans program files for static-library
+ dependencies. It will search the LIBPATH environment variable
+ for libraries specified in the LIBS variable, returning any
+ files it finds as dependencies.
+ """
- try:
- dirs = tuple(SCons.Node.arg2nodes(env.Dictionary('LIBPATH'),
- self.fs.Dir))
- except:
- dirs = ()
+ # This function caches information in target:
+ # target.libpath - env['LIBPATH'] converted to nodes
+ if not hasattr(target, 'libpath'):
+ def Dir(x, dir=target.cwd, fs=fs): return fs.Dir(x,dir)
try:
- prefix = env.Dictionary('LIBPREFIX')
+ target.libpath = tuple(SCons.Node.arg2nodes(env['LIBPATH'],Dir))
except KeyError:
- prefix = ''
+ target.libpath = ()
+
+ libpath = target.libpath
- try:
- suffix = env.Dictionary('LIBSUFFIX')
- except KeyError:
- suffix = ''
+ try:
+ libs = env.Dictionary('LIBS')
+ except KeyError:
+ # There are no LIBS in this environment, so just return a null list:
+ return []
+ if SCons.Util.is_String(libs):
+ libs = string.split(libs)
- key = (dirs, tuple(libs), prefix, suffix)
- if not self.pathscanners.has_key(key):
- clone = copy.copy(self)
- clone.hash = key
- clone.argument = [self.fs, dirs, libs, prefix, suffix] # XXX reaching into object
- self.pathscanners[key] = clone
- return self.pathscanners[key]
+ try:
+ prefix = env.Dictionary('LIBPREFIX')
+ except KeyError:
+ prefix = ''
- def __hash__(self):
- return hash(self.hash)
+ try:
+ suffix = env.Dictionary('LIBSUFFIX')
+ except KeyError:
+ suffix = ''
-def scan(node, env, args = [SCons.Node.FS.default_fs, (), [], '', '']):
- """
- This scanner scans program files for static-library
- dependencies. It will search the LIBPATH environment variable
- for libraries specified in the LIBS variable, returning any
- files it finds as dependencies.
- """
- fs, libpath, libs, prefix, suffix = args
libs = map(lambda x, s=suffix, p=prefix: p + x + s, libs)
return SCons.Node.FS.find_files(libs, libpath, fs.File)
diff --git a/src/engine/SCons/Scanner/ProgTests.py b/src/engine/SCons/Scanner/ProgTests.py
index b59e554..ea3d00d 100644
--- a/src/engine/SCons/Scanner/ProgTests.py
+++ b/src/engine/SCons/Scanner/ProgTests.py
@@ -42,6 +42,10 @@ for h in libs:
# define some helpers:
+class DummyTarget:
+ def __init__(self, cwd=None):
+ self.cwd = cwd
+
class DummyEnvironment:
def __init__(self, **kw):
self._dict = kw
@@ -54,6 +58,14 @@ class DummyEnvironment:
return self._dict[args[0]]
else:
return map(lambda x, s=self: s._dict[x], args)
+ def __getitem__(self,key):
+ return self.Dictionary()[key]
+
+ def __setitem__(self,key,value):
+ self.Dictionary()[key] = value
+
+ def __delitem__(self,key):
+ del self.Dictionary()[key]
def deps_match(deps, libs):
deps=map(str, deps)
@@ -70,7 +82,7 @@ class ProgScanTestCase1(unittest.TestCase):
env = DummyEnvironment(LIBPATH=[ test.workpath("") ],
LIBS=[ 'l1', 'l2', 'l3' ])
s = SCons.Scanner.Prog.ProgScan()
- deps = s.instance(env).scan('dummy', env)
+ deps = s.scan('dummy', env, DummyTarget())
assert deps_match(deps, ['l1.lib']), map(str, deps)
class ProgScanTestCase2(unittest.TestCase):
@@ -79,7 +91,7 @@ class ProgScanTestCase2(unittest.TestCase):
["", "d1", "d1/d2" ]),
LIBS=[ 'l1', 'l2', 'l3' ])
s = SCons.Scanner.Prog.ProgScan()
- deps = s.instance(env).scan('dummy', env)
+ deps = s.scan('dummy', env, DummyTarget())
assert deps_match(deps, ['l1.lib', 'd1/l2.lib', 'd1/d2/l3.lib' ]), map(str, deps)
class ProgScanTestCase3(unittest.TestCase):
@@ -88,7 +100,7 @@ class ProgScanTestCase3(unittest.TestCase):
test.workpath("d1"),
LIBS='l2 l3')
s = SCons.Scanner.Prog.ProgScan()
- deps = s.instance(env).scan('dummy', env)
+ deps = s.scan('dummy', env, DummyTarget())
assert deps_match(deps, ['d1/l2.lib', 'd1/d2/l3.lib']), map(str, deps)
def suite():
@@ -104,7 +116,7 @@ def suite():
test.workpath("d1"),
LIBS=u'l2 l3')
s = SCons.Scanner.Prog.ProgScan()
- deps = s.instance(env).scan('dummy', env)
+ deps = s.scan('dummy', env, DummyTarget())
assert deps_match(deps, ['d1/l2.lib', 'd1/d2/l3.lib']), map(str, deps)
suite.addTest(ProgScanTestCase4())
\n"""
diff --git a/src/engine/SCons/Scanner/ScannerTests.py b/src/engine/SCons/Scanner/ScannerTests.py
index 76df18e..fce4078 100644
--- a/src/engine/SCons/Scanner/ScannerTests.py
+++ b/src/engine/SCons/Scanner/ScannerTests.py
@@ -27,11 +27,16 @@ import unittest
import SCons.Scanner
import sys
+class DummyTarget:
+ cwd = None
+
+
class ScannerTestBase:
- def func(self, filename, env, *args):
+ def func(self, filename, env, target, *args):
self.filename = filename
self.env = env
+ self.target = target
if len(args) > 0:
self.arg = args[0]
@@ -41,7 +46,7 @@ class ScannerTestBase:
def test(self, scanner, env, filename, deps, *args):
self.deps = deps
- scanned = scanner.scan(filename, env)
+ scanned = scanner.scan(filename, env, DummyTarget())
scanned_strs = map(lambda x: str(x), scanned)
self.failUnless(self.filename == filename, "the filename was passed incorrectly")
@@ -67,10 +72,9 @@ class ScannerPositionalTestCase(ScannerTestBase, unittest.TestCase):
env.VARIABLE = "var1"
self.test(s, env, 'f1.cpp', ['f1.h', 'f1.hpp'])
- env = DummyEnvironment()
- env.VARIABLE = "i1"
- i = s.instance(env)
- self.test(i, env, 'i1.cpp', ['i1.h', 'i1.hpp'])
+ env = DummyEnvironment()
+ env.VARIABLE = "i1"
+ self.test(s, env, 'i1.cpp', ['i1.h', 'i1.hpp'])
class ScannerKeywordTestCase(ScannerTestBase, unittest.TestCase):
"Test the Scanner.Base class using the keyword argument"
@@ -80,10 +84,9 @@ class ScannerKeywordTestCase(ScannerTestBase, unittest.TestCase):
env.VARIABLE = "var2"
self.test(s, env, 'f2.cpp', ['f2.h', 'f2.hpp'])
- env = DummyEnvironment()
- env.VARIABLE = "i2"
- i = s.instance(env)
- self.test(i, env, 'i2.cpp', ['i2.h', 'i2.hpp'])
+ env = DummyEnvironment()
+ env.VARIABLE = "i2"
+ self.test(s, env, 'i2.cpp', ['i2.h', 'i2.hpp'])
class ScannerPositionalArgumentTestCase(ScannerTestBase, unittest.TestCase):
"Test the Scanner.Base class using both position and optional arguments"
@@ -94,10 +97,9 @@ class ScannerPositionalArgumentTestCase(ScannerTestBase, unittest.TestCase):
env.VARIABLE = "var3"
self.test(s, env, 'f3.cpp', ['f3.h', 'f3.hpp'], arg)
- env = DummyEnvironment()
- env.VARIABLE = "i3"
- i = s.instance(env)
- self.test(i, env, 'i3.cpp', ['i3.h', 'i3.hpp'], arg)
+ env = DummyEnvironment()
+ env.VARIABLE = "i3"
+ self.test(s, env, 'i3.cpp', ['i3.h', 'i3.hpp'], arg)
class ScannerKeywordArgumentTestCase(ScannerTestBase, unittest.TestCase):
"Test the Scanner.Base class using both keyword and optional arguments"
@@ -109,10 +111,9 @@ class ScannerKeywordArgumentTestCase(ScannerTestBase, unittest.TestCase):
env.VARIABLE = "var4"
self.test(s, env, 'f4.cpp', ['f4.h', 'f4.hpp'], arg)
- env = DummyEnvironment()
- env.VARIABLE = "i4"
- i = s.instance(env)
- self.test(i, env, 'i4.cpp', ['i4.h', 'i4.hpp'], arg)
+ env = DummyEnvironment()
+ env.VARIABLE = "i4"
+ self.test(s, env, 'i4.cpp', ['i4.h', 'i4.hpp'], arg)
class ScannerHashTestCase(ScannerTestBase, unittest.TestCase):
"Test the Scanner.Base class __hash__() method"
diff --git a/src/engine/SCons/Scanner/__init__.py b/src/engine/SCons/Scanner/__init__.py
index 53c67e4..b2e04a3 100644
--- a/src/engine/SCons/Scanner/__init__.py
+++ b/src/engine/SCons/Scanner/__init__.py
@@ -97,7 +97,7 @@ class Base:
self.skeys = skeys
self.node_factory = node_factory
- def scan(self, node, env):
+ def scan(self, node, env, target):
"""
This method scans a single object. 'node' is the node
that will be passed to the scanner function, and 'env' is the
@@ -106,9 +106,9 @@ class Base:
"""
if not self.argument is _null:
- list = self.function(node, env, self.argument)
+ list = self.function(node, env, target, self.argument)
else:
- list = self.function(node, env)
+ list = self.function(node, env, target)
kw = {}
if hasattr(node, 'dir'):
kw['directory'] = node.dir
@@ -119,16 +119,6 @@ class Base:
nodes.append(l)
return nodes
- def instance(self, env):
- """
- Return an instance of a Scanner object for use in scanning.
-
- In the base class, we just return the scanner itself.
- Other Scanner classes may use this to clone copies and/or
- return unique instances as needed.
- """
- return self
-
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
@@ -143,7 +133,7 @@ class Recursive(Base):
list of all dependencies.
"""
- def scan(self, node, env):
+ def scan(self, node, env, target):
"""
This method does the actual scanning. 'node' is the node
that will be passed to the scanner function, and 'env' is the
@@ -158,7 +148,7 @@ class Recursive(Base):
while nodes:
n = nodes.pop(0)
d = filter(lambda x, seen=seen: not seen.has_key(x),
- Base.scan(self, n, env))
+ Base.scan(self, n, env, target))
if d:
deps.extend(d)
nodes.extend(d)
diff --git a/src/engine/SCons/Sig/SigTests.py b/src/engine/SCons/Sig/SigTests.py
index 71d48ce..90488e1 100644
--- a/src/engine/SCons/Sig/SigTests.py
+++ b/src/engine/SCons/Sig/SigTests.py
@@ -50,7 +50,7 @@ class DummyNode:
self.file = file
self.path = file.path
self.builder = file.builder
- self.depends = []
+ self.depends = []
self.ignore = []
self.use_signature = 1
self.bsig = None
@@ -81,11 +81,11 @@ class DummyNode:
self.exists_cache = self.exists()
return self.exists_cache
- def children(self, scanner):
+ def children(self):
return filter(lambda x, i=self.ignore: x not in i,
self.sources + self.depends)
- def all_children(self, scanner):
+ def all_children(self):
return self.sources + self.depends
def current(self):
@@ -139,12 +139,12 @@ def create_nodes(files):
nodes[0].sources = []
nodes[1].sources = [nodes[0]]
- nodes[2].sources = [nodes[3]]
+ nodes[2].sources = []
nodes[3].sources = []
- nodes[4].sources = [nodes[5]]
+ nodes[4].sources = []
nodes[5].sources = [nodes[6]]
nodes[6].sources = [nodes[5]]
- nodes[7].sources = [nodes[2], nodes[4]]
+ nodes[7].sources = [nodes[2], nodes[4], nodes[3], nodes[5]]
nodes[8].sources = []
nodes[9].sources = [nodes[8]]
nodes[10].sources = [nodes[9]]
@@ -296,9 +296,9 @@ class CalcTestCase(unittest.TestCase):
self.ignore = []
self.builder = None
self.use_signature = 1
- def children(self, scanner):
+ def children(self):
return filter(lambda x, i=self.ignore: x not in i, self.kids)
- def all_children(self, scanner):
+ def all_children(self):
return self.kids
def exists(self):
return 1
diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py
index 3770adf..cb03630 100644
--- a/src/engine/SCons/Sig/__init__.py
+++ b/src/engine/SCons/Sig/__init__.py
@@ -192,36 +192,14 @@ class Calculator:
if not bsig is None:
return bsig
- # Collect the signatures for ALL the nodes that this
- # node depends on. Just collecting the direct
- # dependants is not good enough, because
- # the signature of a non-derived file does
- # not include the signatures of its psuedo-sources
- # (e.g. the signature for a .c file does not include
- # the signatures of the .h files that it includes).
-
- # However, we do NOT want to walk dependencies of non-
- # derived files, because calling get_signature() on the
- # derived nodes will in turn call bsig() again and do that
- # for us. Hence:
sigs = []
- def non_derived(n, parent, myself=node):
- if not n.builder or n is myself:
- return filter(lambda x, i=myself.ignore: x not in i,
- n.all_children(None))
- return []
- def get_sig(n, parent, self=self, myself=node, sigs=sigs):
- if not n is myself:
- sigs.append(self.get_signature(n))
- walker = SCons.Node.Walker(node, non_derived, eval_func=get_sig)
- child = walker.next()
- while child:
- child = walker.next()
-
+ for child in node.children():
+ sigs.append(self.get_signature(child))
if node.builder:
sigs.append(self.module.signature(node.builder_sig_adapter()))
- return self.module.collect(filter(lambda x: not x is None, sigs))
+ return self.module.collect(filter(lambda x: not x is None, sigs))
+
def csig(self, node):
"""
Generate a node's content signature, the digested signature
@@ -239,7 +217,7 @@ class Calculator:
return csig
return self.module.signature(node)
-
+
def get_signature(self, node):
"""
Get the appropriate signature for a node.
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index c97d28c..47707b0 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -54,13 +54,16 @@ class Task:
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."""
- def __init__(self, tm, targets, top, scanner = None):
+ def __init__(self, tm, targets, top, node):
self.tm = tm
self.targets = targets
self.top = top
- self.scanner = scanner
+ self.node = node
def execute(self):
+ # This methods is called from multiple threads in
+ # a parallel build, so only do thread safe stuff here.
+ # Do thread unsafe stuff in executed() or failed().
if self.targets[0].get_state() != SCons.Node.up_to_date:
self.targets[0].prepare()
self.targets[0].build()
@@ -68,7 +71,7 @@ class Task:
def get_target(self):
"""Fetch the target being built or updated by this task.
"""
- return self.targets[0]
+ return self.node
def set_tstates(self, state):
"""Set all of the target nodes's states."""
@@ -83,21 +86,14 @@ class Task:
things. Most importantly, this calls back to the
Taskmaster to put any node tasks waiting on this one
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:
t.store_sigs()
- parents = {}
- for p in reduce(lambda x, y: x + y.get_parents(), self.targets, []):
- parents[p] = 1
- ready = filter(lambda x, s=self.scanner:
- (x.get_state() == SCons.Node.pending
- and x.children_are_executed(s)),
- parents.keys())
- tasks = {}
- for t in map(lambda r: r.task, ready):
- tasks[t] = 1
- self.tm.pending_to_ready(tasks.keys())
+ t.built()
+
+ self.tm.executed(self.node)
def failed(self):
"""Default action when a task fails: stop the build."""
@@ -114,20 +110,15 @@ class Task:
This sets failure status on the target nodes and all of
their dependent parent nodes.
"""
- nodes = {}
for t in self.targets:
def get_parents(node, parent): return node.get_parents()
- def set_nodes(node, parent, nodes=nodes): nodes[node] = 1
- walker = SCons.Node.Walker(t, get_parents, eval_func=set_nodes)
+ def set_state(node, parent): node.set_state(SCons.Node.failed)
+ walker = SCons.Node.Walker(t, get_parents, eval_func=set_state)
n = walker.next()
while n:
n = walker.next()
- pending = filter(lambda x: x.get_state() == SCons.Node.pending,
- nodes.keys())
- tasks = {}
- for t in map(lambda r: r.task, pending):
- tasks[t] = 1
- self.tm.pending_remove(tasks.keys())
+
+ self.tm.executed(self.node)
def make_ready(self):
"""Make a task ready for execution."""
@@ -138,9 +129,6 @@ class Task:
if not self.tm.calc.current(t, bsig):
state = SCons.Node.executing
self.set_tstates(state)
- self.tm.add_ready(self)
-
-
class Calc:
def bsig(self, node):
@@ -156,8 +144,6 @@ class Calc:
"""
return 0
-
-
class Taskmaster:
"""A generic Taskmaster for handling a bunch of targets.
@@ -166,118 +152,113 @@ class Taskmaster:
"""
def __init__(self, targets=[], tasker=Task, calc=Calc()):
+ self.targets = targets # top level targets
+ self.candidates = targets[:] # nodes that might be ready to be executed
+ self.candidates.reverse()
+ self.executing = [] # nodes that are currently executing
+ self.pending = [] # nodes that depend on a currently executing node
+ self.tasker = tasker
+ self.ready = None # the next task that is ready to be executed
+ self.calc = calc
+
+ def _find_next_ready_node(self):
+ """Find the next node that is ready to be built"""
+
+ if self.ready:
+ return
- 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.
- return []
- # Scan the file before fetching its children().
- if parent:
- scanner = parent.src_scanner_get(node.scanner_key())
- else:
- scanner = None
- return filter(lambda x: x.get_state() != SCons.Node.up_to_date,
- node.children(scanner))
+ 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()
+ continue
+
+ # keep track of which nodes are in the execution stack:
+ node.set_state(SCons.Node.stack)
- def cycle_error(node, stack):
- if node.builder:
- nodes = stack + [node]
+ children = node.children()
+
+ # detect dependency cycles:
+ def in_stack(node): return node.get_state() == SCons.Node.stack
+ cycle = filter(in_stack, children)
+ if cycle:
+ nodes = filter(in_stack, self.candidates) + cycle
nodes.reverse()
desc = "Dependency cycle: " + string.join(map(str, nodes), " -> ")
raise SCons.Errors.UserError, desc
- 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 ]
- if parent:
- scanner = parent.src_scanner_get(node.scanner_key())
+ for child in children:
+ if not child.builder:
+ # set the signature for non-derived files
+ # here so they don't get recalculated over
+ # and over again:
+ child.set_csig(self.calc.csig(child))
+
+ # Add non-derived files that have not been built
+ # to the candidates list:
+ def derived(node):
+ return node.builder and node.get_state() == None
+ derived = filter(derived, children)
+ if derived:
+ derived.reverse()
+ self.candidates.extend(derived)
+ 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)
+ node.set_state(SCons.Node.pending)
+ self.candidates.pop()
+ continue
else:
- scanner = None
- task = self.tasker(self, tlist, self.walkers[0].is_done(), scanner)
- if not tlist[0].children_are_executed(scanner):
- 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
- self.ready = []
- self.pending = 0
-
- self._find_next_ready_node()
+ self.candidates.pop()
+ self.ready = node
+ break
def next_task(self):
"""Return the next task to be executed."""
- if self.ready:
- task = self.ready.pop()
- if not self.ready:
- self._find_next_ready_node()
- return task
- else:
- return None
+
+ self._find_next_ready_node()
- def _find_next_ready_node(self):
- """Find the next node that is ready to be built"""
- while self.walkers:
- n = self.walkers[0].next()
- if n == None:
- self.walkers.pop(0)
- continue
- if self.ready:
- return
+ node = self.ready
+
+ if node is None:
+ return None
+
+ self.executing.append(node)
+ try:
+ tlist = node.builder.targets(node)
+ except AttributeError:
+ tlist = [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()
+
return not self.ready and self.pending
def stop(self):
"""Stop the current build completely."""
- self.walkers = []
- self.pending = 0
- self.ready = []
+ self.candidates = []
+ self.ready = None
+ self.pending = []
- def add_ready(self, task):
- """Add a task to the ready queue.
- """
- self.ready.append(task)
-
- def pending_to_ready(self, tasks):
- """Move the specified tasks from the pending count
- to the 'ready' queue.
- """
- self.pending_remove(tasks)
- for t in tasks:
- t.make_ready()
-
- def pending_remove(self, tasks):
- """Remove tasks from the pending count.
+ def executed(self, node):
+ self.executing.remove(node)
- We assume that the caller has already confirmed that
- the nodes in this task are in pending state.
- """
- self.pending = self.pending - len(tasks)
+ # 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)
+ for node in self.pending:
+ node.set_state(None)
+ self.pending.reverse()
+ self.candidates.extend(self.pending)
+ self.pending = []
+
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index b6fa685..44b1e40 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -30,7 +30,7 @@ import SCons.Taskmaster
import SCons.Errors
-built = None
+built_text = None
executed = None
scan_called = 0
@@ -39,8 +39,8 @@ class Node:
self.name = name
self.kids = kids
self.scans = scans
- self.scanned = {}
- self.src_scanners = {}
+ self.scanned = 0
+ self.scanner = None
self.builder = Node.build
self.bsig = None
self.csig = None
@@ -51,32 +51,30 @@ class Node:
kid.parents.append(self)
def build(self):
- global built
- built = self.name + " built"
+ global built_text
+ built_text = self.name + " built"
+
+ def built(self):
+ global built_text
+ built_text = built_text + " really"
def prepare(self):
pass
- def children(self, scanner):
- if not self.scanned.get(scanner, None):
- self.scan(scanner)
- self.scanned[scanner] = 1
+ def children(self):
+ if not self.scanned:
+ self.scan()
+ self.scanned = 1
return self.kids
- def scan(self, scanner):
- global scan_called
- scan_called = scan_called + 1
+ def scan(self):
+ global scan_called
+ scan_called = scan_called + 1
self.kids = self.kids + self.scans
for scan in self.scans:
scan.parents.append(self)
self.scans = []
- def src_scanner_set(self, key, scanner):
- self.src_scanners[key] = scanner
-
- def src_scanner_get(self, key):
- return self.src_scanners.get(key, None)
-
def scanner_key(self):
return self.name
@@ -98,12 +96,13 @@ class Node:
def store_sigs(self):
pass
- def children_are_executed(self, scanner):
- return reduce(lambda x,y: ((y.get_state() == SCons.Node.executed
- or y.get_state() == SCons.Node.up_to_date)
- and x),
- self.children(scanner),
- 1)
+
+ def depends_on(self, nodes):
+ for node in nodes:
+ if node in self.kids:
+ return 1
+ return 0
+
def __str__(self):
return self.name
@@ -111,14 +110,14 @@ class Node:
class TaskmasterTestCase(unittest.TestCase):
def test_next_task(self):
- """Test fetching the next task
- """
- global built
+ """Test fetching the next task
+ """
+ global built_text
- n1 = Node("n1")
+ n1 = Node("n1")
tm = SCons.Taskmaster.Taskmaster([n1, n1])
t = tm.next_task()
- t.executed()
+ t.execute()
t = tm.next_task()
assert t == None
@@ -126,26 +125,26 @@ class TaskmasterTestCase(unittest.TestCase):
n2 = Node("n2")
n3 = Node("n3", [n1, n2])
- tm = SCons.Taskmaster.Taskmaster([n3])
+ tm = SCons.Taskmaster.Taskmaster([n3])
t = tm.next_task()
t.execute()
- assert built == "n1 built"
+ assert built_text == "n1 built", built_text
t.executed()
t = tm.next_task()
t.execute()
- assert built == "n2 built"
+ assert built_text == "n2 built", built_text
t.executed()
t = tm.next_task()
t.execute()
- assert built == "n3 built"
+ assert built_text == "n3 built", built_text
t.executed()
assert tm.next_task() == None
- built = "up to date: "
+ built_text = "up to date: "
top_node = n3
class MyCalc(SCons.Taskmaster.Calc):
@@ -154,12 +153,12 @@ class TaskmasterTestCase(unittest.TestCase):
class MyTask(SCons.Taskmaster.Task):
def execute(self):
- global built
+ global built_text
if self.targets[0].get_state() == SCons.Node.up_to_date:
if self.top:
- built = self.targets[0].name + " up-to-date top"
+ built_text = self.targets[0].name + " up-to-date top"
else:
- built = self.targets[0].name + " up-to-date"
+ built_text = self.targets[0].name + " up-to-date"
else:
self.targets[0].build()
@@ -171,24 +170,24 @@ class TaskmasterTestCase(unittest.TestCase):
t = tm.next_task()
t.execute()
- assert built == "n1 up-to-date"
+ assert built_text == "n1 up-to-date", built_text
t.executed()
t = tm.next_task()
t.execute()
- assert built == "n2 up-to-date"
+ assert built_text == "n2 up-to-date", built_text
t.executed()
t = tm.next_task()
t.execute()
- assert built == "n3 up-to-date top"
+ assert built_text == "n3 up-to-date top", built_text
t.executed()
- assert tm.next_task() == None
+ assert tm.next_task() == None
n1 = Node("n1")
- n2 = Node("n2")
+ n2 = Node("n2")
n3 = Node("n3", [n1, n2])
n4 = Node("n4")
n5 = Node("n5", [n3, n4])
@@ -221,7 +220,7 @@ class TaskmasterTestCase(unittest.TestCase):
t3.executed()
assert not tm.is_blocked()
t5 = tm.next_task()
- assert t5.get_target() == n5
+ assert t5.get_target() == n5, t5.get_target()
assert not tm.is_blocked()
assert tm.next_task() == None
@@ -261,35 +260,35 @@ class TaskmasterTestCase(unittest.TestCase):
t.executed()
assert tm.next_task() == None
- n1 = Node("n1")
- n2 = Node("n2")
- n3 = Node("n3", [n1, n2])
- n4 = Node("n4", [n3])
- n5 = Node("n5", [n3])
- global scan_called
- scan_called = 0
- tm = SCons.Taskmaster.Taskmaster([n4])
- t = tm.next_task()
+ n1 = Node("n1")
+ n2 = Node("n2")
+ n3 = Node("n3", [n1, n2])
+ n4 = Node("n4", [n3])
+ n5 = Node("n5", [n3])
+ global scan_called
+ scan_called = 0
+ tm = SCons.Taskmaster.Taskmaster([n4])
+ t = tm.next_task()
assert t.get_target() == n1
- t.executed()
- t = tm.next_task()
+ t.executed()
+ t = tm.next_task()
assert t.get_target() == n2
- t.executed()
- t = tm.next_task()
+ t.executed()
+ t = tm.next_task()
assert t.get_target() == n3
- t.executed()
- t = tm.next_task()
+ t.executed()
+ t = tm.next_task()
assert t.get_target() == n4
- t.executed()
- assert tm.next_task() == None
- assert scan_called == 4, scan_called
+ t.executed()
+ assert tm.next_task() == None
+ assert scan_called == 4, scan_called
- tm = SCons.Taskmaster.Taskmaster([n5])
- t = tm.next_task()
+ tm = SCons.Taskmaster.Taskmaster([n5])
+ t = tm.next_task()
assert t.get_target() == n5, t.get_target()
- t.executed()
- assert tm.next_task() == None
- assert scan_called == 5, scan_called
+ t.executed()
+ assert tm.next_task() == None
+ assert scan_called == 5, scan_called
def test_cycle_detection(self):
n1 = Node("n1")
@@ -302,30 +301,30 @@ class TaskmasterTestCase(unittest.TestCase):
tm = SCons.Taskmaster.Taskmaster([n3])
t = tm.next_task()
except SCons.Errors.UserError, e:
- assert str(e) == "Dependency cycle: n3 -> n1 -> n2 -> n3"
+ assert str(e) == "Dependency cycle: n3 -> n1 -> n2 -> n3", str(e)
else:
assert 0
def test_is_blocked(self):
"""Test whether a task is blocked
- Both default and overridden in a subclass.
- """
- tm = SCons.Taskmaster.Taskmaster()
- assert not tm.is_blocked()
+ Both default and overridden in a subclass.
+ """
+ tm = SCons.Taskmaster.Taskmaster()
+ assert not tm.is_blocked()
- class MyTM(SCons.Taskmaster.Taskmaster):
- def is_blocked(self):
- return 1
- tm = MyTM()
- assert tm.is_blocked() == 1
+ class MyTM(SCons.Taskmaster.Taskmaster):
+ def is_blocked(self):
+ return 1
+ tm = MyTM()
+ assert tm.is_blocked() == 1
def test_stop(self):
"""Test the stop() method
Both default and overridden in a subclass.
"""
- global built
+ global built_text
n1 = Node("n1")
n2 = Node("n2")
@@ -334,48 +333,33 @@ class TaskmasterTestCase(unittest.TestCase):
tm = SCons.Taskmaster.Taskmaster([n3])
t = tm.next_task()
t.execute()
- assert built == "n1 built"
+ assert built_text == "n1 built", built_text
t.executed()
+ assert built_text == "n1 built really", built_text
tm.stop()
assert tm.next_task() is None
class MyTM(SCons.Taskmaster.Taskmaster):
def stop(self):
- global built
- built = "MyTM.stop()"
+ global built_text
+ built_text = "MyTM.stop()"
SCons.Taskmaster.Taskmaster.stop(self)
n1 = Node("n1")
n2 = Node("n2")
n3 = Node("n3", [n1, n2])
- built = None
+ built_text = None
tm = MyTM([n3])
tm.next_task().execute()
- assert built == "n1 built"
+ assert built_text == "n1 built"
tm.stop()
- assert built == "MyTM.stop()"
+ assert built_text == "MyTM.stop()"
assert tm.next_task() is None
- def test_add_ready(self):
- """Test adding a task to the ready queue"""
- class MyTask:
- def __init__(self, tm, tlist, top, scanner):
- pass
- def make_ready(self):
- pass
- n1 = Node("n1")
- tm = SCons.Taskmaster.Taskmaster([n1], tasker = MyTask)
- task = MyTask(tm, [], 0, None)
- tm.add_ready(task)
- assert tm.ready == [ task ], tm.ready
-
- def test_pending_to_ready(self):
- pass
-
- def test_pending_remove(self):
+ def test_executed(self):
pass
@@ -383,4 +367,4 @@ class TaskmasterTestCase(unittest.TestCase):
if __name__ == "__main__":
suite = unittest.makeSuite(TaskmasterTestCase, 'test_')
if not unittest.TextTestRunner().run(suite).wasSuccessful():
- sys.exit(1)
+ sys.exit(1)