From 139a0052dc0bff059dc9b8cf1739396304e7c129 Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Thu, 22 Nov 2001 14:10:14 +0000 Subject: Complete CPPPATH work. --- src/engine/SCons/Scanner/C.py | 5 ++-- src/engine/SCons/Scanner/CTests.py | 21 ++++++++++++---- src/engine/SCons/Scanner/Prog.py | 2 +- src/engine/SCons/Scanner/ScannerTests.py | 8 +++--- src/engine/SCons/Scanner/__init__.py | 43 +++++++++++++++++++++++++++++--- test/CPPPATH.py | 40 +++++++++++++++++++++++------ 6 files changed, 96 insertions(+), 23 deletions(-) diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py index e2842e1..90cb141 100644 --- a/src/engine/SCons/Scanner/C.py +++ b/src/engine/SCons/Scanner/C.py @@ -40,8 +40,9 @@ quote_re = re.compile('^[ \t]*#[ \t]*include[ \t]+"([\\w./\\\\]+)"', re.M) def CScan(): "Return a Scanner instance for scanning C/C++ source files" - s = SCons.Scanner.Scanner(scan, SCons.Node.FS.default_fs.File, - [".c", ".C", ".cxx", ".cpp", ".c++"]) + s = SCons.Scanner.Recursive(scan, SCons.Node.FS.default_fs.File, + [".c", ".C", ".cxx", ".cpp", ".c++", + ".h", ".H", ".hxx", ".hpp"]) s.name = "CScan" return s diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py index e6bd29e..02a423b 100644 --- a/src/engine/SCons/Scanner/CTests.py +++ b/src/engine/SCons/Scanner/CTests.py @@ -79,13 +79,22 @@ int main() test.subdir('d1', ['d1', 'd2']) -headers = ['f1.h','f2.h', 'f3.h', 'never.h', - 'd1/f1.h', 'd1/f2.h', 'd1/f3.h', - 'd1/d2/f1.h', 'd1/d2/f2.h', 'd1/d2/f3.h', 'd1/d2/f4.h'] +headers = ['f1.h','f2.h', 'f3.h', 'fi.h', 'fj.h', 'never.h', + 'd1/f1.h', 'd1/f2.h', 'd1/f3.h', 'd1/fi.h', 'd1/fj.h', + 'd1/d2/f1.h', 'd1/d2/f2.h', 'd1/d2/f3.h', + 'd1/d2/f4.h', 'd1/d2/fi.h', 'd1/d2/fj.h'] for h in headers: test.write(h, " ") +test.write('f2.h',""" +#include "fi.h" +""") + +test.write('f3.h',""" +#include +""") + # define some helpers: class DummyEnvironment: @@ -115,7 +124,8 @@ class CScannerTestCase1(unittest.TestCase): env = DummyEnvironment([]) s = SCons.Scanner.C.CScan() deps = s.scan(test.workpath('f1.cpp'), env) - self.failUnless(deps_match(deps, ['f1.h', 'f2.h']), map(str, deps)) + headers = ['f1.h', 'f2.h', 'fi.h'] + self.failUnless(deps_match(deps, headers), map(str, deps)) class CScannerTestCase2(unittest.TestCase): def runTest(self): @@ -146,7 +156,8 @@ class CScannerTestCase5(unittest.TestCase): env = DummyEnvironment([]) s = SCons.Scanner.C.CScan() deps = s.scan(test.workpath('f3.cpp'), env) - headers = ['f1.h', 'f2.h', 'f3.h', 'd1/f1.h', 'd1/f2.h', 'd1/f3.h'] + headers = ['f1.h', 'f2.h', 'f3.h', 'fi.h', 'fj.h', + 'd1/f1.h', 'd1/f2.h', 'd1/f3.h'] self.failUnless(deps_match(deps, headers), map(str, deps)) def suite(): diff --git a/src/engine/SCons/Scanner/Prog.py b/src/engine/SCons/Scanner/Prog.py index f9d352c..62dee97 100644 --- a/src/engine/SCons/Scanner/Prog.py +++ b/src/engine/SCons/Scanner/Prog.py @@ -30,7 +30,7 @@ import SCons.Util def ProgScan(): """Return a Scanner instance for scanning executable files for static-lib dependencies""" - s = SCons.Scanner.Scanner(scan, SCons.Node.FS.default_fs.File) + s = SCons.Scanner.Base(scan, SCons.Node.FS.default_fs.File) s.name = "ProgScan" return s diff --git a/src/engine/SCons/Scanner/ScannerTests.py b/src/engine/SCons/Scanner/ScannerTests.py index 757f239..5d434a6 100644 --- a/src/engine/SCons/Scanner/ScannerTests.py +++ b/src/engine/SCons/Scanner/ScannerTests.py @@ -59,7 +59,7 @@ class DummyEnvironment: class ScannerPositionalTestCase(ScannerTestBase, unittest.TestCase): "Test the Scanner class using the position argument" def runTest(self): - s = SCons.Scanner.Scanner(self.func) + s = SCons.Scanner.Base(self.func) env = DummyEnvironment() env.VARIABLE = "var1" self.test(s, env, 'f1.cpp', ['f1.h', 'f1.hpp']) @@ -67,7 +67,7 @@ class ScannerPositionalTestCase(ScannerTestBase, unittest.TestCase): class ScannerKeywordTestCase(ScannerTestBase, unittest.TestCase): "Test the Scanner class using the keyword argument" def runTest(self): - s = SCons.Scanner.Scanner(function = self.func) + s = SCons.Scanner.Base(function = self.func) env = DummyEnvironment() env.VARIABLE = "var2" self.test(s, env, 'f2.cpp', ['f2.h', 'f2.hpp']) @@ -76,7 +76,7 @@ class ScannerPositionalArgumentTestCase(ScannerTestBase, unittest.TestCase): "Test the Scanner class using the position argument and optional argument" def runTest(self): arg = "this is the argument" - s = SCons.Scanner.Scanner(self.func, arg) + s = SCons.Scanner.Base(self.func, arg) env = DummyEnvironment() env.VARIABLE = "var3" self.test(s, env, 'f3.cpp', ['f3.h', 'f3.hpp'], arg) @@ -85,7 +85,7 @@ class ScannerKeywordArgumentTestCase(ScannerTestBase, unittest.TestCase): "Test the Scanner class using the keyword argument and optional argument" def runTest(self): arg = "this is another argument" - s = SCons.Scanner.Scanner(function = self.func, argument = arg) + s = SCons.Scanner.Base(function = self.func, argument = arg) env = DummyEnvironment() env.VARIABLE = "var4" self.test(s, env, 'f4.cpp', ['f4.h', 'f4.hpp'], arg) diff --git a/src/engine/SCons/Scanner/__init__.py b/src/engine/SCons/Scanner/__init__.py index 28fab7a..3c53396 100644 --- a/src/engine/SCons/Scanner/__init__.py +++ b/src/engine/SCons/Scanner/__init__.py @@ -42,7 +42,11 @@ class _Null: # used as an actual argument value. _null = _Null -class Scanner: +class Base: + """ + The base class for dependency scanners. This implements + straightforward, single-pass scanning of a single file. + """ def __init__(self, function, argument=_null, skeys=[]): """ @@ -86,10 +90,10 @@ class Scanner: def scan(self, filename, env): """ - This method does the actually scanning. 'filename' is the filename + This method scans a single object. 'filename' is the filename that will be passed to the scanner function, and 'env' is the environment that will be passed to the scanner function. A list of - dependencies will be returned (i.e. a list of 'Node's). + direct dependency nodes for the specified filename will be returned. """ if not self.argument is _null: @@ -108,3 +112,36 @@ class Scanner: if len(slist) == 1: slist = slist[0] return slist + +class Recursive(Base): + """ + 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 scan(self, filename, env): + """ + This method does the actual scanning. 'filename' is the filename + 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. + """ + + files = [filename] + seen = [filename] + deps = [] + while files: + f = files.pop(0) + if not self.argument is _null: + d = self.function(f, env, self.argument) + else: + d = self.function(f, env) + d = filter(lambda x, seen=seen: str(x) not in seen, d) + deps.extend(d) + s = map(str, d) + seen.extend(s) + files.extend(s) + return deps diff --git a/test/CPPPATH.py b/test/CPPPATH.py index 32c00b6..345603b 100644 --- a/test/CPPPATH.py +++ b/test/CPPPATH.py @@ -29,12 +29,13 @@ import TestSCons test = TestSCons.TestSCons() test.write('foo.c', -"""#include "include/foo.h" +"""#include "foo.h" #include int main(void) { - printf(TEST_STRING); + printf(FOO_STRING); + printf(BAR_STRING); return 0; } """) @@ -43,29 +44,52 @@ test.subdir('include') test.write('include/foo.h', """ -#define TEST_STRING "Bad news\n" +#define FOO_STRING "foo.h 1\n" +#include "bar.h" +""") + +test.write('include/bar.h', +""" +#define BAR_STRING "bar.h 1\n" """) test.write('SConstruct', """ -env = Environment() +env = Environment(CPPPATH = ['include']) env.Program(target='prog', source='foo.c') -#env.Depends(target='foo.c', dependency='include/foo.h') """) test.run(arguments = 'prog') test.run(program = test.workpath('prog'), - stdout = "Bad news\n") + stdout = "foo.h 1\nbar.h 1\n") + +test.up_to_date(arguments = 'prog') test.unlink('include/foo.h') test.write('include/foo.h', """ -#define TEST_STRING "Good news\n" +#define FOO_STRING "foo.h 2\n" +#include "bar.h" """) test.run(arguments = 'prog') test.run(program = test.workpath('prog'), - stdout = "Good news\n") + stdout = "foo.h 2\nbar.h 1\n") + +test.up_to_date(arguments = 'prog') + +test.unlink('include/bar.h') +test.write('include/bar.h', +""" +#define BAR_STRING "bar.h 2\n" +""") + +test.run(arguments = 'prog') + +test.run(program = test.workpath('prog'), + stdout = "foo.h 2\nbar.h 2\n") + +test.up_to_date(arguments = 'prog') test.pass_test() -- cgit v0.12