- Fix SCons not exiting with the appropriate status on build errors
(and probably in other situations).
+ - Significant performance improvement from using a more efficient
+ check, throughout the code, for whether a Node has a Builder.
+
From Steve Leblanc:
- Add a Clean() method to support removing user-specified targets
for t in tlist:
if t.side_effect:
raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t)
- if t.builder is not None:
+ if t.has_builder():
if t.env != env:
raise UserError, "Two different environments were specified for the same target: %s"%str(t)
elif t.overrides != overrides:
return self.name
def builder_set(self, builder):
self.builder = builder
+ def has_builder(self):
+ return not self.builder is None
def env_set(self, env, safe=0):
self.env = env
def add_source(self, source):
for side_effect in side_effects:
# A builder of 1 means the node is supposed to appear
- # buildable without actually having a builder, so we allow
- # it to be a side effect as well.
- if side_effect.builder is not None and side_effect.builder != 1:
+ # buildable without actually having a builder, so we allow
+ # it to be a side effect as well.
+ if side_effect.has_builder() and side_effect.builder != 1:
raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
side_effect.add_source(targets)
side_effect.side_effect = 1
def __str__(self):
"""A FS node's string representation is its path name."""
- if self.duplicate or self.builder:
+ if self.duplicate or self.has_builder():
return self.path
return self.srcnode().path
# This is usually the case with BuildDir().
# We only want to find pre-existing files.
if rnode.exists() and \
- (isinstance(rnode, Dir) or not rnode.builder):
+ (isinstance(rnode, Dir) or not rnode.has_builder()):
return rnode
except TypeError:
pass # Wrong type of node.
# want it to show up in the build tree. This is usually the
# case with BuildDir(). We only want to find pre-existing files.
if (not must_exist or rnode.exists()) and \
- (not rnode.builder or isinstance(rnode, Dir)):
+ (not rnode.has_builder() or isinstance(rnode, Dir)):
ret.append(rnode)
except TypeError:
pass # Wrong type of node.
in the .sconsign file.
"""
- if self.builder:
+ if self.has_builder():
if SCons.Sig.build_signature:
if not hasattr(self, 'bsig'):
self.set_bsig(calc.bsig(self.rfile()))
"""Prepare for this file to be created."""
def missing(node):
- return not node.builder and not node.linked and not node.rexists()
+ return not node.has_builder() and not node.linked and not node.rexists()
missing_sources = filter(missing, self.children())
if missing_sources:
desc = "No Builder for target `%s', needed by `%s'." % (missing_sources[0], self)
raise SCons.Errors.StopError, desc
if self.exists():
- if self.builder and not self.precious:
+ if self.has_builder() and not self.precious:
Unlink(self, None, None)
if hasattr(self, '_exists'):
delattr(self, '_exists')
def exists(self):
# Duplicate from source path if we are set up to do this.
- if self.duplicate and not self.builder and not self.linked:
+ if self.duplicate and not self.has_builder() and not self.linked:
src=self.srcnode().rfile()
if src.exists() and src.abspath != self.abspath:
self._createDir()
try:
node = node_factory(filename, dir)
# Return true of the node exists or is a derived node.
- if node.builder or \
+ if node.has_builder() or \
(isinstance(node, SCons.Node.FS.Entry) and node.exists()):
retval = node
break
so only do thread safe stuff here. Do thread unsafe stuff in
built().
"""
- if not self.builder:
+ if not self.has_builder():
return None
action_list = self.builder.get_actions()
if not action_list:
def builder_set(self, builder):
self.builder = builder
+ def has_builder(self):
+ """Return whether this Node has a builder or not.
+
+ In Boolean tests, this turns out to be a *lot* more efficient
+ than simply examining the builder attribute directly ("if
+ node.builder: ..."). When the builder attribute is examined
+ directly, it ends up calling __getattr__ for both the __len__
+ and __nonzero__ attributes on instances of our Builder Proxy
+ class(es), generating a bazillion extra calls and slowing
+ things down immensely.
+ """
+ return not self.builder is None
+
def builder_sig_adapter(self):
"""Create an adapter for calculating a builder's signature.
if not self.implicit is None:
return
self.implicit = []
- if not self.builder:
+ if not self.has_builder():
return
if implicit_cache and not implicit_deps_changed:
in the .sconsign file.
"""
- if self.builder:
+ if self.has_builder():
if SCons.Sig.build_signature:
if not hasattr(self, 'bsig'):
self.set_bsig(calc.bsig(self))
def execute(self):
target = self.targets[0]
if target.get_state() == SCons.Node.up_to_date:
- if self.top and target.builder:
+ if self.top and target.has_builder():
display('scons: "%s" is up to date.' % str(target))
- elif target.builder and not hasattr(target.builder, 'status'):
+ elif target.has_builder() and not hasattr(target.builder, 'status'):
if print_time:
start_time = time.time()
SCons.Taskmaster.Task.execute(self)
def executed(self):
t = self.targets[0]
- if self.top and not t.builder and not t.side_effect:
+ if self.top and not t.has_builder() and not t.side_effect:
if not t.exists():
sys.stderr.write("scons: *** Do not know how to make target `%s'." % t)
if not keep_going_on_error:
class CleanTask(SCons.Taskmaster.Task):
"""An SCons clean task."""
def show(self):
- if self.targets[0].builder or self.targets[0].side_effect:
+ if self.targets[0].has_builder() or self.targets[0].side_effect:
display("Removed " + str(self.targets[0]))
if SCons.Script.SConscript.clean_targets.has_key(str(self.targets[0])):
files = SCons.Script.SConscript.clean_targets[str(self.targets[0])]
SCons.Utils.fs_delete(str(f), 0)
def remove(self):
- if self.targets[0].builder or self.targets[0].side_effect:
+ if self.targets[0].has_builder() or self.targets[0].side_effect:
for t in self.targets:
try:
removed = t.remove()
def get_derived_children(node):
children = node.all_children(None)
- return filter(lambda x: x.builder, children)
+ return filter(lambda x: x.has_builder(), children)
def _scons_syntax_error(e):
"""Handle syntax errors. Print out a message and show where the error
self.oldbsig = 0
self.oldcsig = 0
+ def has_builder(self):
+ return self.builder
+
def get_contents(self):
# a file that doesn't exist has no contents:
assert self.exists()
return None
def calc_signature(self, calc):
- if self.builder:
+ if self.has_builder():
return calc.bsig(self)
else:
return calc.csig(self)
for node in nodes:
self.failUnless(not current(calc, node),
- "none of the nodes should be current")
+ "node %s should not be current" % node.path)
# simulate a build:
self.files[1].modify('built', 222)
for node in nodes:
self.failUnless(current(calc, node),
- "all of the nodes should be current")
+ "node %s should be current" % node.path)
def test_modify(self):
for node in nodes:
self.failUnless(current(calc, node),
- "all of the nodes should be current")
+ "node %s should be current" % node.path)
class MD5TestCase(unittest.TestCase, SigTestBase):
self.ignore = []
self.builder = None
self.use_signature = 1
+ def has_builder(self):
+ return not self.builder is None
def children(self):
return filter(lambda x, i=self.ignore: x not in i, self.kids)
def all_children(self):
what's wanted.
"""
sigs = map(lambda n, c=self: n.calc_signature(c), node.children())
- if node.builder:
+ if node.has_builder():
sigs.append(self.module.signature(node.builder_sig_adapter()))
bsig = self.module.collect(filter(lambda x: not x is None, sigs))
"""
oldtime, oldbsig, oldcsig = node.get_prevsiginfo()
- if not node.builder and node.get_timestamp() == oldtime:
+ if not node.has_builder() and node.get_timestamp() == oldtime:
return 1
return self.module.current(newsig, oldbsig)
# Add non-derived files that have not been built
# to the candidates list:
def derived(node):
- return (node.builder or node.side_effect) and node.get_state() == None
+ return (node.has_builder() or node.side_effect) and node.get_state() == None
derived = filter(derived, children)
if derived:
derived.reverse()
global built_text
built_text = self.name + " built"
+ def has_builder(self):
+ return not self.builder is None
+
def built(self):
global built_text
built_text = built_text + " really"