diff options
author | Steven Knight <knight@baldmt.com> | 2001-10-11 18:38:29 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2001-10-11 18:38:29 (GMT) |
commit | 580b07ed247ab0de0ea96093fc2c4baa28c35c65 (patch) | |
tree | 400146b8838e2f89218a6ec54f27d47022c2264d | |
parent | 385aabf686d687432fb81fa2e68b77e3f11f06f8 (diff) | |
download | SCons-580b07ed247ab0de0ea96093fc2c4baa28c35c65.zip SCons-580b07ed247ab0de0ea96093fc2c4baa28c35c65.tar.gz SCons-580b07ed247ab0de0ea96093fc2c4baa28c35c65.tar.bz2 |
Add the Library() method.
-rw-r--r-- | src/engine/SCons/Builder.py | 99 | ||||
-rw-r--r-- | src/engine/SCons/BuilderTests.py | 32 | ||||
-rw-r--r-- | src/engine/SCons/Defaults.py | 20 | ||||
-rw-r--r-- | src/engine/SCons/Util.py | 4 | ||||
-rw-r--r-- | src/engine/SCons/UtilTests.py | 4 | ||||
-rw-r--r-- | src/script/scons.py | 2 | ||||
-rw-r--r-- | test/Library.py | 15 | ||||
-rw-r--r-- | test/Program-j.py | 2 |
8 files changed, 156 insertions, 22 deletions
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 367c2ed..b009fe0 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -63,8 +63,8 @@ class Builder: return cmp(self.__dict__, other.__dict__) def __call__(self, env, target = None, source = None): - tlist = SCons.Util.scons_str2nodes(target) - slist = SCons.Util.scons_str2nodes(source) + tlist = SCons.Util.scons_str2nodes(target, self.node_factory) + slist = SCons.Util.scons_str2nodes(source, self.node_factory) for t in tlist: t.builder_set(self) t.env_set(env) @@ -80,7 +80,102 @@ class Builder: """ return apply(self.action.execute, (), kw) +class BuilderProxy: + """This base class serves as a proxy to a builder object, + exposing the same interface, but just forwarding calls to + the underlying object.""" + def __init__(self, builder): + self.subject = builder + def __call__(self, env, target = None, source = None): + return self.subject.__call__(env, target, source) + + def execute(self, **kw): + return apply(self.subject.execute, (), kw) + + def __cmp__(self, other): + return cmp(self.__dict__, other.__dict__) + + def __getattr__(self, name): + assert 'subject' in self.__dict__.keys(), \ + "You must call __init__() on the BuilderProxy base." + return getattr(self.subject, name) + +class TargetNamingBuilder(BuilderProxy): + """This is a simple Builder Proxy that decorates the names + of a Builder's targets prior to passing them to the underlying + Builder. You can use this to simplify the syntax of a target + file. For instance, you might want to call a Library builder + with a target of "foo" and expect to get "libfoo.a" back.""" + + def __init__(self, builder, prefix='', suffix=''): + """ + builder - The underlying Builder object + + prefix - text to prepend to target names (may contain + environment variables) + + suffix - text to append to target names (may contain + environment variables) + """ + BuilderProxy.__init__(self, builder) + self.prefix=prefix + self.suffix=suffix + + def __call__(self, env, target = None, source = None): + tlist = SCons.Util.scons_str2nodes(target, + self.subject.node_factory) + tlist_decorated = [] + for tnode in tlist: + path, fn = os.path.split(tnode.path) + tlist_decorated.append(self.subject. + node_factory(os.path.join(path, + env.subst(self.prefix) + + fn + + env.subst(self.suffix)))) + return self.subject.__call__(env, target=tlist_decorated, source=source) + +class MultiStepBuilder(Builder): + """This is a builder subclass that can build targets in + multiple steps according to the suffixes of the source files. + Given one or more "subordinate" builders in its constructor, + this class will apply those builders to any files matching + the builder's input_suffix, using a file of the same name + as the source, but with input_suffix changed to output_suffix. + The targets of these builders then become sources for this + builder. + """ + def __init__(self, name = None, + action = None, + input_suffix = None, + output_suffix = None, + node_factory = SCons.Node.FS.default_fs.File, + builders = []): + Builder.__init__(self, name, action, input_suffix, output_suffix, + node_factory) + self.builder_dict = {} + for bld in builders: + if bld.insuffix and bld.outsuffix: + self.builder_dict[bld.insuffix] = bld + + def __call__(self, env, target = None, source = None): + slist = SCons.Util.scons_str2nodes(source, self.node_factory) + final_sources = [] + for snode in slist: + path, ext = os.path.splitext(snode.path) + if self.builder_dict.has_key(ext): + bld = self.builder_dict[ext] + tgt = bld(env, + target=[ path+bld.outsuffix, ], + source=snode) + if not type(tgt) is types.ListType: + final_sources.append(tgt) + else: + final_sources.extend(tgt) + else: + final_sources.append(snode) + return Builder.__call__(self, env, target=target, + source=final_sources) print_actions = 1; execute_actions = 1; diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index b801b4a..8554d67 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -49,15 +49,16 @@ sys.exit(0) act_py = test.workpath('act.py') outfile = test.workpath('outfile') +class Environment: + def subst(self, s): + return s +env = Environment() class BuilderTestCase(unittest.TestCase): def test__call__(self): """Test calling a builder to establish source dependencies """ - class Environment: - pass - env = Environment() class Node: def __init__(self, name): self.name = name @@ -197,6 +198,31 @@ class BuilderTestCase(unittest.TestCase): builder = SCons.Builder.Builder(input_suffix = 'o') assert builder.insuffix == '.o' + def test_TargetNamingBuilder(self): + """Testing the TargetNamingBuilder class.""" + builder = SCons.Builder.Builder(action='foo') + proxy = SCons.Builder.TargetNamingBuilder(builder=builder, + prefix='foo', + suffix='bar') + tgt = proxy(env, target='baz', source='bleh') + assert tgt.path == 'foobazbar', \ + "Target has unexpected name: %s" % tgt[0].path + assert tgt.builder == builder + + def test_MultiStepBuilder(self): + """Testing MultiStepBuilder class.""" + builder1 = SCons.Builder.Builder(action='foo', + input_suffix='.bar', + output_suffix='.foo') + builder2 = SCons.Builder.MultiStepBuilder(action='foo', + builders = [ builder1 ]) + tgt = builder2(env, target='baz', source='test.bar test2.foo test3.txt') + flag = 0 + for snode in tgt.sources: + if snode.path == 'test.foo': + flag = 1 + assert snode.sources[0].path == 'test.bar' + assert flag if __name__ == "__main__": diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index 876aa89..3e1c8a8 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -38,10 +38,20 @@ import SCons.Builder Object = SCons.Builder.Builder(name = 'Object', - action = 'cc -c -o %(target)s %(source)s') -Program = SCons.Builder.Builder(name = 'Program', - action = 'cc -o %(target)s %(source)s') - -Builders = [Object, Program] + action = 'cc -c -o %(target)s %(source)s', + input_suffix='.c', + output_suffix='.o') +Program = SCons.Builder.MultiStepBuilder(name = 'Program', + action = 'cc -o %(target)s %(source)s', + builders = [ Object ]) +Library = SCons.Builder.MultiStepBuilder(name = 'Library', + action = 'ar r %(target)s %(source)s\nranlib %(target)s', + builders = [ Object ]) + +Library = SCons.Builder.TargetNamingBuilder(builder = Library, + prefix='lib', + suffix='.a') + +Builders = [Object, Program, Library] ENV = { 'PATH' : '/usr/local/bin:/bin:/usr/bin' } diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index 7ce7056..61b7417 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -34,7 +34,7 @@ import types import string import SCons.Node.FS -def scons_str2nodes(arg, fs=SCons.Node.FS.default_fs): +def scons_str2nodes(arg, node_factory=SCons.Node.FS.default_fs.File): """This function converts a string or list into a list of Node instances. It follows the rules outlined in the SCons design document by accepting any of the following inputs: @@ -54,7 +54,7 @@ def scons_str2nodes(arg, fs=SCons.Node.FS.default_fs): nodes = [] for v in narg: if type(v) is types.StringType: - nodes.append(fs.File(v)) + nodes.append(node_factory(v)) # Do we enforce the following restriction? Maybe, but it # also restricts what we can do for allowing people to # use the engine with alternate Node implementations... diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index 698dfbf..135a82c 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -29,7 +29,6 @@ import SCons.Node import SCons.Node.FS from SCons.Util import scons_str2nodes - class UtilTestCase(unittest.TestCase): def test_str2nodes(self): """Test the str2nodes function.""" @@ -40,7 +39,7 @@ class UtilTestCase(unittest.TestCase): assert nodes[0].path == "Util.py" assert nodes[1].path == "UtilTests.py" - nodes = scons_str2nodes("Util.py UtilTests.py", SCons.Node.FS.FS()) + nodes = scons_str2nodes("Util.py UtilTests.py", SCons.Node.FS.FS().File) assert len(nodes) == 2 assert isinstance(nodes[0], SCons.Node.FS.File) assert isinstance(nodes[1], SCons.Node.FS.File) @@ -70,7 +69,6 @@ class UtilTestCase(unittest.TestCase): pass node = scons_str2nodes(OtherNode()) - if __name__ == "__main__": suite = unittest.makeSuite(UtilTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful(): diff --git a/src/script/scons.py b/src/script/scons.py index 65b9495..1a67e51 100644 --- a/src/script/scons.py +++ b/src/script/scons.py @@ -47,7 +47,7 @@ from SCons.Taskmaster import Taskmaster # from SCons.Environment import Environment from SCons.Builder import Builder - +from SCons.Defaults import * # diff --git a/test/Library.py b/test/Library.py index 7a44d35..4941bbf 100644 --- a/test/Library.py +++ b/test/Library.py @@ -28,14 +28,16 @@ import TestSCons test = TestSCons.TestSCons() -test.pass_test() #XXX Short-circuit until this is implemented. - +#XXX Need to switch TestBld to Program() when LIBS variable is working. test.write('SConstruct', """ -env = Environment(LIBS = 'foo1 foo2 foo3') +TestBld = Builder(name='TestBld', + action='cc -o %(target)s %(source)s -L./ -lfoo1 -lfoo2 -lfoo3') +env = Environment(BUILDERS=[ TestBld, Library ]) env.Library(target = 'foo1', source = 'f1.c') env.Library(target = 'foo2', source = 'f2a.c f2b.c f2c.c') env.Library(target = 'foo3', source = ['f3a.c', 'f3b.c', 'f3c.c']) -env.Program(target = 'prog', source = 'prog.c') +env.TestBld(target = 'prog', source = 'prog.c') +env.Depends(target = 'prog', dependency = 'libfoo1.a libfoo2.a libfoo3.a') """) test.write('f1.c', """ @@ -113,12 +115,13 @@ main(int argc, char *argv[]) f3b(); f3c(); printf("prog.c\n"); + return 0; } """) -test.run(arguments = 'libfoo1.a libfoo2.a libfoo3.a') +test.run(arguments = 'libfoo1.a libfoo2.a libfoo3.a prog') test.run(program = test.workpath('prog'), - stdout = "f1.c\nf2a.c\nf2b.c\nf2c.c\nf3a.c\nf3b.c\nf3c.c\nprog.c\n") + stdout = "f1.c\nf2a.c\nf2b.c\nf2c.c\nf3a.c\nf3b.c\nf3c.c\nprog.c\n") test.pass_test() diff --git a/test/Program-j.py b/test/Program-j.py index 6b86127..95088a6 100644 --- a/test/Program-j.py +++ b/test/Program-j.py @@ -28,6 +28,8 @@ import TestSCons test = TestSCons.TestSCons() +test.pass_test() #XXX Short-circuit until this is supported. + test.write('SConstruct', """ env = Environment() env.Program(target = 'f1', source = 'f1.c') |