summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2003-09-05 19:26:05 (GMT)
committerSteven Knight <knight@baldmt.com>2003-09-05 19:26:05 (GMT)
commitbf221d4e593f803116af76ec3bc16514b666c9f1 (patch)
treed80f1ab39365370ce1f50dba335af34f8cad83e2 /src
parentf1d7f1dc87300ea5c905c648c39aeee031100c8c (diff)
downloadSCons-bf221d4e593f803116af76ec3bc16514b666c9f1.zip
SCons-bf221d4e593f803116af76ec3bc16514b666c9f1.tar.gz
SCons-bf221d4e593f803116af76ec3bc16514b666c9f1.tar.bz2
Support construction variable expansion anywhere in a file or path name.
Diffstat (limited to 'src')
-rw-r--r--src/CHANGES.txt3
-rw-r--r--src/RELEASE.txt10
-rw-r--r--src/engine/SCons/Builder.py11
-rw-r--r--src/engine/SCons/BuilderTests.py30
-rw-r--r--src/engine/SCons/Environment.py80
-rw-r--r--src/engine/SCons/EnvironmentTests.py201
-rw-r--r--src/engine/SCons/Util.py4
-rw-r--r--src/engine/SCons/UtilTests.py14
8 files changed, 305 insertions, 48 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 1eeb7a9..8f1f754 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -36,6 +36,9 @@ RELEASE X.XX - XXX
- Accomodate alphanumeric version strings in EnsurePythonVersion().
+ - Support arbitrary expansion of construction variables within
+ file and directory arguments to Builder calls and Environment methods.
+
From Bram Moolenaar:
- Split the non-SCons-specific functionality from SConf.py to a new,
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 36b9f00..ae69387 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -27,6 +27,16 @@ RELEASE X.XX - XXX
Please note the following important changes since release 0.92:
+ - Construction variables are now expanded anywhere within a
+ target or source name, as well as in the arguments to the following
+ Environment methods: AlwaysBuild(), Depends(), Ignore(), Install(),
+ InstallAs(), Precious(), SideEffect() and SourceCode().
+
+ If you have any files or directories that actually contain one or
+ more dollar signs ($), you must now precede the dollar sign with
+ another dollar sign ($$) when referring to the file or directory
+ as part of calling a Builder, or any of the above methods.
+
Please note the following important changes since release 0.91:
- The Debian package available from the SCons web site now
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index af03e82..fe017ae 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -49,7 +49,6 @@ import UserDict
import SCons.Action
from SCons.Errors import InternalError, UserError
import SCons.Executor
-import SCons.Node
import SCons.Node.FS
import SCons.Util
import SCons.Warnings
@@ -329,7 +328,7 @@ class BuilderBase:
src_suf = self.get_src_suffix(env)
source = adjustixes(source, None, src_suf)
- slist = SCons.Node.arg2nodes(source, self.source_factory)
+ slist = env.arg2nodes(source, self.source_factory)
pre = self.get_prefix(env, slist)
suf = self.get_suffix(env, slist)
@@ -342,7 +341,7 @@ class BuilderBase:
tlist = [ t_from_s(pre, suf, self.splitext) ]
else:
target = adjustixes(target, pre, suf)
- tlist = SCons.Node.arg2nodes(target, self.target_factory)
+ tlist = env.arg2nodes(target, self.target_factory)
if self.emitter:
# The emitter is going to do str(node), but because we're
@@ -369,8 +368,8 @@ class BuilderBase:
# Have to call arg2nodes yet again, since it is legal for
# emitters to spit out strings as well as Node instances.
- slist = SCons.Node.arg2nodes(source, self.source_factory)
- tlist = SCons.Node.arg2nodes(target, self.target_factory)
+ slist = env.arg2nodes(source, self.source_factory)
+ tlist = env.arg2nodes(target, self.target_factory)
return tlist, slist
@@ -503,7 +502,7 @@ class MultiStepBuilder(BuilderBase):
source = target
target = None
- slist = SCons.Node.arg2nodes(source, self.source_factory)
+ slist = env.arg2nodes(source, self.source_factory)
final_sources = []
try:
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index e0ba2fe..b51eb9f 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -59,6 +59,8 @@ env_scanner = None
scons_env = SCons.Environment.Environment()
+env_arg2nodes_called = None
+
class Environment:
def __init__(self, **kw):
self.d = {}
@@ -67,6 +69,8 @@ class Environment:
self.d['ESCAPE'] = scons_env['ESCAPE']
for k, v in kw.items():
self.d[k] = v
+ global env_arg2nodes_called
+ env_arg2nodes_called = None
def subst(self, s):
if not SCons.Util.is_String(s):
return s
@@ -78,6 +82,17 @@ class Environment:
except IndexError:
pass
return self.d.get(s, s)
+ def arg2nodes(self, args, factory):
+ global env_arg2nodes_called
+ env_arg2nodes_called = 1
+ if not SCons.Util.is_List(args):
+ args = [args]
+ list = []
+ for a in args:
+ if SCons.Util.is_String(a):
+ a = factory(a)
+ list.append(a)
+ return list
def get_scanner(self, ext):
return env_scanner
def Dictionary(self):
@@ -108,8 +123,6 @@ class Environment:
d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__']
d['SOURCE'] = d['SOURCES'][0]
return d
-
-env = Environment()
class MyNode_without_target_from_source:
def __init__(self, name):
@@ -173,11 +186,13 @@ class BuilderTestCase(unittest.TestCase):
def test__call__(self):
"""Test calling a builder to establish source dependencies
"""
+ env = Environment()
builder = SCons.Builder.Builder(action="foo", node_factory=MyNode)
n1 = MyNode("n1");
n2 = MyNode("n2");
builder(env, target = n1, source = n2)
+ assert env_arg2nodes_called
assert n1.env == env, n1.env
assert n1.builder == builder, n1.builder
assert n1.sources == [n2], n1.sources
@@ -342,6 +357,7 @@ class BuilderTestCase(unittest.TestCase):
Make sure that there is no '.' separator appended.
"""
+ env = Environment()
builder = SCons.Builder.Builder(prefix = 'lib.')
assert builder.get_prefix(env) == 'lib.'
builder = SCons.Builder.Builder(prefix = 'lib')
@@ -431,6 +447,7 @@ class BuilderTestCase(unittest.TestCase):
Make sure that the '.' separator is appended to the
beginning if it isn't already present.
"""
+ env = Environment()
builder = SCons.Builder.Builder(suffix = '.o')
assert builder.get_suffix(env) == '.o', builder.get_suffix(env)
builder = SCons.Builder.Builder(suffix = 'o')
@@ -484,6 +501,7 @@ class BuilderTestCase(unittest.TestCase):
open(t, 'w').write("function2\n")
return 1
+ env = Environment()
builder = SCons.Builder.Builder(action = function2)
tgts = builder(env, target = [outfile, outfile2], source = 'foo')
for t in tgts:
@@ -525,6 +543,7 @@ class BuilderTestCase(unittest.TestCase):
def test_MultiStepBuilder(self):
"""Testing MultiStepBuilder class."""
+ env = Environment()
builder1 = SCons.Builder.Builder(action='foo',
src_suffix='.bar',
suffix='.foo')
@@ -574,8 +593,7 @@ class BuilderTestCase(unittest.TestCase):
def func_action(target, source, env):
return 0
- env['BAR_SUFFIX'] = '.BAR2'
- env['FOO_SUFFIX'] = '.FOO2'
+ env = Environment(BAR_SUFFIX = '.BAR2', FOO_SUFFIX = '.FOO2')
builder = SCons.Builder.Builder(action={ '.foo' : func_action,
'.bar' : func_action,
'$BAR_SUFFIX' : func_action,
@@ -709,6 +727,7 @@ class BuilderTestCase(unittest.TestCase):
class TestScanner:
pass
scn = TestScanner()
+ env = Environment()
builder = SCons.Builder.Builder(scanner=scn)
tgt = builder(env, target='foo2', source='bar')
assert tgt.target_scanner == scn, tgt.target_scanner
@@ -731,6 +750,7 @@ class BuilderTestCase(unittest.TestCase):
def instance(self, env):
return self
env_scanner = TestScanner()
+ env = Environment()
builder = SCons.Builder.Builder(action='action')
tgt = builder(env, target='foo.x', source='bar')
src = tgt.sources[0]
@@ -768,6 +788,7 @@ class BuilderTestCase(unittest.TestCase):
source.append("baz")
return ( target, source )
+ env = Environment()
builder = SCons.Builder.Builder(action='foo',
emitter=emit,
node_factory=MyNode)
@@ -862,6 +883,7 @@ class BuilderTestCase(unittest.TestCase):
def test_no_target(self):
"""Test deducing the target from the source."""
+ env = Environment()
b = SCons.Builder.Builder(action='foo', suffix='.o')
tgt = b(env, 'aaa')
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index fae86e4..f72bc95 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -54,6 +54,11 @@ import SCons.Tool
import SCons.Util
import SCons.Warnings
+class _Null:
+ pass
+
+_null = _Null
+
def installFunc(target, source, env):
"""Install a source file into a target using the function specified
as the INSTALL construction variable."""
@@ -170,6 +175,7 @@ class Environment:
options=None,
**kw):
self.fs = SCons.Node.FS.default_fs
+ self.lookup_list = SCons.Node.arg2nodes_lookups
self._dict = our_deepcopy(SCons.Defaults.ConstructionEnvironment)
self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
@@ -211,6 +217,40 @@ class Environment:
def __cmp__(self, other):
return cmp(self._dict, other._dict)
+ def arg2nodes(self, args, node_factory=_null, lookup_list=_null):
+ if node_factory is _null:
+ node_factory = self.fs.File
+ if lookup_list is _null:
+ lookup_list = self.lookup_list
+
+ if not args:
+ return []
+
+ if not SCons.Util.is_List(args):
+ args = [args]
+
+ nodes = []
+ for v in args:
+ if SCons.Util.is_String(v):
+ n = None
+ for l in lookup_list:
+ n = l(v)
+ if not n is None:
+ break
+ if not n is None:
+ if SCons.Util.is_String(n):
+ n = self.subst(n, raw=1)
+ if node_factory:
+ n = node_factory(n)
+ nodes.append(n)
+ elif node_factory:
+ v = self.subst(v, raw=1)
+ nodes.append(node_factory(v))
+ else:
+ nodes.append(v)
+
+ return nodes
+
def Builders(self):
pass # XXX
@@ -330,21 +370,21 @@ class Environment:
self._dict[envname][name] = nv
- def Depends(self, target, dependency):
- """Explicity specify that 'target's depend on 'dependency'."""
- tlist = SCons.Node.arg2nodes(target, self.fs.File)
- dlist = SCons.Node.arg2nodes(dependency, self.fs.File)
- for t in tlist:
- t.add_dependency(dlist)
+ def Depends(self, target, dependency):
+ """Explicity specify that 'target's depend on 'dependency'."""
+ tlist = self.arg2nodes(target, self.fs.File)
+ dlist = self.arg2nodes(dependency, self.fs.File)
+ for t in tlist:
+ t.add_dependency(dlist)
- if len(tlist) == 1:
- tlist = tlist[0]
- return tlist
+ if len(tlist) == 1:
+ tlist = tlist[0]
+ return tlist
def Ignore(self, target, dependency):
"""Ignore a dependency."""
- tlist = SCons.Node.arg2nodes(target, self.fs.File)
- dlist = SCons.Node.arg2nodes(dependency, self.fs.File)
+ tlist = self.arg2nodes(target, self.fs.File)
+ dlist = self.arg2nodes(dependency, self.fs.File)
for t in tlist:
t.add_ignore(dlist)
@@ -355,7 +395,7 @@ class Environment:
def AlwaysBuild(self, *targets):
tlist = []
for t in targets:
- tlist.extend(SCons.Node.arg2nodes(t, self.fs.File))
+ tlist.extend(self.arg2nodes(t, self.fs.File))
for t in tlist:
t.set_always_build()
@@ -367,7 +407,7 @@ class Environment:
def Precious(self, *targets):
tlist = []
for t in targets:
- tlist.extend(SCons.Node.arg2nodes(t, self.fs.File))
+ tlist.extend(self.arg2nodes(t, self.fs.File))
for t in tlist:
t.set_precious()
@@ -422,11 +462,11 @@ class Environment:
def Install(self, dir, source):
"""Install specified files in the given directory."""
try:
- dnodes = SCons.Node.arg2nodes(dir, self.fs.Dir)
+ dnodes = self.arg2nodes(dir, self.fs.Dir)
except TypeError:
raise SCons.Errors.UserError, "Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir)
try:
- sources = SCons.Node.arg2nodes(source, self.fs.File)
+ sources = self.arg2nodes(source, self.fs.File)
except TypeError:
if SCons.Util.is_List(source):
raise SCons.Errors.UserError, "Source `%s' of Install() contains one or more non-files. Install() source must be one or more files." % repr(map(str, source))
@@ -443,8 +483,8 @@ class Environment:
def InstallAs(self, target, source):
"""Install sources as targets."""
- sources = SCons.Node.arg2nodes(source, self.fs.File)
- targets = SCons.Node.arg2nodes(target, self.fs.File)
+ sources = self.arg2nodes(source, self.fs.File)
+ targets = self.arg2nodes(target, self.fs.File)
ret = []
for src, tgt in map(lambda x, y: (x, y), sources, targets):
ret.append(InstallBuilder(self, tgt, src))
@@ -454,7 +494,7 @@ class Environment:
def SourceCode(self, entry, builder):
"""Arrange for a source code builder for (part of) a tree."""
- entries = SCons.Node.arg2nodes(entry, self.fs.Entry)
+ entries = self.arg2nodes(entry, self.fs.Entry)
for entry in entries:
entry.set_src_builder(builder)
if len(entries) == 1:
@@ -464,8 +504,8 @@ class Environment:
def SideEffect(self, side_effect, target):
"""Tell scons that side_effects are built as side
effects of building targets."""
- side_effects = SCons.Node.arg2nodes(side_effect, self.fs.File)
- targets = SCons.Node.arg2nodes(target, self.fs.File)
+ side_effects = self.arg2nodes(side_effect, self.fs.File)
+ targets = self.arg2nodes(target, self.fs.File)
for side_effect in side_effects:
# A builder of 1 means the node is supposed to appear
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index e79ce7c..12766ec 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -128,7 +128,128 @@ class EnvironmentTestCase(unittest.TestCase):
env2.Replace(ONE = "won")
assert env2['ONE'] == "won"
assert env['ONE'] == 1
-
+
+ def test_arg2nodes(self):
+ """Test the arg2nodes method
+ """
+ env = Environment()
+ dict = {}
+ class X(SCons.Node.Node):
+ pass
+ def Factory(name, directory = None, create = 1, dict=dict, X=X):
+ if not dict.has_key(name):
+ dict[name] = X()
+ dict[name].name = name
+ return dict[name]
+
+ nodes = env.arg2nodes("Util.py UtilTests.py", Factory)
+ assert len(nodes) == 1, nodes
+ assert isinstance(nodes[0], X)
+ assert nodes[0].name == "Util.py UtilTests.py"
+
+ import types
+ if hasattr(types, 'UnicodeType'):
+ code = """if 1:
+ nodes = env.arg2nodes(u"Util.py UtilTests.py", Factory)
+ assert len(nodes) == 1, nodes
+ assert isinstance(nodes[0], X)
+ assert nodes[0].name == u"Util.py UtilTests.py"
+ \n"""
+ exec code in globals(), locals()
+
+ nodes = env.arg2nodes(["Util.py", "UtilTests.py"], Factory)
+ assert len(nodes) == 2, nodes
+ assert isinstance(nodes[0], X)
+ assert isinstance(nodes[1], X)
+ assert nodes[0].name == "Util.py"
+ assert nodes[1].name == "UtilTests.py"
+
+ n1 = Factory("Util.py")
+ nodes = env.arg2nodes([n1, "UtilTests.py"], Factory)
+ assert len(nodes) == 2, nodes
+ assert isinstance(nodes[0], X)
+ assert isinstance(nodes[1], X)
+ assert nodes[0].name == "Util.py"
+ assert nodes[1].name == "UtilTests.py"
+
+ class SConsNode(SCons.Node.Node):
+ pass
+ nodes = env.arg2nodes(SConsNode())
+ assert len(nodes) == 1, nodes
+ assert isinstance(nodes[0], SConsNode), node
+
+ class OtherNode:
+ pass
+ nodes = env.arg2nodes(OtherNode())
+ assert len(nodes) == 1, nodes
+ assert isinstance(nodes[0], OtherNode), node
+
+ def lookup_a(str, F=Factory):
+ if str[0] == 'a':
+ n = F(str)
+ n.a = 1
+ return n
+ else:
+ return None
+
+ def lookup_b(str, F=Factory):
+ if str[0] == 'b':
+ n = F(str)
+ n.b = 1
+ return n
+ else:
+ return None
+
+ env_ll = env.Copy()
+ env_ll.lookup_list = [lookup_a, lookup_b]
+
+ nodes = env_ll.arg2nodes(['aaa', 'bbb', 'ccc'], Factory)
+ assert len(nodes) == 3, nodes
+
+ assert nodes[0].name == 'aaa', nodes[0]
+ assert nodes[0].a == 1, nodes[0]
+ assert not hasattr(nodes[0], 'b'), nodes[0]
+
+ assert nodes[1].name == 'bbb'
+ assert not hasattr(nodes[1], 'a'), nodes[1]
+ assert nodes[1].b == 1, nodes[1]
+
+ assert nodes[2].name == 'ccc'
+ assert not hasattr(nodes[2], 'a'), nodes[1]
+ assert not hasattr(nodes[2], 'b'), nodes[1]
+
+ def lookup_bbbb(str, F=Factory):
+ if str == 'bbbb':
+ n = F(str)
+ n.bbbb = 1
+ return n
+ else:
+ return None
+
+ def lookup_c(str, F=Factory):
+ if str[0] == 'c':
+ n = F(str)
+ n.c = 1
+ return n
+ else:
+ return None
+
+ nodes = env.arg2nodes(['bbbb', 'ccc'], Factory,
+ [lookup_c, lookup_bbbb, lookup_b])
+ assert len(nodes) == 2, nodes
+
+ assert nodes[0].name == 'bbbb'
+ assert not hasattr(nodes[0], 'a'), nodes[1]
+ assert not hasattr(nodes[0], 'b'), nodes[1]
+ assert nodes[0].bbbb == 1, nodes[1]
+ assert not hasattr(nodes[0], 'c'), nodes[0]
+
+ assert nodes[1].name == 'ccc'
+ assert not hasattr(nodes[1], 'a'), nodes[1]
+ assert not hasattr(nodes[1], 'b'), nodes[1]
+ assert not hasattr(nodes[1], 'bbbb'), nodes[0]
+ assert nodes[1].c == 1, nodes[1]
+
def test_Builder_calls(self):
"""Test Builder calls through different environments
"""
@@ -354,7 +475,8 @@ class EnvironmentTestCase(unittest.TestCase):
def test_Install(self):
"""Test Install and InstallAs methods"""
- env=Environment()
+ env = Environment(FOO='iii', BAR='jjj')
+
tgt = env.Install('export', [ 'build/foo1', 'build/foo2' ])
paths = map(str, tgt)
paths.sort()
@@ -363,6 +485,14 @@ class EnvironmentTestCase(unittest.TestCase):
for tnode in tgt:
assert tnode.builder == InstallBuilder
+ tgt = env.Install('$FOO', [ 'build/${BAR}1', 'build/${BAR}2' ])
+ paths = map(str, tgt)
+ paths.sort()
+ expect = map(os.path.normpath, [ 'iii/jjj1', 'iii/jjj2' ])
+ assert paths == expect, paths
+ for tnode in tgt:
+ assert tnode.builder == InstallBuilder
+
exc_caught = None
try:
tgt = env.Install('export', 'export')
@@ -400,6 +530,11 @@ class EnvironmentTestCase(unittest.TestCase):
for tnode in tgt:
assert tnode.builder == InstallBuilder
+ tgt = env.InstallAs(target='${FOO}.t', source='${BAR}.s')
+ assert tgt.path == 'iii.t'
+ assert tgt.sources[0].path == 'jjj.s'
+ assert tgt.builder == InstallBuilder
+
def test_ReservedVariables(self):
"""Test generation of warnings when reserved variable names
are set in an environment."""
@@ -570,7 +705,7 @@ class EnvironmentTestCase(unittest.TestCase):
def test_Depends(self):
"""Test the explicit Depends method."""
- env = Environment()
+ env = Environment(FOO = 'xxx', BAR='yyy')
t = env.Depends(target='EnvironmentTest.py', dependency='Environment.py')
assert t.__class__.__name__ == 'File'
assert t.path == 'EnvironmentTest.py'
@@ -579,9 +714,17 @@ class EnvironmentTestCase(unittest.TestCase):
assert d.__class__.__name__ == 'File'
assert d.path == 'Environment.py'
+ t = env.Depends(target='${FOO}.py', dependency='${BAR}.py')
+ assert t.__class__.__name__ == 'File'
+ assert t.path == 'xxx.py'
+ assert len(t.depends) == 1
+ d = t.depends[0]
+ assert d.__class__.__name__ == 'File'
+ assert d.path == 'yyy.py'
+
def test_Ignore(self):
"""Test the explicit Ignore method."""
- env = Environment()
+ env = Environment(FOO='yyy', BAR='zzz')
t = env.Ignore(target='targ.py', dependency='dep.py')
assert t.__class__.__name__ == 'File'
assert t.path == 'targ.py'
@@ -589,16 +732,23 @@ class EnvironmentTestCase(unittest.TestCase):
i = t.ignore[0]
assert i.__class__.__name__ == 'File'
assert i.path == 'dep.py'
+ t = env.Ignore(target='$FOO$BAR', dependency='$BAR$FOO')
+ assert t.__class__.__name__ == 'File'
+ assert t.path == 'yyyzzz'
+ assert len(t.ignore) == 1
+ i = t.ignore[0]
+ assert i.__class__.__name__ == 'File'
+ assert i.path == 'zzzyyy'
def test_AlwaysBuild(self):
"""Test the AlwaysBuild() method"""
- env = Environment()
- t = env.AlwaysBuild('a', 'b', ['c', 'd'])
+ env = Environment(FOO='fff', BAR='bbb')
+ t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR')
assert t[0].__class__.__name__ == 'File'
assert t[0].path == 'a'
assert t[0].always_build
assert t[1].__class__.__name__ == 'File'
- assert t[1].path == 'b'
+ assert t[1].path == 'bfff'
assert t[1].always_build
assert t[2].__class__.__name__ == 'File'
assert t[2].path == 'c'
@@ -606,16 +756,19 @@ class EnvironmentTestCase(unittest.TestCase):
assert t[3].__class__.__name__ == 'File'
assert t[3].path == 'd'
assert t[3].always_build
+ assert t[4].__class__.__name__ == 'File'
+ assert t[4].path == 'bbb'
+ assert t[4].always_build
def test_Precious(self):
"""Test the Precious() method."""
- env = Environment()
- t = env.Precious('a', 'b', ['c', 'd'])
+ env = Environment(FOO='ggg', BAR='hhh')
+ t = env.Precious('a', '${BAR}b', ['c', 'd'], '$FOO')
assert t[0].__class__.__name__ == 'File'
assert t[0].path == 'a'
assert t[0].precious
assert t[1].__class__.__name__ == 'File'
- assert t[1].path == 'b'
+ assert t[1].path == 'hhhb'
assert t[1].precious
assert t[2].__class__.__name__ == 'File'
assert t[2].path == 'c'
@@ -623,6 +776,9 @@ class EnvironmentTestCase(unittest.TestCase):
assert t[3].__class__.__name__ == 'File'
assert t[3].path == 'd'
assert t[3].precious
+ assert t[4].__class__.__name__ == 'File'
+ assert t[4].path == 'ggg'
+ assert t[4].precious
def test_Command(self):
"""Test the Command() method."""
@@ -654,28 +810,47 @@ class EnvironmentTestCase(unittest.TestCase):
def test_SourceCode(self):
"""Test the SourceCode() method."""
- env = Environment()
+ env = Environment(FOO='mmm', BAR='nnn')
e = env.SourceCode('foo', None)
+ assert e.path == 'foo'
s = e.src_builder()
assert s is None, s
b = Builder()
- env.SourceCode(e, b)
+ e = env.SourceCode(e, b)
+ assert e.path == 'foo'
s = e.src_builder()
assert s is b, s
+ e = env.SourceCode('$BAR$FOO', None)
+ assert e.path == 'nnnmmm'
+ s = e.src_builder()
+ assert s is None, s
+
def test_SideEffect(self):
"""Test the SideEffect() method"""
- env = Environment()
+ env = Environment(LIB='lll', FOO='fff', BAR='bbb')
+
foo = env.Object('foo.obj', 'foo.cpp')
bar = env.Object('bar.obj', 'bar.cpp')
s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])
+ assert s.path == 'mylib.pdb'
assert s.side_effect
assert foo.side_effects == [s]
assert bar.side_effects == [s]
assert s.depends_on([bar])
assert s.depends_on([foo])
+ fff = env.Object('fff.obj', 'fff.cpp')
+ bbb = env.Object('bbb.obj', 'bbb.cpp')
+ s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])
+ assert s.path == 'mylll.pdb'
+ assert s.side_effect
+ assert fff.side_effects == [s], fff.side_effects
+ assert bbb.side_effects == [s], bbb.side_effects
+ assert s.depends_on([bbb])
+ assert s.depends_on([fff])
+
def test_subst(self):
"""Test substituting construction variables within strings
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 3d3f563..38b25af 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -575,7 +575,9 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None):
strSubst = string.replace(string.replace(strSubst, '\0\4', '$'),
'\0\5', '')
# strip out redundant white-space
- return string.strip(_space_sep.sub(' ', strSubst))
+ if mode != SUBST_RAW:
+ strSubst = string.strip(_space_sep.sub(' ', strSubst))
+ return strSubst
def render_tree(root, child_func, prune=0, margin=[0], visited={}):
"""
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index 23120e6..09b96d9 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -172,17 +172,23 @@ class UtilTestCase(unittest.TestCase):
assert newcom == cvt("test foo/blah.cppblah /bar/ack.cppblah"), newcom
newcom = scons_subst("test $xxx", env)
+ assert newcom == cvt("test "), newcom
+ newcom = scons_subst("test $xxx", env, mode=SUBST_CMD)
+ assert newcom == cvt("test"), newcom
+ newcom = scons_subst("test $xxx", env, mode=SUBST_SIG)
assert newcom == cvt("test"), newcom
newcom = scons_subst("test $($xxx$)", env)
assert newcom == cvt("test $($)"), newcom
-
- newcom = scons_subst("test $( $xxx $)", env)
- assert newcom == cvt("test $( $)"), newcom
-
+ newcom = scons_subst("test $($xxx$)", env, mode=SUBST_CMD)
+ assert newcom == cvt("test"), newcom
newcom = scons_subst("test $($xxx$)", env, mode=SUBST_SIG)
assert newcom == cvt("test"), newcom
+ newcom = scons_subst("test $( $xxx $)", env)
+ assert newcom == cvt("test $( $)"), newcom
+ newcom = scons_subst("test $( $xxx $)", env, mode=SUBST_CMD)
+ assert newcom == cvt("test"), newcom
newcom = scons_subst("test $( $xxx $)", env, mode=SUBST_SIG)
assert newcom == cvt("test"), newcom