Commits

Steven Knight  committed 8be6a6a

Give the global functions corresponding Environment methods.

  • Participants
  • Parent commits 8f9363f

Comments (0)

Files changed (10)

File doc/man/scons.1

 be redetected.
 
 SCons supports the following tool specifications out of the box:
+
 .ES
 386asm
 aixc++
 Builds a static object file
 from one or more C, C++, or Fortran source files.
 Source files must have one of the following extensions:
+
 .ES
   .asm    assembly language file
   .ASM    assembly language file
 .IP Jar
 Builds a Java archive (.jar) file
 from a source tree of .class files.
+
 .ES
 env.Jar(target = 'foo.jar', source = 'classes')
 .EE
 .SS Other Construction Environment Methods
 Additional construction environment methods include:
 
+.TP 
+.RI AddPostAction( target ", " action )
+Arranges for the specified
+.I action
+to be performed
+after the specified
+.I target
+has been built.
+The specified action(s) may be
+an Action object, or anything that
+can be converted into an Action object
+(see below).
+
+.TP 
+.RI AddPreAction( target ", " action )
+Arranges for the specified
+.I action
+to be performed
+before the specified
+.I target
+is built.
+The specified action(s) may be
+an Action object, or anything that
+can be converted into an Action object
+(see below).
+
 .TP
 .RI Alias( alias ", " targets )
 Creates a phony target that
 .EE
 
 .TP
