summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2004-04-04 04:01:53 (GMT)
committerSteven Knight <knight@baldmt.com>2004-04-04 04:01:53 (GMT)
commit548e7108e2bc2363aaf1fee7366765faa630be60 (patch)
tree09d153a86945df53d71c32d53e865c6e2fd3c1b4
parentd50b6da90978ca33ad08e66a9777f5113b4ad01e (diff)
downloadSCons-548e7108e2bc2363aaf1fee7366765faa630be60.zip
SCons-548e7108e2bc2363aaf1fee7366765faa630be60.tar.gz
SCons-548e7108e2bc2363aaf1fee7366765faa630be60.tar.bz2
Allow a list of emitters to be called in sequence. (Chad Austin)
-rw-r--r--doc/man/scons.118
-rw-r--r--src/CHANGES.txt3
-rw-r--r--src/engine/SCons/Builder.py25
-rw-r--r--src/engine/SCons/BuilderTests.py36
-rw-r--r--src/engine/SCons/Tool/mingw.py4
-rw-r--r--src/engine/SCons/Tool/mslink.py4
-rw-r--r--src/engine/SCons/Tool/msvc.py4
-rw-r--r--src/engine/SCons/Tool/qt.py16
-rw-r--r--test/emitter.py47
9 files changed, 120 insertions, 37 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 0c46747..da35784 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -6261,12 +6261,12 @@ any of the suffixes of the builder. Using this argument produces a
multi-stage builder.
.IP emitter
-A function to manipulate the target and source
+A function or list of functions to manipulate the target and source
lists before dependencies are established
and the target(s) are actually built.
.B emitter
can also be string containing a construction variable to expand
-to an emitter function,
+to an emitter function or list of functions,
or a dictionary mapping source file suffixes
to emitter functions.
(Only the suffix of the first source file
@@ -6295,11 +6295,23 @@ def e(target, source, env):
b = Builder("my_build < $TARGET > $SOURCE",
emitter = e)
-# Calling an emitter through a construction variable.
+def e2(target, source, env):
+ return (target + ['bar.foo'], source + ['bar.src'])
+
+# Simple association of a list of emitter functions with a Builder.
+b = Builder("my_build < $TARGET > $SOURCE",
+ emitter = [e, e2])
+
+# Calling an emitter function through a construction variable.
env = Environment(MY_EMITTER = e)
b = Builder("my_build < $TARGET > $SOURCE",
emitter = '$MY_EMITTER')
+# Calling a list of emitter functions through a construction variable.
+env = Environment(EMITTER_LIST = [e, e2])
+b = Builder("my_build < $TARGET > $SOURCE",
+ emitter = '$EMITTER_LIST')
+
# Associating multiple emitters with different file
# suffixes using a dictionary.
def e_suf1(target, source, env):
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 49584a1..d2d933b 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -19,6 +19,9 @@ RELEASE 0.96 - XXX
- Add a $QT_AUTOBUILD_MOC_SOURCES construction variable that controls
whether moc-generated .cpp files get compiled.
+ - Allow the emitter argument to a Builder() to be or expand to a list
+ of emitter functions, which will be called in sequence.
+
From Chad Austin and Christoph Wiedemann:
- Add support for a $RPATH variable to supply a list of directories
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index 871a803..0da770a 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -45,6 +45,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os.path
import UserDict
+import UserList
import SCons.Action
from SCons.Debug import logInstanceCreation
@@ -116,6 +117,15 @@ class DictEmitter(SCons.Util.Selector):
target, source = emitter(target, source, env)
return (target, source)
+class ListEmitter(UserList.UserList):
+ """A callable list of emitters that calls each in sequence,
+ returning the result.
+ """
+ def __call__(self, target, source, env):
+ for e in self.data:
+ target, source = e(target, source, env)
+ return (target, source)
+
def Builder(**kw):
"""A factory for builder objects."""
composite = None
@@ -142,6 +152,8 @@ def Builder(**kw):
kw['emitter'] = EmitterProxy(var)
elif SCons.Util.is_Dict(emitter):
kw['emitter'] = DictEmitter(emitter)
+ elif SCons.Util.is_List(emitter):
+ kw['emitter'] = ListEmitter(emitter)
if kw.has_key('src_builder'):
ret = apply(MultiStepBuilder, (), kw)
@@ -242,13 +254,16 @@ class EmitterProxy:
# Recursively substitute the variable.
# We can't use env.subst() because it deals only
# in strings. Maybe we should change that?
- while SCons.Util.is_String(emitter) and \
- env.has_key(emitter):
+ while SCons.Util.is_String(emitter) and env.has_key(emitter):
emitter = env[emitter]
- if not callable(emitter):
- return (target, source)
+ if callable(emitter):
+ target, source = emitter(target, source, env)
+ elif SCons.Util.is_List(emitter):
+ for e in emitter:
+ target, source = e(target, source, env)
+
+ return (target, source)
- return emitter(target, source, env)
def __cmp__(self, other):
return cmp(self.var, other.var)
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index bd41f09..e2dd0e9 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -903,6 +903,42 @@ class BuilderTestCase(unittest.TestCase):
tgt = builder4(env, source='ccc.4c')
assert str(tgt) == 'emit4c-ccc', str(tgt)
+ # Test a list of emitter functions.
+ def emit5a(target, source, env):
+ source = map(str, source)
+ target = target + map(lambda x: 'emit5a-' + x[:-2], source)
+ return (target, source)
+ def emit5b(target, source, env):
+ source = map(str, source)
+ target = target + map(lambda x: 'emit5b-' + x[:-2], source)
+ return (target, source)
+ builder5 = SCons.Builder.Builder(action='foo',
+ emitter=[emit5a, emit5b],
+ node_factory=MyNode)
+
+ tgts = builder5(env, target='target-5', source='aaa.5')
+ tgts = map(str, tgts)
+ assert tgts == ['target-5', 'emit5a-aaa', 'emit5b-aaa'], tgts
+
+ # Test a list of emitter functions through the environment.
+ def emit6a(target, source, env):
+ source = map(str, source)
+ target = target + map(lambda x: 'emit6a-' + x[:-2], source)
+ return (target, source)
+ def emit6b(target, source, env):
+ source = map(str, source)
+ target = target + map(lambda x: 'emit6b-' + x[:-2], source)
+ return (target, source)
+ builder6 = SCons.Builder.Builder(action='foo',
+ emitter='$EMITTERLIST',
+ node_factory=MyNode)
+
+ env = Environment(EMITTERLIST = [emit6a, emit6b])
+
+ tgts = builder6(env, target='target-6', source='aaa.6')
+ tgts = map(str, tgts)
+ assert tgts == ['target-6', 'emit6a-aaa', 'emit6b-aaa'], tgts
+
def test_no_target(self):
"""Test deducing the target from the source."""
diff --git a/src/engine/SCons/Tool/mingw.py b/src/engine/SCons/Tool/mingw.py
index 18fa79e..fa46652 100644
--- a/src/engine/SCons/Tool/mingw.py
+++ b/src/engine/SCons/Tool/mingw.py
@@ -123,7 +123,7 @@ def generate(env):
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
env['SHLINKCOM'] = shlib_action
- env['SHLIBEMITTER']= shlib_emitter
+ env.Append(SHLIBEMITTER = [shlib_emitter])
env['LINK'] = 'g++'
env['AS'] = 'as'
env['WIN32DEFPREFIX'] = ''
@@ -133,7 +133,7 @@ def generate(env):
env['RC'] = 'windres'
env['RCFLAGS'] = SCons.Util.CLVar('')
- env['RCINCFLAGS'] = SCons.Util.CLVar('$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs)} $)')
+ env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs)} $)'
env['RCINCPREFIX'] = '--include-dir '
env['RCINCSUFFIX'] = ''
env['RCCOM'] = '$RC $RCINCFLAGS $RCFLAGS -i $SOURCE -o $TARGET'
diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py
index fd53757..7e32e60 100644
--- a/src/engine/SCons/Tool/mslink.py
+++ b/src/engine/SCons/Tool/mslink.py
@@ -140,12 +140,12 @@ def generate(env):
env['_SHLINK_TARGETS'] = win32ShlinkTargets
env['_SHLINK_SOURCES'] = win32ShlinkSources
env['SHLINKCOM'] = compositeLinkAction
- env['SHLIBEMITTER']= win32LibEmitter
+ env.Append(SHLIBEMITTER = [win32LibEmitter])
env['LINK'] = 'link'
env['LINKFLAGS'] = SCons.Util.CLVar('/nologo')
env['_PDB'] = pdbGenerator
env['LINKCOM'] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $SOURCES")}'
- env['PROGEMITTER'] = prog_emitter
+ env.Append(PROGEMITTER = [prog_emitter])
env['LIBDIRPREFIX']='/LIBPATH:'
env['LIBDIRSUFFIX']=''
env['LIBLINKPREFIX']=''
diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py
index 1a2cb1c..19fbf1d 100644
--- a/src/engine/SCons/Tool/msvc.py
+++ b/src/engine/SCons/Tool/msvc.py
@@ -441,8 +441,8 @@ def generate(env):
env['CPPDEFSUFFIX'] = ''
env['INCPREFIX'] = '/I'
env['INCSUFFIX'] = ''
- env['OBJEMITTER'] = static_object_emitter
- env['SHOBJEMITTER'] = shared_object_emitter
+ env.Append(OBJEMITTER = [static_object_emitter])
+ env.Append(SHOBJEMITTER = [shared_object_emitter])
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
env['RC'] = 'rc'
diff --git a/src/engine/SCons/Tool/qt.py b/src/engine/SCons/Tool/qt.py
index a5a53b7..f8234ba 100644
--- a/src/engine/SCons/Tool/qt.py
+++ b/src/engine/SCons/Tool/qt.py
@@ -93,7 +93,7 @@ class _Automoc:
h=None
for h_ext in header_extensions:
if os.path.exists(src_prefix + h_ext):
- h = FS.File(prefix + h_ext)
+ h = FS.File(src_prefix + h_ext)
if ui:
# file built from .ui file -> build also header from .ui
@@ -102,7 +102,7 @@ class _Automoc:
ui_h_suff = env.subst('$QT_UIHSUFFIX')
if os.path.exists(src_prefix + ui_h_suff):
# if a .ui.h file exists, we need to specify the dependecy ...
- ui_h = FS.File(prefix + ui_h_suff)
+ ui_h = FS.File(src_prefix + ui_h_suff)
env.Depends(cpp, ui_h)
if (h and q_object_search.search(h.get_contents())) or ui:
# h file with the Q_OBJECT macro found -> add moc_cpp
@@ -212,12 +212,12 @@ def generate(env):
# We can't refer to the builders directly, we have to fetch them
# as Environment attributes because that sets them up to be called
# correctly later by our emitter.
- env['PROGEMITTER'] = _Automoc('StaticObject',
- uicDeclBld,mocFromHBld,mocFromCppBld)
- env['SHLIBEMITTER'] = _Automoc('SharedObject',
- uicDeclBld,mocFromHBld,mocFromCppBld)
- env['LIBEMITTER'] = _Automoc('StaticObject',
- uicDeclBld,mocFromHBld,mocFromCppBld)
+ env.Append(PROGEMITTER = [_Automoc('StaticObject',
+ uicDeclBld,mocFromHBld,mocFromCppBld)],
+ SHLIBEMITTER = [_Automoc('SharedObject',
+ uicDeclBld,mocFromHBld,mocFromCppBld)],
+ LIBEMITTER = [_Automoc('StaticObject',
+ uicDeclBld,mocFromHBld,mocFromCppBld)])
# Of course, we need to link against the qt libraries
env.AppendUnique(CPPPATH=[os.path.join('$QTDIR', 'include')])
env.AppendUnique(LIBPATH=[os.path.join('$QTDIR', 'lib')])
diff --git a/test/emitter.py b/test/emitter.py
index 70d4c8f..0bdc619 100644
--- a/test/emitter.py
+++ b/test/emitter.py
@@ -49,30 +49,47 @@ def emitter(target, source, env):
target.append(str(target[0])+".foo")
return target,source
-b = Builder(action=build, emitter=emitter)
+def emit1(t, s, e): return (t + ['emit.1'], s)
+def emit2(t, s, e): return (t + ['emit.2'], s)
-env=Environment(BUILDERS={ 'foo': b })
+foo = Builder(action=build, emitter=emitter)
+bar = Builder(action=build, emitter='$EMITTERS')
+
+env=Environment(BUILDERS={ 'foo': foo, 'bar': bar },
+ EMITTERS=[emit1, emit2])
env.foo('f.out', 'f.in')
env.foo(File('g.out'), 'g.in')
+env.bar('h.out', 'h.in')
""")
test.write(['src', 'f.in'], 'f.in')
test.write(['src', 'g.in'], 'g.in')
+test.write(['src', 'h.in'], 'h.in')
test.run(arguments='.')
-test.fail_test(not os.path.exists(test.workpath('src', 'f.out')))
-test.fail_test(not os.path.exists(test.workpath('src', 'f.out.foo')))
-test.fail_test(not os.path.exists(test.workpath('var1', 'f.out')))
-test.fail_test(not os.path.exists(test.workpath('var1', 'f.out.foo')))
-test.fail_test(not os.path.exists(test.workpath('var2', 'f.out')))
-test.fail_test(not os.path.exists(test.workpath('var2', 'f.out.foo')))
-
-test.fail_test(not os.path.exists(test.workpath('src', 'g.out')))
-test.fail_test(not os.path.exists(test.workpath('src', 'g.out.foo')))
-test.fail_test(not os.path.exists(test.workpath('var1', 'g.out')))
-test.fail_test(not os.path.exists(test.workpath('var1', 'g.out.foo')))
-test.fail_test(not os.path.exists(test.workpath('var2', 'g.out')))
-test.fail_test(not os.path.exists(test.workpath('var2', 'g.out.foo')))
+test.must_exist(test.workpath('src', 'f.out'))
+test.must_exist(test.workpath('src', 'f.out.foo'))
+test.must_exist(test.workpath('var1', 'f.out'))
+test.must_exist(test.workpath('var1', 'f.out.foo'))
+test.must_exist(test.workpath('var2', 'f.out'))
+test.must_exist(test.workpath('var2', 'f.out.foo'))
+
+test.must_exist(test.workpath('src', 'g.out'))
+test.must_exist(test.workpath('src', 'g.out.foo'))
+test.must_exist(test.workpath('var1', 'g.out'))
+test.must_exist(test.workpath('var1', 'g.out.foo'))
+test.must_exist(test.workpath('var2', 'g.out'))
+test.must_exist(test.workpath('var2', 'g.out.foo'))
+
+test.must_exist(test.workpath('src', 'h.out'))
+test.must_exist(test.workpath('src', 'emit.1'))
+test.must_exist(test.workpath('src', 'emit.2'))
+test.must_exist(test.workpath('var1', 'h.out'))
+test.must_exist(test.workpath('var1', 'emit.1'))
+test.must_exist(test.workpath('var1', 'emit.2'))
+test.must_exist(test.workpath('var2', 'h.out'))
+test.must_exist(test.workpath('var2', 'emit.1'))
+test.must_exist(test.workpath('var2', 'emit.2'))
test.pass_test()