import string
import time
import types
+import sys
import SCons.Action
import SCons.Builder
Chmod = ActionFactory(os.chmod,
lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
-def Copy(dest, src):
- def _copy_func(target, source, env, dest=dest, src=src):
- dest = str(env.arg2nodes(dest, env.fs.Entry)[0])
- src = str(env.arg2nodes(src, env.fs.Entry)[0])
- shutil.copytree(src, dest, 1)
- def _copy_str(target, source, env, dest=dest, src=src):
- dest = str(env.arg2nodes(dest, env.fs.Entry)[0])
- src = str(env.arg2nodes(src, env.fs.Entry)[0])
- return 'Copy("%s", "%s")' % (dest, src)
- return SCons.Action.Action(_copy_func, strfunction=_copy_str)
-
def copy_func(dest, src):
if os.path.isfile(src):
return shutil.copy(src, dest)
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
return 0
-def _concat(prefix, list, suffix, env, f=lambda x: x):
+def _concat(prefix, list, suffix, env, f=lambda x: x, target=None):
"""Creates a new list from 'list' by first interpolating each
element in the list using the 'env' dictionary and then calling f
on the list, and finally concatenating 'prefix' and 'suffix' onto
if SCons.Util.is_List(list):
list = SCons.Util.flatten(list)
- list = f(env.subst_path(list))
+ list = f(env.subst_path(list, target=target))
result = []
def __call__(self, target, source, env, for_signature=None):
return self.cmd
+class Variable_Method_Caller:
+ """A class for finding a construction variable on the stack and
+ calling one of its methods.
+
+ We use this to support "construction variables" in our string
+ eval()s that actually stand in for methods--specifically, use
+ of "RDirs" in call to _concat that should actually execute the
+ "TARGET.RDirs" method. (We used to support this by creating a little
+ "build dictionary" that mapped RDirs to the method, but this got in
+ the way of Memoizing construction environments, because we had to
+ create new environment objects to hold the variables.)
+ """
+ def __init__(self, variable, method):
+ self.variable = variable
+ self.method = method
+ def __call__(self, *args, **kw):
+ try: 1/0
+ except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
+ variable = None
+ while frame:
+ try:
+ variable = frame.f_locals[self.variable]
+ except KeyError:
+ pass
+ frame = frame.f_back
+ if variable is None:
+ return None
+ method = getattr(variable, self.method)
+ return apply(method, args, kw)
+
ConstructionEnvironment = {
- 'BUILDERS' : {},
- 'SCANNERS' : [],
- 'CPPSUFFIXES': CSuffixes,
- 'DSUFFIXES' : DSuffixes,
- 'IDLSUFFIXES': IDLSuffixes,
- 'PDFPREFIX' : '',
- 'PDFSUFFIX' : '.pdf',
- 'PSPREFIX' : '',
- 'PSSUFFIX' : '.ps',
- 'ENV' : {},
- 'INSTALL' : copyFunc,
- '_concat' : _concat,
- '_defines' : _defines,
- '_stripixes' : _stripixes,
- '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
- '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs)} $)',
- '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs)} $)',
- '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
- 'TEMPFILE' : NullCmdGenerator
- }
+ 'BUILDERS' : {},
+ 'SCANNERS' : [],
+ 'CPPSUFFIXES' : CSuffixes,
+ 'DSUFFIXES' : DSuffixes,
+ 'IDLSUFFIXES' : IDLSuffixes,
+ 'PDFPREFIX' : '',
+ 'PDFSUFFIX' : '.pdf',
+ 'PSPREFIX' : '',
+ 'PSSUFFIX' : '.ps',
+ 'ENV' : {},
+ 'INSTALL' : copyFunc,
+ '_concat' : _concat,
+ '_defines' : _defines,
+ '_stripixes' : _stripixes,
+ '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
+ '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET)} $)',
+ '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET)} $)',
+ '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
+ 'TEMPFILE' : NullCmdGenerator,
+ 'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
+ 'File' : Variable_Method_Caller('TARGET', 'File'),
+ 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
+}
lvars['__env__'] = self
return SCons.Util.scons_subst_list(string, self, raw, target, source, gvars, lvars, conv)
- def subst_path(self, path):
+ def subst_path(self, path, target=None):
"""Substitute a path list, turning EntryProxies into Nodes
and leaving Nodes (and other objects) as-is."""
r = []
for p in path:
if SCons.Util.is_String(p):
- p = self.subst(p, conv=s)
+ p = self.subst(p, target=target, conv=s)
if SCons.Util.is_List(p):
if len(p) == 1:
p = p[0]
def get(self):
return self.val + '-proxy'
+ class MyNode:
+ def __init__(self, val):
+ self.val = val
+ def get_subst_proxy(self):
+ return self
+ def __str__(self):
+ return self.val
+
class MyObj:
pass
r = env.subst_path(['$FOO', 'xxx', '$BAR'])
assert r == ['foo', 'xxx', 'bar'], r
+ r = env.subst_path(['$FOO', '$TARGET', '$BAR'])
+ assert r == ['foo', '', 'bar'], r
+
+ r = env.subst_path(['$FOO', '$TARGET', '$BAR'], target=MyNode('yyy'))
+ assert map(str, r) == ['foo', 'yyy', 'bar'], r
+
n = MyObj()
r = env.subst_path(['$PROXY', MyProxy('my2'), n])
overrides = {}
for odict in self.overridelist:
overrides.update(odict)
- try:
- generate_build_dict = self.targets[0].generate_build_dict
- except (AttributeError, IndexError):
- pass
- else:
- overrides.update(generate_build_dict())
import SCons.Defaults
env = self.env or SCons.Defaults.DefaultEnvironment()
build_env = env.Override(overrides)
- # Update the overrides with the $TARGET/$SOURCE variables for
- # this target+source pair, so that evaluations of arbitrary
- # Python functions have them in the __env__ environment
- # they're passed. Note that the underlying substitution
- # functions also override these with their own $TARGET/$SOURCE
- # expansions, which is *usually* duplicated effort, but covers
- # a corner case where an Action is called directly from within
- # a function action with different target and source lists.
- build_env._update(SCons.Util.subst_dict(self.targets, self.sources))
-
return build_env
def do_nothing(self, target, errfunc, kw):
return self.fs.Rsearchall(pathlist, clazz=Dir, must_exist=0,
cwd=self.cwd)
- def generate_build_dict(self):
- """Return an appropriate dictionary of values for building
- this File."""
- return {'Dir' : self.Dir,
- 'File' : self.File,
- 'RDirs' : self.RDirs}
-
def _morph(self):
"""Turn a file system node into a File object. __cache_reset__"""
self.scanner_paths = {}
try:
path = self.scanner_paths[scanner]
except KeyError:
- path = scanner.path(env, self.cwd)
+ path = scanner.path(env, self.cwd, target)
self.scanner_paths[scanner] = path
except KeyError:
- path = scanner.path(env, target.cwd)
+ path = scanner.path(env, target.cwd, target)
target.scanner_paths[scanner] = path
return scanner(self, env, path)
scanner_count = scanner_count + 1
self.hash = scanner_count
self.node = node
- def path(self, env, target):
+ def path(self, env, dir, target=None):
return ()
def __call__(self, node, env, path):
return [self.node]
s = n.get_suffix()
assert s == '', s
- def test_generate_build_dict(self):
- """Test the base Node generate_build_dict() method"""
- n = SCons.Node.Node()
- dict = n.generate_build_dict()
- assert dict == {}, dict
-
def test_postprocess(self):
"""Test calling the base Node postprocess() method"""
n = SCons.Node.Node()
def get_suffix(self):
return ''
- def generate_build_dict(self):
- """Return an appropriate dictionary of values for building
- this Node."""
- return {}
-
def get_build_env(self):
"""Fetch the appropriate Environment to build this node.
__cacheable__"""
return [self.data[strSubst[1:]]]
return [[strSubst]]
- def subst_path(self, path):
+ def subst_path(self, path, target=None):
if type(path) != type([]):
path = [path]
return map(self.subst, path)
return self[arg[1:]]
return arg
- def subst_path(self, path):
+ def subst_path(self, path, target=None):
if type(path) != type([]):
path = [path]
return map(self.subst, path)
def subst(self, arg):
return arg
- def subst_path(self, path):
+ def subst_path(self, path, target=None):
if type(path) != type([]):
path = [path]
return map(self.subst, path)
return ''
return s
- def subst_path(self, path):
+ def subst_path(self, path, target=None):
if type(path) != type([]):
path = [path]
return map(self.subst, path)
if strSubst[0] == '$':
return [self.data[strSubst[1:]]]
return [[strSubst]]
- def subst_path(self, path):
+ def subst_path(self, path, target=None):
if type(path) != type([]):
path = [path]
return map(self.subst, path)
def __init__(self, variable, fs):
self.variable = variable
self.fs = fs
- def __call__(self, env, dir, argument=None):
+ def __call__(self, env, dir, target=None, argument=None):
"__cacheable__"
try:
path = env[self.variable]
except KeyError:
return ()
- path_tuple = tuple(self.fs.Rsearchall(env.subst_path(path),
+ path = env.subst_path(path, target=target)
+ path_tuple = tuple(self.fs.Rsearchall(path,
must_exist = 0, #kwq!
clazz = SCons.Node.FS.Dir,
cwd = dir))
self.scan_check = scan_check
self.recursive = recursive
- def path(self, env, dir = None):
+ def path(self, env, dir=None, target=None):
"__cacheable__"
if not self.path_function:
return ()
if not self.argument is _null:
- return self.path_function(env, dir, self.argument)
+ return self.path_function(env, dir, target, self.argument)
else:
- return self.path_function(env, dir)
+ return self.path_function(env, dir, target)
def __call__(self, node, env, path = ()):
"""
thereby prevent expansion of construction variables (since from
the user's point of view this was called as a global function,
with no associated construction environment)."""
- def __init__(self, method_name):
+ def __init__(self, method_name, subst=0):
self.method_name = method_name
+ if subst:
+ self.factory = SCons.Defaults.DefaultEnvironment
+ else:
+ self.factory = get_DefaultEnvironmentProxy
def __call__(self, *args, **kw):
- proxy = get_DefaultEnvironmentProxy()
- method = getattr(proxy, self.method_name)
+ env = self.factory()
+ method = getattr(env, self.method_name)
return apply(method, args, kw)
'BuildDir',
'CacheDir',
'Clean',
- 'Command',
+ #The Command() method is handled separately, below.
'Depends',
'Dir',
'Execute',
for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))
+
+# The global Command() function must be handled differently than the
+# global functions for other construction environment methods because
+# we want people to be able to use Actions that must expand $TARGET
+# and $SOURCE later, when (and if) the Action is invoked to build
+# the target(s). We do this with the subst=1 argument, which creates
+# a DefaultEnvironmentCall instance that wraps up a normal default
+# construction environment that performs variable substitution, not a
+# proxy that doesn't.
+#
+# There's a flaw here, though, because any other $-variables on a command
+# line will *also* be expanded, each to a null string, but that should
+# only be a problem in the unusual case where someone was passing a '$'
+# on a command line and *expected* the $ to get through to the shell
+# because they were calling Command() and not env.Command()... This is
+# unlikely enough that we're going to leave this as is and cross that
+# bridge if someone actually comes to it.
+Command = _SConscript.DefaultEnvironmentCall('Command', subst=1)
env['DC'] = 'dmd'
env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of$TARGET $SOURCES'
- env['_DINCFLAGS'] = '$( ${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs)} $)'
+ env['_DINCFLAGS'] = '$( ${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET)} $)'
env['_DVERFLAGS'] = '$( ${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)} $)'
env['_DDEBUGFLAGS'] = '$( ${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)} $)'
env['_DFLAGS'] = '$( ${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)} $)'
env['DLIB'] = 'lib'
env['DLIBCOM'] = '$DLIB $_DLIBFLAGS -c $TARGET $SOURCES $_DLINKLIBFLAGS'
- env['_DLINKLIBFLAGS'] = '$( ${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs)} $)'
+ env['_DLINKLIBFLAGS'] = '$( ${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs, TARGET)} $)'
env['_DLIBFLAGS'] = '$( ${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)} $)'
env['DLINKFLAGS'] = []
env['DLIBLINKPREFIX'] = ''
env['_SHF77COMSTRG'] = ShF77CommandStrGenerator
env['_SHF77PPCOMSTRG'] = ShF77PPCommandStrGenerator
- env['_F77INCFLAGS'] = '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs)} $)'
+ env['_F77INCFLAGS'] = '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET)} $)'
env['_F77COMD'] = '$_F77G $_F77FLAGSG $_F77INCFLAGS -c -o $TARGET $SOURCES'
env['_F77PPCOMD'] = '$_F77G $_F77FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
env['_SHF90PPCOMG'] = ShF90PPCommandGenerator
env['_SHF90PPCOMSTRG'] = ShF90PPCommandStrGenerator
- env['_F90INCFLAGS'] = '$( ${_concat(INCPREFIX, F90PATH, INCSUFFIX, __env__, RDirs)} $)'
+ env['_F90INCFLAGS'] = '$( ${_concat(INCPREFIX, F90PATH, INCSUFFIX, __env__, RDirs, TARGET)} $)'
env['_F90COMD'] = '$_F90G $_F90FLAGSG $_F90INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_F90PPCOMD'] = '$_F90G $_F90FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F90INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHF90COMD'] = '$_SHF90G $_SHF90FLAGSG $_F90INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHF95PPCOMG'] = ShF95PPCommandGenerator
env['_SHF95PPCOMSTRG'] = ShF95PPCommandStrGenerator
- env['_F95INCFLAGS'] = '$( ${_concat(INCPREFIX, F95PATH, INCSUFFIX, __env__, RDirs)} $)'
+ env['_F95INCFLAGS'] = '$( ${_concat(INCPREFIX, F95PATH, INCSUFFIX, __env__, RDirs, TARGET)} $)'
env['_F95COMD'] = '$_F95G $_F95FLAGSG $_F95INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_F95PPCOMD'] = '$_F95G $_F95FLAGSG $CPPFLAGS $_CPPDEFFLAGS $_F95INCFLAGS $_FORTRANMODFLAG -c -o $TARGET $SOURCES'
env['_SHFORTRANPPCOMG'] = ShFortranPPCommandGenerator
env['_SHFORTRANPPCOMSTRG'] = ShFortranPPCommandStrGenerator
- env['_FORTRANINCFLAGS'] = '$( ${_concat(INCPREFIX, FORTRANPATH, INCSUFFIX, __env__, RDirs)} $)'
+ env['_FORTRANINCFLAGS'] = '$( ${_concat(INCPREFIX, FORTRANPATH, INCSUFFIX, __env__, RDirs, TARGET)} $)'
env['FORTRANMODPREFIX'] = '' # like $LIBPREFIX
env['FORTRANMODSUFFIX'] = '.mod' # like $LIBSUFFIX
env['RC'] = 'windres'
env['RCFLAGS'] = SCons.Util.CLVar('')
- env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs)} $)'
+ env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET)} $)'
env['RCINCPREFIX'] = '--include-dir '
env['RCINCSUFFIX'] = ''
env['RCCOM'] = '$RC $RCINCFLAGS $RCFLAGS -i $SOURCE -o $TARGET'
tnl = NLWrapper(target, lambda x: x.get_subst_proxy())
dict['TARGETS'] = Targets_or_Sources(tnl)
dict['TARGET'] = Target_or_Source(tnl)
+ else:
+ dict['TARGETS'] = None
+ dict['TARGET'] = None
if source:
def get_src_subst_proxy(node):
snl = NLWrapper(source, get_src_subst_proxy)
dict['SOURCES'] = Targets_or_Sources(snl)
dict['SOURCE'] = Target_or_Source(snl)
+ else:
+ dict['SOURCES'] = None
+ dict['SOURCE'] = None
return dict