Add more environment methods for global functions: Action(), Builder(), Environment...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 25 Sep 2003 05:18:23 +0000 (05:18 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 25 Sep 2003 05:18:23 +0000 (05:18 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@808 fdb21ef1-2011-0410-befe-b5e4ea1792b1

13 files changed:
doc/man/scons.1
src/CHANGES.txt
src/RELEASE.txt
src/engine/SCons/Environment.py
src/engine/SCons/EnvironmentTests.py
src/engine/SCons/Script/SConscript.py
src/engine/SCons/Util.py
src/engine/SCons/UtilTests.py
test/Environment.py
test/ParseConfig.py
test/Platform.py
test/Split.py
test/WhereIs.py

index a1f8ecbde532803b287034bf2c4830b457c78288..633f3175d897c49ce74b1077e8dbfe7d832bdeec 100644 (file)
@@ -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.
index 1ac0c21c8bb744d6486dce10bf45a60f405093af..692f3e3f6a1f32a25ecbcda4c2ee12b2e82aecb2 100644 (file)
@@ -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
index ae6938733e01d19ee284cc2c2f7dfbf8f25d7f33..f88394091e8262172d720f30091b1723dd2d3ca5 100644 (file)
@@ -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
index f2beb38081f679afc010bf278e56bf0f60c49f03..40e039d699cd83686e98de282bf905b3832585bb 100644 (file)
@@ -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':
index d0e8a37eff0969780d45c9d7f6e6db052e9951b1..3c8438f31ef8081012058ae774e6cdbd23c81d1e 100644 (file)
@@ -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):
index 0095746a287f53fdbe8e5e7f57c6059078f39cc2..aed43f5fb578e177681e504ab0af375d5c0762a6 100644 (file)
@@ -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
index 38b25af78c63f6eb5ba21d3f1dfa37ff79d13f70..c0bc6ac4faadd6bf5ab8749a3bf68a54d717b9bd 100644 (file)
@@ -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):
index 09b96d956d575fa7a926a97a46206c828bdb145a..cc0d69356d12b7069ea49869253ffaf142be1a3e 100644 (file)
@@ -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'):
index 4d4d34f91c002fdf3be1a3bffd74049694c2c562..b315c4017dd6077a27b55ab038c0d29df7b4ced5 100644 (file)
@@ -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', """
index da9bad10de9ef398a6b348e2980fff7bb72b195e..108aa31392abda18a2795f86a2ea422d44c3e85c 100644 (file)
@@ -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()
index 94961fba01e0d5c7795e190e664f48304f325f01..b0afe2e68d6b7d7fa8c5f315fe69a7e38910b847 100644 (file)
@@ -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']
index 46a19e578fa6a71604fbd2876ad31c7973a2e259..9902bba8c8693f8b07b3edd971594568e0941dd2 100644 (file)
@@ -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']
 """
index 9da3739cfc5db2f27087524e9b9f7aa1465e596a..8347acc707adbe87f0161912cbc3eace95772935 100644 (file)
@@ -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)),