summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-07-03 15:23:57 (GMT)
committerSteven Knight <knight@baldmt.com>2002-07-03 15:23:57 (GMT)
commit397ce8d2a90723d2e47fd913d8246a77c2f30866 (patch)
treef0d6be3436faecf7960d412627525a45237d0cee /src/engine/SCons
parentd9be780213e1be39a19f19d9845629df8860a098 (diff)
downloadSCons-397ce8d2a90723d2e47fd913d8246a77c2f30866.zip
SCons-397ce8d2a90723d2e47fd913d8246a77c2f30866.tar.gz
SCons-397ce8d2a90723d2e47fd913d8246a77c2f30866.tar.bz2
Deduce the target if it's not supplied.
Diffstat (limited to 'src/engine/SCons')
-rw-r--r--src/engine/SCons/Builder.py31
-rw-r--r--src/engine/SCons/BuilderTests.py73
-rw-r--r--src/engine/SCons/Environment.py24
-rw-r--r--src/engine/SCons/EnvironmentTests.py53
4 files changed, 159 insertions, 22 deletions
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index 0b54303..c4e8643 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -56,6 +56,11 @@ import SCons.Node.FS
import SCons.Util
import SCons.Warnings
+class _Null:
+ pass
+
+_null = _Null
+
class DictCmdGenerator:
"""This is a callable class that can be used as a
command generator function. It holds on to a dictionary
@@ -142,6 +147,8 @@ def _init_nodes(builder, env, args, tlist, slist):
s.source_scanner = scanner
for t in tlist:
+ if t.side_effect:
+ raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t)
if t.builder is not None:
if t.env != env:
raise UserError, "Two different environments were specified for the same target: %s"%str(t)
@@ -267,11 +274,11 @@ class BuilderBase:
path, fn = os.path.split(os.path.normpath(f))
f = os.path.join(path, pre + fn)
# Only append a suffix if the file does not have one.
- if suf and not os.path.splitext(f)[1]:
- if f[-len(suf):] != suf:
- f = f + suf
- ret.append(f)
- return ret
+ if suf and not os.path.splitext(f)[1]:
+ if f[-len(suf):] != suf:
+ f = f + suf
+ ret.append(f)
+ return ret
pre = self.get_prefix(env)
suf = self.get_suffix(env)
@@ -290,14 +297,20 @@ class BuilderBase:
emit_args.update(args)
target, source = apply(self.emitter, (), emit_args)
- tlist = SCons.Node.arg2nodes(adjustixes(target, pre, suf),
- self.target_factory)
slist = SCons.Node.arg2nodes(adjustixes(source, None, src_suf),
self.source_factory)
+ if target is None:
+ target = map(lambda x, s=suf: os.path.splitext(str(x))[0] + s,
+ slist)
+ tlist = SCons.Node.arg2nodes(adjustixes(target, pre, suf),
+ self.target_factory)
return tlist, slist
- def __call__(self, env, target = None, source = None, **kw):
+ def __call__(self, env, target = None, source = _null, **kw):
+ if source is _null:
+ source = target
+ target = None
tlist, slist = self._create_nodes(env, kw, target, source)
if len(tlist) == 1:
@@ -456,7 +469,7 @@ class MultiStepBuilder(BuilderBase):
src_bld = sdict[ext]
dictArgs = copy.copy(kw)
- dictArgs['target'] = [ path + src_bld.get_suffix(env) ]
+ dictArgs['target'] = [path]
dictArgs['source'] = snode
dictArgs['env'] = env
tgt = apply(src_bld, (), dictArgs)
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index c0ed108..8451d99 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -107,6 +107,7 @@ class BuilderTestCase(unittest.TestCase):
self.name = name
self.sources = []
self.builder = None
+ self.side_effect = 0
def __str__(self):
return self.name
def builder_set(self, builder):
@@ -474,7 +475,7 @@ class BuilderTestCase(unittest.TestCase):
"Source has unexpected name: %s" % tgt.sources[0].path
tgt = b1(env, target = 'tgt3', source = 'src3a src3b')
- assert len(tgt.sources) == 1
+ assert len(tgt.sources) == 1
assert tgt.sources[0].path == 'src3a src3b.c', \
"Unexpected tgt.sources[0] name: %s" % tgt.sources[0].path
@@ -578,9 +579,9 @@ class BuilderTestCase(unittest.TestCase):
action='bar',
src_builder = builder1,
src_suffix = '.foo')
- tgt = builder2(env, target='baz', source=['test.bleh.bar', 'test2.foo', 'test3.txt'])
- assert str(tgt.sources[0]) == 'test.bleh.foo', str(tgt.sources[0])
- assert str(tgt.sources[0].sources[0]) == 'test.bleh.bar', \
+ tgt = builder2(env, target='baz', source=['test.bar', 'test2.foo', 'test3.txt'])
+ assert str(tgt.sources[0]) == 'test.foo', str(tgt.sources[0])
+ assert str(tgt.sources[0].sources[0]) == 'test.bar', \
str(tgt.sources[0].sources[0])
assert str(tgt.sources[1]) == 'test2.foo', str(tgt.sources[1])
assert str(tgt.sources[2]) == 'test3.txt', str(tgt.sources[2])
@@ -654,7 +655,7 @@ class BuilderTestCase(unittest.TestCase):
assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder)
flag = 0
- tgt = builder(env, target='t5', source=[ 'test5a.foo', 'test5b.inb' ])
+ tgt = builder(env, target='t5', source='test5a.foo test5b.inb')
try:
tgt.build()
except SCons.Errors.UserError:
@@ -662,7 +663,7 @@ class BuilderTestCase(unittest.TestCase):
assert flag, "UserError should be thrown when we build targets with files of different suffixes."
flag = 0
- tgt = builder(env, target='t6', source=[ 'test6a.bar', 'test6b.ina' ])
+ tgt = builder(env, target='t6', source='test6a.bar test6b.ina')
try:
tgt.build()
except SCons.Errors.UserError:
@@ -670,7 +671,7 @@ class BuilderTestCase(unittest.TestCase):
assert flag, "UserError should be thrown when we build targets with files of different suffixes."
flag = 0
- tgt = builder(env, target='t4', source=[ 'test4a.ina', 'test4b.inb' ])
+ tgt = builder(env, target='t4', source='test4a.ina test4b.inb')
try:
tgt.build()
except SCons.Errors.UserError:
@@ -775,6 +776,64 @@ class BuilderTestCase(unittest.TestCase):
emitter="$FOO")
assert builder2 == builder2a, repr(builder2.__dict__) + "\n" + repr(builder2a.__dict__)
+ def test_no_target(self):
+ """Test deducing the target from the source."""
+
+ b = SCons.Builder.Builder(action='foo', suffix='.o')
+
+ tgt = b(env, 'aaa')
+ assert str(tgt) == 'aaa.o', str(tgt)
+ assert len(tgt.sources) == 1, map(str, tgt.sources)
+ assert str(tgt.sources[0]) == 'aaa', map(str, tgt.sources)
+
+ tgt = b(env, 'bbb.c')
+ assert str(tgt) == 'bbb.o', str(tgt)
+ assert len(tgt.sources) == 1, map(str, tgt.sources)
+ assert str(tgt.sources[0]) == 'bbb.c', map(str, tgt.sources)
+
+ tgt = b(env, 'ccc.x.c')
+ assert str(tgt) == 'ccc.x.o', str(tgt)
+ assert len(tgt.sources) == 1, map(str, tgt.sources)
+ assert str(tgt.sources[0]) == 'ccc.x.c', map(str, tgt.sources)
+
+ tgt = b(env, ['d0.c', 'd1.c'])
+ assert len(tgt) == 2, map(str, tgt)
+ assert str(tgt[0]) == 'd0.o', map(str, tgt)
+ assert str(tgt[1]) == 'd1.o', map(str, tgt)
+ assert len(tgt[0].sources) == 2, map(str, tgt[0].sources)
+ assert str(tgt[0].sources[0]) == 'd0.c', map(str, tgt[0].sources)
+ assert str(tgt[0].sources[1]) == 'd1.c', map(str, tgt[0].sources)
+ assert len(tgt[1].sources) == 2, map(str, tgt[1].sources)
+ assert str(tgt[1].sources[0]) == 'd0.c', map(str, tgt[1].sources)
+ assert str(tgt[1].sources[1]) == 'd1.c', map(str, tgt[1].sources)
+
+ tgt = b(env, source='eee')
+ assert str(tgt) == 'eee.o', str(tgt)
+ assert len(tgt.sources) == 1, map(str, tgt.sources)
+ assert str(tgt.sources[0]) == 'eee', map(str, tgt.sources)
+
+ tgt = b(env, source='fff.c')
+ assert str(tgt) == 'fff.o', str(tgt)
+ assert len(tgt.sources) == 1, map(str, tgt.sources)
+ assert str(tgt.sources[0]) == 'fff.c', map(str, tgt.sources)
+
+ tgt = b(env, source='ggg.x.c')
+ assert str(tgt) == 'ggg.x.o', str(tgt)
+ assert len(tgt.sources) == 1, map(str, tgt.sources)
+ assert str(tgt.sources[0]) == 'ggg.x.c', map(str, tgt.sources)
+
+ tgt = b(env, source=['h0.c', 'h1.c'])
+ assert len(tgt) == 2, map(str, tgt)
+ assert str(tgt[0]) == 'h0.o', map(str, tgt)
+ assert str(tgt[1]) == 'h1.o', map(str, tgt)
+ assert len(tgt[0].sources) == 2, map(str, tgt[0].sources)
+ assert str(tgt[0].sources[0]) == 'h0.c', map(str, tgt[0].sources)
+ assert str(tgt[0].sources[1]) == 'h1.c', map(str, tgt[0].sources)
+ assert len(tgt[1].sources) == 2, map(str, tgt[1].sources)
+ assert str(tgt[1].sources[0]) == 'h0.c', map(str, tgt[1].sources)
+ assert str(tgt[1].sources[1]) == 'h1.c', map(str, tgt[1].sources)
+
+
if __name__ == "__main__":
suite = unittest.makeSuite(BuilderTestCase, 'test_')
if not unittest.TextTestRunner().run(suite).wasSuccessful():
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index 30e0a53..42aa326 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -212,9 +212,8 @@ class Environment:
self.env = env
self.builder = builder
- def __call__(self, target = None, source = None, **kw):
- return apply(self.builder, (self.env, target, source),
- kw)
+ def __call__(self, *args, **kw):
+ return apply(self.builder, (self.env,) + args, kw)
# This allows a Builder to be executed directly
# through the Environment to which it's attached.
@@ -356,6 +355,25 @@ class Environment:
if len(ret) == 1:
ret = ret[0]
return ret
+
+ def SideEffect(self, side_effect, target):
+ """Tell scons that side_effects are built as side
+ effects of building targets."""
+ side_effects = SCons.Node.arg2nodes(side_effect, self.fs.File)
+ targets = SCons.Node.arg2nodes(target, self.fs.File)
+
+ for side_effect in side_effects:
+ if side_effect.builder is not None:
+ raise UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
+ side_effect.add_source(targets)
+ side_effect.side_effect = 1
+ self.Precious(side_effect)
+ for target in targets:
+ target.side_effects.append(side_effect)
+ if len(side_effects) == 1:
+ return side_effects[0]
+ else:
+ return side_effects
def subst(self, string):
"""Recursively interpolates construction variables from the
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 2e7003a..75e5e83 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -52,6 +52,7 @@ def diff_env(env1, env2):
s2 = s2 + "}\n"
return s1 + s2
+called_it = {}
built_it = {}
class Builder:
@@ -59,10 +60,15 @@ class Builder:
a target is simply setting a value in the dictionary.
"""
def __init__(self, name = None):
- self.name = name
+ self.name = name
+
+ def __call__(self, env, **kw):
+ global called_it
+ called_it.update(kw)
def execute(self, target = None, **kw):
- built_it[target] = 1
+ global built_it
+ built_it[target] = 1
@@ -86,7 +92,36 @@ class Scanner:
class EnvironmentTestCase(unittest.TestCase):
- def test_Builders(self):
+ def test_Builder_calls(self):
+ """Test Builder calls through different environments
+ """
+ global called_it
+
+ b1 = Builder()
+ b2 = Builder()
+
+ env = Environment()
+ env.Replace(BUILDERS = { 'builder1' : b1,
+ 'builder2' : b2 })
+ called_it = {}
+ env.builder1(target = 'out1')
+ assert called_it['target'] == 'out1', called_it
+ assert not called_it.has_key('source')
+
+ called_it = {}
+ env.builder2(target = 'out2', xyzzy = 1)
+ assert called_it['target'] == 'out2', called_it
+ assert called_it['xyzzy'] == 1, called_it
+ assert not called_it.has_key('source')
+
+ called_it = {}
+ env.builder1(foo = 'bar')
+ assert called_it['foo'] == 'bar', called_it
+ assert not called_it.has_key('target')
+ assert not called_it.has_key('source')
+
+
+ def test_Builder_execs(self):
"""Test Builder execution through different environments
One environment is initialized with a single
@@ -372,6 +407,18 @@ class EnvironmentTestCase(unittest.TestCase):
assert 'foo1.in' in map(lambda x: x.path, t.sources)
assert 'foo2.in' in map(lambda x: x.path, t.sources)
+ def test_SideEffect(self):
+ """Test the SideEffect() method"""
+ env = Environment()
+ foo = env.Object('foo.obj', 'foo.cpp')
+ bar = env.Object('bar.obj', 'bar.cpp')
+ s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])
+ assert s.side_effect
+ assert foo.side_effects == [s]
+ assert bar.side_effects == [s]
+ assert s.depends_on([bar])
+ assert s.depends_on([foo])
+
def test_subst(self):
"""Test substituting construction variables within strings