summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/man/scons.1220
-rw-r--r--etc/TestCmd.py7
-rw-r--r--src/CHANGES.txt5
-rw-r--r--src/engine/SCons/Node/FS.py56
-rw-r--r--src/engine/SCons/Node/FSTests.py14
-rw-r--r--src/engine/SCons/Script/SConscript.py37
-rw-r--r--src/engine/SCons/Util.py23
-rw-r--r--src/engine/SCons/UtilTests.py10
-rw-r--r--test/BuildDir.py47
-rw-r--r--test/CPPPATH.py33
-rw-r--r--test/SConscript.py9
11 files changed, 325 insertions, 136 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 100710f..38b196d 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -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.
diff --git a/etc/TestCmd.py b/etc/TestCmd.py
index d09d35d..8df039e 100644
--- a/etc/TestCmd.py
+++ b/etc/TestCmd.py
@@ -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
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 52671cb..c84d0cb 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -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
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index adfd440..98b6b02 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -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):
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index f2130d7..4801dae 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -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')
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 924fd29..7085547 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -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
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 0d05498..262762e 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -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:
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index 9eebc85..a7c9e70 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -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_')
diff --git a/test/BuildDir.py b/test/BuildDir.py
index 8f7c149..ef11760 100644
--- a/test/BuildDir.py
+++ b/test/BuildDir.py
@@ -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()
diff --git a/test/CPPPATH.py b/test/CPPPATH.py
index fb21426..af7bdd8 100644
--- a/test/CPPPATH.py
+++ b/test/CPPPATH.py
@@ -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()
diff --git a/test/SConscript.py b/test/SConscript.py
index 5172040..496624d 100644
--- a/test/SConscript.py
+++ b/test/SConscript.py
@@ -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()