diff options
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r-- | src/engine/SCons/Node/FS.py | 23 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 33 | ||||
-rw-r--r-- | src/engine/SCons/Node/__init__.py | 24 |
3 files changed, 72 insertions, 8 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 826307b..aa7f973 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -790,6 +790,8 @@ class File(Entry): def _morph(self): """Turn a file system node into a File object.""" self.linked = 0 + self.scanner_paths = {} + self.found_includes = {} if not hasattr(self, '_local'): self._local = 0 @@ -856,11 +858,23 @@ class File(Entry): return self.dir.sconsign().get_implicit(self.name) def get_implicit_deps(self, env, scanner, target): - if scanner: - return scanner.scan(self, env, target) - else: + if not scanner: return [] - + + try: + path = target.scanner_paths[scanner] + except KeyError: + path = scanner.path(env, target.cwd) + target.scanner_paths[scanner] = path + + try: + includes = self.found_includes[path] + except KeyError: + includes = scanner(self, env, path) + self.found_includes[path] = includes + + return includes + def scanner_key(self): return os.path.splitext(self.name)[1] @@ -895,6 +909,7 @@ class File(Entry): def built(self): SCons.Node.Node.built(self) + self.found_includes = {} if hasattr(self, '_exists'): delattr(self, '_exists') if hasattr(self, '_rexists'): diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index a624d97..e23178c 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -69,7 +69,9 @@ class Scanner: global scanner_count scanner_count = scanner_count + 1 self.hash = scanner_count - def scan(self, node, env, target): + def path(self, env, target): + return () + def __call__(self, node, env, path): return [node] def __hash__(self): return self.hash @@ -669,6 +671,35 @@ class FSTestCase(unittest.TestCase): f1.store_implicit() assert f1.get_stored_implicit()[0] == os.path.join("d1", "f1") + # Test underlying scanning functionality in get_implicit_deps() + env = Environment() + f12 = fs.File("f12") + t1 = fs.File("t1") + + deps = f12.get_implicit_deps(env, None, t1) + assert deps == [], deps + + class MyScanner(Scanner): + call_count = 0 + def __call__(self, node, env, path): + self.call_count = self.call_count + 1 + return [node] + s = MyScanner() + + deps = f12.get_implicit_deps(env, s, t1) + assert deps == [f12], deps + assert s.call_count == 1, s.call_count + + deps = f12.get_implicit_deps(env, s, t1) + assert deps == [f12], deps + assert s.call_count == 1, s.call_count + + f12.built() + + deps = f12.get_implicit_deps(env, s, t1) + assert deps == [f12], deps + assert s.call_count == 2, s.call_count + # Test building a file whose directory is not there yet... f1 = fs.File(test.workpath("foo/bar/baz/ack")) assert not f1.dir.exists() diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 3bafb9c..16e28e2 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -221,15 +221,17 @@ class Node: self.implicit = [] self.del_bsig() + build_env = self.generate_build_env() + for child in self.children(scan=0): self._add_child(self.implicit, - child.get_implicit_deps(self.generate_build_env(), + child.get_implicit_deps(build_env, child.source_scanner, self)) # scan this node itself for implicit dependencies self._add_child(self.implicit, - self.get_implicit_deps(self.generate_build_env(), + self.get_implicit_deps(build_env, self.target_scanner, self)) @@ -384,7 +386,23 @@ class Node: def all_children(self, scan=1): """Return a list of all the node's direct children.""" - #XXX Need to remove duplicates from this + # The return list may contain duplicate Nodes, especially in + # source trees where there are a lot of repeated #includes + # of a tangle of .h files. Profiling shows, however, that + # eliminating the duplicates with a brute-force approach that + # preserves the order (that is, something like: + # + # u = [] + # for n in list: + # if n not in u: + # u.append(n)" + # + # takes more cycles than just letting the underlying methods + # hand back cached values if a Node's information is requested + # multiple times. (Other methods of removing duplicates, like + # using dictionary keys, lose the order, and the only ordered + # dictionary patterns I found all ended up using "not in" + # internally anyway...) if scan: self.scan() if self.implicit is None: |