diff options
| author | Steven Knight <knight@baldmt.com> | 2002-07-03 15:23:57 (GMT) |
|---|---|---|
| committer | Steven Knight <knight@baldmt.com> | 2002-07-03 15:23:57 (GMT) |
| commit | 397ce8d2a90723d2e47fd913d8246a77c2f30866 (patch) | |
| tree | f0d6be3436faecf7960d412627525a45237d0cee /src/engine/SCons | |
| parent | d9be780213e1be39a19f19d9845629df8860a098 (diff) | |
| download | SCons-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.py | 31 | ||||
| -rw-r--r-- | src/engine/SCons/BuilderTests.py | 73 | ||||
| -rw-r--r-- | src/engine/SCons/Environment.py | 24 | ||||
| -rw-r--r-- | src/engine/SCons/EnvironmentTests.py | 53 |
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 |
