From 49b54c9d4b7ea6f22951bcaa0087a58e2c18e559 Mon Sep 17 00:00:00 2001 From: stevenknight Date: Sat, 5 Jan 2002 12:40:19 +0000 Subject: [PATCH] Allow Builder objects to have both an action and a src_builder. git-svn-id: http://scons.tigris.org/svn/scons/trunk@189 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- src/CHANGES.txt | 3 +- src/engine/SCons/Builder.py | 48 ++++++++++++++++++++---------- src/engine/SCons/BuilderTests.py | 51 ++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 16 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index fc04479e..856d6dc0 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -24,7 +24,8 @@ RELEASE 0.03 - to each individually. - Refactor to move CompositeBuilder initialization logic from the - factory wrapper to the __init__() method. + factory wrapper to the __init__() method, and allow a Builder to + have both an action and a src_builder (or array of them). From Anthony Roach: diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 27d93e94..0cf70e41 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -122,11 +122,11 @@ elif os.name == 'nt': def Builder(**kw): """A factory for builder objects.""" - if kw.has_key('src_builder'): - return apply(MultiStepBuilder, (), kw) - elif kw.has_key('action') and (type(kw['action']) is types.DictType or - isinstance(kw['action'], UserDict)): + if kw.has_key('action') and (type(kw['action']) is types.DictType or + isinstance(kw['action'], UserDict)): return apply(CompositeBuilder, (), kw) + elif kw.has_key('src_builder'): + return apply(MultiStepBuilder, (), kw) else: return apply(BuilderBase, (), kw) @@ -263,46 +263,64 @@ class CompositeBuilder(BuilderBase): will examine the target's sources. If they are all the same suffix, and that suffix is equal to one of the child builders' src_suffix, then that child builder will be used. Otherwise, - UserError is thrown. - - Child builders are supplied via the builders arg to the - constructor. Each must have its src_suffix set.""" + UserError is thrown.""" def __init__(self, name = None, prefix='', suffix='', - action = {}): + action = {}, + src_builder = []): BuilderBase.__init__(self, name=name, prefix=prefix, suffix=suffix) + if src_builder and not type(src_builder) is types.ListType: + src_builder = [src_builder] + self.src_builder = src_builder self.builder_dict = {} for suff, act in action.items(): - self.builder_dict[suff] = BuilderBase(name = name, - action = act, - src_suffix = suff) + # Create subsidiary builders for every suffix in the + # action dictionary. If there's a src_builder that + # matches the suffix, add that to the initializing + # keywords so that a MultiStepBuilder will get created. + kw = {'name' : name, 'action' : act, 'src_suffix' : suff} + src_bld = filter(lambda x, s=suff: x.suffix == s, self.src_builder) + if src_bld: + kw['src_builder'] = src_bld[0] + self.builder_dict[suff] = apply(Builder, (), kw) def __call__(self, env, target = None, source = None): ret = BuilderBase.__call__(self, env, target=target, source=source) builder_dict = {} + suff_dict = {} for suffix, bld in self.builder_dict.items(): builder_dict[env.subst(bld.src_suffix)] = bld + suff_dict[suffix] = suffix + b = bld + while hasattr(b, 'src_builder'): + # Walk the chain of src_builders and add the + # src_suffix strings to the maps so that we know + # all of those suffixes are legal, too. + b = b.src_builder + s = env.subst(b.src_suffix) + builder_dict[s] = bld + suff_dict[s] = suffix if type(ret) is types.ListType: tlist = ret else: tlist = [ ret ] for tnode in tlist: - suflist = map(lambda x: os.path.splitext(x.path)[1], + suflist = map(lambda x, s=suff_dict: s[os.path.splitext(x.path)[1]], tnode.sources) last_suffix='' for suffix in suflist: if last_suffix and last_suffix != suffix: - raise UserError, "The builder for %s is only capable of building source files of identical suffixes." % tnode.path + raise UserError, "The builder for %s can only build source files of identical suffixes: %s." % (tnode.path, str(map(lambda t: str(t.path), tnode.sources))) last_suffix = suffix if last_suffix: try: tnode.builder_set(builder_dict[last_suffix]) except KeyError: - raise UserError, "Builder not capable of building files with suffix: %s" % suffix + raise UserError, "The builder for %s can not build files with suffix: %s" % (tnode.path, suffix) return ret print_actions = 1; diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index 9f2183fd..b735a093 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -454,6 +454,57 @@ class BuilderTestCase(unittest.TestCase): flag = 1 assert flag, "UserError should be thrown when we build targets with files of different suffixes." + foo_bld = SCons.Builder.Builder(action = 'a-foo', + src_suffix = '.ina', + suffix = '.foo') + assert isinstance(foo_bld, SCons.Builder.BuilderBase) + builder = SCons.Builder.Builder(action = { '.foo' : 'foo', + '.bar' : 'bar' }, + src_builder = foo_bld) + assert isinstance(builder, SCons.Builder.CompositeBuilder) + + tgt = builder(env, target='t1', source='t1a.ina t1b.ina') + assert isinstance(tgt.builder, SCons.Builder.BuilderBase) + + tgt = builder(env, target='t2', source='t2a.foo t2b.ina') + assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder), tgt.builder.__dict__ + + bar_bld = SCons.Builder.Builder(action = 'a-bar', + src_suffix = '.inb', + suffix = '.bar') + assert isinstance(bar_bld, SCons.Builder.BuilderBase) + builder = SCons.Builder.Builder(action = { '.foo' : 'foo', + '.bar' : 'bar' }, + src_builder = [foo_bld, bar_bld]) + assert isinstance(builder, SCons.Builder.CompositeBuilder) + + tgt = builder(env, target='t3-foo', source='t3a.foo t3b.ina') + assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder) + + tgt = builder(env, target='t3-bar', source='t3a.bar t3b.inb') + assert isinstance(tgt.builder, SCons.Builder.MultiStepBuilder) + + flag = 0 + try: + tgt = builder(env, target='t5', source='test5a.foo test5b.inb') + except SCons.Errors.UserError: + flag = 1 + assert flag, "UserError should be thrown when we build targets with files of different suffixes." + + flag = 0 + try: + tgt = builder(env, target='t6', source='test6a.bar test6b.ina') + except SCons.Errors.UserError: + flag = 1 + assert flag, "UserError should be thrown when we build targets with files of different suffixes." + + flag = 0 + try: + tgt = builder(env, target='t4', source='test4a.ina test4b.inb') + except SCons.Errors.UserError: + flag = 1 + assert flag, "UserError should be thrown when we build targets with files of different suffixes." + def test_build_scanner(self): """Testing ability to set a target scanner through a builder.""" global instanced -- 2.26.2