Bug fixes for Scanner handling of subdirectories and Environment copying, courtesy...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 13 Dec 2001 04:42:05 +0000 (04:42 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 13 Dec 2001 04:42:05 +0000 (04:42 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@146 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/engine/SCons/Builder.py
src/engine/SCons/BuilderTests.py
src/engine/SCons/Environment.py
src/engine/SCons/EnvironmentTests.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Node/NodeTests.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Scanner/C.py
src/engine/SCons/Scanner/CTests.py

index a5784059576a8dd6204723eda3de22c3d2d927e0..c7551afc5716ab80e18753aff598192609a8706c 100644 (file)
@@ -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)
index d563bb6161a9f5aed93a3ecbb4edf6e893887d64..575cb7755879f5c6392cc87704a4f5b3cefe3fd8 100644 (file)
@@ -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_')
index b93a3dd2ecd65ee4afb48ac1b1a2eba4501c4748..69455e7156eac902a43cea9e13ba61d357d425e1 100644 (file)
@@ -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'."""
index af9ccb73bf50b4e9bad409577b432e662c1cf59b..3ba8ad4e85040558b3f574a614d570a12e72be95 100644 (file)
@@ -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
 
index cd12f6d810e720a5c68ccb85add6cf5b1a4ad098..648e1f91ebf24111b2bb5333399a74e17007010b 100644 (file)
@@ -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
index aecbfb40c2da989a7dea1de71980955b9172b12f..523f96b9afcaffc5df9d14ad25298525eaf3b3f3 100644 (file)
@@ -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"))
index 9dec623c00c5011c0e35dc0215f620e21a074496..673ab2573ff27dd35dd374f4c35a5b6beff5c664 100644 (file)
@@ -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.
        """
index 17bf539c12136789cfb2cf553c0f48a1ef1ad2f7..ddcddfb9a13492d6cb74eb9c67c2a19e6f862263 100644 (file)
@@ -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:
index 589aef69937108a040669a213bd9afbb4bf6b029..8ad7e002b5e366fbd0cab661390756ff369854ed 100644 (file)
@@ -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,
index ca4abf037fc05508e7acc1a2fcf401816cec6fc5..bc30fa4805febc7918682004fde51cdb8cef0549 100644 (file)
@@ -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__":