+.RI AlwaysBuild( target ", ...)"
+Marks each given
+.I target
+so that it is always assumed to be out of date,
+and will always be rebuilt if needed.
+Note, however, that
+.BR AlwaysBuild ()
+does not add its target(s) to the default target list,
+so the targets will only be built
+if they are specified on the command line,
+or are a dependent of a target specified on the command line--but
+they will
+.I always
+be built if so specified.
+Multiple targets can be passed in to a single call to
+.BR AlwaysBuild ().
+
+.TP
 .RI Append( key = val ", [...])"
 Appends the specified keyword arguments
 to the end of construction variables in the environment.
 .EE
 
 .TP
+.RI AppendENVPath( name ", " newpath ", [" envname ", " sep ])
+This appends new path elements to the given path in the
+specified external environment
+.RB ( ENV
+by default).
+This will only add
+any particular path once (leaving the last one it encounters and
+ignoring the rest, to preserve path order),
+and to help assure this,
+will normalize all paths (using
+.B os.path.normpath
+and
+.BR os.path.normcase ).
+This can also handle the
+case where the given old path variable is a list instead of a
+string, in which case a list will be returned instead of a string.
+Example:
+
+.ES
+print 'before:',env['ENV']['INCLUDE']
+include_path = '/foo/bar:/foo'
+env.PrependENVPath('INCLUDE', include_path)
+print 'after:',env['ENV']['INCLUDE']
+
+yields:
+before: /foo:/biz
+after: /biz:/foo/bar:/foo
+.EE
+
+.TP
+BitKeeper()
+A factory function that
+returns a Builder object
+to be used to fetch source files
+using BitKeeper.
+The returned Builder
+is intended to be passed to the
+.B SourceCode
+function.
+
+.ES
+env.SourceCode('.', env.BitKeeper())
+.EE
+
+.TP
+.RI Command( target ", " source ", " commands )
+Executes a specific action
+(or list of actions)
+to build a target file or files.
+This is more convenient
+than defining a separate Builder object
+for a single special-case build.
+
+Note that an action can be an external command,
+specified as a string,
+or a callable Python object;
+see "Action Objects," below.
+Examples:
+
+.ES
+env.Command('foo.out', 'foo.in',
+            "$FOO_BUILD < $SOURCES > $TARGET")
+
+env.Command('bar.out', 'bar.in',
+            ["rm -f $TARGET",
+             "$BAR_BUILD < $SOURCES > $TARGET"])
+
+def rename(env, target, source):
+    import os
+    os.rename('.tmp', str(target[0]))
+
+env.Command('baz.out', 'baz.in',
+            ["$BAZ_BUILD < $SOURCES > .tmp",
+	     rename ])
+.EE
+
+.TP
+.RI Copy([ key = val ", ...])"
+Return a separate copy of a construction environment.
+If there are any keyword arguments specified,
+they are added to the returned copy,
+overwriting any existing values
+for the keywords.
+
+.ES
+env2 = env.Copy()
+env3 = env.Copy(CCFLAGS = '-g')
+.EE
+.IP
+Additionally, a list of tools may be specified, as in the Environment
+constructor:
+
+.ES
+def MyTool(env): env['FOO'] = 'bar'
+env4 = env.Copy(tools = ['msvc', MyTool])
+.EE
+
+.TP
+.RI CVS( repository ", " module )
+A factory function that
+returns a Builder object
+to be used to fetch source files
+from the specified
+CVS
+.IR repository .
+The returned Builder
+is intended to be passed to the
+.B SourceCode
+function.
+
+The optional specified
+.I module
+will be added to the beginning
+of all repository path names;
+this can be used, in essence,
+to strip initial directory names
+from the repository path names,
+so that you only have to
+replicate part of the repository
+directory hierarchy in your
+local build directory:
+
+.ES
+# Will fetch foo/bar/src.c
+# from /usr/local/CVSROOT/foo/bar/src.c.
+env.SourceCode('.', env.CVS('/usr/local/CVSROOT'))
+
+# Will fetch bar/src.c
+# from /usr/local/CVSROOT/foo/bar/src.c.
+env.SourceCode('.', env.CVS('/usr/local/CVSROOT', 'foo'))
+
+# Will fetch src.c
+# from /usr/local/CVSROOT/foo/bar/src.c.
+env.SourceCode('.', env.CVS('/usr/local/CVSROOT', 'foo/bar'))
+.EE
+
+.TP 
+.RI Default( targets )
+This specifies a list of default targets,
+which will be built by
+.B scons
+if no explicit targets are given on the command line.
+Multiple calls to
+.BR Default ()
+are legal,
+and add to the list of default targets.
+
+Multiple targets should be specified as
+separate arguments to the
+.BR Default ()
+method, or as a list.
+.BR Default ()
+will also accept the Node returned by any
+of a construction environment's
+builder methods.
+Examples:
+
+.ES
+env.Default('foo', 'bar', 'baz')
+env.Default(['a', 'b', 'c'])
+hello = env.Program('hello', 'hello.c')
+env.Default(hello)
+.EE
+.IP
+An argument to
+.BR Default ()
+of
+.B None
+will clear all default targets.
+Later calls to
+.BR Default ()
+will add to the (now empty) default-target list
+like normal.
+
+.TP
+.RI Depends( target ", " dependency )
+Specifies an explicit dependency;
+the target file(s) will be rebuilt
+whenever the dependency file(s) has changed.
+This should only be necessary
+for cases where the dependency
+is not caught by a Scanner
+for the file.
+
+.ES
+env.Depends('foo', 'other-input-file-for-foo')
+.EE
+
+.TP
+.RI Dictionary([ vars ])
+Returns a dictionary object
+containing copies of all of the
+construction variables in the environment.
+If there are any variable names specified,
+only the specified construction
+variables are returned in the dictionary.
+
+.ES
+dict = env.Dictionary()
+cc_dict = env.Dictionary('CC', 'CCFLAGS', 'CCCOM')
+.EE
+
+.TP
+.RI FindFile( file ", " dirs )
+Search for 
+.I file 
+in the path specified by 
+.IR dirs .
+.I file
+may be a list of file names or a single file name. In addition to searching
+for files that exist in the filesytem, this function also searches for
+derived files that have not yet been built.
+
+.ES
+foo = env.FindFile('foo', ['dir1', 'dir2'])
+.EE
+
+.TP
+.RI Ignore( target ", " dependency )
+The specified dependency file(s)
+will be ignored when deciding if
+the target file(s) need to be rebuilt.
+
+.ES
+env.Ignore('foo', 'foo.c')
+env.Ignore('bar', ['bar1.h', 'bar2.h'])
+.EE
+
+.TP
+.RI Install( dir ", " source )
+Installs one or more files in a destination directory.
+The file names remain the same.
+
+.ES
+env.Install(dir = '/usr/local/bin', source = ['foo', 'bar'])
+.EE
+
+.TP
+.RI InstallAs( target ", " source )
+Installs one or more files as specific file names,
+allowing changing a file name as part of the
+installation.
+It is an error if the target and source
+list different numbers of files.
+
+.ES
+env.InstallAs(target = '/usr/local/bin/foo',
+              source = 'foo_debug')
+env.InstallAs(target = ['../lib/libfoo.a', '../lib/libbar.a'],
+              source = ['libFOO.a', 'libBAR.a'])
+.EE
+
+.TP
+.RI Local( targets )
+The specified
+.I targets
+will have copies made in the local tree,
+even if an already up-to-date copy
+exists in a repository.
+Returns a list of the target Node or Nodes.
+
+.TP
+Perforce()
+A factory function that
+returns a Builder object
+to be used to fetch source files
+from the Perforce source code management system.
+The returned Builder
+is intended to be passed to the
+.B SourceCode
+function:
+
+.ES
+env.SourceCode('.', env.Perforce())
+.EE
+.IP
+Perforce uses a number of external
+environment variables for its operation.
+Consequently, this function adds the
+following variables from the user's external environment
+to the construction environment's
+ENV dictionary:
+P4CHARSET,
+P4CLIENT,
+P4LANGUAGE,
+P4PASSWD,
+P4PORT,
+P4USER,
+SYSTEMROOT,
+USER,
+and
+USERNAME.
+
+.TP
+.RI Precious( target ", ...)"
+Marks each given
+.I target
+as precious so it is not deleted before it is rebuilt. Normally
+.B scons
+deletes a target before building it.
+Multiple targets can be passed in to a single call to
+.BR Precious ().
+
+.TP
+.RI Prepend( key = val ", [...])"
+Appends the specified keyword arguments
+to the beginning of construction variables in the environment.
+If the Environment does not have
+the specified construction variable,
+it is simply added to the environment.
+If the values of the construction variable
+and the keyword argument are the same type,
+then the two values will be simply added together.
+Otherwise, the construction variable
+and the value of the keyword argument
+are both coerced to lists,
+and the lists are added together.
+(See also the Append method, above.)
+
+.ES
+env.Prepend(CCFLAGS = '-g ', FOO = ['foo.yyy'])
+.EE
+
+.TP
 .RI PrependENVPath( name ", " newpath ", [" envname ", " sep ])
 This appends new path elements to the given path in the
 specified external environment
 .EE
 
 .TP
-.RI AppendENVPath( name ", " newpath ", [" envname ", " sep ])
-This appends new path elements to the given path in the
-specified external environment
-.RB ( ENV
-by default).
-This will only add
-any particular path once (leaving the last one it encounters and
-ignoring the rest, to preserve path order),
-and to help assure this,
-will normalize all paths (using
-.B os.path.normpath
-and
-.BR os.path.normcase ).
-This can also handle the
-case where the given old path variable is a list instead of a
-string, in which case a list will be returned instead of a string.
-Example:
-
-.ES
-print 'before:',env['ENV']['INCLUDE']
-include_path = '/foo/bar:/foo'
-env.PrependENVPath('INCLUDE', include_path)
-print 'after:',env['ENV']['INCLUDE']
-
-yields:
-before: /foo:/biz
-after: /biz:/foo/bar:/foo
-.EE
-
-.TP
-BitKeeper()
-A factory function that
-returns a Builder object
-to be used to fetch source files
-using BitKeeper.
-The returned Builder
-is intended to be passed to the
-.B SourceCode
-function.
-.ES
-env.SourceCode('.', env.BitKeeper())
-.EE
-
-.TP
-.RI Command( target ", " source ", " commands )
-Executes a specific action
-(or list of actions)
-to build a target file or files.
-This is more convenient
-than defining a separate Builder object
-for a single special-case build.
-
-Note that an action can be an external command,
-specified as a string,
-or a callable Python object;
-see "Action Objects," below.
-Examples:
-
-.ES
-env.Command('foo.out', 'foo.in',
-            "$FOO_BUILD < $SOURCES > $TARGET")
-
-env.Command('bar.out', 'bar.in',
-            ["rm -f $TARGET",
-             "$BAR_BUILD < $SOURCES > $TARGET"])
-
-def rename(env, target, source):
-    import os
-    os.rename('.tmp', str(target[0]))
-
-env.Command('baz.out', 'baz.in',
-            ["$BAZ_BUILD < $SOURCES > .tmp",
-	     rename ])
-.EE
-
-.TP
-.RI Copy([ key = val ", ...])"
-Return a separate copy of a construction environment.
-If there are any keyword arguments specified,
-they are added to the returned copy,
-overwriting any existing values
-for the keywords.
-
-.ES
-env2 = env.Copy()
-env3 = env.Copy(CCFLAGS = '-g')
-.EE
-
-Additionally, a list of tools may be specified, as in the Environment
-constructor:
-
-.ES
-def MyTool(env): env['FOO'] = 'bar'
-env4 = env.Copy(tools = ['msvc', MyTool])
-.EE
-
-
-.TP
-.RI CVS( repository ", " module )
-A factory function that
-returns a Builder object
-to be used to fetch source files
-from the specified
-CVS
-.IR repository .
-The returned Builder
-is intended to be passed to the
-.B SourceCode
-function.
-
-The optional specified
-.I module
-will be added to the beginning
-of all repository path names;
-this can be used, in essence,
-to strip initial directory names
-from the repository path names,
-so that you only have to
-replicate part of the repository
-directory hierarchy in your
-local build directory:
-
-.ES
-# Will fetch foo/bar/src.c
-# from /usr/local/CVSROOT/foo/bar/src.c.
-env.SourceCode('.', env.CVS('/usr/local/CVSROOT'))
-
-# Will fetch bar/src.c
-# from /usr/local/CVSROOT/foo/bar/src.c.
-env.SourceCode('.', env.CVS('/usr/local/CVSROOT', 'foo'))
-
-# Will fetch src.c
-# from /usr/local/CVSROOT/foo/bar/src.c.
-env.SourceCode('.', env.CVS('/usr/local/CVSROOT', 'foo/bar'))
-.EE
-
-.TP
-.RI Depends( target ", " dependency )
-Specifies an explicit dependency;
-the target file(s) will be rebuilt
-whenever the dependency file(s) has changed.
-This should only be necessary
-for cases where the dependency
-is not caught by a Scanner
-for the file.
-
-.ES
-env.Depends('foo', 'other-input-file-for-foo')
-.EE
-
-.TP
-.RI Dictionary([ vars ])
-Returns a dictionary object
-containing copies of all of the
-construction variables in the environment.
-If there are any variable names specified,
-only the specified construction
-variables are returned in the dictionary.
-
-.ES
-dict = env.Dictionary()
-cc_dict = env.Dictionary('CC', 'CCFLAGS', 'CCCOM')
-.EE
-
-.TP
-.RI Ignore( target ", " dependency )
-The specified dependency file(s)
-will be ignored when deciding if
-the target file(s) need to be rebuilt.
-
-.ES
-env.Ignore('foo', 'foo.c')
-env.Ignore('bar', ['bar1.h', 'bar2.h'])
-.EE
-
-.TP
-.RI Install( dir ", " source )
-Installs one or more files in a destination directory.
-The file names remain the same.
-
-.ES
-env.Install(dir = '/usr/local/bin', source = ['foo', 'bar'])
-.EE
-
-.TP
-.RI InstallAs( target ", " source )
-Installs one or more files as specific file names,
-allowing changing a file name as part of the
-installation.
-It is an error if the target and source
-list different numbers of files.
-
-.ES
-env.InstallAs(target = '/usr/local/bin/foo',
-              source = 'foo_debug')
-env.InstallAs(target = ['../lib/libfoo.a', '../lib/libbar.a'],
-              source = ['libFOO.a', 'libBAR.a'])
-.EE
-
-.TP
-Perforce()
-A factory function that
-returns a Builder object
-to be used to fetch source files
-from the Perforce source code management system.
-The returned Builder
-is intended to be passed to the
-.B SourceCode
-function:
-.ES
-env.SourceCode('.', env.Perforce())
-.EE
-.IP
-Perforce uses a number of external
-environment variables for its operation.
-Consequently, this function adds the
-following variables from the user's external environment
-to the construction environment's
-ENV dictionary:
-P4CHARSET,
-P4CLIENT,
-P4LANGUAGE,
-P4PASSWD,
-P4PORT,
-P4USER,
-SYSTEMROOT,
-USER,
-and
-USERNAME.
-
-.TP
-.RI AlwaysBuild( target ", ...)"
-Marks each given
-.I target
-so that it is always assumed to be out of date,
-and will always be rebuilt if needed.
-Note, however, that
-.BR AlwaysBuild ()
-does not add its target(s) to the default target list,
-so the targets will only be built
-if they are specified on the command line,
-or are a dependent of a target specified on the command line--but
-they will
-.I always
-be built if so specified.
-Multiple targets can be passed in to a single call to
-.BR AlwaysBuild ().
-
-.TP
-.RI Precious( target ", ...)"
-Marks each given
-.I target
-as precious so it is not deleted before it is rebuilt. Normally
-.B scons
-deletes a target before building it.
-Multiple targets can be passed in to a single call to
-.BR Precious ().
-
-.TP
-.RI Prepend( key = val ", [...])"
-Appends the specified keyword arguments
-to the beginning of construction variables in the environment.
-If the Environment does not have
-the specified construction variable,
-it is simply added to the environment.
-If the values of the construction variable
-and the keyword argument are the same type,
-then the two values will be simply added together.
-Otherwise, the construction variable
-and the value of the keyword argument
-are both coerced to lists,
-and the lists are added together.
-(See also the Append method, above.)
-
-.ES
-env.Prepend(CCFLAGS = '-g ', FOO = ['foo.yyy'])
-.EE
-
-.TP
 RCS()
 A factory function that
 returns a Builder object
 is intended to be passed to the
 .B SourceCode
 function:
+
 .ES
 env.SourceCode('.', env.RCS())
 .EE
 is intended to be passed to the
 .B SourceCode
 function:
+
 .ES
 env.SourceCode('.', env.SCCS())
 .EE
 You can avoid these extra searches
 and speed up your build a little
 by disabling these searches as follows:
+
 .ES
 env.SourceCode('.', None)
 .EE
 Builders for various popular
 source code management systems.
 Canonical examples of invocation include:
+
 .ES
 env.SourceCode('.', env.BitKeeper('/usr/local/BKsources'))
 env.SourceCode('src', env.CVS('/usr/local/CVSROOT'))
 are available by default.
 If you initialize this variable when an
 Environment is created:
+
 .ES
 env = Environment(BUILDERS = {'NewBuilder' : foo})
 .EE
 the default Builders will no longer be available.
 To use a new Builder object in addition to the default Builders,
 add your new Builder object like this:
+
 .ES
 env = Environment()
 env.Append(BUILDERS = {'NewBuilder' : foo})
 .EE
 .IP
 or this:
+
 .ES
 env = Environment()
 env['BUILDERS]['NewBuilder'] = foo
 variables CPPPATH, LIBPATH, LIBS, PROGEMITTER, SHLIBEMITTER and LIBEMITTER
 are modified. Because the build-performance is affected when using this tool,
 you have to explicitly specify it at Environment creation:
+
 .ES
 Environment(tools=['default','qt']).
 .EE
 will have copies made in the local tree,
 even if an already up-to-date copy
 exists in a repository.
+Returns a list of the target Node or Nodes.
 
 .TP
 .RI ParseConfig( env ", " command ", [" function ])
 subsidiary SConscript file lives.
 This behavior may be disabled
 by specifying:
+
 .ES
 SConscriptChdir(0)
 .EE
 This allows white space to be enclosed
 in an argument by defining
 a command in a list within a list:
+
 .ES
 Action([['cc', '-c', '-DWHITE SPACE', '-o', '$TARGET', '$SOURCES']])
 .EE
 The actual target and source file name(s) may
 be retrieved from their Node objects
 via the built-in Python str() function:
+
 .ES
 target_file_name = str(target)
 source_file_names = map(lambda x: str(x), source)

File src/CHANGES.txt

   - Support arbitrary expansion of construction variables within
     file and directory arguments to Builder calls and Environment methods.
 
+  - Add Environment-method versions of AddPreAction(), AddPostAction(),
+    Default(), FindFile(), and Local().
+
   From Bram Moolenaar:
 
   - Split the non-SCons-specific functionality from SConf.py to a new,

File src/engine/SCons/Environment.py

     # same-named global functions.
     #######################################################################
 
+    def AddPreAction(self, files, action):
+        nodes = self.arg2nodes(files, self.fs.Entry)
+        action = SCons.Action.Action(action)
+        for n in nodes:
+            n.add_pre_action(action)
+        return nodes
+    
+    def AddPostAction(self, files, action):
+        nodes = self.arg2nodes(files, self.fs.Entry)
+        action = SCons.Action.Action(action)
+        for n in nodes:
+            n.add_post_action(action)
+        return nodes
+
     def AlwaysBuild(self, *targets):
         tlist = []
         for t in targets:
                                     source_factory=SCons.Node.FS.default_fs.Entry)
         return bld(self, target, source)
 
+    def Default(self, *targets):
+        global DefaultTargets
+        if DefaultTargets is None:
+            DefaultTargets = []
+        for t in targets:
+            if t is None:
+                DefaultTargets = []
+            elif isinstance(t, SCons.Node.Node):
+                DefaultTargets.append(t)
+            else:
+                DefaultTargets.extend(self.arg2nodes(t, self.fs.Entry))
+
     def Depends(self, target, dependency):
         """Explicity specify that 'target's depend on 'dependency'."""
         tlist = self.arg2nodes(target, self.fs.File)
             tlist = tlist[0]
         return tlist
 
+    def FindFile(self, file, dirs):
+        file = self.subst(file)
+        nodes = self.arg2nodes(dirs, self.fs.Dir)
+        return SCons.Node.FS.find_file(file, nodes, self.fs.File)
+
     def Ignore(self, target, dependency):
         """Ignore a dependency."""
         tlist = self.arg2nodes(target, self.fs.File)
             ret = ret[0]
         return ret
 
+    def Local(self, *targets):
+        ret = []
+        for targ in targets:
+            if isinstance(targ, SCons.Node.Node):
+                targ.set_local()
+                ret.append(targ)
+            else:
+                for t in self.arg2nodes(targ, self.fs.Entry):
+                   t.set_local()
+                   ret.append(t)
+        return ret
+
     def Precious(self, *targets):
         tlist = []
         for t in targets:

File src/engine/SCons/EnvironmentTests.py

         assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
         assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
 
+    def test_PrependENVPath(self):
+        """Test prepending to an ENV path."""
+        env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+                           MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+        # have to include the pathsep here so that the test will work on UNIX too.
+        env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';') 
+        env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';')
+        env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';')
+        env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';')
+        assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
+        assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
+
     def test_Replace(self):
         """Test replacing construction variables in an Environment
 
 
 
 
+    def test_AddPostAction(self):
+        """Test the AddPostAction() method"""
+        env = Environment(FOO='fff', BAR='bbb')
+
+        n = env.AddPostAction('$FOO', lambda x: x)
+        assert str(n[0]) == 'fff', n[0]
+
+        n = env.AddPostAction(['ggg', '$BAR'], lambda x: x)
+        assert str(n[0]) == 'ggg', n[0]
+        assert str(n[1]) == 'bbb', n[1]
+
+    def test_AddPreAction(self):
+        """Test the AddPreAction() method"""
+        env = Environment(FOO='fff', BAR='bbb')
+
+        n = env.AddPreAction('$FOO', lambda x: x)
+        assert str(n[0]) == 'fff', n[0]
+
+        n = env.AddPreAction(['ggg', '$BAR'], lambda x: x)
+        assert str(n[0]) == 'ggg', n[0]
+        assert str(n[1]) == 'bbb', n[1]
+
     def test_AlwaysBuild(self):
         """Test the AlwaysBuild() method"""
         env = Environment(FOO='fff', BAR='bbb')
         assert 'foo1.in' in map(lambda x: x.path, t.sources)
         assert 'foo2.in' in map(lambda x: x.path, t.sources)
 
+    def test_Default(self):
+        """Test the Default() method"""
+        env = Environment(FOO = 'fff', BAR = 'bbb')
+
+        t = env.Default(None)
+        assert SCons.Environment.DefaultTargets == []
+
+        t = env.Default('xyz')
+        d = map(str, SCons.Environment.DefaultTargets)
+        assert d == ['xyz'], d
+
+        t = env.Default('$FOO')
+        d = map(str, SCons.Environment.DefaultTargets)
+        assert d == ['xyz', 'fff'], d
+
+        t = env.Default(None, '$BAR', 'another_file')
+        d = map(str, SCons.Environment.DefaultTargets)
+        assert d == ['bbb', 'another_file'], d
+
     def test_Depends(self):
 	"""Test the explicit Depends method."""
 	env = Environment(FOO = 'xxx', BAR='yyy')
 	assert d.__class__.__name__ == 'File'
 	assert d.path == 'yyy.py'
 
+    def test_FindFile(self):
+        """Test the FindFile() method"""
+        env = Environment(FOO = 'fff', BAR = 'bbb')
+
+        r = env.FindFile('foo', ['no_such_directory'])
+        assert r is None, r
+
+        # XXX
+
     def test_Ignore(self):
         """Test the explicit Ignore method."""
         env = Environment(FOO='yyy', BAR='zzz')
         assert i.path == 'zzzyyy'
 
     def test_Install(self):
-	"""Test Install and InstallAs methods"""
+	"""Test the Install method"""
         env = Environment(FOO='iii', BAR='jjj')
 
         tgt = env.Install('export', [ 'build/foo1', 'build/foo2' ])
         match = str(e) == "Target `export/foo1' of Install() is a file, but should be a directory.  Perhaps you have the Install() arguments backwards?"
         assert match, e
 
+    def test_InstallAs(self):
+	"""Test the InstallAs method"""
+        env = Environment(FOO='iii', BAR='jjj')
+
         tgt = env.InstallAs(target=string.split('foo1 foo2'),
                             source=string.split('bar1 bar2'))
         assert len(tgt) == 2, len(tgt)
         assert tgt.sources[0].path == 'jjj.s'
         assert tgt.builder == InstallBuilder
 
+    def test_Local(self):
+        """Test the Local() method."""
+        env = Environment(FOO='lll')
+
+        l = env.Local(env.fs.File('fff'))
+        assert str(l[0]) == 'fff', l[0]
+
+        l = env.Local('ggg', '$FOO')
+        assert str(l[0]) == 'ggg', l[0]
+        assert str(l[1]) == 'lll', l[1]
+
     def test_Precious(self):
         """Test the Precious() method."""
         env = Environment(FOO='ggg', BAR='hhh')
         s = e.src_builder()
         assert s is None, s
 
-        
+
 if __name__ == "__main__":
     suite = unittest.makeSuite(EnvironmentTestCase, 'test_')
     if not unittest.TextTestRunner().run(suite).wasSuccessful():

File src/engine/SCons/Script/SConscript.py

 def do_nothing(text): pass
 HelpFunction = do_nothing
 
-default_targets = None
 clean_targets = {}
 arguments = {}
 launch_dir = os.path.abspath(os.curdir)
 # leave this disabled until we find a more efficient mechanism.
 #SCons.Node.Annotate = annotate
 
-def Default(*targets):
-    global default_targets
-    if default_targets is None:
-        default_targets = []
-    for t in targets:
-        if t is None:
-            default_targets = []
-        elif isinstance(t, SCons.Node.Node):
-            default_targets.append(t)
-        else:
-            default_targets.extend(SCons.Node.arg2nodes(t,
-                                         SCons.Node.FS.default_fs.Entry))
-
-def Local(*targets):
-    for targ in targets:
-        if isinstance(targ, SCons.Node.Node):
-            targ.set_local()
-        else:
-            for t in SCons.Node.arg2nodes(targ, SCons.Node.FS.default_fs.Entry):
-               t.set_local()
-
 def Help(text):
     HelpFunction(text)
 
         return ret[0]
     return ret
 
-def FindFile(file, dirs):
-    nodes = SCons.Node.arg2nodes(dirs, SCons.Node.FS.default_fs.Dir)
-    return SCons.Node.FS.find_file(file, nodes)
-
 def Export(*vars):
     for var in vars:
         global_exports.update(compute_exports(var))
     except KeyError:
         clean_targets[target] = nodes
 
-def AddPreAction(files, action):
-    nodes = SCons.Node.arg2nodes(files, SCons.Node.FS.default_fs.Entry)
-    for n in nodes:
-        n.add_pre_action(SCons.Action.Action(action))
-
-def AddPostAction(files, action):
-    nodes = SCons.Node.arg2nodes(files, SCons.Node.FS.default_fs.Entry)
-    for n in nodes:
-        n.add_post_action(SCons.Action.Action(action))
-
 def Exit(value=0):
     sys.exit(value)
 
 
     globals = {}
     globals['Action']            = SCons.Action.Action
-    globals['AddPostAction']     = AddPostAction
-    globals['AddPreAction']      = AddPreAction
     globals['Alias']             = Alias
     globals['ARGUMENTS']         = arguments
     globals['BuildDir']          = BuildDir
     globals['Clean']             = Clean
     globals['Configure']         = SCons.SConf.SConf
     globals['CScan']             = SCons.Defaults.CScan
-    globals['Default']           = Default
     globals['DefaultEnvironment'] = SCons.Defaults.DefaultEnvironment
     globals['Dir']               = SCons.Node.FS.default_fs.Dir
     globals['EnsurePythonVersion'] = EnsurePythonVersion
     globals['Exit']              = Exit
     globals['Export']            = Export
     globals['File']              = SCons.Node.FS.default_fs.File
-    globals['FindFile']          = FindFile
     globals['GetBuildPath']      = GetBuildPath
     globals['GetCommandHandler'] = SCons.Action.GetCommandHandler
     globals['GetJobs']           = GetJobs
     globals['Help']              = Help
     globals['Import']            = Import
     globals['Literal']           = SCons.Util.Literal
-    globals['Local']             = Local
     globals['Options']           = Options
     globals['ParseConfig']       = SCons.Util.ParseConfig
     globals['Platform']          = SCons.Platform.Platform
     globals['Tool']              = SCons.Tool.Tool
     globals['Value']             = SCons.Node.Python.Value
     globals['WhereIs']           = SCons.Util.WhereIs
+
+    class DefaultEnvironmentCall:
+        """ """
+        def __init__(self, method_name):
+            self.method_name = method_name
+        def __call__(self, *args, **kw):
+            method = getattr(SCons.Defaults.DefaultEnvironment(),
+                             self.method_name)
+            return apply(method, args, kw)
+
+    EnvironmentMethods = [
+        'AddPostAction',
+        'AddPreAction',
+        'Default',
+        'FindFile',
+        'Local',
+    ]
+
+    for name in EnvironmentMethods:
+        globals[name] = DefaultEnvironmentCall(name)
+
     return globals

File src/engine/SCons/Script/__init__.py

                         # or not a file, so go ahead and keep it as a default
                         # target and let the engine sort it out:
                         return 1                
-                default_targets = SCons.Script.SConscript.default_targets
+                default_targets = SCons.Environment.DefaultTargets
                 if default_targets is None:
                     default_targets = []
                 else:
                     default_targets = filter(check_dir, default_targets)
-                SCons.Script.SConscript.default_targets = default_targets
+                SCons.Environment.DefaultTargets = default_targets
                 target_top = None
                 lookup_top = None
 
-        targets = SCons.Script.SConscript.default_targets
+        targets = SCons.Environment.DefaultTargets
         if targets is None:
             targets = [SCons.Node.FS.default_fs.Dir('.')]
 

File test/Default.py

 
 
 
-test.subdir('sub1')
+test.subdir('nine', ['nine', 'sub1'])
 
-test.write('SConstruct', """
+test.write(['nine', 'SConstruct'], """\
 B = Builder(action = r'%s build.py $TARGET $SOURCES')
 env = Environment(BUILDERS = { 'B' : B })
 env.B(target = 'xxx.out', source = 'xxx.in')
 SConscript('sub1/SConscript')
 """ % python)
 
-test.write('xxx.in', "xxx.in\n")
+test.write(['nine', 'xxx.in'], "xxx.in\n")
 
-test.write(['sub1', 'SConscript'], """
-B = Builder(action = r'%s build.py $TARGET $SOURCES')
+test.write(['nine', 'sub1', 'SConscript'], """
+B = Builder(action = r'%s ../build.py $TARGET $SOURCES')
 env = Environment(BUILDERS = { 'B' : B })
 env.B(target = 'xxx.out', source = 'xxx.in')
 Default('xxx.out')
 """ % python)
 
-test.write(['sub1', 'xxx.in'], "sub1/xxx.in\n")
+test.write(['nine', 'sub1', 'xxx.in'], "sub1/xxx.in\n")
 
-test.run()	# no arguments, use the Default
+test.run(chdir = 'nine')	# no arguments, use the Default
 
-test.fail_test(os.path.exists(test.workpath('xxx.out')))
-test.fail_test(test.read(test.workpath('sub1', 'xxx.out')) != "sub1/xxx.in\n")
+test.fail_test(os.path.exists(test.workpath('nine', 'xxx.out')))
+test.fail_test(test.read(test.workpath('nine', 'sub1', 'xxx.out')) != "sub1/xxx.in\n")
 
 
 
-test.subdir('sub2')
+test.subdir('ten', ['ten', 'sub2'])
 
-test.write('SConstruct', """
+test.write(['ten', 'SConstruct'], """\
 Default('sub2')
-B = Builder(action = r'%s build.py $TARGET $SOURCES')
+B = Builder(action = r'%s ../build.py $TARGET $SOURCES')
 env = Environment(BUILDERS = { 'B' : B })
 env.B(target = 'xxx.out', source = 'xxx.in')
 SConscript('sub2/SConscript')
 """ % python)
 
-test.write('xxx.in', "xxx.in\n")
+test.write(['ten', 'xxx.in'], "xxx.in\n")
 
-test.write(['sub2', 'SConscript'], """
-B = Builder(action = r'%s build.py $TARGET $SOURCES')
+test.write(['ten', 'sub2', 'SConscript'], """
+B = Builder(action = r'%s ../build.py $TARGET $SOURCES')
 env = Environment(BUILDERS = { 'B' : B })
 env.B(target = 'xxx.out', source = 'xxx.in')
 """ % python)
 
-test.write(['sub2', 'xxx.in'], "sub2/xxx.in\n")
+test.write(['ten', 'sub2', 'xxx.in'], "sub2/xxx.in\n")
 
-test.run()	# no arguments, use the Default
+test.run(chdir = 'ten')	# no arguments, use the Default
 
-test.fail_test(os.path.exists(test.workpath('xxx.out')))
-test.fail_test(test.read(test.workpath('sub2', 'xxx.out')) != "sub2/xxx.in\n")
+test.fail_test(os.path.exists(test.workpath('ten', 'xxx.out')))
+test.fail_test(test.read(test.workpath('ten', 'sub2', 'xxx.out')) != "sub2/xxx.in\n")
+
+
+test.subdir('eleven')
+
+test.write(['eleven', 'SConstruct'], """
+B = Builder(action = r'%s ../build.py $TARGET $SOURCES')
+env = Environment(BUILDERS = { 'B' : B }, XXX = 'foo.out')
+env.B(target = 'foo.out', source = 'foo.in')
+env.B(target = 'bar.out', source = 'bar.in')
+env.Default('$XXX')
+""" % python)
+
+test.write(os.path.join('eleven', 'foo.in'), "eleven/foo.in\n");
+
+test.write(os.path.join('eleven', 'bar.in'), "eleven/bar.in\n");
+
+test.run(chdir = 'eleven')	# no arguments, use the Default
+
+test.fail_test(test.read(test.workpath('eleven', 'foo.out')) != "eleven/foo.in\n")
+test.fail_test(os.path.exists(test.workpath('eleven', 'bar')))
 
 
 

File test/FindFile.py

 test.write(['bar', 'baz', 'testfile2'], 'test 4\n')
 
 test.write('SConstruct', """
+env = Environment(FILE = 'file', BAR = 'bar')
 file1 = FindFile('testfile1', [ 'foo', '.', 'bar', 'bar/baz' ])
 print open(str(file1), 'r').read()
-file2 = FindFile('testfile1', [ 'bar', 'foo', '.', 'bar/baz' ])
+file2 = env.FindFile('test${FILE}1', [ 'bar', 'foo', '.', 'bar/baz' ])
 print open(str(file2), 'r').read()
 file3 = FindFile('testfile2', [ 'foo', '.', 'bar', 'bar/baz' ])
 print open(str(file3), 'r').read()
-file4 = FindFile('testfile2', [ 'bar/baz', 'foo', '.', 'bar' ])
+file4 = env.FindFile('testfile2', [ '$BAR/baz', 'foo', '.', 'bar' ])
 print open(str(file4), 'r').read()
 """)
 

File test/Repository/Local.py

     open(target, "wb").write(open(source, "rb").read())
 
 Build = Builder(action=copy)
-env = Environment(BUILDERS={'Build':Build})
+env = Environment(BUILDERS={'Build':Build}, BBB='bbb')
 env.Build('aaa.mid', 'aaa.in')
 env.Build('aaa.out', 'aaa.mid')
 Local('aaa.out')
 
 Import("env")
 env.Build('bbb.1', 'bbb.0')
-Local('bbb.1')
+env.Local('${BBB}.1')
 env.Command('bbb.2', 'bbb.x', bbb_copy)
 env.Depends('bbb.2', 'bbb.1')
 """)

File test/pre-post-actions.py

 
 test = TestSCons.TestSCons()
 
-test.write('foo.c', r"""
-#include <stdio.h>
-
-int main(void)
-{
-    printf("Foo\n");
-    return 0;
-}
-""")
-
 test.write('SConstruct', """
 import os.path
 
-env=Environment()
+env = Environment(XXX='bar%s')
 
 def before(env, target, source):
     f=open(str(target[0]), "wb")
     f.write("Foo\\n")
     f.close()
-    f=open("before.txt", "wb")
-    f.write("Bar\\n")
+    f=open("before.txt", "ab")
+    f.write(str(target[0]) + "\\n")
     f.close()
 
 def after(env, target, source):
     fin = open(str(target[0]), "rb")
-    fout = open("after%s", "wb")
+    fout = open("after_" + str(target[0]), "wb")
     fout.write(fin.read())
     fout.close()
     fin.close()
 foo = env.Program(source='foo.c', target='foo')
 AddPreAction(foo, before)
 AddPostAction('foo%s', after)
+
+bar = env.Program(source='bar.c', target='bar')
+env.AddPreAction('$XXX', before)
+env.AddPostAction('$XXX', after)
 """ % (_exe, _exe))
 
-after_exe = test.workpath('after' + _exe)
+test.write('foo.c', r"""
+#include <stdio.h>
+
+int main(void)
+{
+    printf("foo.c\n");
+    return 0;
+}
+""")
+
+test.write('bar.c', r"""
+#include <stdio.h>
+
+int main(void)
+{
+    printf("bar.c\n");
+    return 0;
+}
+""")
+
 
 test.run(arguments='.')
-test.fail_test(open('before.txt', 'rb').read() != "Bar\n")
-os.chmod(after_exe, os.stat(after_exe)[stat.ST_MODE] | stat.S_IXUSR)
-test.run(program=test.workpath(after_exe), stdout="Foo\n")
+
+test.run(program=test.workpath('foo'+ _exe), stdout="foo.c\n")
+test.run(program=test.workpath('bar'+ _exe), stdout="bar.c\n")
+
+test.fail_test(test.read('before.txt', 'rb') != "bar%s\nfoo%s\n" % (_exe, _exe))
+
+after_foo_exe = test.workpath('after_foo' + _exe)
+os.chmod(after_foo_exe, os.stat(after_foo_exe)[stat.ST_MODE] | stat.S_IXUSR)
+test.run(program=test.workpath(after_foo_exe), stdout="foo.c\n")
+
+after_bar_exe = test.workpath('after_bar' + _exe)
+os.chmod(after_bar_exe, os.stat(after_bar_exe)[stat.ST_MODE] | stat.S_IXUSR)
+test.run(program=test.workpath(after_bar_exe), stdout="bar.c\n")
+
 test.pass_test()