summaryrefslogtreecommitdiff
path: root/engine/SCons/Node/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'engine/SCons/Node/__init__.py')
-rw-r--r--engine/SCons/Node/__init__.py110
1 files changed, 77 insertions, 33 deletions
diff --git a/engine/SCons/Node/__init__.py b/engine/SCons/Node/__init__.py
index ece4a5a..e6a3001 100644
--- a/engine/SCons/Node/__init__.py
+++ b/engine/SCons/Node/__init__.py
@@ -20,7 +20,7 @@ be able to depend on any other type of "thing."
"""
#
-# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 The SCons Foundation
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -41,12 +41,13 @@ be able to depend on any other type of "thing."
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-__revision__ = "src/engine/SCons/Node/__init__.py 2013/03/03 09:48:35 garyo"
+__revision__ = "src/engine/SCons/Node/__init__.py 2014/03/02 14:18:15 garyo"
import collections
import copy
from itertools import chain
+import SCons.Debug
from SCons.Debug import logInstanceCreation
import SCons.Executor
import SCons.Memoize
@@ -57,6 +58,10 @@ from SCons.Debug import Trace
def classname(obj):
return str(obj.__class__).split('.')[-1]
+# Set to false if we're doing a dry run. There's more than one of these
+# little treats
+do_store_info = True
+
# Node states
#
# These are in "priority" order, so that the maximum value for any
@@ -95,6 +100,11 @@ def do_nothing(node): pass
Annotate = do_nothing
+# Gets set to 'True' if we're running in interactive mode. Is
+# currently used to release parts of a target's info during
+# clean builds and update runs (see release_target_info).
+interactive = False
+
# Classes for signature info for Nodes.
class NodeInfoBase(object):
@@ -183,7 +193,7 @@ class Node(object):
pass
def __init__(self):
- if __debug__: logInstanceCreation(self, 'Node.Node')
+ if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.Node')
# Note that we no longer explicitly initialize a self.builder
# attribute to None here. That's because the self.builder
# attribute may be created on-the-fly later by a subclass (the
@@ -204,7 +214,7 @@ class Node(object):
self.depends_set = set()
self.ignore = [] # dependencies to ignore
self.ignore_set = set()
- self.prerequisites = SCons.Util.UniqueList()
+ self.prerequisites = None
self.implicit = None # implicit (scanned) dependencies (None means not scanned yet)
self.waiting_parents = set()
self.waiting_s_e = set()
@@ -214,6 +224,7 @@ class Node(object):
self.env = None
self.state = no_state
self.precious = None
+ self.pseudo = False
self.noclean = 0
self.nocache = 0
self.cached = 0 # is this node pulled from cache?
@@ -286,7 +297,8 @@ class Node(object):
except AttributeError:
pass
else:
- executor.cleanup()
+ if executor is not None:
+ executor.cleanup()
def reset_executor(self):
"Remove cached executor; forces recompute when needed."
@@ -346,10 +358,11 @@ class Node(object):
methods should call this base class method to get the child
check and the BuildInfo structure.
"""
- 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 self.depends is not None:
+ 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 self.implicit is not None:
for i in self.implicit:
if i.missing():
@@ -385,6 +398,13 @@ class Node(object):
self.clear()
+ if self.pseudo:
+ if self.exists():
+ raise SCons.Errors.UserError("Pseudo target " + str(self) + " must not exist")
+ else:
+ if not self.exists() and do_store_info:
+ SCons.Warnings.warn(SCons.Warnings.TargetNotBuiltWarning,
+ "Cannot find target " + str(self) + " after building")
self.ninfo.update(self)
def visited(self):
@@ -400,6 +420,23 @@ class Node(object):
self.ninfo.update(self)
self.store_info()
+ def release_target_info(self):
+ """Called just after this node has been marked
+ up-to-date or was built completely.
+
+ This is where we try to release as many target node infos
+ as possible for clean builds and update runs, in order
+ to minimize the overall memory consumption.
+
+ By purging attributes that aren't needed any longer after
+ a Node (=File) got built, we don't have to care that much how
+ many KBytes a Node actually requires...as long as we free
+ the memory shortly afterwards.
+
+ @see: built() and File.release_target_info()
+ """
+ pass
+
#
#
#
@@ -501,7 +538,7 @@ class Node(object):
def is_derived(self):
"""
- Returns true iff this node is derived (i.e. built).
+ Returns true if this node is derived (i.e. built).
This should return true only for nodes whose path should be in
the variant directory when duplicate=0 and should contribute their build
@@ -788,6 +825,10 @@ class Node(object):
"""Set the Node's precious value."""
self.precious = precious
+ def set_pseudo(self, pseudo = True):
+ """Set the Node's precious value."""
+ self.pseudo = pseudo
+
def set_noclean(self, noclean = 1):
"""Set the Node's noclean value."""
# Make sure noclean is an integer so the --debug=stree
@@ -837,6 +878,8 @@ class Node(object):
def add_prerequisite(self, prerequisite):
"""Adds prerequisites"""
+ if self.prerequisites is None:
+ self.prerequisites = SCons.Util.UniqueList()
self.prerequisites.extend(prerequisite)
self._children_reset()
@@ -924,20 +967,14 @@ class Node(object):
# dictionary patterns I found all ended up using "not in"
# internally anyway...)
if self.ignore_set:
- if self.implicit is None:
- iter = chain(self.sources,self.depends)
- else:
- iter = chain(self.sources, self.depends, self.implicit)
+ iter = chain.from_iterable(filter(None, [self.sources, self.depends, self.implicit]))
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
+ children = self.all_children(scan=0)
self._memo['children_get'] = children
return children
@@ -964,10 +1001,7 @@ class Node(object):
# 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
+ return list(chain.from_iterable(filter(None, [self.sources, self.depends, self.implicit])))
def children(self, scan=1):
"""Return a list of the node's direct children, minus those
@@ -1015,7 +1049,7 @@ class Node(object):
def Decider(self, function):
SCons.Util.AddMethod(self, function, 'changed_since_last_build')
- def changed(self, node=None):
+ def changed(self, node=None, allowcache=False):
"""
Returns if the node is up-to-date with respect to the BuildInfo
stored last time it was built. The default behavior is to compare
@@ -1028,6 +1062,15 @@ class Node(object):
any difference, but we now rely on checking every dependency
to make sure that any necessary Node information (for example,
the content signature of an #included .h file) is updated.
+
+ The allowcache option was added for supporting the early
+ release of the executor/builder structures, right after
+ a File target was built. When set to true, the return
+ value of this changed method gets cached for File nodes.
+ Like this, the executor isn't needed any longer for subsequent
+ calls to changed().
+
+ @see: FS.File.changed(), FS.File.release_target_info()
"""
t = 0
if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node))
@@ -1103,17 +1146,18 @@ class Node(object):
Return a text representation, suitable for displaying to the
user, of the include tree for the sources of this node.
"""
- if self.is_derived() and self.env:
+ if self.is_derived():
env = self.get_build_env()
- for s in self.sources:
- scanner = self.get_source_scanner(s)
- if scanner:
- path = self.get_build_scanner_path(scanner)
- else:
- path = None
- def f(node, env=env, scanner=scanner, path=path):
- return node.get_found_includes(env, scanner, path)
- return SCons.Util.render_tree(s, f, 1)
+ if env:
+ for s in self.sources:
+ scanner = self.get_source_scanner(s)
+ if scanner:
+ path = self.get_build_scanner_path(scanner)
+ else:
+ path = None
+ def f(node, env=env, scanner=scanner, path=path):
+ return node.get_found_includes(env, scanner, path)
+ return SCons.Util.render_tree(s, f, 1)
else:
return None