From ceabf2baf7a2d019940ab30da9b1e477d5d029d1 Mon Sep 17 00:00:00 2001 From: stevenknight Date: Thu, 25 Sep 2003 05:18:23 +0000 Subject: [PATCH] Add more environment methods for global functions: Action(), Builder(), Environment(), Literal(), Platform(), Split(), Tool(). Deprecate ParseConfig() in favor of an environment method. git-svn-id: http://scons.tigris.org/svn/scons/trunk@808 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- doc/man/scons.1 | 94 +++++++++-- src/CHANGES.txt | 19 ++- src/RELEASE.txt | 4 + src/engine/SCons/Environment.py | 129 +++++++++++++-- src/engine/SCons/EnvironmentTests.py | 216 +++++++++++++++++++++++++- src/engine/SCons/Script/SConscript.py | 51 +++--- src/engine/SCons/Util.py | 65 -------- src/engine/SCons/UtilTests.py | 5 - test/Environment.py | 8 +- test/ParseConfig.py | 21 ++- test/Platform.py | 4 +- test/Split.py | 17 +- test/WhereIs.py | 6 +- 13 files changed, 504 insertions(+), 135 deletions(-) diff --git a/doc/man/scons.1 b/doc/man/scons.1 index a1f8ecbd..633f3175 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 @@ -1848,6 +1852,17 @@ and global functions supported by .B scons 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 ) @@ -2085,6 +2100,17 @@ specify a build directory in conjunction with calling a subsidiary 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 ) @@ -2416,6 +2442,16 @@ actual SCons version is not late enough. EnsureSConsVersion(0,9) .EE +'\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.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 ]) @@ -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 1ac0c21c..692f3e3f 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 ae693873..f8839409 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 f2beb380..40e039d6 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 d0e8a37e..3c8438f3 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 0095746a..aed43f5f 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 38b25af7..c0bc6ac4 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 09b96d95..cc0d6935 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 4d4d34f9..b315c401 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 da9bad10..108aa313 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 94961fba..b0afe2e6 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 46a19e57..9902bba8 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 9da3739c..8347acc7 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)), -- 2.26.2