summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2006-12-16 01:43:01 (GMT)
committerSteven Knight <knight@baldmt.com>2006-12-16 01:43:01 (GMT)
commitc4d04b3b45e7b71a1b28053b90084bcf2fdf9c0e (patch)
tree8a0d07c078ac21bf1ab689eacf06577069bb9231 /src/engine/SCons/Node
parentb32cd624a5ad9526d28584b8e6c4a7958f436424 (diff)
downloadSCons-c4d04b3b45e7b71a1b28053b90084bcf2fdf9c0e.zip
SCons-c4d04b3b45e7b71a1b28053b90084bcf2fdf9c0e.tar.gz
SCons-c4d04b3b45e7b71a1b28053b90084bcf2fdf9c0e.tar.bz2
Merged revisions 1675-1736 via svnmerge from
http://scons.tigris.org/svn/scons/branches/core ........ r1689 | stevenknight | 2006-11-06 20:56:29 -0600 (Mon, 06 Nov 2006) | 1 line 0.96.D483 - Merge changes for 0.96.93 packaging from the subsidiary branch. ........ r1690 | stevenknight | 2006-11-06 20:59:30 -0600 (Mon, 06 Nov 2006) | 1 line 0.96.D484 - Update HOWTO for releases. Fix name type in src/CHANGES.txt. ........ r1691 | stevenknight | 2006-11-08 13:55:36 -0600 (Wed, 08 Nov 2006) | 1 line 0.96.D485 - Fix MergeFlags() handling of None values. (John Pye) ........ r1692 | stevenknight | 2006-11-08 17:15:05 -0600 (Wed, 08 Nov 2006) | 1 line 0.96.D486 - Directly execute commands on Windows when possible. (Jay Kint) ........ r1693 | stevenknight | 2006-11-08 18:54:49 -0600 (Wed, 08 Nov 2006) | 1 line 0.96.D487 - Remove the semi-colon from the list of characters that determine when we use cmd ........ r1694 | stevenknight | 2006-11-09 01:34:06 -0600 (Thu, 09 Nov 2006) | 1 line 0.96.D488 - Pick up latex/bibtex 'Rerun to get citations correct' messages. (Dmitry Mikhin) ........ r1695 | stevenknight | 2006-11-11 08:36:33 -0600 (Sat, 11 Nov 2006) | 1 line 0.96.D489 - Back out the direct-execution-on-Windows change until we solve a corner case. ........ r1696 | stevenknight | 2006-11-15 10:33:10 -0600 (Wed, 15 Nov 2006) | 1 line 0.96.D490 - Fix the sconsign script when the .sconsign.dblite file is specified with its suf ........ r1697 | stevenknight | 2006-11-18 10:45:50 -0600 (Sat, 18 Nov 2006) | 4 lines Complete move of test/sconsign/script.py to underneath test/sconsign/script/. (This got left out of the previous checkin due to an error in the script that resubmits Aegis changes to Subversion.) ........ r1698 | stevenknight | 2006-11-18 11:05:26 -0600 (Sat, 18 Nov 2006) | 1 line 0.96.D491 - Allow an Options converter to take the construction environment as a parameter. ........ r1699 | stevenknight | 2006-11-30 15:34:37 -0600 (Thu, 30 Nov 2006) | 1 line 0.96.D492 - Reverse the order in which we try the arguments Options converters, first a sing ........ r1700 | stevenknight | 2006-11-30 16:03:09 -0600 (Thu, 30 Nov 2006) | 1 line 0.96.D493 - Speed up rel_path() by avoiding recomputation of intermediate directory relative ........ r1701 | stevenknight | 2006-11-30 16:14:16 -0600 (Thu, 30 Nov 2006) | 1 line 0.96.D494 - More efficient get_suffix(): compute it once when we set the name. ........ r1702 | stevenknight | 2006-11-30 16:22:55 -0600 (Thu, 30 Nov 2006) | 1 line 0.96.D495 - Fix missing XML end tags. ........ r1703 | stevenknight | 2006-11-30 17:15:25 -0600 (Thu, 30 Nov 2006) | 1 line 0.96.D496 - Turn Memoizer into a simple counter for --debug=memoizer, not something that doe ........ r1704 | stevenknight | 2006-11-30 20:30:50 -0600 (Thu, 30 Nov 2006) | 1 line 0.96.D497 - Add the scons-time script, with doc and tests. ........ r1705 | stevenknight | 2006-11-30 23:28:20 -0600 (Thu, 30 Nov 2006) | 1 line 0.96.D498 - Update the copyright years string. ........ r1706 | stevenknight | 2006-12-01 11:54:22 -0600 (Fri, 01 Dec 2006) | 1 line 0.96.D499 - Fix _do_Lookup => _doLookup value-caching misspellings. (Ben Leslie) ........ r1707 | stevenknight | 2006-12-01 12:03:46 -0600 (Fri, 01 Dec 2006) | 1 line 0.96.D500 - Fix copyright test against debian build. (Walter Franzini) ........ r1708 | stevenknight | 2006-12-01 14:23:29 -0600 (Fri, 01 Dec 2006) | 1 line 0.96.D501 - Add #include lines for test portability. (Gary Oberbrunner) ........ r1709 | stevenknight | 2006-12-01 14:51:12 -0600 (Fri, 01 Dec 2006) | 1 line 0.96.D502 - Fix tests under Python versions with no profiler (pstats module). ........ r1710 | stevenknight | 2006-12-01 20:04:49 -0600 (Fri, 01 Dec 2006) | 1 line 0.96.D503 - Remove unnecessary os.path.normpath() calls. (Gary Oberbrunner) ........ r1711 | stevenknight | 2006-12-01 20:34:31 -0600 (Fri, 01 Dec 2006) | 1 line 0.96.D504 - Accomodate arbitray white space after a SWIG %module keyword. (Anonymous) ........ r1712 | stevenknight | 2006-12-05 14:49:54 -0600 (Tue, 05 Dec 2006) | 1 line 0.96.D506 - Cache substitutions of of Builder source suffixes. Use a new PathList module, and a refactor Node.FS.Rfindalldirs() method, to cache calculations of values like CPPPATH. ........ r1713 | stevenknight | 2006-12-05 18:43:36 -0600 (Tue, 05 Dec 2006) | 1 line 0.96.D507 - Use cached stat() values in diskchecks. ........ r1714 | stevenknight | 2006-12-05 21:11:24 -0600 (Tue, 05 Dec 2006) | 1 line 0.96.D508 - Fix Memoizer hit counts for methods memoizing simple values. Clean up the code for memoizing return values in a dictionary. Fix comments. ........ r1715 | stevenknight | 2006-12-06 07:23:18 -0600 (Wed, 06 Dec 2006) | 1 line 0.96.D369 - More efficient Node.FS.Dir.current() check. Fix some Windows test portability issues. ........ r1716 | stevenknight | 2006-12-06 12:24:32 -0600 (Wed, 06 Dec 2006) | 2 lines Undo previous checkin (distributed incorrect Aegis change number). ........ r1717 | stevenknight | 2006-12-06 12:34:53 -0600 (Wed, 06 Dec 2006) | 1 line 0.96.D505 - Update ae-{cvs,svn}-ci for newer versions of aetar, and to not truncate descriptions. ........ r1718 | stevenknight | 2006-12-07 23:01:41 -0600 (Thu, 07 Dec 2006) | 1 line 0.96.D509 - Only look for mslink on Windows systems. (Sohail Somani) ........ r1719 | stevenknight | 2006-12-07 23:18:33 -0600 (Thu, 07 Dec 2006) | 1 line 0.96.D510 - Have the D compiler Tool use the same logic for shared libraries, too. (Paolo Invernizzi) ........ r1720 | stevenknight | 2006-12-07 23:29:47 -0600 (Thu, 07 Dec 2006) | 1 line 0.96.D511 - Generalize a JobTests.py test so it doesn't assume a specific order in which the operating system executes the threads. ........ r1721 | stevenknight | 2006-12-07 23:39:37 -0600 (Thu, 07 Dec 2006) | 1 line 0.96.D512 - Back out the Tool/dmd.py change; it breaks shared library linking for other lanuages beside D in the construction environment. ........ r1722 | stevenknight | 2006-12-07 23:47:11 -0600 (Thu, 07 Dec 2006) | 1 line 0.96.D513 - Test fixes: Windows portability, handle changes to Python 2.5 messages. ........ r1723 | stevenknight | 2006-12-08 00:00:13 -0600 (Fri, 08 Dec 2006) | 1 line 0.96.D514 - Change how the 'as' Tool is imported to accomodate the Python 2.6 'as' keyword. ........ r1724 | stevenknight | 2006-12-08 11:19:27 -0600 (Fri, 08 Dec 2006) | 1 line 0.96.D515 - Cache both Node.FS.find_file() and Node.FS.Dri.srcdir_find_file(). ........ r1725 | stevenknight | 2006-12-08 17:27:35 -0600 (Fri, 08 Dec 2006) | 1 line 0.96.D516 - Better error when we try to fetch contents from an Entry that doesn't exist. (Tom Parker) ........ r1726 | stevenknight | 2006-12-08 23:28:55 -0600 (Fri, 08 Dec 2006) | 1 line 0.96.D517 - Make sure we pick up the scons-local directory regardless of where we chdir internally. ........ r1727 | stevenknight | 2006-12-11 16:25:53 -0600 (Mon, 11 Dec 2006) | 1 line 0.96.D518 - Cache results of Executor.get_unignored_sources() and Executor.process_sources(). Eliminate some map() and disambiguate() calls when scanning for implicit dependencies. ........ r1728 | stevenknight | 2006-12-12 14:32:22 -0600 (Tue, 12 Dec 2006) | 1 line 0.96.D519 - Fix SideEffect() when -j is used. ........ r1729 | stevenknight | 2006-12-12 16:58:15 -0600 (Tue, 12 Dec 2006) | 1 line 0.96.D520 - Add a srcdir keyword to Builder calls. ........ r1730 | stevenknight | 2006-12-12 21:40:59 -0600 (Tue, 12 Dec 2006) | 1 line 0.96.D521 - TeX/LaTeX updates, including handling files in subdirectories. (Joel B. Mohler, Rob Managan, Dmitry Mikhin) ........ r1731 | stevenknight | 2006-12-14 15:01:02 -0600 (Thu, 14 Dec 2006) | 1 line 0.96.D522 - Propogate TypeErrors during variable substitution for display to the user. ........ r1732 | stevenknight | 2006-12-14 20:01:49 -0600 (Thu, 14 Dec 2006) | 1 line 0.96.D523 - Fix the os.path.join() calls in EnvironmentTests.py. ........ r1733 | stevenknight | 2006-12-15 07:48:22 -0600 (Fri, 15 Dec 2006) | 1 line 0.96.D524 - Fix source directories as dependencies of an Alias (0.96.93 problem found by LilyPond). ........ r1735 | stevenknight | 2006-12-15 12:43:45 -0600 (Fri, 15 Dec 2006) | 1 line 0.96.D525 - Allow printing Debug.caller() output (or other end-of-run debugging info) when using -h. ........ r1736 | stevenknight | 2006-12-15 16:30:08 -0600 (Fri, 15 Dec 2006) | 1 line 0.96.D526 - Add an option to debug IndexError and NameError exceptions during variable substitution. ........
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r--src/engine/SCons/Node/FS.py554
-rw-r--r--src/engine/SCons/Node/FSTests.py83
-rw-r--r--src/engine/SCons/Node/__init__.py54
3 files changed, 461 insertions, 230 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 382bca3..08b8d7d 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -346,9 +346,20 @@ class DiskChecker:
self.set_ignore()
def do_diskcheck_match(node, predicate, errorfmt):
- path = node.abspath
- if predicate(path):
- raise TypeError, errorfmt % path
+ result = predicate()
+ try:
+ # If calling the predicate() cached a None value from stat(),
+ # remove it so it doesn't interfere with later attempts to
+ # build this Node as we walk the DAG. (This isn't a great way
+ # to do this, we're reaching into an interface that doesn't
+ # really belong to us, but it's all about performance, so
+ # for now we'll just document the dependency...)
+ if node._memo['stat'] is None:
+ del node._memo['stat']
+ except (AttributeError, KeyError):
+ pass
+ if result:
+ raise TypeError, errorfmt % node.abspath
def ignore_diskcheck_match(node, predicate, errorfmt):
pass
@@ -520,6 +531,8 @@ class Base(SCons.Node.Node):
object identity comparisons.
"""
+ memoizer_counters = []
+
def __init__(self, name, directory, fs):
"""Initialize a generic Node.FS.Base object.
@@ -531,6 +544,7 @@ class Base(SCons.Node.Node):
SCons.Node.Node.__init__(self)
self.name = name
+ self.suffix = SCons.Util.splitext(name)[1]
self.fs = fs
assert directory, "A directory must be provided"
@@ -550,20 +564,11 @@ class Base(SCons.Node.Node):
self.cwd = None # will hold the SConscript directory for target nodes
self.duplicate = directory.duplicate
- def clear(self):
- """Completely clear a Node.FS.Base object of all its cached
- state (so that it can be re-evaluated by interfaces that do
- continuous integration builds).
- __cache_reset__
- """
- SCons.Node.Node.clear(self)
-
def get_dir(self):
return self.dir
def get_suffix(self):
- "__cacheable__"
- return SCons.Util.splitext(self.name)[1]
+ return self.suffix
def rfile(self):
return self
@@ -576,9 +581,16 @@ class Base(SCons.Node.Node):
return self._save_str()
return self._get_str()
+ memoizer_counters.append(SCons.Memoize.CountValue('_save_str'))
+
def _save_str(self):
- "__cacheable__"
- return self._get_str()
+ try:
+ return self._memo['_save_str']
+ except KeyError:
+ pass
+ result = self._get_str()
+ self._memo['_save_str'] = result
+ return result
def _get_str(self):
if self.duplicate or self.is_derived():
@@ -587,17 +599,20 @@ class Base(SCons.Node.Node):
rstr = __str__
+ memoizer_counters.append(SCons.Memoize.CountValue('stat'))
+
def stat(self):
- "__cacheable__"
- try: return self.fs.stat(self.abspath)
- except os.error: return None
+ try: return self._memo['stat']
+ except KeyError: pass
+ try: result = self.fs.stat(self.abspath)
+ except os.error: result = None
+ self._memo['stat'] = result
+ return result
def exists(self):
- "__cacheable__"
return not self.stat() is None
def rexists(self):
- "__cacheable__"
return self.rfile().exists()
def getmtime(self):
@@ -640,7 +655,7 @@ class Base(SCons.Node.Node):
"""If this node is in a build path, return the node
corresponding to its source file. Otherwise, return
ourself.
- __cacheable__"""
+ """
dir=self.dir
name=self.name
while dir:
@@ -707,9 +722,48 @@ class Base(SCons.Node.Node):
def target_from_source(self, prefix, suffix, splitext=SCons.Util.splitext):
return self.dir.Entry(prefix + splitext(self.name)[0] + suffix)
+ def _Rfindalldirs_key(self, pathlist):
+ return pathlist
+
+ memoizer_counters.append(SCons.Memoize.CountDict('Rfindalldirs', _Rfindalldirs_key))
+
+ def Rfindalldirs(self, pathlist):
+ """
+ Return all of the directories for a given path list, including
+ corresponding "backing" directories in any repositories.
+
+ The Node lookups are relative to this Node (typically a
+ directory), so memoizing result saves cycles from looking
+ up the same path for each target in a given directory.
+ """
+ try:
+ memo_dict = self._memo['Rfindalldirs']
+ except KeyError:
+ memo_dict = {}
+ self._memo['Rfindalldirs'] = memo_dict
+ else:
+ try:
+ return memo_dict[pathlist]
+ except KeyError:
+ pass
+
+ create_dir_relative_to_self = self.Dir
+ result = []
+ for path in pathlist:
+ if isinstance(path, SCons.Node.Node):
+ result.append(path)
+ else:
+ dir = create_dir_relative_to_self(path)
+ result.extend(dir.get_all_rdirs())
+
+ memo_dict[pathlist] = result
+
+ return result
+
def RDirs(self, pathlist):
"""Search for a list of directories in the Repository list."""
- return self.fs.Rfindalldirs(pathlist, self.cwd)
+ cwd = self.cwd or self.fs._cwd
+ return cwd.Rfindalldirs(pathlist)
class Entry(Base):
"""This is the class for generic Node.FS entries--that is, things
@@ -723,13 +777,35 @@ class Entry(Base):
pass
def disambiguate(self):
- if self.isdir() or self.srcnode().isdir():
+ """
+ """
+ if self.isdir():
self.__class__ = Dir
self._morph()
- else:
+ elif self.isfile():
self.__class__ = File
self._morph()
self.clear()
+ else:
+ # There was nothing on-disk at this location, so look in
+ # the src directory.
+ #
+ # We can't just use self.srcnode() straight away because
+ # that would create an actual Node for this file in the src
+ # directory, and there might not be one. Instead, use the
+ # dir_on_disk() method to see if there's something on-disk
+ # with that name, in which case we can go ahead and call
+ # self.srcnode() to create the right type of entry.
+ srcdir = self.dir.srcnode()
+ if srcdir != self.dir and \
+ srcdir.entry_exists_on_disk(self.name) and \
+ self.srcnode().isdir():
+ self.__class__ = Dir
+ self._morph()
+ else:
+ self.__class__ = File
+ self._morph()
+ self.clear()
return self
def rfile(self):
@@ -759,7 +835,8 @@ class Entry(Base):
return self.get_contents()
if self.islink():
return '' # avoid errors for dangling symlinks
- raise AttributeError
+ msg = "No such file or directory: '%s'" % self.abspath
+ raise SCons.Errors.UserError, msg
def must_be_a_Dir(self):
"""Called to make sure a Node is a Dir. Since we're an
@@ -867,14 +944,6 @@ class LocalFS:
return ''
-if SCons.Memoize.use_old_memoization():
- _FSBase = LocalFS
- class LocalFS(SCons.Memoize.Memoizer, _FSBase):
- def __init__(self, *args, **kw):
- apply(_FSBase.__init__, (self,)+args, kw)
- SCons.Memoize.Memoizer.__init__(self)
-
-
#class RemoteFS:
# # Skeleton for the obvious methods we might need from the
# # abstraction layer for a remote filesystem.
@@ -886,6 +955,8 @@ if SCons.Memoize.use_old_memoization():
class FS(LocalFS):
+ memoizer_counters = []
+
def __init__(self, path = None):
"""Initialize the Node.FS subsystem.
@@ -897,6 +968,8 @@ class FS(LocalFS):
"""
if __debug__: logInstanceCreation(self, 'Node.FS')
+ self._memo = {}
+
self.Root = {}
self.SConstruct_dir = None
self.CachePath = None
@@ -915,10 +988,6 @@ class FS(LocalFS):
self.Top.path = '.'
self.Top.tpath = '.'
self._cwd = self.Top
-
- def clear_cache(self):
- "__cache_reset__"
- pass
def set_SConstruct_dir(self, dir):
self.SConstruct_dir = dir
@@ -942,6 +1011,11 @@ class FS(LocalFS):
raise TypeError, "Tried to lookup %s '%s' as a %s." % \
(node.__class__.__name__, node.path, klass.__name__)
+ def _doLookup_key(self, fsclass, name, directory = None, create = 1):
+ return (fsclass, name, directory)
+
+ memoizer_counters.append(SCons.Memoize.CountDict('_doLookup', _doLookup_key))
+
def _doLookup(self, fsclass, name, directory = None, create = 1):
"""This method differs from the File and Dir factory methods in
one important way: the meaning of the directory parameter.
@@ -949,7 +1023,18 @@ class FS(LocalFS):
name is expected to be an absolute path. If you try to look up a
relative path with directory=None, then an AssertionError will be
raised.
- __cacheable__"""
+ """
+ memo_key = (fsclass, name, directory)
+ try:
+ memo_dict = self._memo['_doLookup']
+ except KeyError:
+ memo_dict = {}
+ self._memo['_doLookup'] = memo_dict
+ else:
+ try:
+ return memo_dict[memo_key]
+ except KeyError:
+ pass
if not name:
# This is a stupid hack to compensate for the fact that the
@@ -990,6 +1075,7 @@ class FS(LocalFS):
self.Root[''] = directory
if not path_orig:
+ memo_dict[memo_key] = directory
return directory
last_orig = path_orig.pop() # strip last element
@@ -1040,6 +1126,9 @@ class FS(LocalFS):
directory.add_wkid(result)
else:
result = self.__checkClass(e, fsclass)
+
+ memo_dict[memo_key] = result
+
return result
def _transformPath(self, name, directory):
@@ -1067,7 +1156,8 @@ class FS(LocalFS):
# Correct such that '#/foo' is equivalent
# to '#foo'.
name = name[1:]
- name = os.path.join('.', os.path.normpath(name))
+ name = os.path.normpath(os.path.join('.', name))
+ return (name, directory)
elif not directory:
directory = self._cwd
return (os.path.normpath(name), directory)
@@ -1116,7 +1206,6 @@ class FS(LocalFS):
This method will raise TypeError if a directory is found at the
specified path.
"""
-
return self.Entry(name, directory, create, File)
def Dir(self, name, directory = None, create = 1):
@@ -1129,7 +1218,6 @@ class FS(LocalFS):
This method will raise TypeError if a normal file is found at the
specified path.
"""
-
return self.Entry(name, directory, create, Dir)
def BuildDir(self, build_dir, src_dir, duplicate=1):
@@ -1155,22 +1243,6 @@ class FS(LocalFS):
d = self.Dir(d)
self.Top.addRepository(d)
- def Rfindalldirs(self, pathlist, cwd):
- """__cacheable__"""
- if SCons.Util.is_String(pathlist):
- pathlist = string.split(pathlist, os.pathsep)
- if not SCons.Util.is_List(pathlist):
- pathlist = [pathlist]
- result = []
- for path in filter(None, pathlist):
- if isinstance(path, SCons.Node.Node):
- result.append(path)
- continue
- path, dir = self._transformPath(path, cwd)
- dir = dir.Dir(path)
- result.extend(dir.get_all_rdirs())
- return result
-
def CacheDebugWrite(self, fmt, target, cachefile):
self.CacheDebugFP.write(fmt % (target, os.path.split(cachefile)[1]))
@@ -1194,7 +1266,10 @@ class FS(LocalFS):
Climb the directory tree, and look up path names
relative to any linked build directories we find.
- __cacheable__
+
+ Even though this loops and walks up the tree, we don't memoize
+ the return value because this is really only used to process
+ the command-line targets.
"""
targets = []
message = None
@@ -1223,6 +1298,8 @@ class Dir(Base):
"""A class for directories in a file system.
"""
+ memoizer_counters = []
+
NodeInfo = DirNodeInfo
BuildInfo = DirBuildInfo
@@ -1238,7 +1315,7 @@ class Dir(Base):
Set up this directory's entries and hook it into the file
system tree. Specify that directories (this Node) don't use
signatures for calculating whether they're current.
- __cache_reset__"""
+ """
self.repositories = []
self.srcdir = None
@@ -1258,8 +1335,8 @@ class Dir(Base):
self.get_executor().set_action_list(self.builder.action)
def diskcheck_match(self):
- diskcheck_match(self, self.fs.isfile,
- "File %s found where directory expected.")
+ diskcheck_match(self, self.isfile,
+ "File %s found where directory expected.")
def __clearRepositoryCache(self, duplicate=None):
"""Called when we change the repository(ies) for a directory.
@@ -1305,13 +1382,19 @@ class Dir(Base):
def getRepositories(self):
"""Returns a list of repositories for this directory.
- __cacheable__"""
+ """
if self.srcdir and not self.duplicate:
return self.srcdir.get_all_rdirs() + self.repositories
return self.repositories
+ memoizer_counters.append(SCons.Memoize.CountValue('get_all_rdirs'))
+
def get_all_rdirs(self):
- """__cacheable__"""
+ try:
+ return self._memo['get_all_rdirs']
+ except KeyError:
+ pass
+
result = [self]
fname = '.'
dir = self
@@ -1320,6 +1403,9 @@ class Dir(Base):
result.append(rep.Dir(fname))
fname = dir.name + os.sep + fname
dir = dir.up()
+
+ self._memo['get_all_rdirs'] = result
+
return result
def addRepository(self, dir):
@@ -1331,29 +1417,54 @@ class Dir(Base):
def up(self):
return self.entries['..']
+ def _rel_path_key(self, other):
+ return str(other)
+
+ memoizer_counters.append(SCons.Memoize.CountDict('rel_path', _rel_path_key))
+
def rel_path(self, other):
"""Return a path to "other" relative to this directory.
- __cacheable__"""
- if isinstance(other, Dir):
- name = []
+ """
+ try:
+ memo_dict = self._memo['rel_path']
+ except KeyError:
+ memo_dict = {}
+ self._memo['rel_path'] = memo_dict
else:
try:
- name = [other.name]
- other = other.dir
- except AttributeError:
- return str(other)
+ return memo_dict[other]
+ except KeyError:
+ pass
+
if self is other:
- return name and name[0] or '.'
- i = 0
- for x, y in map(None, self.path_elements, other.path_elements):
- if not x is y:
- break
- i = i + 1
- path_elems = ['..']*(len(self.path_elements)-i) \
- + map(lambda n: n.name, other.path_elements[i:]) \
- + name
+
+ result = '.'
+
+ elif not other in self.path_elements:
+
+ try:
+ other_dir = other.dir
+ except AttributeError:
+ result = str(other)
+ else:
+ dir_rel_path = self.rel_path(other_dir)
+ if dir_rel_path == '.':
+ result = other.name
+ else:
+ result = dir_rel_path + os.sep + other.name
+
+ else:
+
+ i = self.path_elements.index(other) + 1
+
+ path_elems = ['..'] * (len(self.path_elements) - i) \
+ + map(lambda n: n.name, other.path_elements[i:])
- return string.join(path_elems, os.sep)
+ result = string.join(path_elems, os.sep)
+
+ memo_dict[other] = result
+
+ return result
def get_env_scanner(self, env, kw={}):
return SCons.Defaults.DirEntryScanner
@@ -1362,10 +1473,13 @@ class Dir(Base):
return SCons.Defaults.DirEntryScanner
def get_found_includes(self, env, scanner, path):
- """Return the included implicit dependencies in this file.
- Cache results so we only scan the file once per path
- regardless of how many times this information is requested.
- __cacheable__"""
+ """Return this directory's implicit dependencies.
+
+ We don't bother caching the results because the scan typically
+ shouldn't be requested more than once (as opposed to scanning
+ .h file contents, which can be requested as many times as the
+ files is #included by other files).
+ """
if not scanner:
return []
# Clear cached info for this Dir. If we already visited this
@@ -1451,7 +1565,6 @@ class Dir(Base):
return 1
def rdir(self):
- "__cacheable__"
if not self.exists():
norm_name = _my_normcase(self.name)
for dir in self.dir.get_all_rdirs():
@@ -1500,7 +1613,6 @@ class Dir(Base):
return self
def entry_exists_on_disk(self, name):
- """__cacheable__"""
try:
d = self.on_disk_entries
except AttributeError:
@@ -1515,8 +1627,14 @@ class Dir(Base):
self.on_disk_entries = d
return d.has_key(_my_normcase(name))
+ memoizer_counters.append(SCons.Memoize.CountValue('srcdir_list'))
+
def srcdir_list(self):
- """__cacheable__"""
+ try:
+ return self._memo['srcdir_list']
+ except KeyError:
+ pass
+
result = []
dirname = '.'
@@ -1533,6 +1651,8 @@ class Dir(Base):
dirname = dir.name + os.sep + dirname
dir = dir.up()
+ self._memo['srcdir_list'] = result
+
return result
def srcdir_duplicate(self, name):
@@ -1547,8 +1667,23 @@ class Dir(Base):
return srcnode
return None
+ def _srcdir_find_file_key(self, filename):
+ return filename
+
+ memoizer_counters.append(SCons.Memoize.CountDict('srcdir_find_file', _srcdir_find_file_key))
+
def srcdir_find_file(self, filename):
- """__cacheable__"""
+ try:
+ memo_dict = self._memo['srcdir_find_file']
+ except KeyError:
+ memo_dict = {}
+ self._memo['srcdir_find_file'] = memo_dict
+ else:
+ try:
+ return memo_dict[filename]
+ except KeyError:
+ pass
+
def func(node):
if (isinstance(node, File) or isinstance(node, Entry)) and \
(node.is_derived() or node.is_pseudo_derived() or node.exists()):
@@ -1562,7 +1697,9 @@ class Dir(Base):
except KeyError: node = rdir.file_on_disk(filename)
else: node = func(node)
if node:
- return node, self
+ result = (node, self)
+ memo_dict[filename] = result
+ return result
for srcdir in self.srcdir_list():
for rdir in srcdir.get_all_rdirs():
@@ -1570,9 +1707,13 @@ class Dir(Base):
except KeyError: node = rdir.file_on_disk(filename)
else: node = func(node)
if node:
- return File(filename, self, self.fs), srcdir
+ result = (File(filename, self, self.fs), srcdir)
+ memo_dict[filename] = result
+ return result
- return None, None
+ result = (None, None)
+ memo_dict[filename] = result
+ return result
def dir_on_disk(self, name):
if self.entry_exists_on_disk(name):
@@ -1720,12 +1861,14 @@ class File(Base):
"""A class for files in a file system.
"""
+ memoizer_counters = []
+
NodeInfo = FileNodeInfo
BuildInfo = FileBuildInfo
def diskcheck_match(self):
- diskcheck_match(self, self.fs.isdir,
- "Directory %s found where file expected.")
+ diskcheck_match(self, self.isdir,
+ "Directory %s found where file expected.")
def __init__(self, name, directory, fs):
if __debug__: logInstanceCreation(self, 'Node.FS.File')
@@ -1760,7 +1903,7 @@ class File(Base):
# 'RDirs' : self.RDirs}
def _morph(self):
- """Turn a file system node into a File object. __cache_reset__"""
+ """Turn a file system node into a File object."""
self.scanner_paths = {}
if not hasattr(self, '_local'):
self._local = 0
@@ -1789,7 +1932,6 @@ class File(Base):
self.dir.sconsign().set_entry(self.name, entry)
def get_stored_info(self):
- "__cacheable__"
try:
stored = self.dir.sconsign().get_entry(self.name)
except (KeyError, OSError):
@@ -1816,14 +1958,37 @@ class File(Base):
def rel_path(self, other):
return self.dir.rel_path(other)
+ def _get_found_includes_key(self, env, scanner, path):
+ return (id(env), id(scanner), path)
+
+ memoizer_counters.append(SCons.Memoize.CountDict('get_found_includes', _get_found_includes_key))
+
def get_found_includes(self, env, scanner, path):
"""Return the included implicit dependencies in this file.
Cache results so we only scan the file once per path
regardless of how many times this information is requested.
- __cacheable__"""
- if not scanner:
- return []
- return scanner(self, env, path)
+ """
+ memo_key = (id(env), id(scanner), path)
+ try:
+ memo_dict = self._memo['get_found_includes']
+ except KeyError:
+ memo_dict = {}
+ self._memo['get_found_includes'] = memo_dict
+ else:
+ try:
+ return memo_dict[memo_key]
+ except KeyError:
+ pass
+
+ if scanner:
+ result = scanner(self, env, path)
+ result = map(lambda N: N.disambiguate(), result)
+ else:
+ result = []
+
+ memo_dict[memo_key] = result
+
+ return result
def _createDir(self):
# ensure that the directories for this node are
@@ -1875,13 +2040,17 @@ class File(Base):
def built(self):
"""Called just after this node is successfully built.
- __cache_reset__"""
+ """
# Push this file out to cache before the superclass Node.built()
# method has a chance to clear the build signature, which it
# will do if this file has a source scanner.
+ #
+ # We have to clear the memoized values *before* we push it to
+ # cache so that the memoization of the self.exists() return
+ # value doesn't interfere.
+ self.clear_memoized_values()
if self.fs.CachePath and self.exists():
CachePush(self, [], None)
- self.fs.clear_cache()
SCons.Node.Node.built(self)
def visited(self):
@@ -1926,11 +2095,10 @@ class File(Base):
return self.fs.build_dir_target_climb(self, self.dir, [self.name])
def is_pseudo_derived(self):
- "__cacheable__"
return self.has_src_builder()
def _rmv_existing(self):
- '__cache_reset__'
+ self.clear_memoized_values()
Unlink(self, [], None)
def prepare(self):
@@ -1973,29 +2141,36 @@ class File(Base):
# _rexists attributes so they can be reevaluated.
self.clear()
+ memoizer_counters.append(SCons.Memoize.CountValue('exists'))
+
def exists(self):
- "__cacheable__"
+ try:
+ return self._memo['exists']
+ except KeyError:
+ pass
# Duplicate from source path if we are set up to do this.
if self.duplicate and not self.is_derived() and not self.linked:
src = self.srcnode()
- if src is self:
- return Base.exists(self)
- # At this point, src is meant to be copied in a build directory.
- src = src.rfile()
- if src.abspath != self.abspath:
- if src.exists():
- self.do_duplicate(src)
- # Can't return 1 here because the duplication might
- # not actually occur if the -n option is being used.
- else:
- # The source file does not exist. Make sure no old
- # copy remains in the build directory.
- if Base.exists(self) or self.islink():
- self.fs.unlink(self.path)
- # Return None explicitly because the Base.exists() call
- # above will have cached its value if the file existed.
- return None
- return Base.exists(self)
+ if not src is self:
+ # At this point, src is meant to be copied in a build directory.
+ src = src.rfile()
+ if src.abspath != self.abspath:
+ if src.exists():
+ self.do_duplicate(src)
+ # Can't return 1 here because the duplication might
+ # not actually occur if the -n option is being used.
+ else:
+ # The source file does not exist. Make sure no old
+ # copy remains in the build directory.
+ if Base.exists(self) or self.islink():
+ self.fs.unlink(self.path)
+ # Return None explicitly because the Base.exists() call
+ # above will have cached its value if the file existed.
+ self._memo['exists'] = None
+ return None
+ result = Base.exists(self)
+ self._memo['exists'] = result
+ return result
#
# SIGNATURE SUBSYSTEM
@@ -2063,7 +2238,6 @@ class File(Base):
self.binfo = self.gen_binfo(calc)
return self._cur2()
def _cur2(self):
- "__cacheable__"
if self.always_build:
return None
if not self.exists():
@@ -2082,8 +2256,14 @@ class File(Base):
else:
return self.is_up_to_date()
+ memoizer_counters.append(SCons.Memoize.CountValue('rfile'))
+
def rfile(self):
- "__cacheable__"
+ try:
+ return self._memo['rfile']
+ except KeyError:
+ pass
+ result = self
if not self.exists():
norm_name = _my_normcase(self.name)
for dir in self.dir.get_all_rdirs():
@@ -2092,8 +2272,10 @@ class File(Base):
if node and node.exists() and \
(isinstance(node, File) or isinstance(node, Entry) \
or not node.is_derived()):
- return node
- return self
+ result = node
+ break
+ self._memo['rfile'] = result
+ return result
def rstr(self):
return str(self.rfile())
@@ -2121,72 +2303,82 @@ class File(Base):
default_fs = None
-def find_file(filename, paths, verbose=None):
+class FileFinder:
+ """
"""
- find_file(str, [Dir()]) -> [nodes]
+ if SCons.Memoize.use_memoizer:
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass
- filename - a filename to find
- paths - a list of directory path *nodes* to search in. Can be
- represented as a list, a tuple, or a callable that is
- called with no arguments and returns the list or tuple.
+ memoizer_counters = []
- returns - the node created from the found file.
+ def __init__(self):
+ self._memo = {}
- Find a node corresponding to either a derived file or a file
- that exists already.
+ def _find_file_key(self, filename, paths, verbose=None):
+ return (filename, paths)
+
+ memoizer_counters.append(SCons.Memoize.CountDict('find_file', _find_file_key))
- Only the first file found is returned, and none is returned
- if no file is found.
- __cacheable__
- """
- if verbose:
- if not SCons.Util.is_String(verbose):
- verbose = "find_file"
- if not callable(verbose):
- verbose = ' %s: ' % verbose
- verbose = lambda s, v=verbose: sys.stdout.write(v + s)
- else:
- verbose = lambda x: x
+ def find_file(self, filename, paths, verbose=None):
+ """
+ find_file(str, [Dir()]) -> [nodes]
+
+ filename - a filename to find
+ paths - a list of directory path *nodes* to search in. Can be
+ represented as a list, a tuple, or a callable that is
+ called with no arguments and returns the list or tuple.
- if callable(paths):
- paths = paths()
+ returns - the node created from the found file.
- # Give Entries a chance to morph into Dirs.
- paths = map(lambda p: p.must_be_a_Dir(), paths)
+ Find a node corresponding to either a derived file or a file
+ that exists already.
- filedir, filename = os.path.split(filename)
- if filedir:
- def filedir_lookup(p, fd=filedir):
+ Only the first file found is returned, and none is returned
+ if no file is found.
+ """
+ memo_key = self._find_file_key(filename, paths)
+ try:
+ memo_dict = self._memo['find_file']
+ except KeyError:
+ memo_dict = {}
+ self._memo['find_file'] = memo_dict
+ else:
try:
- return p.Dir(fd)
- except TypeError:
- # We tried to look up a Dir, but it seems there's already
- # a File (or something else) there. No big.
- return None
- paths = filter(None, map(filedir_lookup, paths))
-
- for dir in paths:
- verbose("looking for '%s' in '%s' ...\n" % (filename, dir))
- node, d = dir.srcdir_find_file(filename)
- if node:
- verbose("... FOUND '%s' in '%s'\n" % (filename, d))
- return node
- return None
+ return memo_dict[memo_key]
+ except KeyError:
+ pass
-def find_files(filenames, paths):
- """
- find_files([str], [Dir()]) -> [nodes]
+ if verbose:
+ if not SCons.Util.is_String(verbose):
+ verbose = "find_file"
+ if not callable(verbose):
+ verbose = ' %s: ' % verbose
+ verbose = lambda s, v=verbose: sys.stdout.write(v + s)
+ else:
+ verbose = lambda x: x
- filenames - a list of filenames to find
- paths - a list of directory path *nodes* to search in
+ filedir, filename = os.path.split(filename)
+ if filedir:
+ def filedir_lookup(p, fd=filedir):
+ try:
+ return p.Dir(fd)
+ except TypeError:
+ # We tried to look up a Dir, but it seems there's
+ # already a File (or something else) there. No big.
+ return None
+ paths = filter(None, map(filedir_lookup, paths))
- returns - the nodes created from the found files.
+ result = None
+ for dir in paths:
+ verbose("looking for '%s' in '%s' ...\n" % (filename, dir))
+ node, d = dir.srcdir_find_file(filename)
+ if node:
+ verbose("... FOUND '%s' in '%s'\n" % (filename, d))
+ result = node
+ break
- Finds nodes corresponding to either derived files or files
- that exist already.
+ memo_dict[memo_key] = result
- Only the first file found is returned for each filename,
- and any files that aren't found are ignored.
- """
- nodes = map(lambda x, paths=paths: find_file(x, paths), filenames)
- return filter(None, nodes)
+ return result
+
+find_file = FileFinder().find_file
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 1b38ffe..434709c 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -740,14 +740,22 @@ class FileNodeInfoTestCase(_tempdirTestCase):
test.write('fff', "fff\n")
- assert ni.timestamp != os.path.getmtime('fff'), ni.timestamp
- assert ni.size != os.path.getsize('fff'), ni.size
+ st = os.stat('fff')
+
+ mtime = st[stat.ST_MTIME]
+ assert ni.timestamp != mtime, (ni.timestamp, mtime)
+ size = st[stat.ST_SIZE]
+ assert ni.size != size, (ni.size, size)
fff.clear()
ni.update(fff)
- assert ni.timestamp == os.path.getmtime('fff'), ni.timestamp
- assert ni.size == os.path.getsize('fff'), ni.size
+ st = os.stat('fff')
+
+ mtime = st[stat.ST_MTIME]
+ assert ni.timestamp == mtime, (ni.timestamp, mtime)
+ size = st[stat.ST_SIZE]
+ assert ni.size == size, (ni.size, size)
class FileBuildInfoTestCase(_tempdirTestCase):
def test___init__(self):
@@ -1219,9 +1227,9 @@ class FSTestCase(_tempdirTestCase):
exc_caught = 0
try:
e.get_contents()
- except AttributeError:
+ except SCons.Errors.UserError:
exc_caught = 1
- assert exc_caught, "Should have caught an AttributError"
+ assert exc_caught, "Should have caught an IOError"
test.write("file", "file\n")
try:
@@ -1266,18 +1274,18 @@ class FSTestCase(_tempdirTestCase):
assert t == 0, "expected 0, got %s" % str(t)
test.subdir('tdir2')
- d = fs.Dir('tdir2')
f1 = test.workpath('tdir2', 'file1')
f2 = test.workpath('tdir2', 'file2')
test.write(f1, 'file1\n')
test.write(f2, 'file2\n')
- fs.File(f1)
- fs.File(f2)
current_time = float(int(time.time() / 2) * 2)
t1 = current_time - 4.0
t2 = current_time - 2.0
os.utime(f1, (t1 - 2.0, t1))
os.utime(f2, (t2 - 2.0, t2))
+ d = fs.Dir('tdir2')
+ fs.File(f1)
+ fs.File(f2)
t = d.get_timestamp()
assert t == t2, "expected %f, got %f" % (t2, t)
@@ -1861,9 +1869,9 @@ class EntryTestCase(_tempdirTestCase):
exc_caught = None
try:
e3n.get_contents()
- except AttributeError:
+ except SCons.Errors.UserError:
exc_caught = 1
- assert exc_caught, "did not catch expected AttributeError"
+ assert exc_caught, "did not catch expected SCons.Errors.UserError"
test.subdir('e4d')
test.write('e4f', "e4f\n")
@@ -2133,25 +2141,25 @@ class RepositoryTestCase(_tempdirTestCase):
rep2_sub_d1 = fs.Dir(test.workpath('rep2', 'sub', 'd1'))
rep3_sub_d1 = fs.Dir(test.workpath('rep3', 'sub', 'd1'))
- r = fs.Rfindalldirs(d1, fs.Top)
+ r = fs.Top.Rfindalldirs((d1,))
assert r == [d1], map(str, r)
- r = fs.Rfindalldirs([d1, d2], fs.Top)
+ r = fs.Top.Rfindalldirs((d1, d2))
assert r == [d1, d2], map(str, r)
- r = fs.Rfindalldirs('d1', fs.Top)
+ r = fs.Top.Rfindalldirs(('d1',))
assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
- r = fs.Rfindalldirs('#d1', fs.Top)
+ r = fs.Top.Rfindalldirs(('#d1',))
assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
- r = fs.Rfindalldirs('d1', sub)
+ r = sub.Rfindalldirs(('d1',))
assert r == [sub_d1, rep1_sub_d1, rep2_sub_d1, rep3_sub_d1], map(str, r)
- r = fs.Rfindalldirs('#d1', sub)
+ r = sub.Rfindalldirs(('#d1',))
assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
- r = fs.Rfindalldirs(['d1', d2], fs.Top)
+ r = fs.Top.Rfindalldirs(('d1', d2))
assert r == [d1, rep1_d1, rep2_d1, rep3_d1, d2], map(str, r)
def test_rexists(self):
@@ -2223,6 +2231,7 @@ class find_fileTestCase(unittest.TestCase):
"""Testing find_file function"""
test = TestCmd(workdir = '')
test.write('./foo', 'Some file\n')
+ test.write('./foo2', 'Another file\n')
test.subdir('same')
test.subdir('bar')
test.write(['bar', 'on_disk'], 'Another file\n')
@@ -2237,7 +2246,7 @@ class find_fileTestCase(unittest.TestCase):
node_pseudo = fs.File(test.workpath('pseudo'))
node_pseudo.set_src_builder(1) # Any non-zero value.
- paths = map(fs.Dir, ['.', 'same', './bar'])
+ paths = tuple(map(fs.Dir, ['.', 'same', './bar']))
nodes = [SCons.Node.FS.find_file('foo', paths)]
nodes.append(SCons.Node.FS.find_file('baz', paths))
nodes.append(SCons.Node.FS.find_file('pseudo', paths))
@@ -2261,19 +2270,18 @@ class find_fileTestCase(unittest.TestCase):
try:
sio = StringIO.StringIO()
sys.stdout = sio
- SCons.Node.FS.find_file('foo', paths, verbose="xyz")
- expect = " xyz: looking for 'foo' in '.' ...\n" + \
- " xyz: ... FOUND 'foo' in '.'\n"
+ SCons.Node.FS.find_file('foo2', paths, verbose="xyz")
+ expect = " xyz: looking for 'foo2' in '.' ...\n" + \
+ " xyz: ... FOUND 'foo2' in '.'\n"
c = sio.getvalue()
assert c == expect, c
sio = StringIO.StringIO()
sys.stdout = sio
- SCons.Node.FS.find_file('baz', paths, verbose=1)
- expect = " find_file: looking for 'baz' in '.' ...\n" + \
- " find_file: looking for 'baz' in 'same' ...\n" + \
- " find_file: looking for 'baz' in 'bar' ...\n" + \
- " find_file: ... FOUND 'baz' in 'bar'\n"
+ SCons.Node.FS.find_file('baz2', paths, verbose=1)
+ expect = " find_file: looking for 'baz2' in '.' ...\n" + \
+ " find_file: looking for 'baz2' in 'same' ...\n" + \
+ " find_file: looking for 'baz2' in 'bar' ...\n"
c = sio.getvalue()
assert c == expect, c
@@ -2717,12 +2725,29 @@ class disambiguateTestCase(unittest.TestCase):
f = efile.disambiguate()
assert f.__class__ is fff.__class__, f.__class__
+ test.subdir('build')
+ test.subdir(['build', 'bdir'])
+ test.write(['build', 'bfile'], "build/bfile\n")
+
test.subdir('src')
+ test.write(['src', 'bdir'], "src/bdir\n")
+ test.subdir(['src', 'bfile'])
+
test.subdir(['src', 'edir'])
test.write(['src', 'efile'], "src/efile\n")
fs.BuildDir(test.workpath('build'), test.workpath('src'))
+ build_bdir = fs.Entry(test.workpath('build/bdir'))
+ d = build_bdir.disambiguate()
+ assert d is build_bdir, d
+ assert d.__class__ is ddd.__class__, d.__class__
+
+ build_bfile = fs.Entry(test.workpath('build/bfile'))
+ f = build_bfile.disambiguate()
+ assert f is build_bfile, f
+ assert f.__class__ is fff.__class__, f.__class__
+
build_edir = fs.Entry(test.workpath('build/edir'))
d = build_edir.disambiguate()
assert d.__class__ is ddd.__class__, d.__class__
@@ -2731,6 +2756,10 @@ class disambiguateTestCase(unittest.TestCase):
f = build_efile.disambiguate()
assert f.__class__ is fff.__class__, f.__class__
+ build_nonexistant = fs.Entry(test.workpath('build/nonexistant'))
+ f = build_nonexistant.disambiguate()
+ assert f.__class__ is fff.__class__, f.__class__
+
class postprocessTestCase(unittest.TestCase):
def runTest(self):
"""Test calling the postprocess() method."""
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 42be5b1..e5d064e 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -166,6 +166,8 @@ class Node:
if SCons.Memoize.use_memoizer:
__metaclass__ = SCons.Memoize.Memoized_Metaclass
+ memoizer_counters = []
+
class Attrs:
pass
@@ -210,6 +212,8 @@ class Node:
self.post_actions = []
self.linked = 0 # is this node linked to the build directory?
+ self.clear_memoized_values()
+
# Let the interface in which the build engine is embedded
# annotate this Node with its own info (like a description of
# what line in what file created the node, for example).
@@ -223,7 +227,7 @@ class Node:
def get_build_env(self):
"""Fetch the appropriate Environment to build this node.
- __cacheable__"""
+ """
return self.get_executor().get_build_env()
def get_build_scanner_path(self, scanner):
@@ -349,8 +353,8 @@ class Node:
"""Completely clear a Node of all its cached state (so that it
can be re-evaluated by interfaces that do continuous integration
builds).
- __reset_cache__
"""
+ self.clear_memoized_values()
self.executor_cleanup()
self.del_binfo()
try:
@@ -361,13 +365,15 @@ class Node:
self.found_includes = {}
self.implicit = None
+ def clear_memoized_values(self):
+ self._memo = {}
+
def visited(self):
"""Called just after this node has been visited
without requiring a build.."""
pass
def builder_set(self, builder):
- "__cache_reset__"
self.builder = builder
def has_builder(self):
@@ -424,7 +430,6 @@ class Node:
signatures when they are used as source files to other derived files. For
example: source with source builders are not derived in this sense,
and hence should not return true.
- __cacheable__
"""
return self.has_builder() or self.side_effect
@@ -474,7 +479,6 @@ class Node:
d = filter(lambda x, seen=seen: not seen.has_key(x),
n.get_found_includes(env, scanner, path))
if d:
- d = map(lambda N: N.disambiguate(), d)
deps.extend(d)
for n in d:
seen[n] = 1
@@ -609,24 +613,34 @@ class Node:
env = self.env or SCons.Defaults.DefaultEnvironment()
return env.get_calculator()
+ memoizer_counters.append(SCons.Memoize.CountValue('calc_signature'))
+
def calc_signature(self, calc=None):
"""
Select and calculate the appropriate build signature for a node.
- __cacheable__
self - the node
calc - the signature calculation module
returns - the signature
"""
+ try:
+ return self._memo['calc_signature']
+ except KeyError:
+ pass
if self.is_derived():
import SCons.Defaults
env = self.env or SCons.Defaults.DefaultEnvironment()
if env.use_build_signature():
- return self.get_bsig(calc)
+ result = self.get_bsig(calc)
+ else:
+ result = self.get_csig(calc)
elif not self.rexists():
- return None
- return self.get_csig(calc)
+ result = None
+ else:
+ result = self.get_csig(calc)
+ self._memo['calc_signature'] = result
+ return result
def new_ninfo(self):
return self.NodeInfo(self)
@@ -661,7 +675,6 @@ class Node:
node's children's signatures. We expect that they're
already built and updated by someone else, if that's
what's wanted.
- __cacheable__
"""
if calc is None:
@@ -676,7 +689,7 @@ class Node:
def calc_signature(node, calc=calc):
return node.calc_signature(calc)
- sources = executor.process_sources(None, self.ignore)
+ sources = executor.get_unignored_sources(self.ignore)
sourcesigs = executor.process_sources(calc_signature, self.ignore)
depends = self.depends
@@ -767,7 +780,6 @@ class Node:
return self.exists()
def missing(self):
- """__cacheable__"""
return not self.is_derived() and \
not self.is_pseudo_derived() and \
not self.linked and \
@@ -850,7 +862,7 @@ class Node:
self.wkids.append(wkid)
def _children_reset(self):
- "__cache_reset__"
+ self.clear_memoized_values()
# We need to let the Executor clear out any calculated
# bsig info that it's cached so we can re-calculate it.
self.executor_cleanup()
@@ -881,11 +893,17 @@ class Node:
else:
return self.sources + self.depends + self.implicit
+ memoizer_counters.append(SCons.Memoize.CountValue('_children_get'))
+
def _children_get(self):
- "__cacheable__"
+ try:
+ return self._memo['children_get']
+ except KeyError:
+ pass
children = self._all_children_get()
if self.ignore:
children = filter(self.do_not_ignore, children)
+ self._memo['children_get'] = children
return children
def all_children(self, scan=1):
@@ -1101,14 +1119,6 @@ else:
del l
del ul
-if SCons.Memoize.use_old_memoization():
- _Base = Node
- class Node(SCons.Memoize.Memoizer, _Base):
- def __init__(self, *args, **kw):
- apply(_Base.__init__, (self,)+args, kw)
- SCons.Memoize.Memoizer.__init__(self)
-
-
def get_children(node, parent): return node.children()
def ignore_cycle(node, stack): pass
def do_nothing(node, parent): pass