from SCons.Errors import InternalError, UserError
import SCons.Action
+import SCons.Executor
import SCons.Node
import SCons.Node.FS
import SCons.Util
for src in map(str, source):
my_ext = SCons.Util.splitext(src)[1]
if ext and my_ext != ext:
- raise UserError("Cannot build multiple sources with different extensions: %s, %s" % (ext, my_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))
ext = my_ext
- if ext is None:
- raise UserError("Cannot deduce file extension from source files: %s" % repr(map(str, source)))
+ if not ext:
+ raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source))))
try:
- # XXX Do we need to perform Environment substitution
- # on the keys of action_dict before looking it up?
return self.action_dict[ext]
except KeyError:
- raise UserError("Don't know how to build a file with suffix %s." % ext)
+ # Before raising the user error, try to perform Environment
+ # substitution on the keys of action_dict.
+ s_dict = {}
+ for (k,v) in self.action_dict.items():
+ s_k = env.subst(k)
+ if s_dict.has_key(s_k):
+ # XXX Note that we do only raise errors, when variables
+ # point to the same suffix. If one suffix is a
+ # literal and a variable suffix contains this literal
+ # we don't raise an error (cause the literal 'wins')
+ raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (s_dict[s_k][0], k, s_k))
+ s_dict[s_k] = (k,v)
+ try:
+ return s_dict[ext][1]
+ except KeyError:
+ raise UserError("While building `%s': Don't know how to build a file with suffix %s." % (repr(map(str, target)), repr(ext)))
+
def __cmp__(self, other):
return cmp(self.action_dict, other.action_dict)
the proper Builder information.
"""
- for s in slist:
- src_key = s.scanner_key() # the file suffix
- scanner = env.get_scanner(src_key)
- if scanner:
- s.source_scanner = scanner
-
+ # First, figure out if there are any errors in the way the targets
+ # were specified.
for t in tlist:
if t.side_effect:
raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t)
elif t.sources != slist:
raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t)
+ # 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
+ if builder.multi:
+ try:
+ executor = tlist[0].get_executor(create = 0)
+ except AttributeError:
+ pass
+ else:
+ executor.add_sources(slist)
+ if executor is None:
+ executor = SCons.Executor.Executor(builder,
+ tlist[0].generate_build_env(env),
+ overrides,
+ tlist,
+ slist)
+
+ # Now set up the relevant information in the target Nodes themselves.
+ for t in tlist:
t.overrides = overrides
t.cwd = SCons.Node.FS.default_fs.getcwd()
t.builder_set(builder)
t.env_set(env)
t.add_source(slist)
+ t.set_executor(executor)
if builder.scanner:
t.target_scanner = builder.scanner
+ # Last, add scanners from the Environment to the source Nodes.
+ for s in slist:
+ src_key = s.scanner_key() # the file suffix
+ scanner = env.get_scanner(src_key)
+ if scanner:
+ s.source_scanner = scanner
+
+
def _adjust_suffix(suff):
if suff and not suff[0] in [ '.', '$' ]:
return '.' + suff
for f in files:
if SCons.Util.is_String(f):
- if pre and f[:len(pre)] != pre:
+ if pre:
path, fn = os.path.split(os.path.normpath(f))
- f = os.path.join(path, pre + fn)
+ if fn[:len(pre)] != pre:
+ f = os.path.join(path, pre + fn)
# Only append a suffix if the file does not have one.
if suf and not SCons.Util.splitext(f)[1]:
if f[-len(suf):] != suf:
if target is None:
s = source[0]
if isinstance(s, SCons.Node.Node):
- s = os.path.split(str(s))[1]
- target = [ pre + os.path.splitext(s)[0] + suf ]
+ s = str(s)
+ dir, s = os.path.split(s)
+ target = pre + os.path.splitext(s)[0] + suf
+ if dir:
+ target = [ os.path.join(dir, target) ]
else:
target = adjustixes(target, pre, suf)
target, source = self.emitter(target=tlist, source=slist, env=env)
- # Now delete the temporary builders that we attached to the
+ # Now delete the temporary builders that we attached to any
# new targets, so that _init_nodes() doesn't do weird stuff
# to them because it thinks they already have builders.
for t in new_targets:
- t.builder = None
+ if t.builder is self:
+ # Only delete the temporary builder if the emitter
+ # didn't change it on us.
+ t.builder = None
# Have to call arg2nodes yet again, since it is legal for
# emitters to spit out strings as well as Node instances.
return tlist
- def get_actions(self):
- return self.action.get_actions()
-
- def get_raw_contents(self, target, source, env):
- """Fetch the "contents" of the builder's action.
- """
- return self.action.get_raw_contents(target, source, env)
-
- def get_contents(self, target, source, env):
- """Fetch the "contents" of the builder's action
- (for signature calculation).
- """
- return self.action.get_contents(target, source, env)
-
def src_suffixes(self, env):
return map(lambda x, e=env: e.subst(_adjust_suffix(x)),
self.src_suffix)
src_suffixes = self.src_suffixes(env)
for snode in slist:
- path, ext = SCons.Util.splitext(snode.abspath)
+ path, ext = SCons.Util.splitext(snode.get_abspath())
if sdict.has_key(ext):
src_bld = sdict[ext]
tgt = apply(src_bld, (env, path, snode), kw)