Add duplicate (defaults to true) option to BuildDir()
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 29 Dec 2001 08:04:42 +0000 (08:04 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 29 Dec 2001 08:04:42 +0000 (08:04 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@178 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
etc/TestCmd.py
src/CHANGES.txt
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Script/SConscript.py
src/engine/SCons/Util.py
src/engine/SCons/UtilTests.py
test/BuildDir.py
test/CPPPATH.py
test/SConscript.py

index 100710fc44428194b56bf1f351182c927c626235..38b196d057a891cfd6c5e641c971923c36c0c43c 100644 (file)
@@ -78,23 +78,29 @@ is normally executed in a top-level directory containing a
 file, specifying the target or targets to be built as
 command-line arguments.  The command
 
-.RS
+.IP
+.nf
 scons .
-.RE
+.PP
+.fi
 
 will build all target files in or below the current directory 
 .RI ( . ")."
 
-.RS
+.IP
+.nf
 scons /
-.RE
+.PP
+.fi
 
 will build all target files in or below the root directory (i.e.,
 all files).  Specific targets may be supplied:
 
-.RS
+.IP
+.nf
 scons foo bar
-.RE
+.PP
+.fi
 
 Targets may be omitted from the command line,
 in which case the targets specified
@@ -102,9 +108,11 @@ in the configuration file(s) as
 .B Default
 targets will be built:
 
-.RS
+.IP
+.nf
 scons
-.RE
+.PP
+.fi
 
 Specifying "cleanup" targets in configuration files is not
 necessary.  The 
@@ -112,12 +120,16 @@ necessary.  The
 flag removes all files
 necessary to build the specified target:
 .IP
+.nf
 scons -c .
 .PP
+.fi
 to remove all target files, or:
 .IP
+.nf
 scons -c build export
 .PP
+.fi
 to remove target files under build and export.
 
 A subset of a hierarchical tree may be built by
@@ -126,9 +138,11 @@ remaining at the top-level directory (where the
 file lives) and specifying the subdirectory as the target to be
 built:
 
-.RS
+.IP
+.nf
 scons src/subdir
-.RE
+.PP
+.fi
 
 .\" or changing directory and invoking scons with the
 .\" .B -u
@@ -151,18 +165,22 @@ supports building multiple targets in parallel via a
 option that takes, as its argument, the number
 of simultaneous tasks that may be spawned:
 
-.RS
+.IP
+.nf
 scons -j 4
-.RE
+.PP
+.fi
 
 builds four targets in parallel, for example.
 
 .\" Values of variables to be passed to the configuration file(s)
 .\" may be specified on the command line:
 .\" 
-.\" .RS
+.\" .IP
+.\" .nf
 .\" scons debug=1 .
-.\" .RE
+.\" .PP
+.\" .fi
 .\" 
 .\" These variables can be used in the configuration file(s) to modify
 .\" the build in any way.
@@ -375,9 +393,11 @@ any out-of-date target files, but do not execute the commands.
 .\" option.
 .\"
 .\" To print the database without performing a build do:
-.\" .RS
+.\" .IP
+.\" .nf
 .\" scons -p -q
-.\" .RE
+.\" .PP
+.\" .fi
 .\"
 .\" .IP "-q, --question"
 .\" Do not run any commands, or print anything.  Just return an exit
@@ -469,9 +489,11 @@ A new construction environment is created using the
 .B Environment 
 function:
 
-.RS 
+.IP
+.nf 
 env = Environment()
-.RE
+.PP
+.fi
 
 Build rules are specified by calling builder methods on a construction
 environment. The arguments to the builder methods are target (a list of
@@ -481,15 +503,13 @@ for target or source, then
 interprets it as a space delimited list
 of files. The following are examples of calling a builder:
 
-.RS
+.IP
+.nf
 env.Program(target = 'bar', source = 'bar.c foo.c')
-.RE
-.RS
 env.Program('bar', 'bar.c foo.c')
-.RE
-.RS
 env.Program('bar', ['bar.c', 'foo.c'])
-.RE
+.PP
+.fi
 
 .B scons
 provides the following builders:
@@ -498,30 +518,33 @@ Builds an object file from one or more C/C++ source files. Source files
 must have one of the following extensions: .c, .C, .cc, .cpp, .cxx, .c++, .C++. 
 The target object file prefix and suffix (if any) are automatically
 added. Example:
-
-.RS
+.IP
+.nf
 env.Object(target = 'bar', source = 'bar.c')
-.RE
+.PP
+.fi
 
 .IP Program
 Builds an executable given one or more object files or C/C++ source
 files. If any C/C++ source files are given, then they will be automatically
 compiled to object files. The executable prefix and suffix (if any) are
 automatically added to the target. Example:
-
-.RS
+.IP
+.nf
 env.Program(target = 'bar', source = 'bar.c foo.o')
-.RE
+.PP
+.fi
 
 .IP Library
 Builds a library given one or more object files or C/C++ source
 files. If any C/C++ source files are given, then they will be automatically
 compiled to object files. The library prefix and suffix (if any) are
 automatically added to the target. Example:
-
-.RS
+.IP
+.nf
 env.Library(target = 'bar', source = 'bar.c foo.o')
-.RE
+.PP
+.fi
 
 .LP
 
@@ -533,9 +556,11 @@ be specified using the
 .B Depends 
 method of a construction environment:
 
-.RS
+.IP
+.nf
 env.Depends('foo.c', 'foo.h')
-.RE
+.PP
+.fi
 
 When
 .B scons
@@ -544,18 +569,22 @@ line. Default targets can be specified using the
 .B Default 
 function:
 
-.RS
+.IP
+.nf
 Default('foo', 'bar', 'baz')
-.RE
+.PP
+.fi
 
 A configuration file can specify other configuration files to execute using
 the 
 .B SConscript 
 function:
 
-.RS
+.IP
+.nf
 SConscript('dir/SConscript')
-.RE
+.PP
+.fi
 
 A construction environment has an associated dictionary of construction
 variables that are used by built-in or user-supplied build rules. A number
@@ -587,7 +616,28 @@ The list of directories that the C preprocessor will search for include
 directories. The C/C++ implicit dependency scanner will search these
 directories for include files. Don't explicitly put include directory
 arguments in CCFLAGS or CXXFLAGS because the result will be non-portable
-and the directories will not be searched by the depedency scanner.
+and the directories will not be searched by the depedency scanner. Note:
+directory names in CPPPATH will be looked-up relative to the SConscript
+directory when they are used in a command. To force 
+.B scons
+to look-up a directory relative to the root of the source tree use #:
+.IP
+.nf
+env.Environment(CPPPATH='#/include')
+.PP
+.fi
+.RS
+The directory look-up can also be forced using the 
+.BR Dir ()
+function:
+.RE
+.IP
+.nf
+include = Dir('include')
+env.Environment(CPPPATH=include)
+.PP
+.fi
+.RE
 
 .IP LINK
 The linker.
@@ -660,27 +710,31 @@ Construction variables can be retrieved and set using the
 .B Dictionary 
 method of the construction environment:
 
-.RS
+.IP
+.nf
 dict = env.Dictionary()
-.RE
-.RS
 dict["CC"] = "cc"
-.RE
+.PP
+.fi
 
 Construction variables can also be passed to the construction environment
 constructor:
 
-.RS
+.IP
+.nf
 env = Environment(CC="cc")
-.RE
+.PP
+.fi
 
 or when copying a construction environment using the 
 .B Copy 
 method:
 
-.RS
+.IP
+.nf
 env2 = env.Copy(CC="cl.exe")
-.RE
+.PP
+.fi
 
 .B scons
 also provides various function not associated with a construction
@@ -708,9 +762,11 @@ will be returned by the call to
 .BR SConscript (). 
 Example:
 
-.RS
+.IP
+.nf
 foo = SConscript('subdir/SConscript', "env")
-.RE
+.PP
+.fi
 
 .TP
 .RI Export( vars )
@@ -724,9 +780,11 @@ Multiple variable names can be passed to
 .BR Export ()
 in a space delimited string or as seperate arguments. Example:
 
-.RS
+.IP
+.nf
 Export("env")
-.RE
+.PP
+.fi
 
 .TP 
 .RI Import( vars )
@@ -745,9 +803,11 @@ have precedence. Multiple variable names can be passed to
 .BR Import ()
 in a space delimited string or as seperate arguments. Example:
 
-.RS
+.IP
+.nf
 Import("env")
-.RE
+.PP
+.fi
 
 .TP
 .RI Return( vars )
@@ -761,9 +821,11 @@ Multiple variable names can be passed to
 .BR Return ()
 in a space delimited string or as seperate arguments. Example:
 
-.RS
+.IP
+.nf
 Return("foo")
-.RE
+.PP
+.fi
 
 .TP 
 .RI Default( targets )
@@ -786,7 +848,7 @@ argument is given to
 will exit after printing out the help text.
 
 .TP
-.RI BuildDir( build_dir ", " src_dir )
+.RI BuildDir( build_dir ", " src_dir ", [" duplicate ])
 This specifies a build directory to use for all derived files.  
 .I build_dir
 specifies the build directory to be used for all derived files that would
@@ -796,12 +858,38 @@ Multiple build directories can be set up for multiple build variants, for
 example. 
 .B scons
 will link or copy (depending on the platform) all the source files into the
-build directory, so the build commands will not be modifed if 
-.BR BuildDir ()
-is used.
+build directory if 
+.I duplicate
+is set to 1 (the default). If 
+.I duplicate
+is set to 0, then 
+.B scons 
+will not copy or link any source files, which may cause build problems in
+certain situations (e.g. C source files that are generated by the
+build). 
+.IR duplicate =0
+is usually safe, and is always more efficient than 
+.IR duplicate =1.
 
+.TP
+.RI Dir( name ", [" directory ])
+This returns an object that represents a given directory 
+.IR name . 
+.I name
+can be a relative or absolute path. 
+.I directory
+is an optional directory that will be used as the parent directory. 
 
 
+.TP 
+.RI File( name ", [" directory ])
+This returns an object that represents a given file 
+.IR name . 
+.I name
+can be a relative or absolute path. 
+.I directory
+is an optional directory that will be used as the parent directory. 
+
 
 .SH EXTENDING
 .B scons
@@ -860,15 +948,19 @@ The file names of the sources of the build command.
 For example, given the construction variable CC='cc', targets=['foo'], and
 sources=['foo.c', 'bar.c']:
 
-.RS
+.IP
+.nf
 action='$CC -c -o $TARGET $SOURCES'
-.RE
+.PP
+.fi
 
 would produce the command line:
 
-.RS
+.IP
+.nf
 cc -c -o foo foo.c bar.c
-.RE
+.PP
+.fi
 
 .\" XXX document how to add user defined scanners. 
 
index d09d35d3cc7e652af5f9ffea515dbed341b0ab70..8df039e1eea181489a453c3b7aedec3316bf102a 100644 (file)
@@ -564,8 +564,11 @@ class TestCmd:
            f = _mode_writable
        else:
            f = _mode_non_writable
-       os.path.walk(top, _walk_chmod, f)
-
+       try:
+           os.path.walk(top, _walk_chmod, f)
+       except:
+           pass # ignore any problems changing modes
+           
     def write(self, file, content, mode = 'wb'):
        """Writes the specified content text (second argument) to the
        specified file name (first argument).  The file name may be
index 52671cba326ab609fd2127c276cd935664810ac8..c84d0cb4dbd9e2dabab412fff2c09377e5feb008 100644 (file)
@@ -15,6 +15,11 @@ RELEASE 0.03 -
   - Search both /usr/lib and /usr/local/lib for scons directories by
     adding them both to sys.path, with whichever is in sys.prefix first.
 
+  From Anthony Roach:
+
+  - Add a "duplicate" keyword argument to BuildDir() that can be set
+    to prevent linking/copying source files into build directories.
+
 
 
 RELEASE 0.02 - Sun, 23 Dec 2001 19:05:09 -0600
index adfd4401b4169595a0917acc85633c1e132694b7..98b6b02b0bec936e443da57a857ce9bad7e2373e 100644 (file)
@@ -279,18 +279,20 @@ class FS:
         name, directory = self.__transformPath(name, directory)
         return self.__doLookup(Dir, name, directory)
 
-    def BuildDir(self, build_dir, src_dir):
+    def BuildDir(self, build_dir, src_dir, duplicate=1):
         """Link the supplied build directory to the source directory
         for purposes of building files."""
         self.__setTopLevelDir()
-        dirSrc = self.Dir(src_dir)
-        dirBuild = self.Dir(build_dir)
-        if not dirSrc.is_under(self.Top) or not dirBuild.is_under(self.Top):
+        if not isinstance(src_dir, SCons.Node.Node):
+            src_dir = self.Dir(src_dir)
+        if not isinstance(build_dir, SCons.Node.Node):
+            build_dir = self.Dir(build_dir)
+        build_dir.duplicate = duplicate
+        if not src_dir.is_under(self.Top) or not build_dir.is_under(self.Top):
             raise UserError, "Both source and build directories must be under top of build tree."
-        if dirSrc.is_under(dirBuild):
+        if src_dir.is_under(build_dir):
             raise UserError, "Source directory cannot be under build directory."
-        dirBuild.link(dirSrc)
-        
+        build_dir.link(src_dir, duplicate)
 
 class Entry(SCons.Node.Node):
     """A generic class for file system entries.  This class if for
@@ -309,6 +311,7 @@ class Entry(SCons.Node.Node):
 
         self.name = name
         if directory:
+            self.duplicate = directory.duplicate
             self.abspath = os.path.join(directory.abspath, name)
             if str(directory.path) == '.':
                 self.path = name
@@ -316,16 +319,18 @@ class Entry(SCons.Node.Node):
                 self.path = os.path.join(directory.path, name)
         else:
             self.abspath = self.path = name
+            self.duplicate = 1
         self.path_ = self.path
         self.abspath_ = self.abspath
         self.dir = directory
        self.use_signature = 1
-        self.__doSrcpath()
+        self.__doSrcpath(self.duplicate)
 
-    def adjust_srcpath(self):
-        self.__doSrcpath()
+    def adjust_srcpath(self, duplicate):
+        self.__doSrcpath(duplicate)
         
-    def __doSrcpath(self):
+    def __doSrcpath(self, duplicate):
+        self.duplicate = duplicate
         if self.dir:
             if str(self.dir.srcpath) == '.':
                 self.srcpath = self.name
@@ -336,7 +341,10 @@ class Entry(SCons.Node.Node):
 
     def __str__(self):
        """A FS node's string representation is its path name."""
-       return self.path
+        if self.duplicate or self.builder:
+            return self.path
+        else:
+            return self.srcpath
 
     def __cmp__(self, other):
        if type(self) != types.StringType and type(other) != types.StringType:
@@ -351,7 +359,7 @@ class Entry(SCons.Node.Node):
        return hash(self.abspath_)
 
     def exists(self):
-        return os.path.exists(self.abspath)
+        return os.path.exists(str(self))
 
     def current(self):
         """If the underlying path doesn't exist, we know the node is
@@ -411,20 +419,20 @@ class Dir(Entry):
         self.builder = 1
         self._sconsign = None
 
-    def __doReparent(self):
+    def __doReparent(self, duplicate):
         for ent in self.entries.values():
             if not ent is self and not ent is self.dir:
-                ent.adjust_srcpath()
+                ent.adjust_srcpath(duplicate)
 
-    def adjust_srcpath(self):
-        Entry.adjust_srcpath(self)
-        self.__doReparent()
+    def adjust_srcpath(self, duplicate):
+        Entry.adjust_srcpath(self, duplicate)
+        self.__doReparent(duplicate)
                 
-    def link(self, srcdir):
+    def link(self, srcdir, duplicate):
         """Set this directory as the build directory for the
         supplied source directory."""
         self.srcpath = srcdir.path
-        self.__doReparent()
+        self.__doReparent(duplicate)
 
     def up(self):
         return self.entries['..']
@@ -526,7 +534,7 @@ class File(Entry):
 
     def get_timestamp(self):
         if self.exists():
-            return os.path.getmtime(self.path)
+            return os.path.getmtime(str(self))
         else:
             return 0
 
@@ -556,12 +564,12 @@ class File(Entry):
         if self.env:
             for scn in self.scanners:
                 if not self.scanned.has_key(scn):
-                    self.add_implicit(scn.scan(self.path, self.env),
-                                      scn)
+                    deps = scn.scan(str(self), self.env)
+                    self.add_implicit(deps,scn)
                     self.scanned[scn] = 1
                     
     def exists(self):
-        if not self.created:
+        if self.duplicate and not self.created:
             self.created = 1
             if self.srcpath != self.path and \
                os.path.exists(self.srcpath):
index f2130d78ab1e76d74b718fa067cdeb0ae0a31d9a..4801daef70600d16fe6067aa0b10b6b2d01bee5e 100644 (file)
@@ -86,6 +86,20 @@ class BuildDirTestCase(unittest.TestCase):
         assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath
         assert f2.srcpath == os.path.normpath('src/test1'), f2.srcpath
 
+        fs = SCons.Node.FS.FS()
+        fs.BuildDir('build/var1', 'src', duplicate=0)
+        fs.BuildDir('build/var2', 'src')
+        f1 = fs.File('build/var1/test1')
+        f1out = fs.File('build/var1/test1.out')
+        f1out.builder = 1
+        f2 = fs.File('build/var2/test1')
+        assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath
+        assert f1out.srcpath == os.path.normpath('src/test1.out'), f1out.srcpath
+        assert str(f1) == os.path.normpath('src/test1'), str(f1)
+        assert str(f1out) == os.path.normpath('build/var1/test1.out'), str(f1out)
+        assert f2.srcpath == os.path.normpath('src/test1'), str(f2)
+        assert str(f2) == os.path.normpath('build/var2/test1'), str(f2)
+
         # Test to see if file_link() works...
         test=TestCmd(workdir='')
         test.subdir('src','build')
index 924fd29bd6119ae7fc19f4eeab61519f5187e948..7085547c9a114693d2b8be08f0e283af74fdb3a0 100644 (file)
@@ -89,22 +89,23 @@ def SConscript(script, exports=[]):
     # push:
     stack.append(Frame(exports))
 
-    # call:
-    if script == "-":
-        exec sys.stdin in stack[-1].globals
-    else:
-        f = SCons.Node.FS.default_fs.File(script)
-        if f.exists():
-            file = open(str(f), "r")
-            SCons.Node.FS.default_fs.chdir(f.dir)
-            exec file in stack[-1].globals
+    try:
+        # call:
+        if script == "-":
+            exec sys.stdin in stack[-1].globals
         else:
-            sys.stderr.write("Ignoring missing SConscript '%s'\n" % f.path)
-    
-
-    # pop:
-    frame = stack.pop()
-    SCons.Node.FS.default_fs.chdir(frame.prev_dir)
+            if not isinstance(script, SCons.Node.Node):
+                script = SCons.Node.FS.default_fs.File(script)
+            if script.exists():
+                file = open(str(script), "r")
+                SCons.Node.FS.default_fs.chdir(script.dir)
+                exec file in stack[-1].globals
+            else:
+                sys.stderr.write("Ignoring missing SConscript '%s'\n" % script.path)
+    finally:
+        # pop:
+        frame = stack.pop()
+        SCons.Node.FS.default_fs.chdir(frame.prev_dir)
     
     return frame.retval
     
@@ -122,8 +123,8 @@ def Help(text):
         print "Use scons -H for help about command-line options."
         sys.exit(0)
 
-def BuildDir(build_dir, src_dir):
-    SCons.Node.FS.default_fs.BuildDir(build_dir, src_dir)
+def BuildDir(build_dir, src_dir, duplicate=1):
+    SCons.Node.FS.default_fs.BuildDir(build_dir, src_dir, duplicate)
 
 def GetBuildPath(files):
     nodes = SCons.Util.scons_str2nodes(files,
@@ -173,4 +174,6 @@ def BuildDefaultGlobals():
     globals['Export'] = Export
     globals['Import'] = Import
     globals['Return'] = Return
+    globals['Dir'] = SCons.Node.FS.default_fs.Dir
+    globals['File'] = SCons.Node.FS.default_fs.File
     return globals
index 0d054987927b3fe624edafd57607daffd99e4b0f..262762e203acf4b7efbabdd255f40640272f7a67 100644 (file)
@@ -37,6 +37,7 @@ import re
 from UserList import UserList
 import SCons.Node.FS
 import copy
+import SCons.Node
 
 def scons_str2nodes(arg, node_factory=SCons.Node.FS.default_fs.File):
     """This function converts a string or list into a list of Node instances.
@@ -199,7 +200,7 @@ def scons_subst_list(strSubst, locals, globals):
     n = 1
 
     # Tokenize the original string...
-    strSubst = _space_sep.sub('\0', strSubst)
+    strSubst = _space_sep.sub('\0', str(strSubst))
     
     # Now, do the substitution
     while n != 0:
@@ -266,7 +267,14 @@ class VarInterpolator:
         src = dict[self.src]
         if not type(src) is types.ListType and not isinstance(src, UserList):
             src = [ src ]
-        return map(lambda x, d=dict: scons_subst(x, {}, d), src)
+
+        def prepare(x, dict=dict):
+            if isinstance(x, SCons.Node.Node):
+                return x
+            else:
+                return scons_subst(x, {}, dict)
+
+        return map(prepare, src)
 
     def generate(self, dict):
         if not dict.has_key(self.src):
@@ -300,9 +308,14 @@ class DirVarInterp(VarInterpolator):
         
     def prepareSrc(self, dict):
         src = VarInterpolator.prepareSrc(self, dict)
-        return map(lambda x, fs=self.fs, d=self.dir: \
-                   fs.Dir(str(x), directory = d).path,
-                   src)
+       
+       def prepare(x, self=self):
+           if not isinstance(x, SCons.Node.Node):
+               return self.fs.Dir(str(x), directory=self.dir)
+           else:
+               return x
+           
+        return map(prepare, src)
 
     def instance(self, dir, fs):
         try:
index 9eebc85b0c0a59ca1992744b4ca20108ee6c2260..a7c9e7004b3b97dc0a1848f45d1b85b2e7055ce7 100644 (file)
@@ -165,9 +165,10 @@ class UtilTestCase(unittest.TestCase):
         test = TestCmd.TestCmd(workdir = '')
         test.write('./foo', 'Some file\n')
         fs = SCons.Node.FS.FS(test.workpath(""))
+        os.chdir(test.workpath("")) # FS doesn't like the cwd to be something other than it's root
         node_derived = fs.File(test.workpath('./bar/baz'))
         node_derived.builder_set(1) # Any non-zero value.
-        paths = map(lambda x, fs=fs: fs.Dir(x), ['.', './bar'])
+        paths = map(fs.Dir, ['.', './bar'])
         nodes = find_files(['foo', 'baz'], paths, fs.File)
         file_names = map(str, nodes)
         file_names = map(os.path.normpath, file_names)
@@ -188,12 +189,13 @@ class UtilTestCase(unittest.TestCase):
         assert dict['_LIBFLAGS'][2] == 'foobazbar', \
                dict['_LIBFLAGS'][2]
 
-        dict = {'CPPPATH'   : [ 'foo', 'bar', 'baz', '$FOO/bar' ],
+        blat = SCons.Node.FS.default_fs.File('blat')
+        dict = {'CPPPATH'   : [ 'foo', 'bar', 'baz', '$FOO/bar', blat],
                 'INCPREFIX' : 'foo',
                 'INCSUFFIX' : 'bar',
                 'FOO'       : 'baz' }
         autogenerate(dict, dir = SCons.Node.FS.default_fs.Dir('/xx'))
-        assert len(dict['_INCFLAGS']) == 4, dict['_INCFLAGS']
+        assert len(dict['_INCFLAGS']) == 5, dict['_INCFLAGS']
         assert dict['_INCFLAGS'][0] == os.path.normpath('foo/xx/foobar'), \
                dict['_INCFLAGS'][0]
         assert dict['_INCFLAGS'][1] == os.path.normpath('foo/xx/barbar'), \
@@ -203,6 +205,8 @@ class UtilTestCase(unittest.TestCase):
         assert dict['_INCFLAGS'][3] == os.path.normpath('foo/xx/baz/barbar'), \
                dict['_INCFLAGS'][3]
         
+        assert dict['_INCFLAGS'][4] == os.path.normpath('fooblatbar'), \
+               dict['_INCFLAGS'][4]
         
 if __name__ == "__main__":
     suite = unittest.makeSuite(UtilTestCase, 'test_')
index 8f7c149d4e9924760795da6d18a908bdd67843a1..ef11760e377081b1ffd2049ef96897207bc5385d 100644 (file)
@@ -36,17 +36,29 @@ else:
 
 test = TestSCons.TestSCons()
 
-foo1 = test.workpath('build/var1/foo1' + _exe)
-foo2 = test.workpath('build/var1/foo2' + _exe)
-foo3 = test.workpath('build/var2/foo1' + _exe)
-foo4 = test.workpath('build/var2/foo2' + _exe)
+foo11 = test.workpath('build', 'var1', 'foo1' + _exe)
+foo12 = test.workpath('build', 'var1', 'foo2' + _exe)
+foo21 = test.workpath('build', 'var2', 'foo1' + _exe)
+foo22 = test.workpath('build', 'var2', 'foo2' + _exe)
+foo31 = test.workpath('build', 'var3', 'foo1' + _exe)
+foo32 = test.workpath('build', 'var3', 'foo2' + _exe)
 
 test.write('SConstruct', """
-BuildDir('build/var1', 'src')
-BuildDir('build/var2', 'src')
-SConscript('build/var1/SConscript')
-SConscript('build/var2/SConscript')
-""")
+src = Dir('src')
+var2 = Dir('build/var2')
+var3 = Dir('build/var3')
+
+BuildDir('build/var1', src)
+BuildDir(var2, src)
+BuildDir(var3, src, duplicate=0)
+
+env = Environment()
+SConscript('build/var1/SConscript', "env")
+SConscript('build/var2/SConscript', "env")
+
+env = Environment(CPPPATH=src)
+SConscript('build/var3/SConscript', "env")
+""") 
 
 test.subdir('src')
 test.write('src/SConscript', """
@@ -62,8 +74,7 @@ def buildIt(target, source, env):
     f2.close()
     f1.close()
     return 0
-
-env = Environment()
+Import("env")
 env.Command(target='f2.c', source='f2.in', action=buildIt)
 env.Program(target='foo2', source='f2.c')
 env.Program(target='foo1', source='f1.c')
@@ -103,9 +114,15 @@ test.write('src/f2.h', r"""
 
 test.run(arguments = '.')
 
-test.run(program = foo1, stdout = "f1.c\n")
-test.run(program = foo2, stdout = "f2.c\n")
-test.run(program = foo3, stdout = "f1.c\n")
-test.run(program = foo4, stdout = "f2.c\n")
+test.run(program = foo11, stdout = "f1.c\n")
+test.run(program = foo12, stdout = "f2.c\n")
+test.run(program = foo21, stdout = "f1.c\n")
+test.run(program = foo22, stdout = "f2.c\n")
+test.run(program = foo31, stdout = "f1.c\n")
+test.run(program = foo32, stdout = "f2.c\n")
+
+# Make sure we didn't duplicate the source files in build/var3.
+test.fail_test(os.path.exists(test.workpath('build', 'var3', 'f1.c')))
+test.fail_test(os.path.exists(test.workpath('build', 'var3', 'f2.in')))
 
 test.pass_test()
index fb21426efbf442e400d4113c466c469a03113bb4..af7bdd88f90970f59dca3cbb76c3567c02e8ede4 100644 (file)
@@ -35,8 +35,9 @@ else:
 
 prog = 'prog' + _exe
 subdir_prog = os.path.join('subdir', 'prog' + _exe)
+variant_prog = os.path.join('variant', 'prog' + _exe)
 
-args = prog + ' ' + subdir_prog
+args = prog + ' ' + subdir_prog + ' ' + variant_prog
 
 test = TestSCons.TestSCons()
 
@@ -47,6 +48,11 @@ env = Environment(CPPPATH = ['include'])
 obj = env.Object(target='prog', source='subdir/prog.c')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
+
+BuildDir('variant', 'subdir', 0)
+include = Dir('include')
+env = Environment(CPPPATH=[include])
+SConscript('variant/SConscript', "env")
 """)
 
 test.write(['subdir', 'SConscript'], """
@@ -93,7 +99,7 @@ r"""
 
 
 
-test.run(arguments = args, stderr = None)
+test.run(arguments = args)
 
 test.run(program = test.workpath(prog),
          stdout = "subdir/prog.c\ninclude/foo.h 1\ninclude/bar.h 1\n")
@@ -101,9 +107,13 @@ test.run(program = test.workpath(prog),
 test.run(program = test.workpath(subdir_prog),
          stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")
 
-test.up_to_date(arguments = args)
+test.run(program = test.workpath(variant_prog),
+         stdout = "subdir/prog.c\ninclude/foo.h 1\ninclude/bar.h 1\n")
 
+# Make sure we didn't duplicate the source file in the variant subdirectory.
+test.fail_test(os.path.exists(test.workpath('variant', 'prog.c')))
 
+test.up_to_date(arguments = args)
 
 test.unlink('include/foo.h')
 test.write('include/foo.h',
@@ -120,8 +130,13 @@ test.run(program = test.workpath(prog),
 test.run(program = test.workpath(subdir_prog),
          stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")
 
-test.up_to_date(arguments = args)
+test.run(program = test.workpath(variant_prog),
+         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 1\n")
 
+# Make sure we didn't duplicate the source file in the variant subdirectory.
+test.fail_test(os.path.exists(test.workpath('variant', 'prog.c')))
+
+test.up_to_date(arguments = args)
 
 
 test.unlink('include/bar.h')
@@ -130,7 +145,7 @@ r"""
 #define BAR_STRING "include/bar.h 2\n"
 """)
 
-test.run(arguments = prog)
+test.run(arguments = args)
 
 test.run(program = test.workpath(prog),
          stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 2\n")
@@ -138,6 +153,12 @@ test.run(program = test.workpath(prog),
 test.run(program = test.workpath(subdir_prog),
          stdout = "subdir/prog.c\nsubdir/include/foo.h 1\nsubdir/include/bar.h 1\n")
 
-test.up_to_date(arguments = prog)
+test.run(program = test.workpath(variant_prog),
+         stdout = "subdir/prog.c\ninclude/foo.h 2\ninclude/bar.h 2\n")
+
+# Make sure we didn't duplicate the source file in the variant subdirectory.
+test.fail_test(os.path.exists(test.workpath('variant', 'prog.c')))
+
+test.up_to_date(arguments = args)
 
 test.pass_test()
index 51720402e9ce870473c9c95d238b5c0537d24202..496624d68d5a4fab2b19909c8a2c44edeaad506a 100644 (file)
@@ -59,6 +59,10 @@ Import("x1"," x2")
 assert x1 == "SConscript4 x1"
 assert x2 == "SConscript4 x2"
 
+subdir = Dir('subdir')
+script = File('SConscript', subdir)
+foo = SConscript(script)
+assert foo == "subdir/SConscript foo"
 """)
 
 test.write('SConscript', """
@@ -128,6 +132,11 @@ x2 = "SConscript4 x2"
 Export("x1", "x2")
 """)
 
+test.subdir('subdir')
+test.write(['subdir', 'SConscript'], """
+foo = 'subdir/SConscript foo'
+Return('foo')
+""")
 
 wpath = test.workpath()