From c81b4be9b7a06dc41cc1f425887d4600fa47f0bc Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Thu, 13 Dec 2001 04:42:05 +0000 Subject: Bug fixes for Scanner handling of subdirectories and Environment copying, courtesy Charles Crain. --- src/engine/SCons/Builder.py | 2 +- src/engine/SCons/BuilderTests.py | 8 ++++---- src/engine/SCons/Environment.py | 35 ++++++++++++++++++----------------- src/engine/SCons/EnvironmentTests.py | 15 +++++++++++++++ src/engine/SCons/Node/FS.py | 11 ++++++----- src/engine/SCons/Node/FSTests.py | 11 ++++++----- src/engine/SCons/Node/NodeTests.py | 12 ++++++++++++ src/engine/SCons/Node/__init__.py | 8 +++++--- src/engine/SCons/Scanner/C.py | 5 ++--- src/engine/SCons/Scanner/CTests.py | 25 ++++++++++++++++++++++++- 10 files changed, 93 insertions(+), 39 deletions(-) diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index a578405..c7551af 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -236,7 +236,7 @@ class MultiStepBuilder(BuilderBase): final_sources = [] src_suffix = env.subst(self.src_suffix) for snode in slist: - path, ext = os.path.splitext(snode.path) + path, ext = os.path.splitext(snode.abspath) if not src_suffix or ext != src_suffix: tgt = self.src_builder(env, target = [ path ], source=snode) diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index d563bb6..575cb77 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -400,7 +400,7 @@ class BuilderTestCase(unittest.TestCase): scn = TestScanner() builder=SCons.Builder.Builder(scanner=scn) tgt = builder(env, target='foo', source='bar') - assert tgt.scanner == scn, tgt.scanner + assert scn in tgt.scanners, tgt.scanners assert instanced instanced = None @@ -411,7 +411,7 @@ class BuilderTestCase(unittest.TestCase): src_builder = builder1, scanner = scn) tgt = builder2(env, target='baz', source='test.bar test2.foo test3.txt') - assert tgt.scanner == scn, tgt.scanner + assert scn in tgt.scanners, tgt.scanners assert instanced def test_src_scanner(slf): @@ -425,8 +425,8 @@ class BuilderTestCase(unittest.TestCase): env_scanner = TestScanner() builder = SCons.Builder.Builder(action='action') tgt = builder(env, target='foo', source='bar') - assert not tgt.scanner == env_scanner - assert tgt.sources[0].scanner == env_scanner + assert not tgt.scanners == [ env_scanner ] + assert tgt.sources[0].scanners == [ env_scanner ] if __name__ == "__main__": suite = unittest.makeSuite(BuilderTestCase, 'test_') diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index b93a3dd..69455e7 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -37,6 +37,7 @@ import re import types import SCons.Util import SCons.Builder +import SCons.Defaults from SCons.Errors import UserError from UserList import UserList @@ -49,19 +50,18 @@ def Install(): def InstallAs(): pass # XXX - - -def _deepcopy_atomic(x, memo): - return x -copy._deepcopy_dispatch[types.ModuleType] = _deepcopy_atomic -copy._deepcopy_dispatch[types.ClassType] = _deepcopy_atomic -copy._deepcopy_dispatch[types.FunctionType] = _deepcopy_atomic -copy._deepcopy_dispatch[types.MethodType] = _deepcopy_atomic -copy._deepcopy_dispatch[types.TracebackType] = _deepcopy_atomic -copy._deepcopy_dispatch[types.FrameType] = _deepcopy_atomic -copy._deepcopy_dispatch[types.FileType] = _deepcopy_atomic - - +def our_deepcopy(x): + """deepcopy lists and dictionaries, and just copy the reference + for everything else.""" + if type(x) is type({}): + copy = {} + for key in x.keys(): + copy[key] = our_deepcopy(x[key]) + elif type(x) is type([]): + copy = map(our_deepcopy, x) + else: + copy = x + return copy class Environment: """Base class for construction Environments. These are @@ -75,12 +75,12 @@ class Environment: def __init__(self, **kw): import SCons.Defaults - self._dict = copy.deepcopy(SCons.Defaults.ConstructionEnvironment) + self._dict = our_deepcopy(SCons.Defaults.ConstructionEnvironment) if kw.has_key('BUILDERS') and type(kw['BUILDERS']) != type([]): kw['BUILDERS'] = [kw['BUILDERS']] if kw.has_key('SCANNERS') and type(kw['SCANNERS']) != type([]): kw['SCANNERS'] = [kw['SCANNERS']] - self._dict.update(copy.deepcopy(kw)) + self._dict.update(our_deepcopy(kw)) class BuilderWrapper: """Wrapper class that allows an environment to @@ -124,7 +124,8 @@ class Environment: (like a function). There are no references to any mutable objects in the original Environment. """ - clone = copy.deepcopy(self) + clone = copy.copy(self) + clone._dict = our_deepcopy(self._dict) apply(clone.Update, (), kw) return clone @@ -135,7 +136,7 @@ class Environment: """Update an existing construction Environment with new construction variables and/or values. """ - self._dict.update(copy.deepcopy(kw)) + self._dict.update(our_deepcopy(kw)) def Depends(self, target, dependency): """Explicity specify that 'target's depend on 'dependency'.""" diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index af9ccb7..3ba8ad4 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -159,6 +159,21 @@ class EnvironmentTestCase(unittest.TestCase): assert env3.Dictionary('ZZZ') == 'z3' assert env1 == env1copy + # Ensure that lists and dictionaries are + # deep copied, but not instances. + class TestA: + pass + env1 = Environment(XXX=TestA(), YYY = [ 1, 2, 3 ], + ZZZ = { 1:2, 3:4 }) + env2=env1.Copy() + env2.Dictionary('YYY').append(4) + env2.Dictionary('ZZZ')[5] = 6 + assert env1.Dictionary('XXX') is env2.Dictionary('XXX') + assert 4 in env2.Dictionary('YYY') + assert not 4 in env1.Dictionary('YYY') + assert env2.Dictionary('ZZZ').has_key(5) + assert not env1.Dictionary('ZZZ').has_key(5) + def test_Dictionary(self): """Test retrieval of known construction variables diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index cd12f6d..648e1f9 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -466,11 +466,12 @@ class File(Entry): return self.dir.sconsign().get(self.name) def scan(self): - if not self.scanned.has_key(self.scanner) and self.env: - if self.scanner: - self.add_implicit(self.scanner.scan(self.path, self.env), - self.scanner) - self.scanned[self.scanner] = 1 + if self.env: + for scn in self.scanners: + if not self.scanned.has_key(scn): + self.add_implicit(scn.scan(self.path, self.env), + scn) + self.scanned[scn] = 1 def __createDir(self): # ensure that the directories for this node are diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index aecbfb4..523f96b 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -301,15 +301,16 @@ class FSTestCase(unittest.TestCase): match(e13.path, "subdir/subdir/e13") # Test scanning - f1.scanner = Scanner() + scn = Scanner() + f1.scanners = [ scn ] f1.scan() - assert f1.implicit[f1.scanner][0].path_ == os.path.join("d1", "f1") - del f1.implicit[f1.scanner] + assert f1.implicit[scn][0].path_ == os.path.join("d1", "f1") + del f1.implicit[scn] f1.scan() assert len(f1.implicit) == 0, f1.implicit - del f1.scanned[f1.scanner] + del f1.scanned[scn] f1.scan() - assert f1.implicit[f1.scanner][0].path_ == os.path.join("d1", "f1") + assert f1.implicit[scn][0].path_ == os.path.join("d1", "f1") # Test building a file whose directory is not there yet... f1 = fs.File(test.workpath("foo/bar/baz/ack")) diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 9dec623..673ab25 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -259,6 +259,18 @@ class NodeTestCase(unittest.TestCase): assert node.implicit[3] == [two, three] assert node.implicit[4] == [three, four, one] + def test_scan(self): + """Test Scanner functionality""" + class DummyScanner: + pass + ds=DummyScanner() + node = SCons.Node.Node() + assert node.scanners == [], node.scanners + node.scanner_set(ds) + assert node.scanners == [ ds ], node.scanners + node.scan() + assert node.scanned[ds] == 1, node.scanned + def test_children(self): """Test fetching the "children" of a Node. """ diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 17bf539..ddcddfb 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -60,7 +60,7 @@ class Node: self.implicit = {} # implicit (scanned) dependencies self.parents = [] self.builder = None - self.scanner = None + self.scanners = [] self.scanned = {} self.env = None self.state = None @@ -103,10 +103,12 @@ class Node: return Adapter(self) def scanner_set(self, scanner): - self.scanner = scanner + if not scanner in self.scanners: + self.scanners.append(scanner) def scan(self): - self.scanned[self.scanner] = 1 + for scn in self.scanners: + self.scanned[scn] = 1 def env_set(self, env, safe=0): if safe and self.env: diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py index 589aef6..8ad7e00 100644 --- a/src/engine/SCons/Scanner/C.py +++ b/src/engine/SCons/Scanner/C.py @@ -106,10 +106,9 @@ def scan(filename, env, args = [SCons.Node.FS.default_fs, ()]): dir = os.path.dirname(filename) if dir: - source_dir = (fs.Dir(dir),) + source_dir = (fs.Dir(dir, fs.Top),) else: - source_dir = () - + source_dir = ( fs.Top, ) return (SCons.Util.find_files(angle_includes, cpppath + source_dir, fs.File) + SCons.Util.find_files(quote_includes, source_dir + cpppath, diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py index ca4abf0..bc30fa4 100644 --- a/src/engine/SCons/Scanner/CTests.py +++ b/src/engine/SCons/Scanner/CTests.py @@ -206,7 +206,7 @@ class CScannerTestCase7(unittest.TestCase): dict = {} dict[s1] = 777 assert dict[s2] == 777 - + class CScannerTestCase8(unittest.TestCase): def runTest(self): fs = SCons.Node.FS.FS(test.workpath('')) @@ -220,6 +220,27 @@ class CScannerTestCase8(unittest.TestCase): deps_match(self, deps1, headers1) deps_match(self, deps2, headers2) +class CScannerTestCase9(unittest.TestCase): + def runTest(self): + fs = SCons.Node.FS.FS(test.workpath('')) + s = SCons.Scanner.C.CScan(fs=fs) + env = DummyEnvironment([]) + test.write('fa.h','\n') + deps = s.instance(env).scan('fa.cpp', None) + deps_match(self, deps, [ 'fa.h' ]) + test.unlink('fa.h') + +class CScannerTestCase10(unittest.TestCase): + def runTest(self): + fs = SCons.Node.FS.FS(test.workpath('')) + fs.chdir(fs.Dir('include')) + s = SCons.Scanner.C.CScan(fs=fs) + env = DummyEnvironment([]) + test.write('include/fa.cpp', test.read('fa.cpp')) + deps = s.instance(env).scan('include/fa.cpp', None) + deps_match(self, deps, [ 'include/fa.h', 'include/fb.h' ]) + test.unlink('include/fa.cpp') + def suite(): suite = unittest.TestSuite() suite.addTest(CScannerTestCase1()) @@ -230,6 +251,8 @@ def suite(): suite.addTest(CScannerTestCase6()) suite.addTest(CScannerTestCase7()) suite.addTest(CScannerTestCase8()) + suite.addTest(CScannerTestCase9()) + suite.addTest(CScannerTestCase10()) return suite if __name__ == "__main__": -- cgit v0.12