summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Scanner
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-04-04 09:07:00 (GMT)
committerSteven Knight <knight@baldmt.com>2002-04-04 09:07:00 (GMT)
commit6603cc0d6643e529da45fef6f85fcc1a0fc02ea4 (patch)
tree4a27de7c3fd70e5af0f257ccc73aab38e343f156 /src/engine/SCons/Scanner
parenta7669bc6a02999a3375c7e732a27ded5f9bb9935 (diff)
downloadSCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.zip
SCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.tar.gz
SCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.tar.bz2
Fix --debug=tree for directory targets (Anthony Roach)
Diffstat (limited to 'src/engine/SCons/Scanner')
-rw-r--r--src/engine/SCons/Scanner/C.py57
-rw-r--r--src/engine/SCons/Scanner/CTests.py54
-rw-r--r--src/engine/SCons/Scanner/Prog.py87
-rw-r--r--src/engine/SCons/Scanner/ProgTests.py20
-rw-r--r--src/engine/SCons/Scanner/ScannerTests.py37
-rw-r--r--src/engine/SCons/Scanner/__init__.py20
6 files changed, 119 insertions, 156 deletions
diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py
index 0a2654e..c81417a 100644
--- a/src/engine/SCons/Scanner/C.py
+++ b/src/engine/SCons/Scanner/C.py
@@ -41,45 +41,16 @@ import SCons.Util
include_re = re.compile('^[ \t]*#[ \t]*include[ \t]+(<|")([\\w./\\\\]+)(>|")', re.M)
-include_cache = {}
-
def CScan(fs = SCons.Node.FS.default_fs):
"""Return a prototype Scanner instance for scanning source files
that use the C pre-processor"""
- cs = CScanner(scan, "CScan", [fs, ()],
- [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
- ".h", ".H", ".hxx", ".hpp", ".hh",
- ".F", ".fpp", ".FPP"])
- cs.fs = fs
+ cs = SCons.Scanner.Recursive(scan, "CScan", fs,
+ [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
+ ".h", ".H", ".hxx", ".hpp", ".hh",
+ ".F", ".fpp", ".FPP"])
return cs
-class CScanner(SCons.Scanner.Recursive):
- def __init__(self, *args, **kw):
- apply(SCons.Scanner.Recursive.__init__, (self,) + args, kw)
- self.hash = None
- self.pathscanners = {}
-
- def instance(self, env):
- """
- Return a unique instance of a C scanner object for a
- given environment.
- """
- try:
- dirs = tuple(SCons.Node.arg2nodes(env.Dictionary('CPPPATH'),
- self.fs.Dir))
- except:
- dirs = ()
- if not self.pathscanners.has_key(dirs):
- clone = copy.copy(self)
- clone.hash = dirs
- clone.argument = [self.fs, dirs] # XXX reaching into object
- self.pathscanners[dirs] = clone
- return self.pathscanners[dirs]
-
- def __hash__(self):
- return hash(self.hash)
-
-def scan(node, env, args = [SCons.Node.FS.default_fs, ()]):
+def scan(node, env, target, fs = SCons.Node.FS.default_fs):
"""
scan(node, Environment) -> [node]
@@ -100,7 +71,21 @@ def scan(node, env, args = [SCons.Node.FS.default_fs, ()]):
dependencies.
"""
- fs, cpppath = args
+ # This function caches various information in node and target:
+ # target.cpppath - env['CPPPATH'] converted to nodes
+ # node.found_includes - include files found by previous call to scan,
+ # keyed on cpppath
+ # node.includes - the result of include_re.findall()
+
+ if not hasattr(target, 'cpppath'):
+ def Dir(x, dir=target.cwd, fs=fs): return fs.Dir(x,dir)
+ try:
+ target.cpppath = tuple(SCons.Node.arg2nodes(env['CPPPATH'],Dir))
+ except KeyError:
+ target.cpppath = ()
+
+ cpppath = target.cpppath
+
nodes = []
try:
@@ -109,7 +94,7 @@ def scan(node, env, args = [SCons.Node.FS.default_fs, ()]):
if node.exists():
# cache the includes list in node so we only scan it once:
- if hasattr(node, 'includes'):
+ if node.includes != None:
includes = node.includes
else:
includes = include_re.findall(node.get_contents())
diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py
index 684df99..f99af18 100644
--- a/src/engine/SCons/Scanner/CTests.py
+++ b/src/engine/SCons/Scanner/CTests.py
@@ -119,6 +119,10 @@ test.write('subdir/include/fb.h', "\n")
# define some helpers:
+class DummyTarget:
+ def __init__(self, cwd=None):
+ self.cwd = cwd
+
class DummyEnvironment:
def __init__(self, listCppPath):
self.path = listCppPath
@@ -131,6 +135,15 @@ class DummyEnvironment:
else:
raise KeyError, "Dummy environment only has CPPPATH attribute."
+ def __getitem__(self,key):
+ return self.Dictionary()[key]
+
+ def __setitem__(self,key,value):
+ self.Dictionary()[key] = value
+
+ def __delitem__(self,key):
+ del self.Dictionary()[key]
+
def deps_match(self, deps, headers):
scanned = map(os.path.normpath, map(str, deps))
expect = map(os.path.normpath, headers)
@@ -145,15 +158,15 @@ class CScannerTestCase1(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f1.cpp'), env)
- headers = ['f1.h', 'f2.h', 'fi.h']
+ deps = s.scan(make_node('f1.cpp'), env, DummyTarget())
+ headers = ['f1.h', 'f2.h', 'fi.h']
deps_match(self, deps, map(test.workpath, headers))
class CScannerTestCase2(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1")])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f1.cpp'), env)
+ deps = s.scan(make_node('f1.cpp'), env, DummyTarget())
headers = ['d1/f2.h', 'f1.h']
deps_match(self, deps, map(test.workpath, headers))
@@ -161,7 +174,7 @@ class CScannerTestCase3(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1")])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f2.cpp'), env)
+ deps = s.scan(make_node('f2.cpp'), env, DummyTarget())
headers = ['d1/d2/f1.h', 'd1/f1.h', 'f1.h']
deps_match(self, deps, map(test.workpath, headers))
@@ -169,7 +182,7 @@ class CScannerTestCase4(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1"), test.workpath("d1/d2")])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f2.cpp'), env)
+ deps = s.scan(make_node('f2.cpp'), env, DummyTarget())
headers = ['d1/d2/f1.h', 'd1/d2/f4.h', 'd1/f1.h', 'f1.h']
deps_match(self, deps, map(test.workpath, headers))
@@ -177,7 +190,7 @@ class CScannerTestCase5(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([])
s = SCons.Scanner.C.CScan()
- deps = s.instance(env).scan(make_node('f3.cpp'), env)
+ deps = s.scan(make_node('f3.cpp'), env, DummyTarget())
# Make sure exists() gets called on the file node being
# scanned, essential for cooperation with BuildDir functionality.
@@ -193,35 +206,23 @@ class CScannerTestCase6(unittest.TestCase):
env2 = DummyEnvironment([test.workpath("d1/d2")])
env3 = DummyEnvironment([test.workpath("d1/../d1")])
s = SCons.Scanner.C.CScan()
- s1 = s.instance(env1)
- s2 = s.instance(env2)
- s3 = s.instance(env3)
- assert not s1 is s2
- assert s1 is s3
- deps1 = s1.scan(make_node('f1.cpp'), None)
- deps2 = s2.scan(make_node('f1.cpp'), None)
+ deps1 = s.scan(make_node('f1.cpp'), env1, DummyTarget())
+ deps2 = s.scan(make_node('f1.cpp'), env2, DummyTarget())
headers1 = ['d1/f2.h', 'f1.h']
headers2 = ['d1/d2/f2.h', 'f1.h']
deps_match(self, deps1, map(test.workpath, headers1))
deps_match(self, deps2, map(test.workpath, headers2))
-class CScannerTestCase7(unittest.TestCase):
- def runTest(self):
- s = SCons.Scanner.C.CScan()
- s1 = s.instance(DummyEnvironment([test.workpath("d1")]))
- s2 = s.instance(DummyEnvironment([test.workpath("d1/../d1")]))
- dict = {}
- dict[s1] = 777
- assert dict[s2] == 777
-
class CScannerTestCase8(unittest.TestCase):
def runTest(self):
fs = SCons.Node.FS.FS(test.workpath(''))
env = DummyEnvironment(["include"])
s = SCons.Scanner.C.CScan(fs = fs)
- deps1 = s.instance(env).scan(fs.File('fa.cpp'), None)
+ deps1 = s.scan(fs.File('fa.cpp'), env, DummyTarget())
fs.chdir(fs.Dir('subdir'))
- deps2 = s.instance(env).scan(fs.File('#fa.cpp'), None)
+ target = DummyTarget(fs.getcwd())
+ fs.chdir(fs.Dir('..'))
+ deps2 = s.scan(fs.File('#fa.cpp'), env, target)
headers1 = ['include/fa.h', 'include/fb.h']
headers2 = ['subdir/include/fa.h', 'subdir/include/fb.h']
deps_match(self, deps1, headers1)
@@ -233,7 +234,7 @@ class CScannerTestCase9(unittest.TestCase):
fs = SCons.Node.FS.FS(test.workpath(''))
s = SCons.Scanner.C.CScan(fs=fs)
env = DummyEnvironment([])
- deps = s.instance(env).scan(fs.File('fa.cpp'), None)
+ deps = s.scan(fs.File('fa.cpp'), env, DummyTarget())
deps_match(self, deps, [ 'fa.h' ])
test.unlink('fa.h')
@@ -244,7 +245,7 @@ class CScannerTestCase10(unittest.TestCase):
s = SCons.Scanner.C.CScan(fs=fs)
env = DummyEnvironment([])
test.write('include/fa.cpp', test.read('fa.cpp'))
- deps = s.instance(env).scan(fs.File('#include/fa.cpp'), None)
+ deps = s.scan(fs.File('#include/fa.cpp'), env, DummyTarget())
deps_match(self, deps, [ 'include/fa.h', 'include/fb.h' ])
test.unlink('include/fa.cpp')
@@ -256,7 +257,6 @@ def suite():
suite.addTest(CScannerTestCase4())
suite.addTest(CScannerTestCase5())
suite.addTest(CScannerTestCase6())
- suite.addTest(CScannerTestCase7())
suite.addTest(CScannerTestCase8())
suite.addTest(CScannerTestCase9())
suite.addTest(CScannerTestCase10())
diff --git a/src/engine/SCons/Scanner/Prog.py b/src/engine/SCons/Scanner/Prog.py
index 9ecc37b..76567ab 100644
--- a/src/engine/SCons/Scanner/Prog.py
+++ b/src/engine/SCons/Scanner/Prog.py
@@ -31,74 +31,49 @@ import SCons.Node.FS
import SCons.Scanner
import SCons.Util
-class NullProgScanner:
- """A do-nothing ProgScanner for Environments that have no LIBS."""
- def scan(node, env, args = []):
- return []
-
-null_scanner = NullProgScanner()
-
def ProgScan(fs = SCons.Node.FS.default_fs):
"""Return a prototype Scanner instance for scanning executable
files for static-lib dependencies"""
- ps = ProgScanner(scan, "ProgScan")
- ps.fs = fs
+ ps = SCons.Scanner.Base(scan, "ProgScan", fs)
return ps
-class ProgScanner(SCons.Scanner.Base):
- def __init__(self, *args, **kw):
- apply(SCons.Scanner.Base.__init__, (self,) + args, kw)
- self.hash = None
- self.pathscanners = {}
-
- def instance(self, env):
- """
- Return a unique instance of a Prog scanner object for a
- given environment.
- """
- try:
- libs = env.Dictionary('LIBS')
- except KeyError:
- # There are no LIBS in this environment, so just return the
- # fake "scanner" instance that always returns a null list.
- return null_scanner
- if SCons.Util.is_String(libs):
- libs = string.split(libs)
+def scan(node, env, target, fs):
+ """
+ This scanner scans program files for static-library
+ dependencies. It will search the LIBPATH environment variable
+ for libraries specified in the LIBS variable, returning any
+ files it finds as dependencies.
+ """
- try:
- dirs = tuple(SCons.Node.arg2nodes(env.Dictionary('LIBPATH'),
- self.fs.Dir))
- except:
- dirs = ()
+ # This function caches information in target:
+ # target.libpath - env['LIBPATH'] converted to nodes
+ if not hasattr(target, 'libpath'):
+ def Dir(x, dir=target.cwd, fs=fs): return fs.Dir(x,dir)
try:
- prefix = env.Dictionary('LIBPREFIX')
+ target.libpath = tuple(SCons.Node.arg2nodes(env['LIBPATH'],Dir))
except KeyError:
- prefix = ''
+ target.libpath = ()
+
+ libpath = target.libpath
- try:
- suffix = env.Dictionary('LIBSUFFIX')
- except KeyError:
- suffix = ''
+ try:
+ libs = env.Dictionary('LIBS')
+ except KeyError:
+ # There are no LIBS in this environment, so just return a null list:
+ return []
+ if SCons.Util.is_String(libs):
+ libs = string.split(libs)
- key = (dirs, tuple(libs), prefix, suffix)
- if not self.pathscanners.has_key(key):
- clone = copy.copy(self)
- clone.hash = key
- clone.argument = [self.fs, dirs, libs, prefix, suffix] # XXX reaching into object
- self.pathscanners[key] = clone
- return self.pathscanners[key]
+ try:
+ prefix = env.Dictionary('LIBPREFIX')
+ except KeyError:
+ prefix = ''
- def __hash__(self):
- return hash(self.hash)
+ try:
+ suffix = env.Dictionary('LIBSUFFIX')
+ except KeyError:
+ suffix = ''
-def scan(node, env, args = [SCons.Node.FS.default_fs, (), [], '', '']):
- """
- This scanner scans program files for static-library
- dependencies. It will search the LIBPATH environment variable
- for libraries specified in the LIBS variable, returning any
- files it finds as dependencies.
- """
- fs, libpath, libs, prefix, suffix = args
libs = map(lambda x, s=suffix, p=prefix: p + x + s, libs)
return SCons.Node.FS.find_files(libs, libpath, fs.File)
diff --git a/src/engine/SCons/Scanner/ProgTests.py b/src/engine/SCons/Scanner/ProgTests.py
index b59e554..ea3d00d 100644
--- a/src/engine/SCons/Scanner/ProgTests.py
+++ b/src/engine/SCons/Scanner/ProgTests.py
@@ -42,6 +42,10 @@ for h in libs:
# define some helpers:
+class DummyTarget:
+ def __init__(self, cwd=None):
+ self.cwd = cwd
+
class DummyEnvironment:
def __init__(self, **kw):
self._dict = kw
@@ -54,6 +58,14 @@ class DummyEnvironment:
return self._dict[args[0]]
else:
return map(lambda x, s=self: s._dict[x], args)
+ def __getitem__(self,key):
+ return self.Dictionary()[key]
+
+ def __setitem__(self,key,value):
+ self.Dictionary()[key] = value
+
+ def __delitem__(self,key):
+ del self.Dictionary()[key]
def deps_match(deps, libs):
deps=map(str, deps)
@@ -70,7 +82,7 @@ class ProgScanTestCase1(unittest.TestCase):
env = DummyEnvironment(LIBPATH=[ test.workpath("") ],
LIBS=[ 'l1', 'l2', 'l3' ])
s = SCons.Scanner.Prog.ProgScan()
- deps = s.instance(env).scan('dummy', env)
+ deps = s.scan('dummy', env, DummyTarget())
assert deps_match(deps, ['l1.lib']), map(str, deps)
class ProgScanTestCase2(unittest.TestCase):
@@ -79,7 +91,7 @@ class ProgScanTestCase2(unittest.TestCase):
["", "d1", "d1/d2" ]),
LIBS=[ 'l1', 'l2', 'l3' ])
s = SCons.Scanner.Prog.ProgScan()
- deps = s.instance(env).scan('dummy', env)
+ deps = s.scan('dummy', env, DummyTarget())
assert deps_match(deps, ['l1.lib', 'd1/l2.lib', 'd1/d2/l3.lib' ]), map(str, deps)
class ProgScanTestCase3(unittest.TestCase):
@@ -88,7 +100,7 @@ class ProgScanTestCase3(unittest.TestCase):
test.workpath("d1"),
LIBS='l2 l3')
s = SCons.Scanner.Prog.ProgScan()
- deps = s.instance(env).scan('dummy', env)
+ deps = s.scan('dummy', env, DummyTarget())
assert deps_match(deps, ['d1/l2.lib', 'd1/d2/l3.lib']), map(str, deps)
def suite():
@@ -104,7 +116,7 @@ def suite():
test.workpath("d1"),
LIBS=u'l2 l3')
s = SCons.Scanner.Prog.ProgScan()
- deps = s.instance(env).scan('dummy', env)
+ deps = s.scan('dummy', env, DummyTarget())
assert deps_match(deps, ['d1/l2.lib', 'd1/d2/l3.lib']), map(str, deps)
suite.addTest(ProgScanTestCase4())
\n"""
diff --git a/src/engine/SCons/Scanner/ScannerTests.py b/src/engine/SCons/Scanner/ScannerTests.py
index 76df18e..fce4078 100644
--- a/src/engine/SCons/Scanner/ScannerTests.py
+++ b/src/engine/SCons/Scanner/ScannerTests.py
@@ -27,11 +27,16 @@ import unittest
import SCons.Scanner
import sys
+class DummyTarget:
+ cwd = None
+
+
class ScannerTestBase:
- def func(self, filename, env, *args):
+ def func(self, filename, env, target, *args):
self.filename = filename
self.env = env
+ self.target = target
if len(args) > 0:
self.arg = args[0]
@@ -41,7 +46,7 @@ class ScannerTestBase:
def test(self, scanner, env, filename, deps, *args):
self.deps = deps
- scanned = scanner.scan(filename, env)
+ scanned = scanner.scan(filename, env, DummyTarget())
scanned_strs = map(lambda x: str(x), scanned)
self.failUnless(self.filename == filename, "the filename was passed incorrectly")
@@ -67,10 +72,9 @@ class ScannerPositionalTestCase(ScannerTestBase, unittest.TestCase):
env.VARIABLE = "var1"
self.test(s, env, 'f1.cpp', ['f1.h', 'f1.hpp'])
- env = DummyEnvironment()
- env.VARIABLE = "i1"
- i = s.instance(env)
- self.test(i, env, 'i1.cpp', ['i1.h', 'i1.hpp'])
+ env = DummyEnvironment()
+ env.VARIABLE = "i1"
+ self.test(s, env, 'i1.cpp', ['i1.h', 'i1.hpp'])
class ScannerKeywordTestCase(ScannerTestBase, unittest.TestCase):
"Test the Scanner.Base class using the keyword argument"
@@ -80,10 +84,9 @@ class ScannerKeywordTestCase(ScannerTestBase, unittest.TestCase):
env.VARIABLE = "var2"
self.test(s, env, 'f2.cpp', ['f2.h', 'f2.hpp'])
- env = DummyEnvironment()
- env.VARIABLE = "i2"
- i = s.instance(env)
- self.test(i, env, 'i2.cpp', ['i2.h', 'i2.hpp'])
+ env = DummyEnvironment()
+ env.VARIABLE = "i2"
+ self.test(s, env, 'i2.cpp', ['i2.h', 'i2.hpp'])
class ScannerPositionalArgumentTestCase(ScannerTestBase, unittest.TestCase):
"Test the Scanner.Base class using both position and optional arguments"
@@ -94,10 +97,9 @@ class ScannerPositionalArgumentTestCase(ScannerTestBase, unittest.TestCase):
env.VARIABLE = "var3"
self.test(s, env, 'f3.cpp', ['f3.h', 'f3.hpp'], arg)
- env = DummyEnvironment()
- env.VARIABLE = "i3"
- i = s.instance(env)
- self.test(i, env, 'i3.cpp', ['i3.h', 'i3.hpp'], arg)
+ env = DummyEnvironment()
+ env.VARIABLE = "i3"
+ self.test(s, env, 'i3.cpp', ['i3.h', 'i3.hpp'], arg)
class ScannerKeywordArgumentTestCase(ScannerTestBase, unittest.TestCase):
"Test the Scanner.Base class using both keyword and optional arguments"
@@ -109,10 +111,9 @@ class ScannerKeywordArgumentTestCase(ScannerTestBase, unittest.TestCase):
env.VARIABLE = "var4"
self.test(s, env, 'f4.cpp', ['f4.h', 'f4.hpp'], arg)
- env = DummyEnvironment()
- env.VARIABLE = "i4"
- i = s.instance(env)
- self.test(i, env, 'i4.cpp', ['i4.h', 'i4.hpp'], arg)
+ env = DummyEnvironment()
+ env.VARIABLE = "i4"
+ self.test(s, env, 'i4.cpp', ['i4.h', 'i4.hpp'], arg)
class ScannerHashTestCase(ScannerTestBase, unittest.TestCase):
"Test the Scanner.Base class __hash__() method"
diff --git a/src/engine/SCons/Scanner/__init__.py b/src/engine/SCons/Scanner/__init__.py
index 53c67e4..b2e04a3 100644
--- a/src/engine/SCons/Scanner/__init__.py
+++ b/src/engine/SCons/Scanner/__init__.py
@@ -97,7 +97,7 @@ class Base:
self.skeys = skeys
self.node_factory = node_factory
- def scan(self, node, env):
+ def scan(self, node, env, target):
"""
This method scans a single object. 'node' is the node
that will be passed to the scanner function, and 'env' is the
@@ -106,9 +106,9 @@ class Base:
"""
if not self.argument is _null:
- list = self.function(node, env, self.argument)
+ list = self.function(node, env, target, self.argument)
else:
- list = self.function(node, env)
+ list = self.function(node, env, target)
kw = {}
if hasattr(node, 'dir'):
kw['directory'] = node.dir
@@ -119,16 +119,6 @@ class Base:
nodes.append(l)
return nodes
- def instance(self, env):
- """
- Return an instance of a Scanner object for use in scanning.
-
- In the base class, we just return the scanner itself.
- Other Scanner classes may use this to clone copies and/or
- return unique instances as needed.
- """
- return self
-
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
@@ -143,7 +133,7 @@ class Recursive(Base):
list of all dependencies.
"""
- def scan(self, node, env):
+ def scan(self, node, env, target):
"""
This method does the actual scanning. 'node' is the node
that will be passed to the scanner function, and 'env' is the
@@ -158,7 +148,7 @@ class Recursive(Base):
while nodes:
n = nodes.pop(0)
d = filter(lambda x, seen=seen: not seen.has_key(x),
- Base.scan(self, n, env))
+ Base.scan(self, n, env, target))
if d:
deps.extend(d)
nodes.extend(d)