diff options
author | Steven Knight <knight@baldmt.com> | 2003-09-05 19:26:05 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2003-09-05 19:26:05 (GMT) |
commit | bf221d4e593f803116af76ec3bc16514b666c9f1 (patch) | |
tree | d80f1ab39365370ce1f50dba335af34f8cad83e2 /src | |
parent | f1d7f1dc87300ea5c905c648c39aeee031100c8c (diff) | |
download | SCons-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.txt | 3 | ||||
-rw-r--r-- | src/RELEASE.txt | 10 | ||||
-rw-r--r-- | src/engine/SCons/Builder.py | 11 | ||||
-rw-r--r-- | src/engine/SCons/BuilderTests.py | 30 | ||||
-rw-r--r-- | src/engine/SCons/Environment.py | 80 | ||||
-rw-r--r-- | src/engine/SCons/EnvironmentTests.py | 201 | ||||
-rw-r--r-- | src/engine/SCons/Util.py | 4 | ||||
-rw-r--r-- | src/engine/SCons/UtilTests.py | 14 |
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 |