- Initialize all *FLAGS variables with objects do the right thing with
appending flags as strings or lists.
+ - Make things like ${TARGET.dir} work in *PATH construction variables.
+
From Vincent Risi:
- Add support for the bcc32, ilink32 and tlib Borland tools.
return scanner
return None
- def subst(self, string, raw=0, target=None, source=None, dict=None):
- """Recursively interpolates construction variables from the
- Environment into the specified string, returning the expanded
- result. Construction variables are specified by a $ prefix
- in the string and begin with an initial underscore or
- alphabetic character followed by any number of underscores
- or alphanumeric characters. The construction variable names
- may be surrounded by curly braces to separate the name from
- trailing characters.
- """
- return SCons.Util.scons_subst(string, self, raw, target, source, dict)
+ def subst(self, string, raw=0, target=None, source=None, dict=None, conv=None):
+ """Recursively interpolates construction variables from the
+ Environment into the specified string, returning the expanded
+ result. Construction variables are specified by a $ prefix
+ in the string and begin with an initial underscore or
+ alphabetic character followed by any number of underscores
+ or alphanumeric characters. The construction variable names
+ may be surrounded by curly braces to separate the name from
+ trailing characters.
+ """
+ return SCons.Util.scons_subst(string, self, raw, target, source, dict, conv)
def subst_kw(self, kw, raw=0, target=None, source=None, dict=None):
nkw = {}
nkw[k] = v
return nkw
- def subst_list(self, string, raw=0, target=None, source=None, dict=None):
+ def subst_list(self, string, raw=0, target=None, source=None, dict=None, conv=None):
"""Calls through to SCons.Util.scons_subst_list(). See
the documentation for that function."""
- return SCons.Util.scons_subst_list(string, self, raw, target, source, dict)
+ return SCons.Util.scons_subst_list(string, self, raw, target, source, dict, conv)
+
def subst_path(self, path):
- """Substitute a path list."""
+ """Substitute a path list, turning EntryProxies into Nodes
+ and leaving Nodes (and other objects) as-is."""
if not SCons.Util.is_List(path):
path = [path]
+ def s(obj):
+ """This is the "string conversion" routine that we have our
+ substitutions use to return Nodes, not strings. This relies
+ on the fact that an EntryProxy object has a get() method that
+ returns the underlying Node that it wraps, which is a bit of
+ architectural dependence that we might need to break or modify
+ in the future in response to additional requirements."""
+ try:
+ get = obj.get
+ except AttributeError:
+ pass
+ else:
+ obj = get()
+ return obj
+
r = []
for p in path:
if SCons.Util.is_String(p):
- p = self.subst(p)
+ p = self.subst(p, conv=s)
+ if SCons.Util.is_List(p):
+ p = p[0]
+ else:
+ p = s(p)
r.append(p)
return r
def test_subst_path(self):
"""Test substituting a path list
"""
- env = Environment(FOO='foo', BAR='bar')
+ class MyProxy:
+ def __init__(self, val):
+ self.val = val
+ def get(self):
+ return self.val + '-proxy'
+
+ class MyObj:
+ pass
+
+ env = Environment(FOO='foo', BAR='bar', PROXY=MyProxy('my1'))
r = env.subst_path('$FOO')
assert r == ['foo'], r
r = env.subst_path(['$FOO', 'xxx', '$BAR'])
assert r == ['foo', 'xxx', 'bar'], r
+ n = MyObj()
+
+ r = env.subst_path(['$PROXY', MyProxy('my2'), n])
+ assert r == ['my1-proxy', 'my2-proxy', n], r
+
def test_Builder_calls(self):
"""Test Builder calls through different environments
"""
# space characters in the string result from the scons_subst() function.
_space_sep = re.compile(r'[\t ]+(?![^{]*})')
-def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, dict=None):
+def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, dict=None, conv=None):
"""Expand a string containing construction variable substitutions.
This is the work-horse function for substitutions in file names
source with two methods (substitute() and expand()) that handle
the expansion.
"""
- def __init__(self, env, mode, target, source):
+ def __init__(self, env, mode, target, source, conv):
self.env = env
self.mode = mode
self.target = target
self.source = source
self.gvars = env.Dictionary()
- self.str = _strconv[mode]
+ self.conv = conv
def expand(self, s, lvars):
"""Expand a single "token" as necessary, returning an
elif is_List(s):
r = []
for l in s:
- r.append(self.str(self.substitute(l, lvars)))
+ r.append(self.conv(self.substitute(l, lvars)))
return string.join(r)
elif callable(s):
s = s(target=self.target,
args = _separate_args.findall(args)
result = []
for a in args:
- result.append(self.str(self.expand(a, lvars)))
- return string.join(result, '')
+ result.append(self.conv(self.expand(a, lvars)))
+ try:
+ result = string.join(result, '')
+ except TypeError:
+ pass
+ return result
else:
return self.expand(args, lvars)
if dict is None:
dict = subst_dict(target, source)
+ if conv is None:
+ conv = _strconv[mode]
- ss = StringSubber(env, mode, target, source)
+ ss = StringSubber(env, mode, target, source, conv)
result = ss.substitute(strSubst, dict)
if is_String(result):
return result
-def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, dict=None):
+def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, dict=None, conv=None):
"""Substitute construction variables in a string (or list or other
object) and separate the arguments into a command list.
and the rest of the object takes care of doing the right thing
internally.
"""
- def __init__(self, env, mode, target, source):
+ def __init__(self, env, mode, target, source, conv):
UserList.UserList.__init__(self, [])
self.env = env
self.mode = mode
self.add_strip = lambda x, s=self: s.append(x)
else:
self.add_strip = lambda x, s=self: None
- self.str = _strconv[mode]
+ self.conv = conv
self.in_strip = None
self.next_line()
literal = None
else:
literal = l()
- self[-1].append(CmdStringHolder(self.str(x), literal))
+ x = self.conv(x)
+ if is_String(x):
+ x = CmdStringHolder(x, literal)
+ self[-1].append(x)
self.append = self.add_to_current_word
def open_strip(self, x):
if dict is None:
dict = subst_dict(target, source)
+ if conv is None:
+ conv = _strconv[mode]
- ls = ListSubber(env, mode, target, source)
+ ls = ListSubber(env, mode, target, source, conv)
ls.substitute(strSubst, dict, 0)
return ls.data
else:
raise AssertionError, "did not catch expected UserError"
+ # Test we handle overriding the internal conversion routines.
+ def s(obj):
+ return obj
+
+ n1 = MyNode('n1')
+ env = DummyEnv({'NODE' : n1})
+ node = scons_subst("$NODE", env, mode=SUBST_RAW, conv=s)
+ assert node == [n1], node
+ node = scons_subst("$NODE", env, mode=SUBST_CMD, conv=s)
+ assert node == [n1], node
+ node = scons_subst("$NODE", env, mode=SUBST_SIG, conv=s)
+ assert node == [n1], node
+
# Test returning a function.
#env = DummyEnv({'FUNCTION' : foo})
#func = scons_subst("$FUNCTION", env, mode=SUBST_RAW, call=None)
else:
raise AssertionError, "did not catch expected SyntaxError"
+ # Test we handle overriding the internal conversion routines.
+ def s(obj):
+ return obj
+
+ n1 = MyNode('n1')
+ env = DummyEnv({'NODE' : n1})
+ node = scons_subst_list("$NODE", env, mode=SUBST_RAW, conv=s)
+ assert node == [[n1]], node
+ node = scons_subst_list("$NODE", env, mode=SUBST_CMD, conv=s)
+ assert node == [[n1]], node
+ node = scons_subst_list("$NODE", env, mode=SUBST_SIG, conv=s)
+ assert node == [[n1]], node
+
def test_subst_once(self):
"""Testing the scons_subst_once() method"""
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test use of ${TARGET.dir} to specify a CPPPATH directory in
+combination BuildDirs and a generated .h file.
+"""
+
+import TestSCons
+
+_exe = TestSCons._exe
+
+test = TestSCons.TestSCons()
+
+build1_foo = test.workpath('build1', 'foo' + _exe)
+build2_foo = test.workpath('build2', 'foo' + _exe)
+
+test.subdir('src', 'build1', 'build2')
+
+test.write('SConstruct', """
+def cat(env, source, target):
+ target = str(target[0])
+ source = map(str, source)
+ f = open(target, "wb")
+ for src in source:
+ f.write(open(src, "rb").read())
+ f.close()
+env = Environment(CPPPATH='${TARGET.dir}')
+env.Append(BUILDERS = {'Cat' : Builder(action=cat)})
+Export('env')
+BuildDir('build1', 'src')
+SConscript('build1/SConscript')
+BuildDir('build2', 'src')
+SConscript('build2/SConscript', duplicate=0)
+""")
+
+test.write(['src', 'SConscript'], """
+Import('env')
+env.Cat('foo.h', 'foo.h.in')
+env.Program('foo', ['foo.c'])
+""")
+
+test.write(['src', 'foo.h.in'], """\
+#define STRING "foo.h.in\\n"
+""")
+
+test.write(['src', 'foo.c'], """\
+#include <foo.h>
+
+int
+main(int argc, char *argv[])
+{
+ printf(STRING);
+ printf("foo.c\\n");
+ exit (0);
+}
+""")
+
+test.run(arguments = '.')
+
+test.run(program = build1_foo, stdout = "foo.h.in\nfoo.c\n")
+test.run(program = build2_foo, stdout = "foo.h.in\nfoo.c\n")
+
+test.pass_test()