# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
+from __future__ import generators ### KEEP FOR COMPATIBILITY FIXERS
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import SCons.compat
-
-import UserDict
-import UserList
+import collections
import SCons.Action
from SCons.Debug import logInstanceCreation
_null = _Null
+def match_splitext(path, suffixes = []):
+ if suffixes:
+ matchsuf = [S for S in suffixes if path[-len(S):] == S]
+ if matchsuf:
+ suf = max(list(map(None, list(map(len, matchsuf)), matchsuf)))[1]
+ return [path[:-len(suf)], path[-len(suf):]]
+ return SCons.Util.splitext(path)
+
class DictCmdGenerator(SCons.Util.Selector):
"""This is a callable class that can be used as a
command generator function. It holds on to a dictionary
return []
if self.source_ext_match:
+ suffixes = self.src_suffixes()
ext = None
for src in map(str, source):
- my_ext = SCons.Util.splitext(src)[1]
+ my_ext = match_splitext(src, suffixes)[1]
if ext and my_ext != ext:
- raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s" % (repr(map(str, target)), src, ext, my_ext))
+ raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s"
+ % (repr(list(map(str, target))), src, ext, my_ext))
ext = my_ext
else:
- ext = SCons.Util.splitext(str(source[0]))[1]
+ ext = match_splitext(str(source[0]), self.src_suffixes())[1]
if not ext:
- raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source))))
+ #return ext
+ raise UserError("While building `%s': "
+ "Cannot deduce file extension from source files: %s"
+ % (repr(list(map(str, target))), repr(list(map(str, source)))))
try:
- ret = SCons.Util.Selector.__call__(self, env, source)
+ ret = SCons.Util.Selector.__call__(self, env, source, ext)
except KeyError, e:
raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e[0], e[1], e[2]))
if ret is None:
raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \
- (repr(map(str, target)), repr(map(str, source)), ext, repr(self.keys())))
+ (repr(list(map(str, target))), repr(list(map(str, source))), ext, repr(self.keys())))
return ret
class CallableSelector(SCons.Util.Selector):
target, source = emitter(target, source, env)
return (target, source)
-class ListEmitter(UserList.UserList):
+class ListEmitter(collections.UserList):
"""A callable list of emitters that calls each in sequence,
returning the result.
"""
'sources' : 'source',
}
-class OverrideWarner(UserDict.UserDict):
+class OverrideWarner(collections.UserDict):
"""A class for warning about keyword arguments that we use as
overrides in a Builder call.
warnings once, no matter how many Builders are invoked.
"""
def __init__(self, dict):
- UserDict.UserDict.__init__(self, dict)
+ collections.UserDict.__init__(self, dict)
if __debug__: logInstanceCreation(self, 'Builder.OverrideWarner')
self.already_warned = None
def warn(self):
if self.already_warned:
return
for k in self.keys():
- if misleading_keywords.has_key(k):
+ if k in misleading_keywords:
alt = misleading_keywords[k]
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg)
def Builder(**kw):
"""A factory for builder objects."""
composite = None
- if kw.has_key('generator'):
- if kw.has_key('action'):
- raise UserError, "You must not specify both an action and a generator."
- kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'])
+ if 'generator' in kw:
+ if 'action' in kw:
+ raise UserError("You must not specify both an action and a generator.")
+ kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'], {})
del kw['generator']
- elif kw.has_key('action'):
+ elif 'action' in kw:
source_ext_match = kw.get('source_ext_match', 1)
- if kw.has_key('source_ext_match'):
+ if 'source_ext_match' in kw:
del kw['source_ext_match']
if SCons.Util.is_Dict(kw['action']):
composite = DictCmdGenerator(kw['action'], source_ext_match)
- kw['action'] = SCons.Action.CommandGeneratorAction(composite)
+ kw['action'] = SCons.Action.CommandGeneratorAction(composite, {})
kw['src_suffix'] = composite.src_suffixes()
else:
kw['action'] = SCons.Action.Action(kw['action'])
- if kw.has_key('emitter'):
+ if 'emitter' in kw:
emitter = kw['emitter']
if SCons.Util.is_String(emitter):
# This allows users to pass in an Environment
# a callable to use as the actual emitter.
var = SCons.Util.get_environment_var(emitter)
if not var:
- raise UserError, "Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter
+ raise UserError("Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter)
kw['emitter'] = EmitterProxy(var)
elif SCons.Util.is_Dict(emitter):
kw['emitter'] = DictEmitter(emitter)
elif SCons.Util.is_List(emitter):
kw['emitter'] = ListEmitter(emitter)
- result = apply(BuilderBase, (), kw)
+ result = BuilderBase(**kw)
if not composite is None:
result = CompositeBuilder(result, composite)
# were specified.
for t in tlist:
if t.side_effect:
- raise UserError, "Multiple ways to build the same target were specified for: %s" % t
+ raise UserError("Multiple ways to build the same target were specified for: %s" % t)
if t.has_explicit_builder():
if not t.env is None and not t.env is env:
action = t.builder.action
SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
else:
msg = "Two environments with different actions were specified for the same target: %s" % t
- raise UserError, msg
+ raise UserError(msg)
if builder.multi:
if t.builder != builder:
msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t)
- raise UserError, msg
- if t.get_executor().targets != tlist:
- msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, map(str, t.get_executor().targets), map(str, tlist))
- raise UserError, msg
+ raise UserError(msg)
+ # TODO(batch): list constructed each time!
+ if t.get_executor().get_all_targets() != tlist:
+ msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, list(map(str, t.get_executor().get_all_targets())), list(map(str, tlist)))
+ raise UserError(msg)
elif t.sources != slist:
- msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, map(str, t.sources), map(str, slist))
- raise UserError, msg
+ msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, list(map(str, t.sources)), list(map(str, slist)))
+ raise UserError(msg)
if builder.single_source:
if len(slist) > 1:
- raise UserError, "More than one source given for single-source builder: targets=%s sources=%s" % (map(str,tlist), map(str,slist))
+ raise UserError("More than one source given for single-source builder: targets=%s sources=%s" % (list(map(str,tlist)), list(map(str,slist))))
class EmitterProxy:
"""This is a callable class that can act as a
# Recursively substitute the variable.
# We can't use env.subst() because it deals only
# in strings. Maybe we should change that?
- while SCons.Util.is_String(emitter) and env.has_key(emitter):
+ while SCons.Util.is_String(emitter) and emitter in env:
emitter = env[emitter]
if callable(emitter):
target, source = emitter(target, source, env)
suffix = CallableSelector(suffix)
self.env = env
self.single_source = single_source
- if overrides.has_key('overrides'):
+ if 'overrides' in overrides:
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
"The \"overrides\" keyword to Builder() creation has been deprecated;\n" +\
"\tspecify the items as keyword arguments to the Builder() call instead.")
overrides.update(overrides['overrides'])
del overrides['overrides']
- if overrides.has_key('scanner'):
+ if 'scanner' in overrides:
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
"The \"scanner\" keyword to Builder() creation has been deprecated;\n"
"\tuse: source_scanner or target_scanner as appropriate.")
self.src_builder = src_builder
def __nonzero__(self):
- raise InternalError, "Do not test for the Node.builder attribute directly; use Node.has_builder() instead"
+ raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead")
def get_name(self, env):
"""Attempts to get the name of the Builder.
if not env:
env = self.env
if env:
- matchsuf = filter(lambda S,path=path: path[-len(S):] == S,
- self.src_suffixes(env))
- if matchsuf:
- suf = max(map(None, map(len, matchsuf), matchsuf))[1]
- return [path[:-len(suf)], path[-len(suf):]]
- return SCons.Util.splitext(path)
-
- def get_single_executor(self, env, tlist, slist, executor_kw):
- if not self.action:
- raise UserError, "Builder %s must have an action to build %s."%(self.get_name(env or self.env), map(str,tlist))
- return self.action.get_executor(env or self.env,
- [], # env already has overrides
- tlist,
- slist,
- executor_kw)
-
- def get_multi_executor(self, env, tlist, slist, executor_kw):
- try:
- executor = tlist[0].get_executor(create = 0)
- except (AttributeError, IndexError):
- return self.get_single_executor(env, tlist, slist, executor_kw)
+ suffixes = self.src_suffixes(env)
else:
- executor.add_sources(slist)
- return executor
+ suffixes = []
+ return match_splitext(path, suffixes)
def _adjustixes(self, files, pre, suf, ensure_suffix=False):
if not files:
except IndexError:
tlist = []
else:
- splitext = lambda S,self=self,env=env: self.splitext(S,env)
+ splitext = lambda S: self.splitext(S,env)
tlist = [ t_from_s(pre, suf, splitext) ]
else:
target = self._adjustixes(target, pre, suf, self.ensure_suffix)
- tlist = env.arg2nodes(target, target_factory)
+ tlist = env.arg2nodes(target, target_factory, target=target, source=source)
if self.emitter:
# The emitter is going to do str(node), but because we're
# The targets are fine, so find or make the appropriate Executor to
# build this particular list of targets from this particular list of
# sources.
+
+ executor = None
+ key = None
+
if self.multi:
- get_executor = self.get_multi_executor
- else:
- get_executor = self.get_single_executor
- executor = get_executor(env, tlist, slist, executor_kw)
+ try:
+ executor = tlist[0].get_executor(create = 0)
+ except (AttributeError, IndexError):
+ pass
+ else:
+ executor.add_sources(slist)
+
+ if executor is None:
+ if not self.action:
+ fmt = "Builder %s must have an action to build %s."
+ raise UserError(fmt % (self.get_name(env or self.env),
+ list(map(str,tlist))))
+ key = self.action.batch_key(env or self.env, tlist, slist)
+ if key:
+ try:
+ executor = SCons.Executor.GetBatchExecutor(key)
+ except KeyError:
+ pass
+ else:
+ executor.add_batch(tlist, slist)
+
+ if executor is None:
+ executor = SCons.Executor.Executor(self.action, env, [],
+ tlist, slist, executor_kw)
+ if key:
+ SCons.Executor.AddBatchExecutor(key, executor)
# Now set up the relevant information in the target Nodes themselves.
for t in tlist:
ekw = self.executor_kw.copy()
ekw['chdir'] = chdir
if kw:
- if kw.has_key('srcdir'):
+ if 'srcdir' in kw:
def prependDirIfRelative(f, srcdir=kw['srcdir']):
import os.path
if SCons.Util.is_String(f) and not os.path.isabs(f):
return f
if not SCons.Util.is_List(source):
source = [source]
- source = map(prependDirIfRelative, source)
+ source = list(map(prependDirIfRelative, source))
del kw['srcdir']
if self.overrides:
env_kw = self.overrides.copy()
src_suffix = []
elif not SCons.Util.is_List(src_suffix):
src_suffix = [ src_suffix ]
- adjust = lambda suf, s=self: \
- callable(suf) and suf or s.adjust_suffix(suf)
- self.src_suffix = map(adjust, src_suffix)
+ self.src_suffix = [callable(suf) and suf or self.adjust_suffix(suf) for suf in src_suffix]
def get_src_suffix(self, env):
"""Get the first src_suffix in the list of src_suffixes."""
lengths = list(set(map(len, src_suffixes)))
def match_src_suffix(name, src_suffixes=src_suffixes, lengths=lengths):
- node_suffixes = map(lambda l, n=name: n[-l:], lengths)
+ node_suffixes = [name[-l:] for l in lengths]
for suf in src_suffixes:
if suf in node_suffixes:
return suf
# target, then filter out any sources that this
# Builder isn't capable of building.
if len(tlist) > 1:
- mss = lambda t, m=match_src_suffix: m(t.name)
- tlist = filter(mss, tlist)
+ tlist = [t for t in tlist if match_src_suffix(t.name)]
result.extend(tlist)
else:
result.append(s)
return memo_dict[memo_key]
except KeyError:
pass
- suffixes = map(lambda x, s=self, e=env: e.subst(x), self.src_suffix)
+ suffixes = [env.subst(x) for x in self.src_suffix]
memo_dict[memo_key] = suffixes
return suffixes
sdict[s] = 1
for builder in self.get_src_builders(env):
for s in builder.src_suffixes(env):
- if not sdict.has_key(s):
+ if s not in sdict:
sdict[s] = 1
suffixes.append(s)
return suffixes
def add_action(self, suffix, action):
self.cmdgen.add_action(suffix, action)
self.set_src_suffix(self.cmdgen.src_suffixes())
+
+def is_a_Builder(obj):
+ """"Returns True iff the specified obj is one of our Builder classes.
+
+ The test is complicated a bit by the fact that CompositeBuilder
+ is a proxy, not a subclass of BuilderBase.
+ """
+ return (isinstance(obj, BuilderBase)
+ or isinstance(obj, CompositeBuilder)
+ or callable(obj))
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: