diff options
author | Steven Knight <knight@baldmt.com> | 2003-01-12 16:25:20 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2003-01-12 16:25:20 (GMT) |
commit | 5d3b3d8891c805fe334be3cd71a2670b5c76d65a (patch) | |
tree | 02c6faa63bafe79bd10f4b51aaba813f86725aa9 /src/engine/SCons/Scanner | |
parent | e1c2427eeba11db45c65fbefb38d7f4b603121f0 (diff) | |
download | SCons-5d3b3d8891c805fe334be3cd71a2670b5c76d65a.zip SCons-5d3b3d8891c805fe334be3cd71a2670b5c76d65a.tar.gz SCons-5d3b3d8891c805fe334be3cd71a2670b5c76d65a.tar.bz2 |
Eliminate unnecessary scanning before a Node is rebuilt.
Diffstat (limited to 'src/engine/SCons/Scanner')
-rw-r--r-- | src/engine/SCons/Scanner/C.py | 11 | ||||
-rw-r--r-- | src/engine/SCons/Scanner/CTests.py | 4 | ||||
-rw-r--r-- | src/engine/SCons/Scanner/Fortran.py | 7 | ||||
-rw-r--r-- | src/engine/SCons/Scanner/FortranTests.py | 19 | ||||
-rw-r--r-- | src/engine/SCons/Scanner/ScannerTests.py | 65 | ||||
-rw-r--r-- | src/engine/SCons/Scanner/__init__.py | 54 |
6 files changed, 106 insertions, 54 deletions
diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py index cbcf1c6..b9f2d8f 100644 --- a/src/engine/SCons/Scanner/C.py +++ b/src/engine/SCons/Scanner/C.py @@ -45,11 +45,12 @@ include_re = re.compile('^[ \t]*#[ \t]*include[ \t]+(<|")([^>"]+)(>|")', re.M) def CScan(fs = SCons.Node.FS.default_fs): """Return a prototype Scanner instance for scanning source files that use the C pre-processor""" - cs = SCons.Scanner.Recursive(scan, "CScan", fs, - [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", - ".h", ".H", ".hxx", ".hpp", ".hh", - ".F", ".fpp", ".FPP"], - path_function = path) + cs = SCons.Scanner.Current(scan, "CScan", fs, + [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", + ".h", ".H", ".hxx", ".hpp", ".hh", + ".F", ".fpp", ".FPP"], + path_function = path, + recursive = 1) return cs def path(env, dir, fs = SCons.Node.FS.default_fs): diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py index f02474c..8f5a7dd 100644 --- a/src/engine/SCons/Scanner/CTests.py +++ b/src/engine/SCons/Scanner/CTests.py @@ -208,7 +208,7 @@ class CScannerTestCase1(unittest.TestCase): s = SCons.Scanner.C.CScan() path = s.path(env) deps = s(make_node('f1.cpp'), env, path) - headers = ['f1.h', 'f2.h', 'fi.h'] + headers = ['f1.h', 'f2.h'] deps_match(self, deps, map(test.workpath, headers)) class CScannerTestCase2(unittest.TestCase): @@ -258,7 +258,7 @@ class CScannerTestCase5(unittest.TestCase): assert n.rexists_called headers = ['d1/f1.h', 'd1/f2.h', 'd1/f3-test.h', - 'f1.h', 'f2.h', 'f3-test.h', 'fi.h', 'fj.h'] + 'f1.h', 'f2.h', 'f3-test.h'] deps_match(self, deps, map(test.workpath, headers)) class CScannerTestCase6(unittest.TestCase): diff --git a/src/engine/SCons/Scanner/Fortran.py b/src/engine/SCons/Scanner/Fortran.py index e23c7a5..034d5ac 100644 --- a/src/engine/SCons/Scanner/Fortran.py +++ b/src/engine/SCons/Scanner/Fortran.py @@ -45,9 +45,10 @@ include_re = re.compile("INCLUDE[ \t]+'([\\w./\\\\]+)'", re.M) def FortranScan(fs = SCons.Node.FS.default_fs): """Return a prototype Scanner instance for scanning source files for Fortran INCLUDE statements""" - scanner = SCons.Scanner.Recursive(scan, "FortranScan", fs, - [".f", ".F", ".for", ".FOR"], - path_function = path) + scanner = SCons.Scanner.Current(scan, "FortranScan", fs, + [".f", ".F", ".for", ".FOR"], + path_function = path, + recursive = 1) return scanner def path(env, dir, fs = SCons.Node.FS.default_fs): diff --git a/src/engine/SCons/Scanner/FortranTests.py b/src/engine/SCons/Scanner/FortranTests.py index f721d89..03165df 100644 --- a/src/engine/SCons/Scanner/FortranTests.py +++ b/src/engine/SCons/Scanner/FortranTests.py @@ -92,6 +92,15 @@ test.write('fff4.f',""" test.write('include/f4.f', "\n") test.write('subdir/include/f4.f', "\n") +test.write('fff5.f',""" + PROGRAM FOO + INCLUDE 'f5.f' + INCLUDE 'not_there.f' + STOP + END +""") + +test.write('f5.f', "\n") test.subdir('repository', ['repository', 'include'], [ 'repository', 'src' ]) @@ -173,7 +182,7 @@ class FortranScannerTestCase1(unittest.TestCase): path = s.path(env) fs = SCons.Node.FS.FS(original) deps = s(make_node('fff1.f', fs), env, path) - headers = ['f1.f', 'f2.f', 'fi.f'] + headers = ['f1.f', 'f2.f'] deps_match(self, deps, map(test.workpath, headers)) test.unlink('f1.f') test.unlink('f2.f') @@ -187,7 +196,7 @@ class FortranScannerTestCase2(unittest.TestCase): path = s.path(env) fs = SCons.Node.FS.FS(original) deps = s(make_node('fff1.f', fs), env, path) - headers = ['f1.f', 'f2.f', 'fi.f'] + headers = ['f1.f', 'f2.f'] deps_match(self, deps, map(test.workpath, headers)) test.unlink('f1.f') test.unlink('f2.f') @@ -309,18 +318,16 @@ class FortranScannerTestCase11(unittest.TestCase): to = TestOut() to.out = None SCons.Warnings._warningOut = to - test.write('f4.f'," INCLUDE 'not_there.f'\n") fs = SCons.Node.FS.FS(test.workpath('')) env = DummyEnvironment([]) s = SCons.Scanner.Fortran.FortranScan(fs=fs) path = s.path(env) - deps = s(fs.File('fff4.f'), env, path) + deps = s(fs.File('fff5.f'), env, path) # Did we catch the warning from not finding not_there.f? assert to.out - deps_match(self, deps, [ 'f4.f' ]) - test.unlink('f4.f') + deps_match(self, deps, [ 'f5.f' ]) class FortranScannerTestCase12(unittest.TestCase): def runTest(self): diff --git a/src/engine/SCons/Scanner/ScannerTests.py b/src/engine/SCons/Scanner/ScannerTests.py index 7280c2f..431e7ae 100644 --- a/src/engine/SCons/Scanner/ScannerTests.py +++ b/src/engine/SCons/Scanner/ScannerTests.py @@ -122,7 +122,7 @@ class ScannerHashTestCase(ScannerTestBase, unittest.TestCase): "did not hash Scanner base class as expected") class ScannerCheckTestCase(unittest.TestCase): - "Test the Scanner.Base class __hash__() method" + "Test the Scanner.Base class scan_check method" def setUp(self): self.checked = {} def runTest(self): @@ -138,6 +138,67 @@ class ScannerCheckTestCase(unittest.TestCase): self.failUnless(self.checked['x'] == 1, "did not call check function") +class ScannerRecursiveTestCase(ScannerTestBase, unittest.TestCase): + "Test the Scanner.Base class recursive flag" + def runTest(self): + s = SCons.Scanner.Base(function = self.func) + self.failUnless(s.recursive == None, + "incorrect default recursive value") + s = SCons.Scanner.Base(function = self.func, recursive = None) + self.failUnless(s.recursive == None, + "did not set recursive flag to None") + s = SCons.Scanner.Base(function = self.func, recursive = 1) + self.failUnless(s.recursive == 1, + "did not set recursive flag to 1") + +class CurrentTestCase(ScannerTestBase, unittest.TestCase): + "Test the Scanner.Current class" + def runTest(self): + class MyNode: + def __init__(self): + self.called_has_builder = None + self.called_current = None + self.func_called = None + class HasNoBuilder(MyNode): + def has_builder(self): + self.called_has_builder = 1 + return None + class IsNotCurrent(MyNode): + def has_builder(self): + self.called_has_builder = 1 + return 1 + def current(self, sig): + self.called_current = 1 + return None + class IsCurrent(MyNode): + def has_builder(self): + self.called_has_builder = 1 + return 1 + def current(self, sig): + self.called_current = 1 + return 1 + def func(node, env, path): + node.func_called = 1 + return [] + env = DummyEnvironment() + s = SCons.Scanner.Current(func) + path = s.path(env) + hnb = HasNoBuilder() + s(hnb, env, path) + self.failUnless(hnb.called_has_builder, "did not call has_builder()") + self.failUnless(not hnb.called_current, "did call current()") + self.failUnless(hnb.func_called, "did not call func()") + inc = IsNotCurrent() + s(inc, env, path) + self.failUnless(inc.called_has_builder, "did not call has_builder()") + self.failUnless(inc.called_current, "did not call current()") + self.failUnless(not inc.func_called, "did call func()") + ic = IsCurrent() + s(ic, env, path) + self.failUnless(ic.called_has_builder, "did not call has_builder()") + self.failUnless(ic.called_current, "did not call current()") + self.failUnless(ic.func_called, "did not call func()") + def suite(): suite = unittest.TestSuite() suite.addTest(ScannerPositionalTestCase()) @@ -146,6 +207,8 @@ def suite(): suite.addTest(ScannerKeywordArgumentTestCase()) suite.addTest(ScannerHashTestCase()) suite.addTest(ScannerCheckTestCase()) + suite.addTest(ScannerRecursiveTestCase()) + suite.addTest(CurrentTestCase()) return suite if __name__ == "__main__": diff --git a/src/engine/SCons/Scanner/__init__.py b/src/engine/SCons/Scanner/__init__.py index c27c762..cd157af 100644 --- a/src/engine/SCons/Scanner/__init__.py +++ b/src/engine/SCons/Scanner/__init__.py @@ -31,6 +31,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.Node.FS +import SCons.Sig import SCons.Util @@ -55,7 +56,8 @@ class Base: path_function = None, node_class = SCons.Node.FS.Entry, node_factory = SCons.Node.FS.default_fs.File, - scan_check = None): + scan_check = None, + recursive = None): """ Construct a new scanner object given a scanner function. @@ -88,6 +90,10 @@ class Base: 'scan_check' - a function to be called to first check whether this node really needs to be scanned. + 'recursive' - specifies that this scanner should be invoked + recursively on the implicit dependencies it returns (the + canonical example being #include lines in C source files). + The scanner function's first argument will be the name of a file that should be scanned for dependencies, the second argument will be an Environment object, the third argument will be the value @@ -117,6 +123,7 @@ class Base: self.node_class = node_class self.node_factory = node_factory self.scan_check = scan_check + self.recursive = recursive def path(self, env, dir = None): if not self.path_function: @@ -160,43 +167,16 @@ class Base: """Add a skey to the list of skeys""" self.skeys.append(skey) -class RExists(Base): +class Current(Base): """ - Scan a node only if it exists (locally or in a Repository). + A class for scanning files that are source files (have no builder) + or are derived files and are current (which implies that they exist, + either locally or in a repository). """ + def __init__(self, *args, **kw): - def rexists_check(node): - return node.rexists() - kw['scan_check'] = rexists_check + def current_check(node): + c = not node.has_builder() or node.current(SCons.Sig.default_calc) + return c + kw['scan_check'] = current_check apply(Base.__init__, (self,) + args, kw) - -class Recursive(RExists): - """ - The class for recursive dependency scanning. This will - re-scan any new files returned by each call to the - underlying scanning function, and return the aggregate - list of all dependencies. - """ - - def __call__(self, node, env, path = ()): - """ - This method does the actual scanning. 'node' is the node - that will be passed to the scanner function, and 'env' is the - environment that will be passed to the scanner function. An - aggregate list of dependency nodes for the specified filename - and any of its scanned dependencies will be returned. - """ - - nodes = [node] - seen = {node : 0} - deps = [] - while nodes: - n = nodes.pop(0) - d = filter(lambda x, seen=seen: not seen.has_key(x), - Base.__call__(self, n, env, path)) - if d: - deps.extend(d) - nodes.extend(d) - for n in d: - seen[n] = 0 - return deps |