summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/man/scons.194
-rw-r--r--src/CHANGES.txt19
-rw-r--r--src/RELEASE.txt4
-rw-r--r--src/engine/SCons/Environment.py129
-rw-r--r--src/engine/SCons/EnvironmentTests.py216
-rw-r--r--src/engine/SCons/Script/SConscript.py51
-rw-r--r--src/engine/SCons/Util.py65
-rw-r--r--src/engine/SCons/UtilTests.py5
-rw-r--r--test/Environment.py8
-rw-r--r--test/ParseConfig.py21
-rw-r--r--test/Platform.py4
-rw-r--r--test/Split.py17
-rw-r--r--test/WhereIs.py6
13 files changed, 504 insertions, 135 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index a1f8ecb..633f317 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -979,13 +979,15 @@ can lead to a lot of quoting,
.B scons
supplies a
.B Split()
-function that splits a single string
+global function
+and a same-named environment method
+that split a single string
into a list, separated on
strings of white-space characters.
-(This is similar to the
+(These are similar to the
string.split() method
from the standard Python library,
-but it works even if the input isn't a string.)
+but work even if the input isn't a string.)
Like all Python arguments,
the target and source arguments to a builder method
@@ -999,8 +1001,10 @@ The following are equivalent examples of calling the Program builder method:
.ES
env.Program('bar', ['bar.c', 'foo.c'])
env.Program('bar', Split('bar.c foo.c'))
+env.Program('bar', env.Split('bar.c foo.c'))
env.Program(source = ['bar.c', 'foo.c'], target = 'bar')
env.Program(target = 'bar', Split('bar.c foo.c'))
+env.Program(target = 'bar', env.Split('bar.c foo.c'))
env.Program('bar', source = string.split('bar.c foo.c'))
.EE
@@ -1850,6 +1854,17 @@ include:
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
+.RI Action( action ", [" strfunction ", " varlist ])
+.TP
+.RI env.Action( action ", [" strfunction ", " varlist ])
+Creates an Action object for
+the specified
+.IR action .
+See the section "Action Objects,"
+below, for a complete explanation of the arguments and behavior.
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
.RI AddPostAction( target ", " action )
.TP
.RI env.AddPostAction( target ", " action )
@@ -2087,6 +2102,17 @@ SConscript file.)
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
+.RI Builder( action ", [" multi ", " prefix ", " suffix ", " src_suffix ", " src_builder ", " emitter ])
+.TP
+.RI env.Builder( action ", [" multi ", " prefix ", " suffix ", " src_suffix ", " src_builder ", " emitter ])
+Creates a Builder object for
+the specified
+.IR action .
+See the section "Builder Objects,"
+below, for a complete explanation of the arguments and behavior.
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
.RI CacheDir( cache_dir )
.TP
.RI env.CacheDir( cache_dir )
@@ -2418,6 +2444,16 @@ EnsureSConsVersion(0,9)
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
+.RI Environment([ key = value ", ...])"
+.TP
+.RI env.Environment([ key = value ", ...])"
+Return a new construction environment
+initialized with the specified
+.IR key = value
+pairs.
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
.RI Exit([ value ])
.TP
.RI env.Exit([ value ])
@@ -2643,6 +2679,8 @@ env.InstallAs(target = ['../lib/libfoo.a', '../lib/libbar.a'],
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
.RI Literal( string )
+.TP
+.RI env.Literal( string )
The specified
.I string
will be preserved as-is
@@ -2662,12 +2700,10 @@ Returns a list of the target Node or Nodes.
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
-.RI ParseConfig( env ", " command ", [" function ])
+.RI env.ParseConfig( command ", [" function ])
Calls the specified
.I function
-to modify the specified environment
-.I env
-as specified by the output of
+to modify the environment as specified by the output of
.I command .
The default
.I function
@@ -2728,11 +2764,20 @@ USERNAME.
Returns a callable object
that can be used to initialize
a construction environment using the
-platform keyword of the Environment() method.
+platform keyword of the Environment() method:
.ES
env = Environment(platform = Platform('win32'))
.EE
+.TP
+.RI env.Platform( string )
+Applies the callable object for the specified platform
+.I string
+to the environment through which the method was called.
+
+.ES
+env.Platform('posix')
+.EE
.IP
Note that the
.B win32
@@ -3334,6 +3379,8 @@ The default is "MD5".
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
.RI Split( arg )
+.TP
+.RI env.Split( arg )
Returns a list of file names or other objects.
If arg is a string,
it will be split on strings of white-space characters
@@ -3347,10 +3394,11 @@ containing just the object.
.ES
files = Split("f1.c f2.c f3.c")
+files = env.Split("f4.c f5.c f6.c")
files = Split("""
- f4.c
- f5.c
- f6.c
+ f7.c
+ f8.c
+ f9.c
""")
.EE
@@ -3391,11 +3439,6 @@ Returns a callable object
that can be used to initialize
a construction environment using the
tools keyword of the Environment() method.
-
-.ES
-env = Environment(tools = [ Tool('msvc') ])
-.EE
-.IP
The object may be called with a construction
environment as an argument,
in which case the object will be
@@ -3406,10 +3449,21 @@ and the name of the tool will be added to the
construction variable.
.ES
+env = Environment(tools = [ Tool('msvc') ])
+
env = Environment()
t = Tool('msvc')
t(env) # adds 'msvc' to the TOOLS variable
.EE
+.TP
+.RI env.Tool( string )
+Applies the callable object for the specified tool
+.I string
+to the environment through which the method was called.
+
+.ES
+env.Tool('gcc')
+.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
@@ -3437,6 +3491,8 @@ env.Config(target = 'package-config', source = Value(prefix))
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
.RI WhereIs( program ", [" path ", [" pathext ]])
+.TP
+.RI env.WhereIs( program ", [" path ", [" pathext ]])
Searches for the specified executable
.I program,
@@ -3445,13 +3501,17 @@ if it is found,
and returning None if not.
Searches the specified
.I path,
-or the user's current PATH
+the value of the calling environment's PATH
+(env['ENV']['PATH']),
+or the user's current external PATH
(os.environ['PATH'])
by default.
On Win32 systems, searches for executable
programs with any of the file extensions
listed in the specified
.I pathext,
+the calling environment's PATHEXT
+(env['ENV']['PATHEXT'])
or the user's current PATHEXT
(os.environ['PATHEXT'])
by default.
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 1ac0c21..692f3e3 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -58,12 +58,13 @@ RELEASE X.XX - XXX
- Support arbitrary expansion of construction variables within
file and directory arguments to Builder calls and Environment methods.
- - Add Environment-method versions of the following global functions:
- AddPreAction(), AddPostAction(), BuildDir(), CacheDir(), Clean(),
- Default(), EnsurePythonVersion(), EnsureSConsVersion(), Exit(),
- Export(), FindFile(), GetBuildPath(), GetOption(), Help(),
- Import(), Local(), Repository(), SConsignFile(), SetOption(),
- SourceSignatures(), TargetSignatures().
+ - Add Environment-method versions of the following global
+ functions: Action(), AddPostAction(), AddPreAction(), Builder(),
+ BuildDir(), CacheDir(), Clean(), Default(), EnsurePythonVersion(),
+ EnsureSConsVersion(), Environment(), Exit(), Export(), FindFile(),
+ GetBuildPath(), GetOption(), Help(), Import(), Literal(),
+ Local(), Platform(), Repository(), SConsignFile(), SetOption(),
+ SourceSignatures(), Split(), TargetSignatures(), Tool().
- Add the following global functions that correspond to the same-named
Environment methods: AlwaysBuild(), Command(), Depends(), Ignore(),
@@ -86,6 +87,12 @@ RELEASE X.XX - XXX
subclass of Environment.Base and setting a new Environment.Environment
variable as the calling entry point.
+ - Deprecate the ParseConfig() global function in favor of a same-named
+ construction environment method.
+
+ - Allow the Environment.WhereIs() method to take explicit path and
+ pathext arguments (like the underlying SCons.Util.WhereIs() function).
+
From Clark McGrew:
- Generalize the action for .tex files so that it will decide whether
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index ae69387..f883940 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -37,6 +37,10 @@ RELEASE X.XX - XXX
another dollar sign ($$) when referring to the file or directory
as part of calling a Builder, or any of the above methods.
+ - The ParseConfig() global function has now been deprecated in favor
+ of using the env.ParseConfig() method. The global function will be
+ removed in some future release of SCons.
+
Please note the following important changes since release 0.91:
- The Debian package available from the SCons web site now
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index f2beb38..40e039d 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -365,8 +365,19 @@ class Base:
mode = SCons.Util.SUBST_RAW
else:
mode = SCons.Util.SUBST_CMD
- return SCons.Util.scons_subst(string, self, mode,
- target, source)
+ 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
+ nkw = {}
+ for k, v in kw.items():
+ if SCons.Util.is_String(v):
+ v = SCons.Util.scons_subst(v, self, mode, target, source)
+ nkw[k] = v
+ return nkw
def subst_list(self, string, raw=0, target=None, source=None):
"""Calls through to SCons.Util.scons_subst_list(). See
@@ -375,8 +386,7 @@ class Base:
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, mode, target, source)
def use_build_signature(self):
try:
@@ -513,6 +523,61 @@ class Base:
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
+ 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.
+ """
+
+ # 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'] = []
+
+ params = string.split(output)
+ 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)
+ else:
+ static_libs.append(arg)
+ return static_libs
+
+ if function is None:
+ function = parse_conf
+ if type(command) is type([]):
+ command = string.join(command)
+ command = self.subst(command)
+ return function(self, os.popen(command).read())
+
+ def Platform(self, platform):
+ platform = self.subst(platform)
+ return SCons.Platform.Platform(platform)(self)
+
def Prepend(self, **kw):
"""Prepend values to existing construction variables
in an Environment.
@@ -588,16 +653,27 @@ class Base:
name = name[:-len(old_suffix)]
return os.path.join(dir, new_prefix+name+new_suffix)
- def WhereIs(self, prog):
+ def Tool(self, tool):
+ tool = self.subst(tool)
+ return SCons.Tool.Tool(tool)(self)
+
+ def WhereIs(self, prog, path=None, pathext=None):
"""Find prog in the path.
"""
- path = None
- pathext = None
- if self.has_key('ENV'):
- if self['ENV'].has_key('PATH'):
+ if path is None:
+ try:
path = self['ENV']['PATH']
- if self['ENV'].has_key('PATHEXT'):
+ except KeyError:
+ pass
+ elif SCons.Util.is_String(path):
+ path = self.subst(path)
+ if pathext is None:
+ try:
pathext = self['ENV']['PATHEXT']
+ except KeyError:
+ pass
+ elif SCons.Util.is_String(pathext):
+ pathext = self.subst(pathext)
path = SCons.Util.WhereIs(prog, path, pathext)
if path: return path
return None
@@ -610,6 +686,11 @@ class Base:
# same-named global functions.
#######################################################################
+ def Action(self, *args, **kw):
+ nargs = self.subst_list(args)
+ nkw = self.subst_kw(kw)
+ return apply(SCons.Action.Action, nargs, nkw)
+
def AddPreAction(self, files, action):
nodes = self.arg2nodes(files, self.fs.Entry)
action = SCons.Action.Action(action)
@@ -641,6 +722,10 @@ class Base:
src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0]
self.fs.BuildDir(build_dir, src_dir, duplicate)
+ def Builder(self, **kw):
+ nkw = self.subst_kw(kw)
+ return apply(SCons.Builder.Builder, [], nkw)
+
def CacheDir(self, path):
self.fs.CacheDir(self.subst(path))
@@ -703,6 +788,9 @@ class Base:
"""
return apply(self.fs.Dir, (self.subst(name),) + args, kw)
+ def Environment(self, **kw):
+ return apply(SCons.Environment.Environment, [], self.subst_kw(kw))
+
def File(self, name, *args, **kw):
"""
"""
@@ -763,6 +851,9 @@ class Base:
ret = ret[0]
return ret
+ def Literal(self, string):
+ return SCons.Util.Literal(string)
+
def Local(self, *targets):
ret = []
for targ in targets:
@@ -839,6 +930,24 @@ class Base:
else:
raise UserError, "Unknown source signature type '%s'"%type
+ def Split(self, arg):
+ """This function converts a string or list into a list of strings
+ or Nodes. This makes things easier for users by allowing files to
+ be specified as a white-space separated list to be split.
+ The input rules are:
+ - A single string containing names separated by spaces. These will be
+ split apart at the spaces.
+ - A single Node instance
+ - A list containing either strings or Node instances. Any strings
+ in the list are not split at spaces.
+ In all cases, the function returns a list of Nodes and strings."""
+ if SCons.Util.is_List(arg):
+ return map(self.subst, arg)
+ elif SCons.Util.is_String(arg):
+ return string.split(self.subst(arg))
+ else:
+ return [self.subst(arg)]
+
def TargetSignatures(self, type):
type = self.subst(type)
if type == 'build':
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index d0e8a37..3c8438f 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -914,6 +914,54 @@ class EnvironmentTestCase(unittest.TestCase):
assert env2['ONE'] == "won"
assert env['ONE'] == 1
+ def test_ParseConfig(self):
+ """Test the ParseConfig() method"""
+ env = Environment(COMMAND='command')
+ save_command = []
+ orig_popen = os.popen
+ def my_popen(command, save_command=save_command):
+ save_command.append(command)
+ class fake_file:
+ def read(self):
+ return "-I/usr/include/fum -Ibar -X\n" + \
+ "-L/usr/fax -Lfoo -lxxx abc"
+ return fake_file()
+ try:
+ os.popen = my_popen
+ libs = env.ParseConfig("fake $COMMAND")
+ assert save_command == ['fake command'], save_command
+ assert libs == ['abc'], libs
+ assert env['CPPPATH'] == ['/usr/include/fum', 'bar'], env['CPPPATH']
+ assert env['LIBPATH'] == ['/usr/fax', 'foo'], env['LIBPATH']
+ assert env['LIBS'] == ['xxx'], env['LIBS']
+ assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
+ finally:
+ os.popen = orig_popen
+
+ def test_Platform(self):
+ """Test the Platform() method"""
+ env = Environment(WIN32='win32', NONE='no-such-platform')
+
+ exc_caught = None
+ try:
+ env.Platform('does_not_exist')
+ except SCons.Errors.UserError:
+ exc_caught = 1
+ assert exc_caught, "did not catch expected UserError"
+
+ exc_caught = None
+ try:
+ env.Platform('$NONE')
+ except SCons.Errors.UserError:
+ exc_caught = 1
+ assert exc_caught, "did not catch expected UserError"
+
+ env.Platform('posix')
+ assert env['OBJSUFFIX'] == '.o', env['OBJSUFFIX']
+
+ env.Platform('$WIN32')
+ assert env['OBJSUFFIX'] == '.obj', env['OBJSUFFIX']
+
def test_Prepend(self):
"""Test prepending to construction variables in an Environment
"""
@@ -1007,7 +1055,119 @@ class EnvironmentTestCase(unittest.TestCase):
'PREFIX', 'SUFFIX',
'LIBPREFIX', 'LIBSUFFIX')
+ def test_Tool(self):
+ """Test the Tool() method"""
+ env = Environment(LINK='link', NONE='no-such-tool')
+
+ exc_caught = None
+ try:
+ env.Tool('does_not_exist')
+ except SCons.Errors.UserError:
+ exc_caught = 1
+ assert exc_caught, "did not catch expected UserError"
+
+ exc_caught = None
+ try:
+ env.Tool('$NONE')
+ except SCons.Errors.UserError:
+ exc_caught = 1
+ assert exc_caught, "did not catch expected UserError"
+
+ env.Tool('cc')
+ assert env['CC'] == 'cc', env['CC']
+
+ env.Tool('$LINK')
+ assert env['LINK'] == '$SMARTLINK', env['LINK']
+
+ def test_WhereIs(self):
+ """Test the WhereIs() method"""
+ test = TestCmd.TestCmd(workdir = '')
+
+ sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
+ sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
+ sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
+ sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
+ test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
+
+ if sys.platform != 'win32':
+ test.write(sub1_xxx_exe, "\n")
+
+ os.mkdir(sub2_xxx_exe)
+
+ test.write(sub3_xxx_exe, "\n")
+ os.chmod(sub3_xxx_exe, 0777)
+
+ test.write(sub4_xxx_exe, "\n")
+ os.chmod(sub4_xxx_exe, 0777)
+
+ env_path = os.environ['PATH']
+
+ pathdirs_1234 = [ test.workpath('sub1'),
+ test.workpath('sub2'),
+ test.workpath('sub3'),
+ test.workpath('sub4'),
+ ] + string.split(env_path, os.pathsep)
+
+ pathdirs_1243 = [ test.workpath('sub1'),
+ test.workpath('sub2'),
+ test.workpath('sub4'),
+ test.workpath('sub3'),
+ ] + string.split(env_path, os.pathsep)
+
+ path = string.join(pathdirs_1234, os.pathsep)
+ env = Environment(ENV = {'PATH' : path})
+ wi = env.WhereIs('xxx.exe')
+ assert wi == test.workpath(sub3_xxx_exe), wi
+ wi = env.WhereIs('xxx.exe', pathdirs_1243)
+ assert wi == test.workpath(sub4_xxx_exe), wi
+ wi = env.WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep))
+ assert wi == test.workpath(sub4_xxx_exe), wi
+
+ path = string.join(pathdirs_1243, os.pathsep)
+ env = Environment(ENV = {'PATH' : path})
+ wi = env.WhereIs('xxx.exe')
+ assert wi == test.workpath(sub4_xxx_exe), wi
+ wi = env.WhereIs('xxx.exe', pathdirs_1234)
+ assert wi == test.workpath(sub3_xxx_exe), wi
+ wi = env.WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep))
+ assert wi == test.workpath(sub3_xxx_exe), wi
+
+ if sys.platform == 'win32':
+ wi = env.WhereIs('xxx', pathext = '')
+ assert wi is None, wi
+
+ wi = env.WhereIs('xxx', pathext = '.exe')
+ assert wi == test.workpath(sub4_xxx_exe), wi
+
+ wi = env.WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
+ assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
+
+ # Test that we return a normalized path even when
+ # the path contains forward slashes.
+ forward_slash = test.workpath('') + '/sub3'
+ wi = env.WhereIs('xxx', path = forward_slash, pathext = '.EXE')
+ assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
+
+
+
+ def test_Action(self):
+ """Test the Action() method"""
+ env = Environment(FOO = 'xyzzy')
+
+ a = env.Action('foo')
+ assert a, a
+
+ a = env.Action('$FOO')
+ assert a, a
+
+ a = env.Action(['$FOO', 'foo'])
+ assert a, a
+
+ def func(arg):
+ pass
+ a = env.Action(func)
+ assert a, a
def test_AddPostAction(self):
"""Test the AddPostAction() method"""
@@ -1074,6 +1234,26 @@ class EnvironmentTestCase(unittest.TestCase):
assert env.fs.src_dir == 'bbbsrc', env.fs.src_dir
assert env.fs.duplicate == 0, env.fs.duplicate
+ def test_Builder(self):
+ """Test the Builder() method"""
+ env = Environment(FOO = 'xyzzy')
+
+ b = env.Builder(action = 'foo')
+ assert not b is None, b
+
+ b = env.Builder(action = '$FOO')
+ assert not b is None, b
+
+ b = env.Builder(action = ['$FOO', 'foo'])
+ assert not b is None, b
+
+ def func(arg):
+ pass
+ b = env.Builder(action = func)
+ assert not b is None, b
+ b = env.Builder(generator = func)
+ assert not b is None, b
+
def test_CacheDir(self):
"""Test the CacheDir() method"""
class MyFS:
@@ -1199,6 +1379,14 @@ class EnvironmentTestCase(unittest.TestCase):
d = env.Dir('${BAR}_$BAR')
assert d == 'Dir(bardir_bardir)', d
+ def test_Environment(self):
+ """Test the Environment() method"""
+ env = Environment(FOO = 'xxx', BAR = 'yyy')
+
+ e2 = env.Environment(X = '$FOO', Y = '$BAR')
+ assert e2['X'] == 'xxx', e2['X']
+ assert e2['Y'] == 'yyy', e2['Y']
+
def test_File(self):
"""Test the File() method"""
class MyFS:
@@ -1320,6 +1508,14 @@ class EnvironmentTestCase(unittest.TestCase):
assert tgt.sources[0].path == 'jjj.s'
assert tgt.builder == InstallBuilder
+ def test_Literal(self):
+ """Test the Literal() method"""
+ env = Environment(FOO='fff', BAR='bbb')
+ list = env.subst_list([env.Literal('$FOO'), '$BAR'])[0]
+ assert list == ['$FOO', 'bbb'], list
+ list = env.subst_list(['$FOO', env.Literal('$BAR')])[0]
+ assert list == ['fff', '$BAR'], list
+
def test_Local(self):
"""Test the Local() method."""
env = Environment(FOO='lll')
@@ -1332,7 +1528,7 @@ class EnvironmentTestCase(unittest.TestCase):
assert str(l[1]) == 'lll', l[1]
def test_Precious(self):
- """Test the Precious() method."""
+ """Test the Precious() method"""
env = Environment(FOO='ggg', BAR='hhh')
t = env.Precious('a', '${BAR}b', ['c', 'd'], '$FOO')
assert t[0].__class__.__name__ == 'File'
@@ -1470,6 +1666,22 @@ class EnvironmentTestCase(unittest.TestCase):
env.SourceSignatures('$T')
assert env._calc_module is t
+ def test_Split(self):
+ """Test the Split() method"""
+ env = Environment(FOO='fff', BAR='bbb')
+ s = env.Split("foo bar")
+ assert s == ["foo", "bar"], s
+ s = env.Split("$FOO bar")
+ assert s == ["fff", "bar"], s
+ s = env.Split(["foo", "bar"])
+ assert s == ["foo", "bar"], s
+ s = env.Split(["foo", "${BAR}-bbb"])
+ assert s == ["foo", "bbb-bbb"], s
+ s = env.Split("foo")
+ assert s == ["foo"], s
+ s = env.Split("$FOO$BAR")
+ assert s == ["fffbbb"], s
+
def test_TargetSignatures(type):
"""Test the TargetSignatures() method"""
env = Environment(B = 'build', C = 'content')
@@ -1494,7 +1706,7 @@ class EnvironmentTestCase(unittest.TestCase):
env.TargetSignatures('$C')
assert env._build_signature == 0, env._build_signature
- def test_Environment(type):
+ def test_Environment_global_variable(type):
"""Test setting Environment variable to an Environment.Base subclass"""
class MyEnv(SCons.Environment.Base):
def xxx(self, string):
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 0095746..aed43f5 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -43,6 +43,7 @@ import SCons.Node.Python
import SCons.Platform
import SCons.SConf
import SCons.Script
+import SCons.Tool
import SCons.Util
import SCons.Options
@@ -58,6 +59,7 @@ def do_nothing(text): pass
HelpFunction = do_nothing
arguments = {}
+GlobalDict = {}
launch_dir = os.path.abspath(os.curdir)
# global exports set by Export():
@@ -285,10 +287,13 @@ class SConsEnvironment(SCons.Environment.Base):
"""An Environment subclass that contains all of the methods that
are particular to the wrapper SCons interface and which aren't
(or shouldn't be) part of the build engine itself.
+
+ Note that not all of the methods of this class have corresponding
+ global functions, there are some private methods.
"""
#
- # Private functions of an SConsEnvironment.
+ # Private methods of an SConsEnvironment.
#
def _check_version(self, major, minor, version_string):
@@ -336,7 +341,7 @@ class SConsEnvironment(SCons.Environment.Base):
elif len(ls) == 2:
files = ls[0]
- exports = SCons.Util.Split(ls[1])
+ exports = self.Split(ls[1])
else:
@@ -347,7 +352,7 @@ class SConsEnvironment(SCons.Environment.Base):
files = [ files ]
if kw.get('exports'):
- exports.extend(SCons.Util.Split(kw['exports']))
+ exports.extend(self.Split(kw['exports']))
build_dir = kw.get('build_dir')
if build_dir:
@@ -376,7 +381,7 @@ class SConsEnvironment(SCons.Environment.Base):
return (files, exports)
#
- # Public functions of an SConsEnvironment. These get
+ # Public methods of an SConsEnvironment. These get
# entry points in the global name space so they can be called
# as global functions.
#
@@ -399,7 +404,7 @@ class SConsEnvironment(SCons.Environment.Base):
def Export(self, *vars):
for var in vars:
- global_exports.update(compute_exports(SCons.Util.Split(var)))
+ global_exports.update(compute_exports(self.Split(var)))
def GetLaunchDir(self):
global launch_dir
@@ -416,7 +421,7 @@ class SConsEnvironment(SCons.Environment.Base):
def Import(self, *vars):
try:
for var in vars:
- var = SCons.Util.Split(var)
+ var = self.Split(var)
for v in var:
if v == '*':
stack[-1].globals.update(global_exports)
@@ -478,6 +483,12 @@ def SetJobs(num):
"The SetJobs() function has been deprecated;\n" +\
"\tuse SetOption('num_jobs', num) instead.")
SetOption('num_jobs', num)
+
+def ParseConfig(env, command, function=None):
+ SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning,
+ "The ParseConfig() function has been deprecated;\n" +\
+ "\tuse the env.ParseConfig() method instead.")
+ return env.ParseConfig(command, function)
def Alias(name):
@@ -508,6 +519,8 @@ def get_DefaultEnvironmentProxy():
return setattr(self.__dict__['__subject'], name, value)
def subst(self, string, raw=0, target=None, source=None):
return string
+ def subst_kw(self, kw, raw=0, target=None, source=None):
+ return kw
def subst_list(self, string, raw=0, target=None, source=None):
return string
default_env = SCons.Defaults.DefaultEnvironment()
@@ -547,22 +560,26 @@ GlobalDefaultEnvironmentFunctions = [
'SetOption',
# Methods from the Environment.Base class.
+ 'Action',
'AddPostAction',
'AddPreAction',
'AlwaysBuild',
'BuildDir',
+ 'Builder',
'CacheDir',
'Clean',
'Command',
'Default',
'Depends',
'Dir',
+ 'Environment',
'File',
'FindFile',
'GetBuildPath',
'Ignore',
'Install',
'InstallAs',
+ 'Literal',
'Local',
'Precious',
'Repository',
@@ -570,6 +587,7 @@ GlobalDefaultEnvironmentFunctions = [
'SideEffect',
'SourceCode',
'SourceSignatures',
+ 'Split',
'TargetSignatures',
# Supported builders.
@@ -598,10 +616,8 @@ GlobalDefaultEnvironmentFunctions = [
'Zip',
]
-GlobalFunctionDict = {}
-
for name in GlobalDefaultEnvironmentFunctions:
- GlobalFunctionDict[name] = DefaultEnvironmentCall(name)
+ GlobalDict[name] = DefaultEnvironmentCall(name)
def BuildDefaultGlobals():
"""
@@ -610,34 +626,31 @@ def BuildDefaultGlobals():
"""
globals = {}
- globals['Action'] = SCons.Action.Action
+ globals['Platform'] = SCons.Platform.Platform
+ globals['Tool'] = SCons.Tool.Tool
+ globals['WhereIs'] = SCons.Util.WhereIs
+
+ # Functions we're in the process of converting to Environment methods.
globals['Alias'] = Alias
globals['ARGUMENTS'] = arguments
- globals['Builder'] = SCons.Builder.Builder
globals['Configure'] = SCons.SConf.SConf
globals['CScan'] = SCons.Defaults.CScan
globals['DefaultEnvironment'] = SCons.Defaults.DefaultEnvironment
- globals['Environment'] = SCons.Environment.Environment
globals['GetCommandHandler'] = SCons.Action.GetCommandHandler
- globals['Literal'] = SCons.Util.Literal
globals['Options'] = Options
- globals['ParseConfig'] = SCons.Util.ParseConfig
- globals['Platform'] = SCons.Platform.Platform
globals['Return'] = Return
globals['SConscriptChdir'] = SConscriptChdir
globals['Scanner'] = SCons.Scanner.Base
globals['SetCommandHandler'] = SCons.Action.SetCommandHandler
- globals['Split'] = SCons.Util.Split
- globals['Tool'] = SCons.Tool.Tool
globals['Value'] = SCons.Node.Python.Value
- globals['WhereIs'] = SCons.Util.WhereIs
# Deprecated functions, leave these here for now.
globals['GetJobs'] = GetJobs
+ globals['ParseConfig'] = ParseConfig
globals['SetBuildSignatureType'] = SetBuildSignatureType
globals['SetContentSignatureType'] = SetContentSignatureType
globals['SetJobs'] = SetJobs
- globals.update(GlobalFunctionDict)
+ globals.update(GlobalDict)
return globals
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 38b25af..c0bc6ac 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -621,24 +621,6 @@ def is_Dict(e):
def is_List(e):
return type(e) is types.ListType or isinstance(e, UserList.UserList)
-def Split(arg):
- """This function converts a string or list into a list of strings
- or Nodes. This makes things easier for users by allowing files to
- be specified as a white-space separated list to be split.
- The input rules are:
- - A single string containing names separated by spaces. These will be
- split apart at the spaces.
- - A single Node instance
- - A list containing either strings or Node instances. Any strings
- in the list are not split at spaces.
- In all cases, the function returns a list of Nodes and strings."""
- if is_List(arg):
- return arg
- elif is_String(arg):
- return string.split(arg)
- else:
- return [arg]
-
def mapPaths(paths, dir, env=None):
"""Takes a single node or string, or a list of nodes and/or
strings. We leave the nodes untouched, but we put the strings
@@ -918,53 +900,6 @@ def AppendPath(oldpath, newpath, sep = os.pathsep):
return string.join(paths, sep)
-def ParseConfig(env, command, function=None):
- """Use the specified function to parse the output of the command in order
- to modify the specified 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.
- """
- # 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'] = []
-
- params = string.split(output)
- 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)
- else:
- static_libs.append(arg)
- return static_libs
-
- if function is None:
- function = parse_conf
- if type(command) is type([]):
- command = string.join(command)
- return function(env, os.popen(command).read())
-
def dir_index(directory):
files = []
for file in os.listdir(directory):
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index 09b96d9..cc0d693 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -458,11 +458,6 @@ class UtilTestCase(unittest.TestCase):
if hasattr(types, 'UnicodeType'):
exec "assert not is_List(u'')"
- def test_Split(self):
- assert Split("foo bar") == ["foo", "bar"]
- assert Split(["foo", "bar"]) == ["foo", "bar"]
- assert Split("foo") == ["foo"]
-
def test_is_String(self):
assert is_String("")
if hasattr(types, 'UnicodeType'):
diff --git a/test/Environment.py b/test/Environment.py
index 4d4d34f..b315c40 100644
--- a/test/Environment.py
+++ b/test/Environment.py
@@ -33,11 +33,17 @@ test = TestSCons.TestSCons()
test.write('SConstruct', """
env=Environment(BAR='#bar.in', BLAT='subdir/../blat blat')
-target = env.Command('foo.out', 'foo.in', r'%s build.py $SOURCE $TARGET ${File(BAR)} ${Dir(BLAT)}')
+target = env.Command('foo.out',
+ 'foo.in',
+ r'%s build.py $SOURCE $TARGET ${File(BAR)} ${Dir(BLAT)}')
assert target == Dir('.').File('foo.out')
assert Dir('.') == Dir('.').Dir('.')
assert target == target.File('foo.out')
+
+e2 = env.Environment(XXX='$BAR', YYY='$BLAT')
+print e2['XXX']
+print e2['YYY']
"""%python)
test.write('build.py', """
diff --git a/test/ParseConfig.py b/test/ParseConfig.py
index da9bad1..108aa31 100644
--- a/test/ParseConfig.py
+++ b/test/ParseConfig.py
@@ -40,7 +40,7 @@ print "-L/usr/fax -Lfoo -lxxx abc"
test.write('SConstruct', """
env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [], CCFLAGS = '')
-static_libs = ParseConfig(env, [r"%s", r"%s", "--libs --cflags"])
+static_libs = env.ParseConfig([r"%s", r"%s", "--libs --cflags"])
print env['CPPPATH']
print env['LIBPATH']
print env['LIBS']
@@ -49,6 +49,17 @@ print static_libs
""" % (TestSCons.python, test_config))
test.write('SConstruct2', """
+env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [], CCFLAGS = '',
+ PYTHON = '%s')
+static_libs = env.ParseConfig(r"$PYTHON %s --libs --cflags")
+print env['CPPPATH']
+print env['LIBPATH']
+print env['LIBS']
+print env['CCFLAGS']
+print static_libs
+""" % (TestSCons.python, test_config))
+
+test.write('SConstruct3', """
env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [], CCFLAGS = '')
static_libs = ParseConfig(env, r"%s %s --libs --cflags")
print env['CPPPATH']
@@ -70,4 +81,12 @@ test.run(arguments = ".", stdout = good_stdout)
test.run(arguments = "-f SConstruct2 .", stdout = good_stdout)
+test.run(arguments = "-f SConstruct3 .",
+ stdout = good_stdout,
+ stderr = """
+scons: warning: The ParseConfig() function has been deprecated;
+ use the env.ParseConfig() method instead.
+File "SConstruct3", line 3, in ?
+""")
+
test.pass_test()
diff --git a/test/Platform.py b/test/Platform.py
index 94961fb..b0afe2e 100644
--- a/test/Platform.py
+++ b/test/Platform.py
@@ -35,7 +35,7 @@ print "'%s'" % env['PROGSUFFIX']
assert env['SHELL'] == 'sh'
Platform('os2')(env)
print "'%s'" % env['PROGSUFFIX']
-Platform('posix')(env)
+env.Platform('posix')
print "'%s'" % env['PROGSUFFIX']
Platform('win32')(env)
print "'%s'" % env['PROGSUFFIX']
@@ -48,7 +48,7 @@ Platform('cygwin')(env)
print "'%s'" % env['LIBSUFFIX']
Platform('os2')(env)
print "'%s'" % env['LIBSUFFIX']
-Platform('posix')(env)
+env.Platform('posix')
print "'%s'" % env['LIBSUFFIX']
Platform('win32')(env)
print "'%s'" % env['LIBSUFFIX']
diff --git a/test/Split.py b/test/Split.py
index 46a19e5..9902bba 100644
--- a/test/Split.py
+++ b/test/Split.py
@@ -29,22 +29,29 @@ import TestSCons
test = TestSCons.TestSCons()
test.write('SConstruct', """
+env = Environment(BBB = 'bbb', CCC = 'ccc')
print Split('aaa')
-print Split('bbb ccc')
+print Split('aaa $BBB')
+print env.Split('bbb $CCC')
+print env.Split('$BBB ccc')
print Split(['ddd', 'eee'])
SConscript('SConscript')
""")
test.write('SConscript', """
-print Split('fff')
+env = Environment(FFF='fff', JJJ='jjj')
+print env.Split('${FFF}.f')
print Split('ggg hhh')
-print Split(['iii', 'jjj'])
+print env.Split(['iii', '$JJJ'])
""")
-expect = """['aaa']
+expect = """\
+['aaa']
+['aaa', '$BBB']
+['bbb', 'ccc']
['bbb', 'ccc']
['ddd', 'eee']
-['fff']
+['fff.f']
['ggg', 'hhh']
['iii', 'jjj']
"""
diff --git a/test/WhereIs.py b/test/WhereIs.py
index 9da3739..8347acc 100644
--- a/test/WhereIs.py
+++ b/test/WhereIs.py
@@ -67,9 +67,10 @@ pathdirs_1243 = [ test.workpath('sub1'),
test.write('SConstruct', """
SConscript('%s')
+env = Environment()
print WhereIs('xxx.exe')
print WhereIs('xxx.exe', %s)
-print WhereIs('xxx.exe', %s)
+print env.WhereIs('xxx.exe', %s)
print WhereIs('xxx.exe', %s)
print WhereIs('xxx.exe', %s)
""" % (subdir_SConscript,
@@ -80,9 +81,10 @@ print WhereIs('xxx.exe', %s)
))
test.write(subdir_SConscript, """
+env = Environment()
print WhereIs('xxx.exe')
print WhereIs('xxx.exe', %s)
-print WhereIs('xxx.exe', %s)
+print env.WhereIs('xxx.exe', %s)
print WhereIs('xxx.exe', %s)
print WhereIs('xxx.exe', %s)
""" % (repr(string.join(pathdirs_1234, os.pathsep)),