import os
import os.path
import string
-import re
-import shutil
from UserDict import UserDict
import SCons.Action
import SCons.Builder
+from SCons.Debug import logInstanceCreation
import SCons.Defaults
import SCons.Errors
import SCons.Node
import SCons.Node.FS
import SCons.Node.Python
import SCons.Platform
+import SCons.SConsign
import SCons.Sig
import SCons.Sig.MD5
import SCons.Sig.TimeStamp
_null = _Null
-DefaultTargets = None
CleanTargets = {}
CalculatorArgs = {}
installAction = SCons.Action.Action(installFunc, installString)
-InstallBuilder = SCons.Builder.Builder(action=installAction)
+InstallBuilder = SCons.Builder.Builder(action=installAction,
+ name='InstallBuilder')
def alias_builder(env, target, source):
pass
AliasBuilder = SCons.Builder.Builder(action = alias_builder,
target_factory = SCons.Node.Alias.default_ans.Alias,
source_factory = SCons.Node.FS.default_fs.Entry,
- multi = 1)
+ multi = 1,
+ name='AliasBuilder')
def our_deepcopy(x):
"""deepcopy lists and dictionaries, and just copy the reference
copy[key] = our_deepcopy(x[key])
elif SCons.Util.is_List(x):
copy = map(our_deepcopy, x)
+ try:
+ copy = x.__class__(copy)
+ except AttributeError:
+ pass
else:
copy = x
return copy
-def apply_tools(env, tools):
+def apply_tools(env, tools, toolpath):
if tools:
+ # Filter out null tools from the list.
+ tools = filter(None, tools)
for tool in tools:
if SCons.Util.is_String(tool):
- tool = SCons.Tool.Tool(tool)
- tool(env)
+ env.Tool(tool, toolpath)
+ else:
+ tool(env)
+
+# These names are controlled by SCons; users should never set or override
+# them. This warning can optionally be turned off, but scons will still
+# ignore the illegal variable names even if it's off.
+reserved_construction_var_names = \
+ ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']
+
+def copy_non_reserved_keywords(dict):
+ result = our_deepcopy(dict)
+ for k in result.keys():
+ if k in reserved_construction_var_names:
+ SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning,
+ "Ignoring attempt to set reserved variable `%s'" % k)
+ del result[k]
+ return result
class BuilderWrapper:
"""Wrapper class that associates an environment with a Builder at
def __init__(self,
platform=None,
tools=None,
+ toolpath=[],
options=None,
**kw):
+ if __debug__: logInstanceCreation(self)
self.fs = SCons.Node.FS.default_fs
self.ans = SCons.Node.Alias.default_ans
self.lookup_list = SCons.Node.arg2nodes_lookups
self._dict = our_deepcopy(SCons.Defaults.ConstructionEnvironment)
+ self._dict['__env__'] = self
self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self)
if platform is None:
tools = self._dict.get('TOOLS', None)
if tools is None:
tools = ['default']
- apply_tools(self, tools)
+ apply_tools(self, tools, toolpath)
# Reapply the passed in variables after calling the tools,
# since they should overide anything set by the tools:
options.Update(self)
def __cmp__(self, other):
- return cmp(self._dict, other._dict)
+ # Since an Environment now has an '__env__' construction variable
+ # that refers to itself, delete that variable to avoid infinite
+ # loops when comparing the underlying dictionaries in some Python
+ # versions (*cough* 1.5.2 *cough*)...
+ sdict = self._dict.copy()
+ del sdict['__env__']
+ odict = other._dict.copy()
+ del odict['__env__']
+ return cmp(sdict, odict)
def __getitem__(self, key):
return self._dict[key]
def __setitem__(self, key, value):
- if key in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']:
+ if key in reserved_construction_var_names:
SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning,
"Ignoring attempt to set reserved variable `%s'" % key)
elif key == 'BUILDERS':
except KeyError:
self._dict[key] = BuilderDict(kwbd, self)
self._dict[key].update(value)
+ elif key == 'SCANNERS':
+ self._dict[key] = value
+ self.scanner_map_delete()
else:
if not SCons.Util.is_valid_construction_var(key):
raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
if not args:
return []
- if not SCons.Util.is_List(args):
+ if SCons.Util.is_List(args):
+ args = SCons.Util.flatten(args)
+ else:
args = [args]
nodes = []
n = self.subst(n, raw=1)
if node_factory:
n = node_factory(n)
- nodes.append(n)
+ if SCons.Util.is_List(n):
+ nodes.extend(n)
+ else:
+ nodes.append(n)
elif node_factory:
- v = self.subst(v, raw=1)
- nodes.append(node_factory(v))
+ v = node_factory(self.subst(v, raw=1))
+ if SCons.Util.is_List(v):
+ nodes.extend(v)
+ else:
+ nodes.append(v)
else:
nodes.append(v)
def get_scanner(self, skey):
"""Find the appropriate scanner given a key (usually a file suffix).
- Does a linear search. Could be sped up by creating a dictionary if
- this proves too slow.
"""
- if self._dict['SCANNERS']:
- for scanner in self._dict['SCANNERS']:
- if skey in scanner.skeys:
- return scanner
- return None
+ try:
+ sm = self.scanner_map
+ except AttributeError:
+ try:
+ scanners = self._dict['SCANNERS']
+ except KeyError:
+ self.scanner_map = {}
+ return None
+ else:
+ self.scanner_map = sm = {}
+ # Reverse the scanner list so that, if multiple scanners
+ # claim they can scan the same suffix, earlier scanners
+ # in the list will overwrite later scanners, so that
+ # the result looks like a "first match" to the user.
+ if not SCons.Util.is_List(scanners):
+ scanners = [scanners]
+ scanners.reverse()
+ for scanner in scanners:
+ for k in scanner.get_skeys(self):
+ sm[k] = scanner
+ try:
+ return sm[skey]
+ except KeyError:
+ return None
- def subst(self, string, raw=0, target=None, source=None):
- """Recursively interpolates construction variables from the
- Environment into the specified string, returning the expanded
- result. Construction variables are specified by a $ prefix
- in the string and begin with an initial underscore or
- alphabetic character followed by any number of underscores
- or alphanumeric characters. The construction variable names
- may be surrounded by curly braces to separate the name from
- trailing characters.
- """
- if raw:
- mode = SCons.Util.SUBST_RAW
- else:
- mode = SCons.Util.SUBST_CMD
- return SCons.Util.scons_subst(string, self, mode, target, source)
-
- def subst_kw(self, kw, raw=0, target=None, source=None):
- if raw:
- mode = SCons.Util.SUBST_RAW
- else:
- mode = SCons.Util.SUBST_CMD
+ def scanner_map_delete(self, kw=None):
+ """Delete the cached scanner map (if we need to).
+ """
+ if not kw is None and not kw.has_key('SCANNERS'):
+ return
+ try:
+ del self.scanner_map
+ except AttributeError:
+ pass
+
+ def subst(self, string, raw=0, target=None, source=None, dict=None, conv=None):
+ """Recursively interpolates construction variables from the
+ Environment into the specified string, returning the expanded
+ result. Construction variables are specified by a $ prefix
+ in the string and begin with an initial underscore or
+ alphabetic character followed by any number of underscores
+ or alphanumeric characters. The construction variable names
+ may be surrounded by curly braces to separate the name from
+ trailing characters.
+ """
+ return SCons.Util.scons_subst(string, self, raw, target, source, dict, conv)
+
+ def subst_kw(self, kw, raw=0, target=None, source=None, dict=None):
nkw = {}
for k, v in kw.items():
- k = SCons.Util.scons_subst(k, self, mode, target, source)
+ k = self.subst(k, raw, target, source, dict)
if SCons.Util.is_String(v):
- v = SCons.Util.scons_subst(v, self, mode, target, source)
+ v = self.subst(v, raw, target, source, dict)
nkw[k] = v
return nkw
-
- def subst_list(self, string, raw=0, target=None, source=None):
+
+ def subst_list(self, string, raw=0, target=None, source=None, dict=None, conv=None):
"""Calls through to SCons.Util.scons_subst_list(). See
the documentation for that function."""
- if raw:
- mode = SCons.Util.SUBST_RAW
- else:
- mode = SCons.Util.SUBST_CMD
- return SCons.Util.scons_subst_list(string, self, mode, target, source)
+ return SCons.Util.scons_subst_list(string, self, raw, target, source, dict, conv)
+
+
+ def subst_path(self, path):
+ """Substitute a path list, turning EntryProxies into Nodes
+ and leaving Nodes (and other objects) as-is."""
+
+ if not SCons.Util.is_List(path):
+ path = [path]
+
+ def s(obj):
+ """This is the "string conversion" routine that we have our
+ substitutions use to return Nodes, not strings. This relies
+ on the fact that an EntryProxy object has a get() method that
+ returns the underlying Node that it wraps, which is a bit of
+ architectural dependence that we might need to break or modify
+ in the future in response to additional requirements."""
+ try:
+ get = obj.get
+ except AttributeError:
+ pass
+ else:
+ obj = get()
+ return obj
+
+ r = []
+ for p in path:
+ if SCons.Util.is_String(p):
+ p = self.subst(p, conv=s)
+ if SCons.Util.is_List(p):
+ if len(p) == 1:
+ p = p[0]
+ else:
+ # We have an object plus a string, or multiple
+ # objects that we need to smush together. No choice
+ # but to make them into a string.
+ p = string.join(map(SCons.Util.to_String, p), '')
+ else:
+ p = s(p)
+ r.append(p)
+ return r
+
+ subst_target_source = subst
+
+ def _update(self, dict):
+ """Update an environment's values directly, bypassing the normal
+ checks that occur when users try to set items.
+ """
+ self._dict.update(dict)
def use_build_signature(self):
try:
"""Append values to existing construction variables
in an Environment.
"""
- kw = our_deepcopy(kw)
- for key in kw.keys():
- if not self._dict.has_key(key):
- self._dict[key] = kw[key]
- elif SCons.Util.is_List(self._dict[key]) and not \
- SCons.Util.is_List(kw[key]):
- self._dict[key] = self._dict[key] + [ kw[key] ]
- elif SCons.Util.is_List(kw[key]) and not \
- SCons.Util.is_List(self._dict[key]):
- self._dict[key] = [ self._dict[key] ] + kw[key]
- elif SCons.Util.is_Dict(self._dict[key]) and \
- SCons.Util.is_Dict(kw[key]):
- self._dict[key].update(kw[key])
+ kw = copy_non_reserved_keywords(kw)
+ for key, val in kw.items():
+ # It would be easier on the eyes to write this using
+ # "continue" statements whenever we finish processing an item,
+ # but Python 1.5.2 apparently doesn't let you use "continue"
+ # within try:-except: blocks, so we have to nest our code.
+ try:
+ orig = self._dict[key]
+ except KeyError:
+ # No existing variable in the environment, so just set
+ # it to the new value.
+ self._dict[key] = val
else:
- self._dict[key] = self._dict[key] + kw[key]
+ try:
+ # Most straightforward: just try to add them
+ # together. This will work in most cases, when the
+ # original and new values are of compatible types.
+ self._dict[key] = orig + val
+ except TypeError:
+ try:
+ # Try to update a dictionary value with another.
+ # If orig isn't a dictionary, it won't have an
+ # update() method; if val isn't a dictionary,
+ # it won't have a keys() method. Either way,
+ # it's an AttributeError.
+ orig.update(val)
+ except AttributeError:
+ try:
+ # Check if the original is a list.
+ add_to_orig = orig.append
+ except AttributeError:
+ # The original isn't a list, but the new
+ # value is (by process of elimination),
+ # so insert the original in the new value
+ # (if there's one to insert) and replace
+ # the variable with it.
+ if orig:
+ val.insert(0, orig)
+ self._dict[key] = val
+ else:
+ # The original is a list, so append the new
+ # value to it (if there's a value to append).
+ if val:
+ add_to_orig(val)
+ self.scanner_map_delete(kw)
def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
"""Append path elements to the path 'name' in the 'ENV'
self._dict[envname][name] = nv
- def Copy(self, tools=None, **kw):
+ def AppendUnique(self, **kw):
+ """Append values to existing construction variables
+ in an Environment, if they're not already there.
+ """
+ kw = copy_non_reserved_keywords(kw)
+ for key, val in kw.items():
+ if not self._dict.has_key(key):
+ self._dict[key] = val
+ elif SCons.Util.is_Dict(self._dict[key]) and \
+ SCons.Util.is_Dict(val):
+ self._dict[key].update(val)
+ elif SCons.Util.is_List(val):
+ dk = self._dict[key]
+ if not SCons.Util.is_List(dk):
+ dk = [dk]
+ val = filter(lambda x, dk=dk: x not in dk, val)
+ self._dict[key] = dk + val
+ else:
+ dk = self._dict[key]
+ if SCons.Util.is_List(dk):
+ if not val in dk:
+ self._dict[key] = dk + val
+ else:
+ self._dict[key] = self._dict[key] + val
+ self.scanner_map_delete(kw)
+
+ def Copy(self, tools=None, toolpath=[], **kw):
"""Return a copy of a construction Environment. The
copy is like a Python "deep copy"--that is, independent
copies are made recursively of each objects--except that
"""
clone = copy.copy(self)
clone._dict = our_deepcopy(self._dict)
+ clone['__env__'] = clone
try:
cbd = clone._dict['BUILDERS']
clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
except KeyError:
pass
- apply_tools(clone, tools)
+ apply_tools(clone, tools, toolpath)
# Apply passed-in variables after the new tools.
- apply(clone.Replace, (), kw)
+ kw = copy_non_reserved_keywords(kw)
+ new = {}
+ for key, value in kw.items():
+ new[key] = SCons.Util.scons_subst_once(value, self, key)
+ apply(clone.Replace, (), new)
return clone
def Detect(self, progs):
dlist = dlist[0]
return dlist
+ def Dump(self, key = None):
+ """
+ Using the standard Python pretty printer, dump the contents of the
+ scons build environment to stdout.
+
+ If the key passed in is anything other than None, then that will
+ be used as an index into the build environment dictionary and
+ whatever is found there will be fed into the pretty printer. Note
+ that this key is case sensitive.
+ """
+ import pprint
+ pp = pprint.PrettyPrinter(indent=2)
+ if key:
+ dict = self.Dictionary(key)
+ else:
+ dict = self.Dictionary()
+ return pp.pformat(dict)
+
def FindIxes(self, paths, prefix, suffix):
"""
Search a list of paths for something that matches the prefix and suffix.
suffix - construction variable for the suffix.
"""
- suffix = self.subst('$%s'%suffix)
- prefix = self.subst('$%s'%prefix)
+ suffix = self.subst('$'+suffix)
+ prefix = self.subst('$'+prefix)
for path in paths:
dir,name = os.path.split(str(path))
if overrides:
env = copy.copy(self)
env._dict = copy.copy(self._dict)
- env._dict.update(overrides)
+ env['__env__'] = env
+ overrides = copy_non_reserved_keywords(overrides)
+ new = {}
+ for key, value in overrides.items():
+ new[key] = SCons.Util.scons_subst_once(value, self, key)
+ env._dict.update(new)
return env
else:
return self
def ParseConfig(self, command, function=None):
"""
Use the specified function to parse the output of the command
- in order to modify the current environment. The 'command'
- can be a string or a list of strings representing a command and
+ in order to modify the current environment. The 'command' can
+ be a string or a list of strings representing a command and
it's arguments. 'Function' is an optional argument that takes
the environment and the output of the command. If no function is
specified, the output will be treated as the output of a typical
- 'X-config' command (i.e. gtk-config) and used to set the CPPPATH,
- LIBPATH, LIBS, and CCFLAGS variables.
+ 'X-config' command (i.e. gtk-config) and used to append to the
+ ASFLAGS, CCFLAGS, CPPFLAGS, CPPPATH, LIBPATH, LIBS, LINKFLAGS
+ and CCFLAGS variables.
"""
# the default parse function
- def parse_conf(env, output):
- env_dict = env.Dictionary()
- static_libs = []
-
- # setup all the dictionary options
- if not env_dict.has_key('CPPPATH'):
- env_dict['CPPPATH'] = []
- if not env_dict.has_key('LIBPATH'):
- env_dict['LIBPATH'] = []
- if not env_dict.has_key('LIBS'):
- env_dict['LIBS'] = []
- if not env_dict.has_key('CCFLAGS') or env_dict['CCFLAGS'] == "":
- env_dict['CCFLAGS'] = []
+ def parse_conf(env, output, fs=self.fs):
+ dict = {
+ 'ASFLAGS' : [],
+ 'CCFLAGS' : [],
+ 'CPPFLAGS' : [],
+ 'CPPPATH' : [],
+ 'LIBPATH' : [],
+ 'LIBS' : [],
+ 'LINKFLAGS' : [],
+ }
params = string.split(output)
+ append_next_arg_to='' # for multi-word args
for arg in params:
- switch = arg[0:1]
- opt = arg[1:2]
- if switch == '-':
- if opt == 'L':
- env_dict['LIBPATH'].append(arg[2:])
- elif opt == 'l':
- env_dict['LIBS'].append(arg[2:])
- elif opt == 'I':
- env_dict['CPPPATH'].append(arg[2:])
- else:
- env_dict['CCFLAGS'].append(arg)
+ if append_next_arg_to:
+ dict[append_next_arg_to].append(arg)
+ append_next_arg_to = ''
+ elif arg[0] != '-':
+ dict['LIBS'].append(fs.File(arg))
+ elif arg[:2] == '-L':
+ dict['LIBPATH'].append(arg[2:])
+ elif arg[:2] == '-l':
+ dict['LIBS'].append(arg[2:])
+ elif arg[:2] == '-I':
+ dict['CPPPATH'].append(arg[2:])
+ elif arg[:4] == '-Wa,':
+ dict['ASFLAGS'].append(arg)
+ elif arg[:4] == '-Wl,':
+ dict['LINKFLAGS'].append(arg)
+ elif arg[:4] == '-Wp,':
+ dict['CPPFLAGS'].append(arg)
+ elif arg == '-framework':
+ dict['LINKFLAGS'].append(arg)
+ append_next_arg_to='LINKFLAGS'
+ elif arg == '-mno-cygwin':
+ dict['CCFLAGS'].append(arg)
+ dict['LINKFLAGS'].append(arg)
+ elif arg == '-mwindows':
+ dict['LINKFLAGS'].append(arg)
+ elif arg == '-pthread':
+ dict['CCFLAGS'].append(arg)
+ dict['LINKFLAGS'].append(arg)
else:
- static_libs.append(arg)
- return static_libs
+ dict['CCFLAGS'].append(arg)
+ apply(env.Append, (), dict)
if function is None:
function = parse_conf
command = self.subst(command)
return function(self, os.popen(command).read())
+ def ParseDepends(self, filename, must_exist=None):
+ """
+ Parse a mkdep-style file for explicit dependencies. This is
+ completely abusable, and should be unnecessary in the "normal"
+ case of proper SCons configuration, but it may help make
+ the transition from a Make hierarchy easier for some people
+ to swallow. It can also be genuinely useful when using a tool
+ that can write a .d file, but for which writing a scanner would
+ be too complicated.
+ """
+ try:
+ fp = open(filename, 'r')
+ except IOError:
+ if must_exist:
+ raise
+ return
+ for line in SCons.Util.LogicalLines(fp).readlines():
+ if line[0] == '#':
+ continue
+ try:
+ target, depends = string.split(line, ':', 1)
+ except:
+ pass
+ else:
+ self.Depends(string.split(target), string.split(depends))
+
def Platform(self, platform):
platform = self.subst(platform)
return SCons.Platform.Platform(platform)(self)
"""Prepend values to existing construction variables
in an Environment.
"""
- kw = our_deepcopy(kw)
- for key in kw.keys():
- if not self._dict.has_key(key):
- self._dict[key] = kw[key]
- elif SCons.Util.is_List(self._dict[key]) and not \
- SCons.Util.is_List(kw[key]):
- self._dict[key] = [ kw[key] ] + self._dict[key]
- elif SCons.Util.is_List(kw[key]) and not \
- SCons.Util.is_List(self._dict[key]):
- self._dict[key] = kw[key] + [ self._dict[key] ]
- elif SCons.Util.is_Dict(self._dict[key]) and \
- SCons.Util.is_Dict(kw[key]):
- self._dict[key].update(kw[key])
+ kw = copy_non_reserved_keywords(kw)
+ for key, val in kw.items():
+ # It would be easier on the eyes to write this using
+ # "continue" statements whenever we finish processing an item,
+ # but Python 1.5.2 apparently doesn't let you use "continue"
+ # within try:-except: blocks, so we have to nest our code.
+ try:
+ orig = self._dict[key]
+ except KeyError:
+ # No existing variable in the environment, so just set
+ # it to the new value.
+ self._dict[key] = val
else:
- self._dict[key] = kw[key] + self._dict[key]
+ try:
+ # Most straightforward: just try to add them
+ # together. This will work in most cases, when the
+ # original and new values are of compatible types.
+ self._dict[key] = val + orig
+ except TypeError:
+ try:
+ # Try to update a dictionary value with another.
+ # If orig isn't a dictionary, it won't have an
+ # update() method; if val isn't a dictionary,
+ # it won't have a keys() method. Either way,
+ # it's an AttributeError.
+ orig.update(val)
+ except AttributeError:
+ try:
+ # Check if the added value is a list.
+ add_to_val = val.append
+ except AttributeError:
+ # The added value isn't a list, but the
+ # original is (by process of elimination),
+ # so insert the the new value in the original
+ # (if there's one to insert).
+ if val:
+ orig.insert(0, val)
+ else:
+ # The added value is a list, so append
+ # the original to it (if there's a value
+ # to append).
+ if orig:
+ add_to_val(orig)
+ self._dict[key] = val
+ self.scanner_map_delete(kw)
def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
"""Prepend path elements to the path 'name' in the 'ENV'
self._dict[envname][name] = nv
+ def PrependUnique(self, **kw):
+ """Append values to existing construction variables
+ in an Environment, if they're not already there.
+ """
+ kw = copy_non_reserved_keywords(kw)
+ for key, val in kw.items():
+ if not self._dict.has_key(key):
+ self._dict[key] = val
+ elif SCons.Util.is_Dict(self._dict[key]) and \
+ SCons.Util.is_Dict(val):
+ self._dict[key].update(val)
+ elif SCons.Util.is_List(val):
+ dk = self._dict[key]
+ if not SCons.Util.is_List(dk):
+ dk = [dk]
+ val = filter(lambda x, dk=dk: x not in dk, val)
+ self._dict[key] = val + dk
+ else:
+ dk = self._dict[key]
+ if SCons.Util.is_List(dk):
+ if not val in dk:
+ self._dict[key] = val + dk
+ else:
+ self._dict[key] = val + dk
+ self.scanner_map_delete(kw)
+
def Replace(self, **kw):
"""Replace existing construction variables in an Environment
with new construction variables and/or values.
self.__setitem__('BUILDERS', kwbd)
except KeyError:
pass
+ kw = copy_non_reserved_keywords(kw)
self._dict.update(our_deepcopy(kw))
+ self.scanner_map_delete(kw)
def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix):
"""
new_prefix - construction variable for the new prefix.
new_suffix - construction variable for the new suffix.
"""
- old_prefix = self.subst('$%s'%old_prefix)
- old_suffix = self.subst('$%s'%old_suffix)
+ old_prefix = self.subst('$'+old_prefix)
+ old_suffix = self.subst('$'+old_suffix)
- new_prefix = self.subst('$%s'%new_prefix)
- new_suffix = self.subst('$%s'%new_suffix)
+ new_prefix = self.subst('$'+new_prefix)
+ new_suffix = self.subst('$'+new_suffix)
dir,name = os.path.split(str(path))
if name[:len(old_prefix)] == old_prefix:
name = name[:-len(old_suffix)]
return os.path.join(dir, new_prefix+name+new_suffix)
- def Tool(self, tool):
+ def SetDefault(self, **kw):
+ for k in kw.keys():
+ if self._dict.has_key(k):
+ del kw[k]
+ apply(self.Replace, (), kw)
+
+ def Tool(self, tool, toolpath=[]):
tool = self.subst(tool)
- return SCons.Tool.Tool(tool)(self)
+ return SCons.Tool.Tool(tool, map(self.subst, toolpath))(self)
- def WhereIs(self, prog, path=None, pathext=None):
+ def WhereIs(self, prog, path=None, pathext=None, reject=[]):
"""Find prog in the path.
"""
if path is None:
pass
elif SCons.Util.is_String(pathext):
pathext = self.subst(pathext)
- path = SCons.Util.WhereIs(prog, path, pathext)
+ path = SCons.Util.WhereIs(prog, path, pathext, reject)
if path: return path
return None
#######################################################################
def Action(self, *args, **kw):
- nargs = self.subst_list(args)
+ nargs = self.subst(args)
nkw = self.subst_kw(kw)
return apply(SCons.Action.Action, nargs, nkw)
s = self.arg2nodes(s, self.fs.Entry)
for t in tlist:
AliasBuilder(self, t, s)
- if len(tlist) == 1:
- tlist = tlist[0]
return tlist
def AlwaysBuild(self, *targets):
tlist = []
for t in targets:
tlist.extend(self.arg2nodes(t, self.fs.File))
-
for t in tlist:
t.set_always_build()
-
- if len(tlist) == 1:
- tlist = tlist[0]
return tlist
def BuildDir(self, build_dir, src_dir, duplicate=1):
def CacheDir(self, path):
self.fs.CacheDir(self.subst(path))
- def Clean(self, target, files):
+ def Clean(self, targets, files):
global CleanTargets
-
- if not isinstance(target, SCons.Node.Node):
- target = self.subst(target)
- target = self.fs.Entry(target, create=1)
-
- if not SCons.Util.is_List(files):
- files = [files]
-
- nodes = []
- for f in files:
- if isinstance(f, SCons.Node.Node):
- nodes.append(f)
- else:
- nodes.extend(self.arg2nodes(f, self.fs.Entry))
-
- try:
- CleanTargets[target].extend(nodes)
- except KeyError:
- CleanTargets[target] = nodes
+ tlist = self.arg2nodes(targets, self.fs.Entry)
+ flist = self.arg2nodes(files, self.fs.Entry)
+ for t in tlist:
+ try:
+ CleanTargets[t].extend(flist)
+ except KeyError:
+ CleanTargets[t] = flist
def Configure(self, *args, **kw):
nargs = [self]
if args:
nargs = nargs + self.subst_list(args)[0]
nkw = self.subst_kw(kw)
+ nkw['called_from_env_method'] = 1
try:
nkw['custom_tests'] = self.subst_kw(nkw['custom_tests'])
except KeyError:
pass
return apply(SCons.SConf.SConf, nargs, nkw)
- def Command(self, target, source, action):
+ def Command(self, target, source, action, **kw):
"""Builds the supplied target files from the supplied
source files using the supplied action. Action may
be any type that the Builder constructor will accept
for an action."""
- bld = SCons.Builder.Builder(action=action,
- source_factory=self.fs.Entry)
+ nkw = self.subst_kw(kw)
+ nkw['action'] = action
+ nkw['source_factory'] = self.fs.Entry
+ bld = apply(SCons.Builder.Builder, (), nkw)
return bld(self, target, source)
- def Default(self, *targets):
- global DefaultTargets
- if DefaultTargets is None:
- DefaultTargets = []
- for t in targets:
- if t is None:
- DefaultTargets = []
- elif isinstance(t, SCons.Node.Node):
- DefaultTargets.append(t)
- else:
- DefaultTargets.extend(self.arg2nodes(t, self.fs.Entry))
-
def Depends(self, target, dependency):
"""Explicity specify that 'target's depend on 'dependency'."""
tlist = self.arg2nodes(target, self.fs.Entry)
dlist = self.arg2nodes(dependency, self.fs.Entry)
for t in tlist:
t.add_dependency(dlist)
-
- if len(tlist) == 1:
- tlist = tlist[0]
return tlist
def Dir(self, name, *args, **kw):
def Environment(self, **kw):
return apply(SCons.Environment.Environment, [], self.subst_kw(kw))
+ def Execute(self, action, *args, **kw):
+ """Directly execute an action through an Environment
+ """
+ action = apply(self.Action, (action,) + args, kw)
+ return action([], [], self)
+
def File(self, name, *args, **kw):
"""
"""
nodes = self.arg2nodes(dirs, self.fs.Dir)
return SCons.Node.FS.find_file(file, nodes, self.fs.File)
+ def Flatten(self, sequence):
+ return SCons.Util.flatten(sequence)
+
def GetBuildPath(self, files):
- ret = map(str, self.arg2nodes(files, self.fs.Entry))
- if len(ret) == 1:
- return ret[0]
- return ret
+ result = map(str, self.arg2nodes(files, self.fs.Entry))
+ if SCons.Util.is_List(files):
+ return result
+ else:
+ return result[0]
def Ignore(self, target, dependency):
"""Ignore a dependency."""
dlist = self.arg2nodes(dependency, self.fs.Entry)
for t in tlist:
t.add_ignore(dlist)
-
- if len(tlist) == 1:
- tlist = tlist[0]
return tlist
def Install(self, dir, source):
for dnode in dnodes:
for src in sources:
target = self.fs.File(src.name, dnode)
- tgt.append(InstallBuilder(self, target, src))
- if len(tgt) == 1:
- tgt = tgt[0]
+ tgt.extend(InstallBuilder(self, target, src))
return tgt
def InstallAs(self, target, source):
"""Install sources as targets."""
sources = self.arg2nodes(source, self.fs.File)
targets = self.arg2nodes(target, self.fs.File)
- ret = []
+ result = []
for src, tgt in map(lambda x, y: (x, y), sources, targets):
- ret.append(InstallBuilder(self, tgt, src))
- if len(ret) == 1:
- ret = ret[0]
- return ret
+ result.extend(InstallBuilder(self, tgt, src))
+ return result
def Literal(self, string):
return SCons.Util.Literal(string)
tlist = []
for t in targets:
tlist.extend(self.arg2nodes(t, self.fs.Entry))
-
for t in tlist:
t.set_precious()
-
- if len(tlist) == 1:
- tlist = tlist[0]
return tlist
def Repository(self, *dirs, **kw):
arg = self.subst(arg)
nargs.append(arg)
nkw = self.subst_kw(kw)
- return apply(SCons.Scanner.Base, nargs, nkw)
+ return apply(SCons.Scanner.Scanner, nargs, nkw)
- def SConsignFile(self, name=".sconsign.dbm"):
+ def SConsignFile(self, name=".sconsign", dbm_module=None):
name = self.subst(name)
if not os.path.isabs(name):
name = os.path.join(str(self.fs.SConstruct_dir), name)
- SCons.Sig.SConsignFile(name)
+ SCons.SConsign.File(name, dbm_module)
def SideEffect(self, side_effect, target):
"""Tell scons that side_effects are built as side
targets = self.arg2nodes(target, self.fs.Entry)
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.has_builder() and side_effect.builder != 1:
+ if side_effect.multiple_side_effect_has_builder():
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
self.Precious(side_effect)
for target in targets:
target.side_effects.append(side_effect)
- if len(side_effects) == 1:
- return side_effects[0]
- else:
- return side_effects
+ return side_effects
def SourceCode(self, entry, builder):
"""Arrange for a source code builder for (part of) a tree."""
entries = self.arg2nodes(entry, self.fs.Entry)
for entry in entries:
entry.set_src_builder(builder)
- if len(entries) == 1:
- return entries[0]
return entries
def SourceSignatures(self, type):
# class to SCons.Environment.Environment.
Environment = Base
+
+# An entry point for returning a proxy subclass instance that overrides
+# the subst*() methods so they don't actually perform construction
+# variable substitution. This is specifically intended to be the shim
+# layer in between global function calls (which don't want construction
+# variable substitution) and the DefaultEnvironment() (which would
+# substitute variables if left to its own devices)."""
+#
+# We have to wrap this in a function that allows us to delay definition of
+# the class until it's necessary, so that when it subclasses Environment
+# it will pick up whatever Environment subclass the wrapper interface
+# might have assigned to SCons.Environment.Environment.
+
+def NoSubstitutionProxy(subject):
+ class _NoSubstitutionProxy(Environment):
+ def __init__(self, subject):
+ self.__dict__['__subject'] = subject
+ def __getattr__(self, name):
+ return getattr(self.__dict__['__subject'], name)
+ def __setattr__(self, name, value):
+ return setattr(self.__dict__['__subject'], name, value)
+ def raw_to_mode(self, dict):
+ try:
+ raw = dict['raw']
+ except KeyError:
+ pass
+ else:
+ del dict['raw']
+ dict['mode'] = raw
+ def subst(self, string, *args, **kwargs):
+ return string
+ def subst_kw(self, kw, *args, **kwargs):
+ return kw
+ def subst_list(self, string, *args, **kwargs):
+ nargs = (string, self,) + args
+ nkw = kwargs.copy()
+ nkw['gvars'] = {}
+ self.raw_to_mode(nkw)
+ return apply(SCons.Util.scons_subst_list, nargs, nkw)
+ def subst_target_source(self, string, *args, **kwargs):
+ nargs = (string, self,) + args
+ nkw = kwargs.copy()
+ nkw['gvars'] = {}
+ self.raw_to_mode(nkw)
+ return apply(SCons.Util.scons_subst, nargs, nkw)
+ return _NoSubstitutionProxy(subject)