diff options
Diffstat (limited to 'engine/SCons/Node/__init__.py')
-rw-r--r-- | engine/SCons/Node/__init__.py | 110 |
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 |