diff options
| author | Steven Knight <knight@baldmt.com> | 2008-04-17 06:35:51 (GMT) |
|---|---|---|
| committer | Steven Knight <knight@baldmt.com> | 2008-04-17 06:35:51 (GMT) |
| commit | 12ced93c8d443babcf3ba0c0a3503ed6a8fed2d9 (patch) | |
| tree | 340da0ff0ef5002982fcfd5ee2a2a5e34a4bf5e0 /src/engine/SCons/Node | |
| parent | f80d3313d70eace1274f0b5ffbdc53b19acf8250 (diff) | |
| download | SCons-12ced93c8d443babcf3ba0c0a3503ed6a8fed2d9.zip SCons-12ced93c8d443babcf3ba0c0a3503ed6a8fed2d9.tar.gz SCons-12ced93c8d443babcf3ba0c0a3503ed6a8fed2d9.tar.bz2 | |
Merged revisions 2725-2865 via svnmerge from
http://scons.tigris.org/svn/scons/branches/core
........
r2731 | stevenknight | 2008-04-01 09:22:37 -0700 (Tue, 01 Apr 2008) | 4 lines
Fix test/Interactive/version.py, which still had the old hard-coded
Copyright string, by moving the test copy of the Copyright string
into QMTest/TestSCons.py, where it's available to all test scripts.
........
r2732 | stevenknight | 2008-04-02 13:28:32 -0700 (Wed, 02 Apr 2008) | 3 lines
Issues 317, 323, 329: Ignore the -d, -e and -w options, which we're
not going to implement.
........
r2734 | stevenknight | 2008-04-05 07:50:49 -0700 (Sat, 05 Apr 2008) | 2 lines
Fix bootstrap.py for pre-2.3 versions of Python, which don't have __file__.
........
r2735 | stevenknight | 2008-04-05 07:54:44 -0700 (Sat, 05 Apr 2008) | 2 lines
Fix the non-breaking-hyphen regular expression(s) for Python 1.5.
........
r2736 | garyo | 2008-04-05 19:15:52 -0700 (Sat, 05 Apr 2008) | 1 line
Added Users Guide section for AddMethod.
........
r2737 | stevenknight | 2008-04-08 09:43:31 -0700 (Tue, 08 Apr 2008) | 3 lines
Don't raise strings as exceptions in the exception-handling unit tests.
That's now deprecated Python behavior.
........
r2738 | stevenknight | 2008-04-08 10:36:00 -0700 (Tue, 08 Apr 2008) | 5 lines
Address a serious inefficiency in Java builds by moving the pre-build
check for whether source files exist from the Node class to the Executor
class, so we only have to perform the check once when building a whole
bunch of targets from a whole bunch of sources.
........
r2739 | stevenknight | 2008-04-08 13:53:44 -0700 (Tue, 08 Apr 2008) | 2 lines
Add a backwards-compatibility version of the "itertools" module.
........
r2740 | stevenknight | 2008-04-08 14:12:05 -0700 (Tue, 08 Apr 2008) | 2 lines
Issue 1961: speed up SCons.Util.to_String*() functions. (Benoit Belley)
........
r2741 | stevenknight | 2008-04-08 14:15:36 -0700 (Tue, 08 Apr 2008) | 2 lines
Use the itertools.izip() method for some key Node.FS methods. (Benoit Belley)
........
r2742 | stevenknight | 2008-04-08 14:35:35 -0700 (Tue, 08 Apr 2008) | 2 lines
Issues 1961: use izip() instead of zip() where possible (Benoit Belley)
........
r2743 | stevenknight | 2008-04-08 14:48:08 -0700 (Tue, 08 Apr 2008) | 3 lines
Issue 1961: more efficient get_contents() implementation for Python
function Actions. (Benoit Belley)
........
r2744 | stevenknight | 2008-04-08 17:55:30 -0700 (Tue, 08 Apr 2008) | 3 lines
Issue 1961: make SCons.Node.* state variables global in Taskmaster.py so
we avoid unneceesary attribute fetches. (Benoit Belley)
........
r2745 | stevenknight | 2008-04-08 20:40:31 -0700 (Tue, 08 Apr 2008) | 2 lines
Issue 1961: Optimize the code in Node.get_binfo(). (Benoit Belley)
........
r2746 | stevenknight | 2008-04-08 21:05:17 -0700 (Tue, 08 Apr 2008) | 3 lines
Issue 1961: Enhance the backwards-compatibility sets() module with the
ability to compare sets. (Benoit Belley)
........
r2747 | stevenknight | 2008-04-08 22:11:20 -0700 (Tue, 08 Apr 2008) | 2 lines
Issue 1961: Optimize Executor.scan(). (Benoit Belley)
........
r2748 | stevenknight | 2008-04-08 22:17:55 -0700 (Tue, 08 Apr 2008) | 3 lines
Python 1.5 compatibility: use for p in paths.keys() for dictionaries.
(Benoit Belley)
........
r2749 | stevenknight | 2008-04-08 22:54:02 -0700 (Tue, 08 Apr 2008) | 10 lines
Issue 1961: additional build optimizations:
-- Make taskmastertrace output more useful and readable.
-- Move dependency cycle checking to avoid re-doing it.
-- Have Nodes use sets, not dictionaries, to track various things.
-- Eliminate intermediate function calls from fetching Node children.
-- Add a Task.needs_execute() method to avoid doing that check over and
over as part of needs_execute().
-- Remove the unused Node.found_includes attribute.
(Benoit Belley)
........
r2750 | stevenknight | 2008-04-09 14:47:44 -0700 (Wed, 09 Apr 2008) | 4 lines
Make target Java .class files depend *only* on the input .java files as
their sources when determining if they require rebuilding. This eliminates
O(NxM) checking for every single edge in a big, overly-connected DAG mesh.
........
r2751 | stevenknight | 2008-04-09 16:58:41 -0700 (Wed, 09 Apr 2008) | 2 lines
Remove 0.95 and 0.96* release notes.
........
r2752 | stevenknight | 2008-04-10 02:24:50 -0700 (Thu, 10 Apr 2008) | 2 lines
Issue 1956: Fix --debug=stree printing its tree twice. (Benoit Belley)
........
r2753 | stevenknight | 2008-04-10 02:33:28 -0700 (Thu, 10 Apr 2008) | 2 lines
Issue 1896: Add support for the GDC D language compiler. (Matthew Wesley)
........
r2754 | stevenknight | 2008-04-10 02:39:24 -0700 (Thu, 10 Apr 2008) | 2 lines
Fix tabs.
........
r2755 | stevenknight | 2008-04-10 02:41:50 -0700 (Thu, 10 Apr 2008) | 3 lines
Issue 1964: Fix passing variable names in a list to Return() (as
already documented in the man page!) (Mike Wake)
........
r2756 | stevenknight | 2008-04-10 02:55:40 -0700 (Thu, 10 Apr 2008) | 2 lines
Support the ability to download 2.6 candidate releases (e.g. 2.6a2).
........
r2757 | stevenknight | 2008-04-10 02:58:35 -0700 (Thu, 10 Apr 2008) | 3 lines
Issue 1669: Fix the ability to use LoadableModule() under MinGW.
(Johan Boule)
........
r2758 | stevenknight | 2008-04-10 03:03:15 -0700 (Thu, 10 Apr 2008) | 3 lines
Update the test/Interactive/tree.py script for Benoit's fix to
remove duplicate tree printing.
........
r2759 | stevenknight | 2008-04-10 06:43:44 -0700 (Thu, 10 Apr 2008) | 3 lines
Fix Tool/dmd.py when no D compiler is installed -- we don't want to
search for a path if the result is None.
........
r2760 | GregNoel | 2008-04-10 15:30:34 -0700 (Thu, 10 Apr 2008) | 1 line
Issue 2009: separate Debug.caller() by functionality
........
r2761 | stevenknight | 2008-04-11 04:47:25 -0700 (Fri, 11 Apr 2008) | 3 lines
Issue 1882: Add the scons.bat directory to %PATH% so it can find python.exe.
(Anatoly Techtonik)
........
r2762 | stevenknight | 2008-04-11 09:15:22 -0700 (Fri, 11 Apr 2008) | 4 lines
Issues 1835,1901: fix the ability to list a source file multiple
times for a target by making sure we only store unique entries in the
.sconsign file.
........
r2763 | stevenknight | 2008-04-11 10:58:26 -0700 (Fri, 11 Apr 2008) | 4 lines
Issue 1882: Fix earlier patch to scons.bat by adding ~dp0;~dp0.. to
the front of %PATH%, and only executing endlocal on NT-based systems.
(Anatoly Techtonik)
........
r2764 | stevenknight | 2008-04-11 13:06:29 -0700 (Fri, 11 Apr 2008) | 4 lines
Add a Variables object and {Bool,Envum,List,Package,Path}Variable()
functions as a first step towards eventually deprecating the
Options object and {Bool,Envum,List,Package,Path}Option() functions.
........
r2765 | stevenknight | 2008-04-11 18:13:53 -0700 (Fri, 11 Apr 2008) | 3 lines
Issue 1962: Capture a test case for ListActions that contain a
command-line string containing unicode, and Python FunctionAction.
........
r2766 | stevenknight | 2008-04-11 22:03:14 -0700 (Fri, 11 Apr 2008) | 3 lines
Issue 1933: expect .py files generated by the SWIG -python option
to be in the same (sub)directory as the target.
........
r2767 | stevenknight | 2008-04-12 06:41:57 -0700 (Sat, 12 Apr 2008) | 2 lines
Remove the SCons.Options package in favor of the new SCons.Variables package.
........
r2768 | stevenknight | 2008-04-12 13:33:52 -0700 (Sat, 12 Apr 2008) | 5 lines
Issue 1971: Move the incorporation of $CCFLAGS and $SHCCFLAGS directly
into the C++ command lines (${SHCXX,CXX}COM) instead of through indirect
expansion of $CXXFLAGS and $SHCXXFLAGS. This requires removing -fPIC
from the default setting of $SHCXXFLAGS under the GNU toolchain.
........
r2769 | stevenknight | 2008-04-13 07:01:27 -0700 (Sun, 13 Apr 2008) | 3 lines
Fix __all__ definitions in the Variables/*Variable.py file that were
cause epydoc to blow up when generating developer documentation.
........
r2770 | stevenknight | 2008-04-13 11:47:49 -0700 (Sun, 13 Apr 2008) | 3 lines
Add variables= keyword argument to Environment() creation as a first
step towards deprecating options=.
........
r2771 | stevenknight | 2008-04-13 11:54:19 -0700 (Sun, 13 Apr 2008) | 2 lines
Correct underscore-instead-of-hyphen misspellings in option names.
........
r2772 | bdbaddog | 2008-04-13 17:39:21 -0700 (Sun, 13 Apr 2008) | 3 lines
Changes to fix 15 tests which were failing on cygwin.
........
r2773 | GregNoel | 2008-04-13 22:31:07 -0700 (Sun, 13 Apr 2008) | 1 line
Various fixes to tests on Darwin using 1.5.2
........
r2774 | stevenknight | 2008-04-14 15:00:44 -0700 (Mon, 14 Apr 2008) | 2 lines
Python 1.5.2 fix in new test/SWIG/subdir.py script (use the -classic option).
........
r2775 | belley | 2008-04-14 18:02:40 -0700 (Mon, 14 Apr 2008) | 32 lines
Dont use KeyboardInterrupt to stop a build! [Issue 1907]
SCons would often hang after pressing Ctrl-C. I started investigating and I
realized that most of the Python libraries are not really safe with respect to
asynchronous exceptions. Although,there are enough try/finally blocks to handle
exceptions thrown synchronously by the library code, the Python libraries are
not always protected against exceptions being thrown asynchronously, such as a
KeyboardInterrupt being thrown at a completely random location.
For example, the function Queue.empty() does not protect its mutex with a
try/finally block. If the KeyboardInterrupt exception gets thrown while the
mutex is held, any further attempt to access the Queue will lead to dead-lock
(explaining why SCons hangs sometimes after pressing CTRL-C). Even the
threading.Condition condition variables are not async-exception safe. It
therefore seems a lost battle to try to stop a build by raising an exception.
Instead, I have implemented a signal handler that tells the Jobs (and its
associated Taskmaster) to stop the build. I have been careful to wait after the
.sconsign file has been written back to re-install the default SIGINT signal
handler that raises a KeyboardInterrupt exception.
This patch is submitted against changeset 2773 of branches/core. The
regression test suite has been run on RHEL4 using Pyhon 2.5.1 and
1.5.2. My team has been using an SCons build with this patch for a
while now on Windows, Linux and OSX.
See:
http://scons.tigris.org/issues/show_bug.cgi?id=1907
Benoit Belley
........
r2777 | cournape | 2008-04-14 20:11:56 -0700 (Mon, 14 Apr 2008) | 3 lines
Initialized merge tracking via "svnmerge" with revisions "1-2776" from
http://scons.tigris.org/svn/scons/branches/fortran_refactor
........
r2788 | stevenknight | 2008-04-14 22:09:27 -0700 (Mon, 14 Apr 2008) | 2 lines
Fix the print the "script" line in the --version output.
........
r2789 | stevenknight | 2008-04-14 22:18:27 -0700 (Mon, 14 Apr 2008) | 2 lines
Add a __COPYRIGHT__ line.
........
r2790 | stevenknight | 2008-04-14 22:20:39 -0700 (Mon, 14 Apr 2008) | 3 lines
Issue 2008: in checkpoint releases, use a '.' to separate (e.g.) 0.98.0
from 0d20080414.
........
r2817 | belley | 2008-04-15 06:44:21 -0700 (Tue, 15 Apr 2008) | 13 lines
TestSCons.up_to_date() should use match_re_dotall
I changed TestSCons.up_to_date() to use match_re_dotall instead of
match_exact. This is necessary so that I can call up_to_date() with
the TestSCons.deprecated_python_expr error message in one of my test.
Note that TestSCons.not_up_to_date() is already using match_re_dotall.
Ran the test suite on both Python 2.5.1 and 1.5.2.
Benoit
........
r2818 | belley | 2008-04-15 12:10:52 -0700 (Tue, 15 Apr 2008) | 10 lines
Improved the multiple-parents.py test to also tests the following
cases:
d) Some children are ignored
e) Some children are pre-requesites
f) Some sources are missing
The test still passes. No extra bug were found.
........
r2850 | stevenknight | 2008-04-16 11:15:24 -0700 (Wed, 16 Apr 2008) | 4 lines
Fix problems with the __del__() method referencing other module functions
through global variables, which can get deleted out from under us at
shutdown.
........
r2851 | stevenknight | 2008-04-16 11:17:07 -0700 (Wed, 16 Apr 2008) | 4 lines
Fix use of --interactive with -u/-U/-D and VariantDir() by making the
method that cleans Node states between interactive commands aware of
the alter_targets() method that tells us about an associated VariantDir().
........
Diffstat (limited to 'src/engine/SCons/Node')
| -rw-r--r-- | src/engine/SCons/Node/FS.py | 7 | ||||
| -rw-r--r-- | src/engine/SCons/Node/NodeTests.py | 49 | ||||
| -rw-r--r-- | src/engine/SCons/Node/__init__.py | 211 |
3 files changed, 149 insertions, 118 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index f73161f..6ff3833 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -36,6 +36,7 @@ that can be used by scripts or modules looking for the canonical default. __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import fnmatch +from itertools import izip import os import os.path import re @@ -1895,7 +1896,7 @@ class Dir(Base): rep_nodes = map(dir.Entry, disk_names) #rep_nodes = [ n.disambiguate() for n in rep_nodes ] rep_nodes = map(lambda n: n.disambiguate(), rep_nodes) - for node, name in zip(rep_nodes, disk_names): + for node, name in izip(rep_nodes, disk_names): n = self.Entry(name) if n.__class__ != node.__class__: n.__class__ = node.__class__ @@ -2110,7 +2111,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): pass else: nodes = [] - for s, ni in zip(strings, nodeinfos): + for s, ni in izip(strings, nodeinfos): if not isinstance(s, SCons.Node.Node): s = ni.str_to_node(s) nodes.append(s) @@ -2119,7 +2120,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): result = [] bkids = self.bsources + self.bdepends + self.bimplicit bkidsigs = self.bsourcesigs + self.bdependsigs + self.bimplicitsigs - for bkid, bkidsig in zip(bkids, bkidsigs): + for bkid, bkidsig in izip(bkids, bkidsigs): result.append(str(bkid) + ': ' + string.join(bkidsig.format(names=names), ' ')) result.append('%s [%s]' % (self.bactsig, self.bact)) diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 8e9a3f8..8bceaf6 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -714,23 +714,23 @@ class NodeTestCase(unittest.TestCase): n1 = SCons.Node.Node() n1.builder_set(Builder()) node.implicit = [] - node.implicit_dict = {} - node._add_child(node.implicit, node.implicit_dict, [n1]) + node.implicit_set = set() + node._add_child(node.implicit, node.implicit_set, [n1]) node.prepare() # should not throw an exception n2 = SCons.Node.Node() n2.linked = 1 node.implicit = [] - node.implicit_dict = {} - node._add_child(node.implicit, node.implicit_dict, [n2]) + node.implicit_set = set() + node._add_child(node.implicit, node.implicit_set, [n2]) node.prepare() # should not throw an exception n3 = SCons.Node.Node() node.implicit = [] - node.implicit_dict = {} - node._add_child(node.implicit, node.implicit_dict, [n3]) + node.implicit_set = set() + node._add_child(node.implicit, node.implicit_set, [n3]) node.prepare() # should not throw an exception @@ -739,8 +739,8 @@ class NodeTestCase(unittest.TestCase): return None n4 = MyNode() node.implicit = [] - node.implicit_dict = {} - node._add_child(node.implicit, node.implicit_dict, [n4]) + node.implicit_set = set() + node._add_child(node.implicit, node.implicit_set, [n4]) exc_caught = 0 try: node.prepare() @@ -810,7 +810,7 @@ class NodeTestCase(unittest.TestCase): pass else: raise "did not catch expected exception" - assert node.sources == [zero, one, two, three, four] + assert node.sources == [zero, one, two, three, four], node.sources def test_add_ignore(self): """Test adding files whose dependencies should be ignored. @@ -1033,9 +1033,9 @@ class NodeTestCase(unittest.TestCase): node.add_source([n1, n2, n3]) node.add_dependency([n4, n5, n6]) node.implicit = [] - node.implicit_dict = {} - node._add_child(node.implicit, node.implicit_dict, [n7, n8, n9]) - node._add_child(node.implicit, node.implicit_dict, [n10, n11, n12]) + node.implicit_set = set() + node._add_child(node.implicit, node.implicit_set, [n7, n8, n9]) + node._add_child(node.implicit, node.implicit_set, [n10, n11, n12]) node.add_ignore([n2, n5, n8, n11]) kids = node.children() @@ -1064,9 +1064,9 @@ class NodeTestCase(unittest.TestCase): node.add_source([n1, n2, n3]) node.add_dependency([n4, n5, n6]) node.implicit = [] - node.implicit_dict = {} - node._add_child(node.implicit, node.implicit_dict, [n7, n8, n9]) - node._add_child(node.implicit, node.implicit_dict, [n10, n11, n12]) + node.implicit_set = set() + node._add_child(node.implicit, node.implicit_set, [n7, n8, n9]) + node._add_child(node.implicit, node.implicit_set, [n10, n11, n12]) node.add_ignore([n2, n5, n8, n11]) kids = node.all_children() @@ -1217,7 +1217,6 @@ class NodeTestCase(unittest.TestCase): n.clear() assert n.includes is None, n.includes - assert n.found_includes == {}, n.found_includes assert x.cleaned_up def test_get_subst_proxy(self): @@ -1241,32 +1240,22 @@ class NodeTestCase(unittest.TestCase): def test_postprocess(self): """Test calling the base Node postprocess() method""" n = SCons.Node.Node() - n.waiting_parents = {'foo':1, 'bar':1} + n.waiting_parents = set( ['foo','bar'] ) n.postprocess() - assert n.waiting_parents == {}, n.waiting_parents + assert n.waiting_parents == set(), n.waiting_parents def test_add_to_waiting_parents(self): """Test the add_to_waiting_parents() method""" n1 = SCons.Node.Node() n2 = SCons.Node.Node() - assert n1.waiting_parents == {}, n1.waiting_parents + assert n1.waiting_parents == set(), n1.waiting_parents r = n1.add_to_waiting_parents(n2) assert r == 1, r - assert n1.waiting_parents == {n2:1}, n1.waiting_parents + assert n1.waiting_parents == set((n2,)), n1.waiting_parents r = n1.add_to_waiting_parents(n2) assert r == 0, r - def test_call_for_all_waiting_parents(self): - """Test the call_for_all_waiting_parents() method""" - n1 = SCons.Node.Node() - n2 = SCons.Node.Node() - n1.add_to_waiting_parents(n2) - result = [] - def func(node, result=result): - result.append(node) - n1.call_for_all_waiting_parents(func) - assert result == [n1, n2], result class NodeListTestCase(unittest.TestCase): def test___str__(self): diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 2e136f0..c765ee9 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -47,6 +47,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import SCons.compat import copy +from itertools import chain, izip import string import UserList @@ -75,7 +76,7 @@ executed = 4 failed = 5 StateString = { - 0 : "0", + 0 : "no_state", 1 : "pending", 2 : "executing", 3 : "up_to_date", @@ -202,15 +203,16 @@ class Node: # a class. (Of course, we could always still do that in the # future if we had a good reason to...). self.sources = [] # source files used to build node - self.sources_dict = {} + self.sources_set = set() + self._specific_sources = False self.depends = [] # explicit dependencies (from Depends) - self.depends_dict = {} + self.depends_set = set() self.ignore = [] # dependencies to ignore - self.ignore_dict = {} + self.ignore_set = set() self.prerequisites = SCons.Util.UniqueList() self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) - self.waiting_parents = {} - self.waiting_s_e = {} + self.waiting_parents = set() + self.waiting_s_e = set() self.ref_count = 0 self.wkids = None # Kids yet to walk, when it's an array @@ -220,7 +222,6 @@ class Node: self.noclean = 0 self.nocache = 0 self.always_build = None - self.found_includes = {} self.includes = None self.attributes = self.Attrs() # Generic place to stick information about the Node. self.side_effect = 0 # true iff this node is a side effect @@ -330,24 +331,29 @@ class Node: is out-of-date and must be rebuilt, but before actually calling the method to build the Node. - This default implemenation checks that all children either exist - or are derived, and initializes the BuildInfo structure that - will hold the information about how this node is, uh, built. + This default implementation checks that explicit or implicit + dependencies either exist or are derived, and initializes the + BuildInfo structure that will hold the information about how + this node is, uh, built. + + (The existence of source files is checked separately by the + Executor, which aggregates checks for all of the targets built + by a specific action.) Overriding this method allows for for a Node subclass to remove the underlying file from the file system. Note that subclass methods should call this base class method to get the child check and the BuildInfo structure. """ - l = self.depends + for d in self.depends: + if d.missing(): + msg = "Explicit dependency `%s' not found, needed by target `%s'." + raise SCons.Errors.StopError, msg % (d, self) if not self.implicit is None: - l = l + self.implicit - missing_sources = self.get_executor().get_missing_sources() \ - + filter(lambda c: c.missing(), l) - if missing_sources: - desc = "Source `%s' not found, needed by target `%s'." % (missing_sources[0], self) - raise SCons.Errors.StopError, desc - + for i in self.implicit: + if i.missing(): + msg = "Implicit dependency `%s' not found, needed by target `%s'." + raise SCons.Errors.StopError, msg % (i, self) self.binfo = self.get_binfo() def build(self, **kw): @@ -373,7 +379,7 @@ class Node: # Clear the implicit dependency caches of any Nodes # waiting for this Node to be built. - for parent in self.waiting_parents.keys(): + for parent in self.waiting_parents: parent.implicit = None self.clear() @@ -398,7 +404,7 @@ class Node: # def add_to_waiting_s_e(self, node): - self.waiting_s_e[node] = 1 + self.waiting_s_e.add(node) def add_to_waiting_parents(self, node): """ @@ -409,23 +415,16 @@ class Node: True and False instead...) """ wp = self.waiting_parents - if wp.has_key(node): - result = 0 - else: - result = 1 - wp[node] = 1 - return result - - def call_for_all_waiting_parents(self, func): - func(self) - for parent in self.waiting_parents.keys(): - parent.call_for_all_waiting_parents(func) + if node in wp: + return 0 + wp.add(node) + return 1 def postprocess(self): """Clean up anything we don't need to hang onto after we've been built.""" self.executor_cleanup() - self.waiting_parents = {} + self.waiting_parents = set() def clear(self): """Completely clear a Node of all its cached state (so that it @@ -444,7 +443,6 @@ class Node: except AttributeError: pass self.includes = None - self.found_includes = {} def clear_memoized_values(self): self._memo = {} @@ -592,9 +590,9 @@ class Node: def add_to_implicit(self, deps): if not hasattr(self, 'implicit') or self.implicit is None: self.implicit = [] - self.implicit_dict = {} + self.implicit_set = set() self._children_reset() - self._add_child(self.implicit, self.implicit_dict, deps) + self._add_child(self.implicit, self.implicit_set, deps) def scan(self): """Scan this node's dependents for implicit dependencies.""" @@ -604,7 +602,7 @@ class Node: if not self.implicit is None: return self.implicit = [] - self.implicit_dict = {} + self.implicit_set = set() self._children_reset() if not self.has_builder(): return @@ -633,7 +631,7 @@ class Node: # one of this node's sources has changed, # so we must recalculate the implicit deps: self.implicit = [] - self.implicit_dict = {} + self.implicit_set = set() # Have the executor scan the sources. executor.scan_sources(self.builder.source_scanner) @@ -706,33 +704,44 @@ class Node: self.binfo = binfo executor = self.get_executor() - - sources = executor.get_unignored_sources(self.ignore) - - depends = self.depends - implicit = self.implicit or [] - - if self.ignore: - depends = filter(self.do_not_ignore, depends) - implicit = filter(self.do_not_ignore, implicit) - - def get_ninfo(node): - return node.get_ninfo() - - sourcesigs = map(get_ninfo, sources) - dependsigs = map(get_ninfo, depends) - implicitsigs = map(get_ninfo, implicit) + ignore_set = self.ignore_set if self.has_builder(): binfo.bact = str(executor) binfo.bactsig = SCons.Util.MD5signature(executor.get_contents()) - binfo.bsources = sources - binfo.bdepends = depends - binfo.bimplicit = implicit + if self._specific_sources: + sources = [] + for s in self.sources: + if s not in ignore_set: + sources.append(s) + else: + sources = executor.get_unignored_sources(self.ignore) + seen = set() + bsources = [] + bsourcesigs = [] + for s in sources: + if not s in seen: + seen.add(s) + bsources.append(s) + bsourcesigs.append(s.get_ninfo()) + binfo.bsources = bsources + binfo.bsourcesigs = bsourcesigs - binfo.bsourcesigs = sourcesigs + depends = self.depends + dependsigs = [] + for d in depends: + if d not in ignore_set: + dependsigs.append(d.get_ninfo()) + binfo.bdepends = depends binfo.bdependsigs = dependsigs + + implicit = self.implicit or [] + implicitsigs = [] + for i in implicit: + if i not in ignore_set: + implicitsigs.append(i.get_ninfo()) + binfo.bimplicit = implicit binfo.bimplicitsigs = implicitsigs return binfo @@ -816,7 +825,7 @@ class Node: def add_dependency(self, depend): """Adds dependencies.""" try: - self._add_child(self.depends, self.depends_dict, depend) + self._add_child(self.depends, self.depends_set, depend) except TypeError, e: e = e.args[0] if SCons.Util.is_List(e): @@ -833,7 +842,7 @@ class Node: def add_ignore(self, depend): """Adds dependencies to ignore.""" try: - self._add_child(self.ignore, self.ignore_dict, depend) + self._add_child(self.ignore, self.ignore_set, depend) except TypeError, e: e = e.args[0] if SCons.Util.is_List(e): @@ -844,8 +853,10 @@ class Node: def add_source(self, source): """Adds sources.""" + if self._specific_sources: + return try: - self._add_child(self.sources, self.sources_dict, source) + self._add_child(self.sources, self.sources_set, source) except TypeError, e: e = e.args[0] if SCons.Util.is_List(e): @@ -854,9 +865,9 @@ class Node: s = str(e) raise SCons.Errors.UserError("attempted to add a non-Node as source of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) - def _add_child(self, collection, dict, child): - """Adds 'child' to 'collection', first checking 'dict' to see - if it's already present.""" + def _add_child(self, collection, set, child): + """Adds 'child' to 'collection', first checking 'set' to see if it's + already present.""" #if type(child) is not type([]): # child = [child] #for c in child: @@ -864,13 +875,17 @@ class Node: # raise TypeError, c added = None for c in child: - if not dict.has_key(c): + if c not in set: + set.add(c) collection.append(c) - dict[c] = 1 added = 1 if added: self._children_reset() + def set_specific_source(self, source): + self.add_source(source) + self._specific_sources = True + def add_wkid(self, wkid): """Add a node to the list of kids waiting to be evaluated""" if self.wkids != None: @@ -882,10 +897,14 @@ class Node: # build info that it's cached so we can re-calculate it. self.executor_cleanup() - def do_not_ignore(self, node): - return node not in self.ignore + memoizer_counters.append(SCons.Memoize.CountValue('_children_get')) + + def _children_get(self): + try: + return self._memo['children_get'] + except KeyError: + pass - def _all_children_get(self): # 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 @@ -903,21 +922,22 @@ class Node: # using dictionary keys, lose the order, and the only ordered # dictionary patterns I found all ended up using "not in" # internally anyway...) - if self.implicit is None: - return self.sources + self.depends - else: - return self.sources + self.depends + self.implicit + if self.ignore_set: + if self.implicit is None: + iter = chain(self.sources,self.depends) + else: + iter = chain(self.sources, self.depends, self.implicit) - memoizer_counters.append(SCons.Memoize.CountValue('_children_get')) + children = [] + for i in iter: + if i not in self.ignore_set: + children.append(i) + else: + if self.implicit is None: + children = self.sources + self.depends + else: + children = self.sources + self.depends + self.implicit - def _children_get(self): - 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 @@ -925,7 +945,28 @@ class Node: """Return a list of all the node's direct children.""" if scan: self.scan() - return self._all_children_get() + + # 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 self.implicit is None: + return self.sources + self.depends + else: + return self.sources + self.depends + self.implicit def children(self, scan=1): """Return a list of the node's direct children, minus those @@ -1009,7 +1050,7 @@ class Node: if t: Trace(': old %s new %s' % (len(then), len(children))) result = True - for child, prev_ni in zip(children, then): + for child, prev_ni in izip(children, then): if child.changed_since_last_build(self, prev_ni): if t: Trace(': %s changed' % child) result = True @@ -1152,8 +1193,8 @@ class Node: new_bkids = new.bsources + new.bdepends + new.bimplicit new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs - osig = dict(zip(old_bkids, old_bkidsigs)) - nsig = dict(zip(new_bkids, new_bkidsigs)) + osig = dict(izip(old_bkids, old_bkidsigs)) + nsig = dict(izip(new_bkids, new_bkidsigs)) # The sources and dependencies we'll want to report are all stored # as relative paths to this target's directory, but we want to |
