From: stevenknight Date: Fri, 12 Oct 2001 00:56:40 +0000 (+0000) Subject: Use the prefix and suffix arguments in the Builder base class. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=09bce3d0d9a3c752914bd751c2ad35ba7ff1ba36;p=scons.git Use the prefix and suffix arguments in the Builder base class. git-svn-id: http://scons.tigris.org/svn/scons/trunk@95 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/doc/design/engine.sgml b/doc/design/engine.sgml index 8c7babf7..d325c9a0 100644 --- a/doc/design/engine.sgml +++ b/doc/design/engine.sgml @@ -691,8 +691,8 @@ Feedback? WebPage = Builder(command = 'htmlgen $HTMLGENFLAGS $sources > $target', - input_suffix = '.in', - output_suffix = '.html') + suffix = '.html', + src_suffix = '.in') @@ -708,7 +708,7 @@ Feedback? return 1 OtherBuilder1 = Builder(function = update, - input_suffix = ['.in', '.input']) + src_suffix = ['.in', '.input']) @@ -723,8 +723,8 @@ Feedback? return 1 OtherBuilder2 = Builder(function = update_arg, - function_arg = 'xyzzy', - input_suffix = ['.in', '.input']) + function_arg = 'xyzzy', + src_suffix = ['.in', '.input']) @@ -748,8 +748,8 @@ Feedback? WebPage = Builder(command = 'htmlgen $HTMLGENFLAGS $sources > $target', - input_suffix = '.in', - output_suffix = '.html') + suffix = '.html', + src_suffix = '.in') env = Environment(BUILDERS = ['WebPage']) env.WebPage(target = 'foo.html', source = 'foo.in') # Builds 'bar.html' on UNIX, 'bar.htm' on Windows NT: @@ -765,12 +765,42 @@ Feedback? - A &Builder; object may optionally be initialized with a list of - the expected suffixes of input files for this object. It may also - be initialized with an output suffix for the files that this - &Builder; object builds. These arguments are used in automatic - dependency analysis and in generating output file names that don't - have suffixes supplied explicitly. + A &Builder; object may optionally be initialized with a list of: + + + + + + + + the prefix of the target file (e.g., 'lib' for libraries) + + + + + + + + the suffix of the target file (e.g., '.a' for libraries) + + + + + + + + the expected suffixes of the input files + (e.g., '.o' for object files) + + + + + + + + These arguments are used in automatic + dependency analysis and to generate output file names that don't + have suffixes supplied explicitly. @@ -788,7 +818,7 @@ Feedback? build = Builder(function = my_build) - build_out = build.Copy(output_suffix = '.out') + build_out = build.Copy(suffix = '.out') @@ -891,8 +921,8 @@ Feedback? Do we even need this anymore? Now that the individual builders -have specified input_suffix -and output_suffix values, +have specified suffix +and src_suffix values, all of the information we need to support the &MakeBuilder; builder is right there in the environment. I think this is a holdover from before I @@ -1237,7 +1267,7 @@ you set it up with another environment... If the &BUILDERMAP; proves unnecessary, we could/should get rid of this one, too, -by adding a parallel input_suffix +by adding a parallel src_suffix argument to the &Scanner; factory... Comments? diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 65d4d413..9e84a7d8 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -39,32 +39,60 @@ import types -class Builder: +def Builder(**kw): + """A factory for builder objects.""" + if kw.has_key('builders'): + return apply(MultiStepBuilder, (), kw) + else: + return apply(BuilderBase, (), kw) + + + +class BuilderBase: """Base class for Builders, objects that create output nodes (files) from input nodes (files). """ def __init__(self, name = None, action = None, - input_suffix = None, - output_suffix = None, + prefix = None, + suffix = None, + src_suffix = None, node_factory = SCons.Node.FS.default_fs.File): self.name = name self.action = Action(action) - self.insuffix = input_suffix - self.outsuffix = output_suffix + self.prefix = prefix + self.suffix = suffix + self.src_suffix = src_suffix self.node_factory = node_factory - if not self.insuffix is None and self.insuffix[0] != '.': - self.insuffix = '.' + self.insuffix - if not self.outsuffix is None and self.outsuffix[0] != '.': - self.outsuffix = '.' + self.outsuffix + if not self.suffix is None and self.suffix[0] != '.': + self.suffix = '.' + self.suffix + if not self.src_suffix is None and self.src_suffix[0] != '.': + self.src_suffix = '.' + self.src_suffix def __cmp__(self, other): return cmp(self.__dict__, other.__dict__) def __call__(self, env, target = None, source = None): - tlist = scons_str2nodes(target, self.node_factory) - slist = scons_str2nodes(source, self.node_factory) + def adjustixes(files, pre, suf): + ret = [] + if not type(files) is type([]): + files = [files] + for f in files: + if type(f) == type(""): + if pre and f[:len(pre)] != pre: + f = pre + f + if suf: + if f[-len(suf):] != suf: + f = f + suf + ret.append(f) + return ret + + + tlist = scons_str2nodes(adjustixes(target, self.prefix, self.suffix), + self.node_factory) + slist = scons_str2nodes(adjustixes(source, None, self.src_suffix), + self.node_factory) for t in tlist: t.builder_set(self) t.env_set(env) @@ -83,7 +111,8 @@ class Builder: 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.""" + the underlying object. Use it for subclass Builders that + need to wrap or decorate another Builder class.""" def __init__(self, builder): self.subject = builder @@ -100,62 +129,30 @@ class BuilderProxy: 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_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): +class MultiStepBuilder(BuilderBase): """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 builder's src_suffix, using a file of the same name + as the source, but with src_suffix changed to 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, + prefix = None, + suffix = None, + src_suffix = None, node_factory = SCons.Node.FS.default_fs.File, builders = []): - Builder.__init__(self, name, action, input_suffix, output_suffix, - node_factory) + BuilderBase.__init__(self, name, action, prefix, suffix, src_suffix, + node_factory) self.builder_dict = {} for bld in builders: - if bld.insuffix and bld.outsuffix: - self.builder_dict[bld.insuffix] = bld + if bld.suffix and bld.src_suffix: + self.builder_dict[bld.src_suffix] = bld def __call__(self, env, target = None, source = None): slist = scons_str2nodes(source, self.node_factory) @@ -165,7 +162,7 @@ class MultiStepBuilder(Builder): if self.builder_dict.has_key(ext): bld = self.builder_dict[ext] tgt = bld(env, - target=[ path+bld.outsuffix, ], + target=[ path+bld.suffix, ], source=snode) if not type(tgt) is types.ListType: final_sources.append(tgt) @@ -173,8 +170,8 @@ class MultiStepBuilder(Builder): final_sources.extend(tgt) else: final_sources.append(snode) - return Builder.__call__(self, env, target=target, - source=final_sources) + return BuilderBase.__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 7db69ef2..46e926c3 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -59,12 +59,13 @@ class BuilderTestCase(unittest.TestCase): def test__call__(self): """Test calling a builder to establish source dependencies """ - env = Environment() class Node: def __init__(self, name): self.name = name self.sources = [] self.derived = 0 + def __str__(self): + return self.name def builder_set(self, builder): self.builder = builder def env_set(self, env): @@ -91,10 +92,10 @@ class BuilderTestCase(unittest.TestCase): def test_cmp(self): """Test simple comparisons of Builder objects """ - b1 = SCons.Builder.Builder(input_suffix = '.o') - b2 = SCons.Builder.Builder(input_suffix = '.o') + b1 = SCons.Builder.Builder(src_suffix = '.o') + b2 = SCons.Builder.Builder(src_suffix = '.o') assert b1 == b2 - b3 = SCons.Builder.Builder(input_suffix = '.x') + b3 = SCons.Builder.Builder(src_suffix = '.x') assert b1 != b3 assert b2 != b3 @@ -198,17 +199,6 @@ class BuilderTestCase(unittest.TestCase): c = test.read(outfile, 'r') assert c == "act.py: syzygy\nfunction2\nclass2a\nclass2b\n", c - def test_insuffix(self): - """Test Builder creation with a specified input suffix - - Make sure that the '.' separator is appended to the - beginning if it isn't already present. - """ - builder = SCons.Builder.Builder(input_suffix = '.c') - assert builder.insuffix == '.c' - builder = SCons.Builder.Builder(input_suffix = 'c') - assert builder.insuffix == '.c' - def test_name(self): """Test Builder creation with a specified name """ @@ -225,33 +215,52 @@ class BuilderTestCase(unittest.TestCase): builder = SCons.Builder.Builder(node_factory = FooFactory) assert builder.node_factory is FooFactory - def test_outsuffix(self): - """Test Builder creation with a specified output suffix + def test_prefix(self): + """Test Builder creation with a specified target prefix + + Make sure that there is no '.' separator appended. + """ + builder = SCons.Builder.Builder(prefix = 'lib.') + assert builder.prefix == 'lib.' + builder = SCons.Builder.Builder(prefix = 'lib') + assert builder.prefix == 'lib' + tgt = builder(env, target = 'tgt1', source = 'src1') + assert tgt.path == 'libtgt1', \ + "Target has unexpected name: %s" % tgt[0].path + + def test_src_suffix(self): + """Test Builder creation with a specified source file suffix + + Make sure that the '.' separator is appended to the + beginning if it isn't already present. + """ + builder = SCons.Builder.Builder(src_suffix = '.c') + assert builder.src_suffix == '.c' + builder = SCons.Builder.Builder(src_suffix = 'c') + assert builder.src_suffix == '.c' + tgt = builder(env, target = 'tgt2', source = 'src2') + assert tgt.sources[0].path == 'src2.c', \ + "Source has unexpected name: %s" % tgt.sources[0].path + + 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(input_suffix = '.o') - assert builder.insuffix == '.o' - 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 + builder = SCons.Builder.Builder(suffix = '.o') + assert builder.suffix == '.o' + builder = SCons.Builder.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 def test_MultiStepBuilder(self): """Testing MultiStepBuilder class.""" builder1 = SCons.Builder.Builder(action='foo', - input_suffix='.bar', - output_suffix='.foo') + src_suffix='.bar', + suffix='.foo') builder2 = SCons.Builder.MultiStepBuilder(action='foo', builders = [ builder1 ]) tgt = builder2(env, target='baz', source='test.bar test2.foo test3.txt') diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index d9120de6..230f432c 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -39,18 +39,18 @@ import SCons.Builder Object = SCons.Builder.Builder(name = 'Object', action = 'cc -c -o $target $sources', - input_suffix='.c', - output_suffix='.o') -Program = SCons.Builder.MultiStepBuilder(name = 'Program', - action = 'cc -o $target $sources', - builders = [ Object ]) -Library = SCons.Builder.MultiStepBuilder(name = 'Library', - action = 'ar r $target $sources\nranlib $target', - builders = [ Object ]) - -Library = SCons.Builder.TargetNamingBuilder(builder = Library, - prefix='lib', - suffix='.a') + src_suffix='.c', + suffix='.o') + +Program = SCons.Builder.Builder(name = 'Program', + action = 'cc -o $target $sources', + builders = [ Object ]) + +Library = SCons.Builder.Builder(name = 'Library', + action = 'ar r $target $sources\nranlib $target', + prefix = 'lib', + suffix = '.a', + builders = [ Object ]) Builders = [Object, Program, Library]