From a538b7dded2a3d4ff54fdc9598bb8c9578c7d7d5 Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Sat, 9 Oct 2004 03:23:36 +0000 Subject: Win32 portability fixes for tests. --- src/CHANGES.txt | 5 -- src/engine/SCons/ActionTests.py | 6 +-- src/engine/SCons/Builder.py | 19 ++++++++ src/engine/SCons/BuilderTests.py | 99 +++++++------------------------------- src/engine/SCons/Node/FS.py | 2 +- src/engine/SCons/Node/FSTests.py | 3 +- src/engine/SCons/Node/NodeTests.py | 46 +++++------------- src/engine/SCons/Node/__init__.py | 21 ++++---- src/engine/SCons/Tool/linkloc.py | 3 +- test/Command.py | 2 +- test/Scanner.py | 12 ++--- test/chdir.py | 11 +++-- test/option/debug-findlibs.py | 5 +- test/srcchange.py | 24 ++++----- 14 files changed, 92 insertions(+), 166 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index d8ce645..25603b3 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -196,11 +196,6 @@ RELEASE 0.97 - XXX - Improve the --debug=explain message when the build action changes. - - Properly reset cached state when a Node subclass has been built. - - - Remove the old target_scanner and source_scanner attributes from - Nodes, we're now getting these from the Builder(s). - - Test enhancements in SourceCode.py, option-n.py, midl.py. Better Command() and Scanner test coverage. Improved test infrastructure for -c output. diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index af03cd5..6bff0e3 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -411,21 +411,21 @@ class ActionBaseTestCase(unittest.TestCase): assert s == 'execfunc(["out"], ["in"])\n', s a.chdir = 'xyz' - expect = 'os.chdir(\'%s\')\nexecfunc(["out"], ["in"])\nos.chdir(\'%s\')\n' + expect = 'os.chdir(%s)\nexecfunc(["out"], ["in"])\nos.chdir(%s)\n' sio = StringIO.StringIO() sys.stdout = sio result = a("out", "in", env) assert result == 7, result s = sio.getvalue() - assert s == expect % ('xyz', test.workpath()), s + assert s == expect % (repr('xyz'), repr(test.workpath())), s sio = StringIO.StringIO() sys.stdout = sio result = a("out", "in", env, chdir='sub') assert result == 7, result s = sio.getvalue() - assert s == expect % ('sub', test.workpath()), s + assert s == expect % (repr('sub'), repr(test.workpath())), s a.chdir = None diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index f3d6977..e9d4e11 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -299,6 +299,9 @@ def _init_nodes(builder, env, overrides, executor_kw, tlist, slist): elif t.overrides != overrides: raise UserError, "Two different sets of overrides were specified for the same target: %s"%str(t) + elif builder.target_scanner and t.target_scanner and builder.target_scanner != t.target_scanner: + raise UserError, "Two different scanners were specified for the same target: %s"%str(t) + if builder.multi: if t.builder != builder: if isinstance(t.builder, ListBuilder) and isinstance(builder, ListBuilder) and t.builder.builder == builder.builder: @@ -343,6 +346,22 @@ def _init_nodes(builder, env, overrides, executor_kw, tlist, slist): t.env_set(env) t.add_source(slist) t.set_executor(executor) + if builder.target_scanner: + t.target_scanner = builder.target_scanner + if t.source_scanner is None: + t.source_scanner = builder.source_scanner + + # Add backup source scanners from the environment to the source + # nodes. This may not be necessary if the node will have a real + # source scanner added later (which is why these are the "backup" + # source scanners, not the real ones), but because source nodes may + # be used multiple times for different targets, it ends up being + # more efficient to do this calculation once here, as opposed to + # delaying it until later when we potentially have to calculate it + # over and over and over. + for s in slist: + if s.source_scanner is None and s.backup_source_scanner is None: + s.backup_source_scanner = env.get_scanner(s.scanner_key()) class EmitterProxy: """This is a callable class that can act as a diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index 8850ab6..a67d22a 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -82,14 +82,6 @@ class Environment: except IndexError: pass return self.d.get(s, s) - def subst_target_source(self, string, raw=0, target=None, - source=None, dict=None, conv=None): - return SCons.Util.scons_subst(string, self, raw, target, - source, dict, conv) - def subst_list(self, string, raw=0, target=None, - source=None, dict=None, conv=None): - return SCons.Util.scons_subst_list(string, self, raw, target, - source, dict, conv) def arg2nodes(self, args, factory): global env_arg2nodes_called env_arg2nodes_called = 1 @@ -120,7 +112,6 @@ class Environment: def Override(self, overrides): env = apply(Environment, (), self.d) env.d.update(overrides) - env.scanner = self.scanner return env def _update(self, dict): self.d.update(dict) @@ -134,8 +125,6 @@ class Environment: d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__'] d['SOURCE'] = d['SOURCES'][0] return d - def __cmp__(self, other): - return cmp(self.scanner, other.scanner) or cmp(self.d, other.d) class MyNode_without_target_from_source: def __init__(self, name): @@ -143,6 +132,8 @@ class MyNode_without_target_from_source: self.sources = [] self.builder = None self.side_effect = 0 + self.source_scanner = None + self.backup_source_scanner = None def __str__(self): return self.name def builder_set(self, builder): @@ -859,8 +850,8 @@ class BuilderTestCase(unittest.TestCase): source_scanner=sscan, action='') tgt = builder(env, target='foo2', source='bar')[0] - assert tgt.builder.target_scanner == tscan, tgt.builder.target_scanner - assert tgt.builder.source_scanner == sscan, tgt.builder.source_scanner + assert tgt.target_scanner == tscan, tgt.target_scanner + assert tgt.source_scanner == sscan, tgt.source_scanner builder1 = SCons.Builder.Builder(action='foo', src_suffix='.bar', @@ -870,8 +861,8 @@ class BuilderTestCase(unittest.TestCase): target_scanner = tscan, source_scanner = tscan) tgt = builder2(env, target='baz2', source='test.bar test2.foo test3.txt')[0] - assert tgt.builder.target_scanner == tscan, tgt.builder.target_scanner - assert tgt.builder.source_scanner == tscan, tgt.builder.source_scanner + assert tgt.target_scanner == tscan, tgt.target_scanner + assert tgt.source_scanner == tscan, tgt.source_scanner def test_actual_scanner(self): """Test usage of actual Scanner objects.""" @@ -897,82 +888,28 @@ class BuilderTestCase(unittest.TestCase): return 'TestScannerkey' def instance(self, env): return self - name = 'TestScanner' - def __str__(self): - return self.name scanner = TestScanner() builder = SCons.Builder.Builder(action='action') # With no scanner specified, source_scanner and # backup_source_scanner are None. - bar_y = MyNode('bar.y') env1 = Environment() tgt = builder(env1, target='foo1.x', source='bar.y')[0] src = tgt.sources[0] - assert tgt.builder.target_scanner != scanner, tgt.builder.target_scanner - assert tgt.builder.source_scanner is None, tgt.builder.source_scanner - assert tgt.get_source_scanner(bar_y) is None, tgt.get_source_scanner(bar_y) - assert not src.has_builder(), src.has_builder() - assert src.get_source_scanner(bar_y) is None, src.get_source_scanner(bar_y) - - # An Environment that has suffix-specified SCANNERS should - # provide a source scanner to the target. - class EnvTestScanner: - def key(self, env): - return '.y' - def instance(self, env): - return self - name = 'EnvTestScanner' - def __str__(self): - return self.name - def select(self, scanner): - return self - def path(self, env, dir=None): - return () - def __call__(self, node, env, path): - return [] - env3 = Environment(SCANNERS = [EnvTestScanner()]) - env3.scanner = EnvTestScanner() # test env's version of SCANNERS - tgt = builder(env3, target='foo2.x', source='bar.y')[0] - src = tgt.sources[0] - assert tgt.builder.target_scanner != scanner, tgt.builder.target_scanner - assert not tgt.builder.source_scanner, tgt.builder.source_scanner - assert tgt.get_source_scanner(bar_y), tgt.get_source_scanner(bar_y) - assert str(tgt.get_source_scanner(bar_y)) == 'EnvTestScanner', tgt.get_source_scanner(bar_y) - assert not src.has_builder(), src.has_builder() - assert src.get_source_scanner(bar_y) is None, src.get_source_scanner(bar_y) - - # Can't simply specify the scanner as a builder argument; it's - # global to all invocations of this builder. - tgt = builder(env3, target='foo3.x', source='bar.y', source_scanner = scanner)[0] + assert tgt.target_scanner != scanner, tgt.target_scanner + assert src.source_scanner is None, src.source_scanner + assert src.backup_source_scanner is None, src.backup_source_scanner + + # Later use of the same source file with an environment that + # has a scanner must still set the scanner. + env2 = Environment() + env2.scanner = scanner + tgt = builder(env2, target='foo2.x', source='bar.y')[0] src = tgt.sources[0] - assert tgt.builder.target_scanner != scanner, tgt.builder.target_scanner - assert not tgt.builder.source_scanner, tgt.builder.source_scanner - assert tgt.get_source_scanner(bar_y), tgt.get_source_scanner(bar_y) - assert str(tgt.get_source_scanner(bar_y)) == 'EnvTestScanner', tgt.get_source_scanner(bar_y) - assert not src.has_builder(), src.has_builder() - assert src.get_source_scanner(bar_y) is None, src.get_source_scanner(bar_y) - - # Now use a builder that actually has scanners and ensure that - # the target is set accordingly (using the specified scanner - # instead of the Environment's scanner) - builder = SCons.Builder.Builder(action='action', - source_scanner=scanner, - target_scanner=scanner) - tgt = builder(env3, target='foo4.x', source='bar.y')[0] - src = tgt.sources[0] - assert tgt.builder.target_scanner == scanner, tgt.builder.target_scanner - assert tgt.builder.source_scanner, tgt.builder.source_scanner - assert tgt.builder.source_scanner == scanner, tgt.builder.source_scanner - assert str(tgt.builder.source_scanner) == 'TestScanner', str(tgt.builder.source_scanner) - assert tgt.get_source_scanner(bar_y), tgt.get_source_scanner(bar_y) - assert tgt.get_source_scanner(bar_y) == scanner, tgt.get_source_scanner(bar_y) - assert str(tgt.get_source_scanner(bar_y)) == 'TestScanner', tgt.get_source_scanner(bar_y) - assert not src.has_builder(), src.has_builder() - assert src.get_source_scanner(bar_y) is None, src.get_source_scanner(bar_y) - - + assert tgt.target_scanner != scanner, tgt.target_scanner + assert src.source_scanner is None, src.source_scanner + assert src.backup_source_scanner == scanner, src.backup_source_scanner def test_Builder_API(self): """Test Builder interface. diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 947963f..2bd68e1 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -1769,7 +1769,7 @@ class File(Base): return csig - def current(self, calc=None): + def current(self, calc=None, scan=1): self.binfo = self.gen_binfo(calc) if self.always_build: return None diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index ebaf3b9..2259b7b 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -93,7 +93,6 @@ class Builder: self.env = Environment() self.overrides = {} self.action = action - self.target_scanner = None def targets(self, t): return [t] @@ -802,7 +801,7 @@ class FSTestCase(unittest.TestCase): f1.builder_set(Builder(fs.File)) f1.env_set(Environment()) xyz = fs.File("xyz") - f1.builder.target_scanner = Scanner(xyz) + f1.target_scanner = Scanner(xyz) f1.scan() assert f1.implicit[0].path == "xyz" diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index b9b1b1f..f8cd62b 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -91,18 +91,12 @@ class Environment: return apply(Environment, (), d) def _update(self, dict): self._dict.update(dict) - def get_calculator(self): - return SCons.Sig.default_calc - def get_scanner(self, scanner_key): - return self._dict['SCANNERS'][0] class Builder: - def __init__(self, env=None): - if env is None: env = Environment() - self.env = env + def __init__(self): + self.env = Environment() self.overrides = {} self.action = MyAction() - self.source_factory = MyNode def targets(self, t): return [t] def get_actions(self): @@ -710,6 +704,8 @@ class NodeTestCase(unittest.TestCase): def test_get_source_scanner(self): """Test fetching the source scanner for a Node """ + class Builder: + pass target = SCons.Node.Node() source = SCons.Node.Node() s = target.get_source_scanner(source) @@ -719,34 +715,19 @@ class NodeTestCase(unittest.TestCase): ts2 = Scanner() ts3 = Scanner() - class Builder1(Builder): - def __call__(self, source): - r = SCons.Node.Node() - r.builder = self - return [r] - class Builder2 (Builder1): - def __init__(self, source_scanner): - self.source_scanner = source_scanner - - builder = Builder2(ts1) - - targets = builder([source]) - s = targets[0].get_source_scanner(source) + source.backup_source_scanner = ts1 + s = target.get_source_scanner(source) assert s is ts1, s - target.builder_set(Builder2(ts1)) + target.builder = Builder() target.builder.source_scanner = ts2 s = target.get_source_scanner(source) assert s is ts2, s - builder = Builder1(env=Environment(SCANNERS = [ts3])) - - targets = builder([source]) - - s = targets[0].get_source_scanner(source) + target.source_scanner = ts3 + s = target.get_source_scanner(source) assert s is ts3, s - def test_scan(self): """Test Scanner functionality """ @@ -758,7 +739,8 @@ class NodeTestCase(unittest.TestCase): d = MyNode("ddd") node.found_includes = [d] - node.builder.target_scanner = s + assert node.target_scanner == None, node.target_scanner + node.target_scanner = s assert node.implicit is None node.scan() @@ -791,14 +773,12 @@ class NodeTestCase(unittest.TestCase): try: sn = StoredNode("eee") sn._children = ['fake'] - sn.builder_set(Builder()) - sn.builder.target_scanner = s + sn.target_scanner = s sn.scan() assert sn.implicit == [], sn.implicit - assert sn._children == [], sn._children - + assert not hasattr(sn, '_children'), "unexpected _children attribute" finally: SCons.Sig.default_calc = save_default_calc SCons.Node.implicit_cache = save_implicit_cache diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 27e185e..338df07 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -67,7 +67,7 @@ executed = 4 failed = 5 stack = 6 # nodes that are in the current Taskmaster execution stack -# controls whether implicit dependencies are cached: +# controls whether implicit depedencies are cached: implicit_cache = 0 # controls whether implicit dep changes are ignored: @@ -118,6 +118,9 @@ class Node: self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) self.waiting_parents = [] self.wkids = None # Kids yet to walk, when it's an array + self.target_scanner = None # explicit scanner from this node's Builder + self.source_scanner = None + self.backup_source_scanner = None self.env = None self.state = None @@ -399,17 +402,15 @@ class Node: NOTE: "self" is the target being built, "node" is the source file for which we want to fetch the scanner. """ - if not self.has_builder(): - return None # if not buildable, can't have sources... + if self.source_scanner: + return self.source_scanner try: scanner = self.builder.source_scanner if scanner: return scanner except AttributeError: pass - - # No scanner specified by builder, try env['SCANNERS'] - return self.get_build_env().get_scanner(node.scanner_key()) + return node.backup_source_scanner or None def scan(self): """Scan this node's dependents for implicit dependencies.""" @@ -433,7 +434,7 @@ class Node: implicit = map(self.implicit_factory, implicit) self._add_child(self.implicit, self.implicit_dict, implicit) calc = build_env.get_calculator() - if implicit_deps_unchanged or self.current(calc): + if implicit_deps_unchanged or self.current(calc, scan=0): return else: # one of this node's sources has changed, so @@ -451,10 +452,8 @@ class Node: self._add_child(self.implicit, self.implicit_dict, deps) # scan this node itself for implicit dependencies - scanner = self.builder.target_scanner - if scanner: - deps = self.get_implicit_deps(build_env, scanner, self) - self._add_child(self.implicit, self.implicit_dict, deps) + deps = self.get_implicit_deps(build_env, self.target_scanner, self) + self._add_child(self.implicit, self.implicit_dict, deps) # XXX See note above re: --implicit-cache. #if implicit_cache: diff --git a/src/engine/SCons/Tool/linkloc.py b/src/engine/SCons/Tool/linkloc.py index 3c25760..867b788 100644 --- a/src/engine/SCons/Tool/linkloc.py +++ b/src/engine/SCons/Tool/linkloc.py @@ -94,7 +94,8 @@ def generate(env): env['LIBLINKPREFIX']='-lib ' env['LIBLINKSUFFIX']='$LIBSUFFIX' - include_path, lib_path, exe_path = get_msvc_paths(env['MSVS_VERSION']) + msvs_version = env.get('MSVS_VERSION') + include_path, lib_path, exe_path = get_msvc_paths(msvs_version) env['ENV']['LIB'] = lib_path env['ENV']['PATH'] = exe_path diff --git a/test/Command.py b/test/Command.py index 5266886..eddc1f5 100644 --- a/test/Command.py +++ b/test/Command.py @@ -65,7 +65,7 @@ def sub(env, target, source): t.close() return 0 -env = Environment(COPY_THROUGH_TEMP = "cp $SOURCE .tmp\\ncp .tmp $TARGET", +env = Environment(COPY_THROUGH_TEMP = "%(python)s build.py .tmp $SOURCE\\n%(python)s build.py $TARGET .tmp", EXPAND = "$COPY_THROUGH_TEMP") env.Command(target = 'f1.out', source = 'f1.in', action = buildIt) diff --git a/test/Scanner.py b/test/Scanner.py index 828d198..2814759 100644 --- a/test/Scanner.py +++ b/test/Scanner.py @@ -88,6 +88,7 @@ k2scan = env.Scanner(name = 'k2', ########################################################## # Test scanner as found automatically from the environment +# (backup_source_scanner) env = Environment() env.Append(SCANNERS = kscan) @@ -102,15 +103,14 @@ env2.Append(SCANNERS = [k2scan]) env2.Command('junk', 'junk.k2', r'%(python)s build.py $SOURCES $TARGET') ########################################################## -# Test specifying a specific source scanner for a Builder +# Test specifying a specific source scanner for a target Node -bar = env.Command('bar', 'bar.in', - r'%(python)s build.py $SOURCES $TARGET', - source_scanner=kscan) +bar = env.Command('bar', 'bar.in', r'%(python)s build.py $SOURCES $TARGET') +bar[0].source_scanner = kscan ########################################################## -# Test specifying a source scanner for an intermediary Builder to -# ensure that the right scanner gets used for the right nodes. +# Test specifying a source scanner for a Builder that gets +# automatically applied to targets generated from that Builder import string diff --git a/test/chdir.py b/test/chdir.py index e2d0894..9a77d75 100644 --- a/test/chdir.py +++ b/test/chdir.py @@ -91,8 +91,9 @@ other9_f19_in = test.workpath('other9', 'f19.in') test.write(cat_py, """\ import sys -ofp = open(sys.argv[1], 'w') -for ifp in map(open, sys.argv[2:]): +ofp = open(sys.argv[1], 'wb') +for f in sys.argv[2:]: + ifp = open(f, 'rb') ofp.write(ifp.read()) ofp.close """) @@ -223,7 +224,7 @@ test.must_match(['work1', 'sub23', 'f23.out'], "work1/sub23/f23.in\n") test.subdir('work2', ['work2', 'sub']) -work2 = test.workpath('work2') +work2 = repr(test.workpath('work2')) work2_sub_f1_out = test.workpath('work2', 'sub', 'f1.out') work2_sub_f2_out = test.workpath('work2', 'sub', 'f2.out') @@ -246,11 +247,11 @@ test.write(['work2', 'sub', 'f2.in'], "work2/sub/f2.in") expect = test.wrap_stdout("""\ os.chdir('sub') %(python)s %(cat_py)s f1.out f1.in -os.chdir('%(work2)s') +os.chdir(%(work2)s) os.chdir('sub') %(python)s %(cat_py)s .temp f2.in %(python)s %(cat_py)s f2.out .temp -os.chdir('%(work2)s') +os.chdir(%(work2)s) """ % locals()) test.run(chdir='work2', arguments='-n .', stdout=expect) diff --git a/test/option/debug-findlibs.py b/test/option/debug-findlibs.py index 4827ab0..b18841b 100644 --- a/test/option/debug-findlibs.py +++ b/test/option/debug-findlibs.py @@ -36,8 +36,9 @@ test.subdir('sub1', 'sub2') test.write('cat.py', """\ import sys -ofp = open(sys.argv[1], "w") -for ifp in map(open, sys.argv[2:]): +ofp = open(sys.argv[1], 'wb') +for f in sys.argv[2:]: + ifp = open(f, 'rb') ofp.write(ifp.read()) ofp.close() """) diff --git a/test/srcchange.py b/test/srcchange.py index 2188bcc..ef92aea 100644 --- a/test/srcchange.py +++ b/test/srcchange.py @@ -61,18 +61,19 @@ content_env=env.Copy() content_env.TargetSignatures('content') content_env.Command('revision.in', [], '%(python)s getrevision > $TARGET') content_env.AlwaysBuild('revision.in') -env.Precious('main.cpp') -env.Command('main.cpp', 'revision.in', SubRevision) -exe = env.Program('main.cpp') +env.Precious('main.c') +env.Command('main.c', 'revision.in', SubRevision) +exe = env.Program('main.c') env.Default(exe) """ % {'python':TestSCons.python}) -test.write('main.cpp', """\ -#include +test.write('main.c', """\ +#include int main(int argc, char *argv[]) { - std::cout << "Revision $REV$" << std::endl; + printf("Revision $REV$\\n"); + exit (0); } """) @@ -80,18 +81,11 @@ test.write('revnum.in', '3.2\n') prog = 'main' + TestSCons._exe -full_build=test.wrap_stdout("""\ -%(python)s getrevision > revision.in -subrevision(["main.cpp"], ["revision.in"]) -g++ -c -o main.o main.cpp -g++ -o main main.o -""" % {'python':TestSCons.python}) - light_build=test.wrap_stdout("""\ %(python)s getrevision > revision.in """ % {'python':TestSCons.python}) -test.run(arguments='.', stdout=full_build) +test.run(arguments='.') test.must_exist(prog) test.run(program=test.workpath(prog), stdout='Revision $REV: 3.2$\n') @@ -103,7 +97,7 @@ test.must_exist(prog) test.write('revnum.in', '3.3\n') -test.run(arguments='.', stdout=full_build) +test.run(arguments='.') test.must_exist(prog) test.run(program=test.workpath(prog), stdout='Revision $REV: 3.3$\n') -- cgit v0.12