summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-04-11 01:34:07 (GMT)
committerSteven Knight <knight@baldmt.com>2002-04-11 01:34:07 (GMT)
commit3207c9ca9efaac1b8d3f2174d2e5f336f92887ab (patch)
tree184b6e6e1fb12fde12568a6ad52149821670f28b /src/engine/SCons/Node
parent48b6454994a21440a03cacaf14bad63295a62bbf (diff)
downloadSCons-3207c9ca9efaac1b8d3f2174d2e5f336f92887ab.zip
SCons-3207c9ca9efaac1b8d3f2174d2e5f336f92887ab.tar.gz
SCons-3207c9ca9efaac1b8d3f2174d2e5f336f92887ab.tar.bz2
Implement implicit dependency caching.
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r--src/engine/SCons/Node/FS.py12
-rw-r--r--src/engine/SCons/Node/FSTests.py15
-rw-r--r--src/engine/SCons/Node/__init__.py66
3 files changed, 69 insertions, 24 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index c49361d..1c506c9 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -467,10 +467,8 @@ class Dir(Entry):
"""Return the .sconsign file info for this directory,
creating it first if necessary."""
if not self._sconsign:
- #XXX Rework this to get rid of the hard-coding
import SCons.Sig
- import SCons.Sig.MD5
- self._sconsign = SCons.Sig.SConsignFile(self, SCons.Sig.MD5)
+ self._sconsign = SCons.Sig.SConsignFile(self)
return self._sconsign
@@ -534,11 +532,15 @@ class File(Entry):
self.get_bsig(),
old[2])
+ def store_implicit(self):
+ self.dir.sconsign().set_implicit(self.name, self.implicit)
+
def get_prevsiginfo(self):
- """Fetch the previous signature information from the
- .sconsign entry."""
return self.dir.sconsign().get(self.name)
+ def get_stored_implicit(self):
+ return self.dir.sconsign().get_implicit(self.name)
+
def get_implicit_deps(self, env, scanner, target):
if scanner:
return scanner.scan(self, env, target)
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 0e19cec..6b35adb 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -36,10 +36,16 @@ import stat
built_it = None
class Builder:
+ def __init__(self, factory):
+ self.factory = factory
+
def execute(self, **kw):
global built_it
built_it = 1
return 0
+
+ def source_factory(self, name):
+ return self.factory(name)
scanner_count = 0
@@ -285,7 +291,7 @@ class FSTestCase(unittest.TestCase):
built_it = None
assert not built_it
d1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
- d1.builder_set(Builder())
+ d1.builder_set(Builder(fs.File))
d1.env_set(Environment())
d1.build()
assert not built_it
@@ -293,7 +299,7 @@ class FSTestCase(unittest.TestCase):
built_it = None
assert not built_it
f1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
- f1.builder_set(Builder())
+ f1.builder_set(Builder(fs.File))
f1.env_set(Environment())
f1.build()
assert built_it
@@ -381,6 +387,7 @@ class FSTestCase(unittest.TestCase):
match(d12.path_, "subdir/d12/")
e13 = fs.Entry("subdir/e13")
match(e13.path, "subdir/subdir/e13")
+ fs.chdir(fs.Dir('..'))
# Test scanning
f1.target_scanner = Scanner()
@@ -391,7 +398,9 @@ class FSTestCase(unittest.TestCase):
assert f1.implicit == []
f1.implicit = None
f1.scan()
- assert f1.implicit[0].path_ == os.path.join("d1", "f1")
+ assert f1.implicit[0].path_ == os.path.join("d1", "f1"), f1.implicit[0].path_
+ f1.store_implicit()
+ assert f1.get_stored_implicit()[0] == os.path.join("d1", "f1")
# Test building a file whose directory is not there yet...
f1 = fs.File(test.workpath("foo/bar/baz/ack"))
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index a9ca790..cbaed7b 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -35,6 +35,7 @@ import string
import types
import copy
import sys
+import SCons.Sig
from SCons.Errors import BuildError
import SCons.Util
@@ -53,6 +54,9 @@ executed = 4
failed = 5
stack = 6 # nodes that are in the current Taskmaster execution stack
+# controls whether implicit depedencies are cached:
+implicit_cache = 0
+
class Node:
"""The base Node class, for entities that we know how to
build, or use to build other Nodes.
@@ -116,9 +120,9 @@ class Node:
if self.source_scanner:
self.found_includes = {}
self.includes = None
-
+
def get_parents(node, parent): return node.get_parents()
- def clear_cache(node, parent):
+ def clear_cache(node, parent):
node.implicit = None
node.bsig = None
w = Walker(self, get_parents, ignore_cycle, clear_cache)
@@ -170,17 +174,38 @@ class Node:
# Don't bother scanning non-derived files, because we don't
# care what their dependencies are.
# Don't scan again, if we already have scanned.
- if self.implicit is None:
- if self.builder:
- self.implicit = []
- for child in self.children(scan=0):
- self._add_child(self.implicit, child.get_implicit_deps(self.env, child.source_scanner, self))
-
- # scan this node itself for implicit dependencies
- self._add_child(self.implicit, self.get_implicit_deps(self.env, self.target_scanner, self))
- else:
- self.implicit = []
-
+ if not self.implicit is None:
+ return
+ self.implicit = []
+ if not self.builder:
+ return
+
+ if implicit_cache:
+ implicit = self.get_stored_implicit()
+ if implicit is not None:
+ implicit = map(self.builder.source_factory, implicit)
+ self._add_child(self.implicit, implicit)
+ calc = SCons.Sig.default_calc
+ if calc.current(self, calc.bsig(self)):
+ return
+ else:
+ self.implicit = []
+
+ for child in self.children(scan=0):
+ self._add_child(self.implicit,
+ child.get_implicit_deps(self.env,
+ child.source_scanner,
+ self))
+
+ # scan this node itself for implicit dependencies
+ self._add_child(self.implicit,
+ self.get_implicit_deps(self.env,
+ self.target_scanner,
+ self))
+
+ if implicit_cache:
+ self.store_implicit()
+
def scanner_key(self):
return None
@@ -225,6 +250,15 @@ class Node:
def get_timestamp(self):
return 0
+ def store_implicit(self):
+ """Make the implicit deps permanent (that is, store them in the
+ .sconsign file or equivalent)."""
+ pass
+
+ def get_stored_implicit(self):
+ """Fetch the stored implicit dependencies"""
+ return None
+
def set_precious(self, precious = 1):
"""Set the Node's precious value."""
self.precious = precious
@@ -276,7 +310,7 @@ class Node:
return self.sources + self.depends
else:
return self.sources + self.depends + self.implicit
-
+
def get_parents(self):
return self.parents.keys()
@@ -300,10 +334,10 @@ class Walker:
The Walker object can be initialized with any node, and
returns the next node on the descent with each next() call.
'kids_func' is an optional function that will be called to
- get the children of a node instead of calling 'children'.
+ get the children of a node instead of calling 'children'.
'cycle_func' is an optional function that will be called
when a cycle is detected.
-
+
This class does not get caught in node cycles caused, for example,
by C header file include loops.
"""