summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/AR/AR.py3
-rw-r--r--test/AR/ARFLAGS.py3
-rw-r--r--test/BuildDir/Clean.py71
-rw-r--r--test/BuildDir/File-create.py70
-rw-r--r--test/BuildDir/Sconscript-build_dir.py3
-rw-r--r--test/CC/SHCCCOMSTR.py1
-rw-r--r--test/CXX/CXX.py4
-rw-r--r--test/CXX/SHCXX.py4
-rw-r--r--test/CXX/SHCXXCOMSTR.py2
-rw-r--r--test/CacheDir/timestamp-content.py (renamed from test/CacheDir/timestamp.py)17
-rw-r--r--test/CacheDir/timestamp-match.py59
-rw-r--r--test/CacheDir/timestamp-newer.py59
-rw-r--r--test/CacheDir/timestamp-timestamp.py61
-rw-r--r--test/Chmod.py22
-rw-r--r--test/Configure/clean.py34
-rw-r--r--test/Configure/help.py53
-rw-r--r--test/Copy.py4
-rw-r--r--test/Errors/preparation.py13
-rw-r--r--test/Fortran/SHF77COMSTR.py2
-rw-r--r--test/Fortran/SHF90COMSTR.py2
-rw-r--r--test/Fortran/SHF95COMSTR.py2
-rw-r--r--test/Fortran/SHFORTRANCOMSTR.py2
-rw-r--r--test/GetBuildFailures/option-k.py112
-rw-r--r--test/GetBuildFailures/parallel.py127
-rw-r--r--test/GetBuildFailures/serial.py115
-rw-r--r--test/Glob/BuildDir.py71
-rw-r--r--test/Glob/Repository.py117
-rw-r--r--test/Glob/basic.py59
-rw-r--r--test/Glob/source.py88
-rw-r--r--test/Glob/strings.py72
-rw-r--r--test/Glob/subdir.py60
-rw-r--r--test/Glob/subst.py60
-rw-r--r--test/Install/Clone.py69
-rw-r--r--test/LINK/SHLINKCOMSTR.py1
-rw-r--r--test/Library.py2
-rw-r--r--test/MSVC/multiple-pdb.py10
-rw-r--r--test/Mkdir.py5
-rw-r--r--test/Move.py9
-rw-r--r--test/NodeOps.py4
-rw-r--r--test/Object.py2
-rw-r--r--test/Options/chdir.py71
-rw-r--r--test/Options/import.py69
-rw-r--r--test/Parallel/duplicate-target.py48
-rw-r--r--test/Parallel/failed-build.py111
-rw-r--r--test/Repository/variants.py3
-rw-r--r--test/Requires/basic.py95
-rw-r--r--test/Scanner/no-Dir-node.py136
-rw-r--r--test/Touch.py22
-rw-r--r--test/implicit-cache/DualTargets.py137
-rw-r--r--test/no-global-dependencies.py170
-rw-r--r--test/option-j.py37
-rw-r--r--test/option/debug-dtree.py1
-rw-r--r--test/option/debug-includes.py1
-rw-r--r--test/option/debug-stree.py1
-rw-r--r--test/option/debug-tree.py1
-rw-r--r--test/option/tree-all.py1
-rw-r--r--test/option/tree-derived.py1
-rw-r--r--test/packaging/multiple-packages-at-once.py17
-rw-r--r--test/packaging/rpm/explicit-target.py14
-rw-r--r--test/sconsign/ghost-entries.py111
-rw-r--r--test/sconsign/script/Configure.py3
-rw-r--r--test/sconsign/script/SConsignFile.py139
-rw-r--r--test/sconsign/script/Signatures.py89
-rw-r--r--test/sconsign/script/no-SConsignFile.py100
-rw-r--r--test/subdivide.py83
65 files changed, 2594 insertions, 341 deletions
diff --git a/test/AR/AR.py b/test/AR/AR.py
index cb11175..4048340 100644
--- a/test/AR/AR.py
+++ b/test/AR/AR.py
@@ -79,6 +79,9 @@ test.write('main.c', r"""
#include <stdio.h>
#include <stdlib.h>
+extern void
+library_function(void);
+
int
main(int argc, char *argv[])
{
diff --git a/test/AR/ARFLAGS.py b/test/AR/ARFLAGS.py
index d4d122e..fbca0ff 100644
--- a/test/AR/ARFLAGS.py
+++ b/test/AR/ARFLAGS.py
@@ -78,6 +78,9 @@ library_function(void)
test.write('main.c', r"""
#include <stdlib.h>
+extern void
+library_function();
+
int
main(int argc, char *argv[])
{
diff --git a/test/BuildDir/Clean.py b/test/BuildDir/Clean.py
new file mode 100644
index 0000000..f4a8c48
--- /dev/null
+++ b/test/BuildDir/Clean.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that we can Clean() files in a BuildDir() that's underneath us.
+(At one point this didn't work because we were using str() instead of
+abspath to remove the files, which would interfere with the removal by
+returning a path relative to the BuildDir(), not the top-level SConstruct
+directory, if the source directory was the top-level directory.)
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+BuildDir('build0', '.', duplicate=0)
+BuildDir('build1', '.', duplicate=1)
+
+def build_sample(target, source, env):
+ targetdir = str(target[0].dir)
+ target = str(target[0])
+ open(target, 'wb').write(open(str(source[0]), 'rb').read())
+ open(targetdir+'/sample.junk', 'wb').write('Side effect!\\n')
+
+t0 = Command("build0/sample.out", "sample.in", build_sample)
+t1 = Command("build1/sample.out", "sample.in", build_sample)
+
+Clean(t0, 'build0/sample.junk')
+Clean(t1, 'build1/sample.junk')
+""")
+
+test.write('sample.in', "sample.in\n")
+
+test.run(arguments = '.')
+
+test.must_match(['build0', 'sample.out'], "sample.in\n")
+test.must_exist(['build0', 'sample.junk'])
+
+test.must_match(['build1', 'sample.out'], "sample.in\n")
+test.must_exist(['build1', 'sample.junk'])
+
+test.run(arguments = '-c .')
+
+test.must_not_exist(['build', 'sample.out'])
+test.must_not_exist(['build', 'sample.junk'])
+
+test.pass_test()
diff --git a/test/BuildDir/File-create.py b/test/BuildDir/File-create.py
new file mode 100644
index 0000000..0a838be
--- /dev/null
+++ b/test/BuildDir/File-create.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that explicit use of File() Nodes in a BuildDir, followed by
+*direct* creation of the file by Python in the SConscript file itself,
+works correctly, with both duplicate=0 and duplicate=1.
+
+Right now it only works if you explicitly str() the Node before the file
+is created on disk, but we at least want to make sure that continues
+to work. The non-str() case, which doesn't currently work, is captured
+here but commented out.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('src')
+
+test.write('SConstruct', """\
+SConscript('src/SConscript', build_dir='build0', chdir=1, duplicate=0)
+SConscript('src/SConscript', build_dir='build1', chdir=1, duplicate=1)
+""")
+
+test.write(['src', 'SConscript'], """\
+#f1_in = File('f1.in')
+#Command('f1.out', f1_in, Copy('$TARGET', '$SOURCE'))
+#open('f1.in', 'wb').write("f1.in\\n")
+
+f2_in = File('f2.in')
+str(f2_in)
+Command('f2.out', f2_in, Copy('$TARGET', '$SOURCE'))
+open('f2.in', 'wb').write("f2.in\\n")
+""")
+
+test.run(arguments = '--tree=all .')
+
+#test.must_match(['build0', 'f1.out'], "f1.in\n")
+test.must_match(['build0', 'f2.out'], "f2.in\n")
+
+#test.must_match(['build1', 'f1.out'], "f1.in\n")
+test.must_match(['build1', 'f2.out'], "f2.in\n")
+
+test.up_to_date(arguments = '.')
+
+test.pass_test()
diff --git a/test/BuildDir/Sconscript-build_dir.py b/test/BuildDir/Sconscript-build_dir.py
index 685011d..50e2c4f 100644
--- a/test/BuildDir/Sconscript-build_dir.py
+++ b/test/BuildDir/Sconscript-build_dir.py
@@ -225,6 +225,9 @@ test.write(['test2', 'foo.c'], r"""
#include <stdio.h>
#include <stdlib.h>
+extern void
+bar(void);
+
int
main(int argc, char *argv[]) {
bar();
diff --git a/test/CC/SHCCCOMSTR.py b/test/CC/SHCCCOMSTR.py
index 4d240ae..562961a 100644
--- a/test/CC/SHCCCOMSTR.py
+++ b/test/CC/SHCCCOMSTR.py
@@ -58,6 +58,7 @@ else:
test.write('SConstruct', """
env = Environment(SHCCCOM = r'%(_python_)s mycc.py $TARGET $SOURCE',
SHCCCOMSTR = 'Building $TARGET from $SOURCE',
+ SHOBJPREFIX='',
SHOBJSUFFIX='.obj')
env.SharedObject(target = 'test1', source = 'test1.c')
env.SharedObject(target = 'test2', source = 'test2%(alt_c_suffix)s')
diff --git a/test/CXX/CXX.py b/test/CXX/CXX.py
index a1b4c2a..f537ee8 100644
--- a/test/CXX/CXX.py
+++ b/test/CXX/CXX.py
@@ -199,7 +199,7 @@ test.write('foo.cxx', r"""
int
main(int argc, char *argv[])
{
- argv[argc++] = "--";
+ argv[argc++] = (char *)"--";
printf("foo.cxx\n");
exit (0);
}
@@ -211,7 +211,7 @@ test.write('bar.cxx', r"""
int
main(int argc, char *argv[])
{
- argv[argc++] = "--";
+ argv[argc++] = (char *)"--";
printf("foo.cxx\n");
exit (0);
}
diff --git a/test/CXX/SHCXX.py b/test/CXX/SHCXX.py
index c02086b..abfc19d 100644
--- a/test/CXX/SHCXX.py
+++ b/test/CXX/SHCXX.py
@@ -55,7 +55,7 @@ test.write('foo.cpp', r"""
int
main(int argc, char *argv[])
{
- argv[argc++] = "--";
+ argv[argc++] = (char *)"--";
printf("foo.c\n");
exit (0);
}
@@ -67,7 +67,7 @@ test.write('bar.cpp', r"""
int
main(int argc, char *argv[])
{
- argv[argc++] = "--";
+ argv[argc++] = (char *)"--";
printf("foo.c\n");
exit (0);
}
diff --git a/test/CXX/SHCXXCOMSTR.py b/test/CXX/SHCXXCOMSTR.py
index 33beae7..8e55441 100644
--- a/test/CXX/SHCXXCOMSTR.py
+++ b/test/CXX/SHCXXCOMSTR.py
@@ -58,7 +58,7 @@ else:
test.write('SConstruct', """
env = Environment(SHCXXCOM = r'%(_python_)s mycc.py $TARGET $SOURCE',
SHCXXCOMSTR = 'Building shared object $TARGET from $SOURCE',
- SHOBJSUFFIX='.obj')
+ SHOBJPREFIX='', SHOBJSUFFIX='.obj')
env.SharedObject(target = 'test1', source = 'test1.cpp')
env.SharedObject(target = 'test2', source = 'test2.cc')
env.SharedObject(target = 'test3', source = 'test3.cxx')
diff --git a/test/CacheDir/timestamp.py b/test/CacheDir/timestamp-content.py
index b0d45b6..6434d0c 100644
--- a/test/CacheDir/timestamp.py
+++ b/test/CacheDir/timestamp-content.py
@@ -25,7 +25,8 @@
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
-Verify that CacheDir() works even when using timestamp signatures.
+Verify that CacheDir() works when using SourceSignatures('timestamp')
+and TargetSignatures 'content'.
"""
import TestSCons
@@ -41,8 +42,20 @@ Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
test.write('file.in', "file.in\n")
-test.run()
+test.run(arguments = '.')
test.must_match('file.out', "file.in\n")
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.sleep()
+
+test.touch('file.in')
+
+test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
test.pass_test()
diff --git a/test/CacheDir/timestamp-match.py b/test/CacheDir/timestamp-match.py
new file mode 100644
index 0000000..0e0074d
--- /dev/null
+++ b/test/CacheDir/timestamp-match.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that CAcheDir() works when using 'timestamp-match' decisions.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write(['SConstruct'], """\
+Decider('timestamp-match')
+CacheDir('cache')
+Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
+""")
+
+test.write('file.in', "file.in\n")
+
+test.run(arguments = '--cache-show --debug=explain .')
+
+test.must_match('file.out', "file.in\n")
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.sleep()
+
+test.touch('file.in')
+
+test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.pass_test()
diff --git a/test/CacheDir/timestamp-newer.py b/test/CacheDir/timestamp-newer.py
new file mode 100644
index 0000000..36267f8
--- /dev/null
+++ b/test/CacheDir/timestamp-newer.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that CAcheDir() works when using 'timestamp-newer' decisions.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write(['SConstruct'], """\
+Decider('timestamp-newer')
+CacheDir('cache')
+Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
+""")
+
+test.write('file.in', "file.in\n")
+
+test.run(arguments = '--cache-show --debug=explain .')
+
+test.must_match('file.out', "file.in\n")
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.sleep()
+
+test.touch('file.in')
+
+test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.pass_test()
diff --git a/test/CacheDir/timestamp-timestamp.py b/test/CacheDir/timestamp-timestamp.py
new file mode 100644
index 0000000..2bef1cd
--- /dev/null
+++ b/test/CacheDir/timestamp-timestamp.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that CacheDir() works when using both SourceSignatures()
+and TargetSignatures values of 'timestamp'.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write(['SConstruct'], """\
+SourceSignatures('timestamp')
+TargetSignatures('timestamp')
+CacheDir('cache')
+Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
+""")
+
+test.write('file.in', "file.in\n")
+
+test.run(arguments = '--cache-show --debug=explain .')
+
+test.must_match('file.out', "file.in\n")
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.sleep()
+
+test.touch('file.in')
+
+test.not_up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.up_to_date(options = '--cache-show --debug=explain', arguments = '.')
+
+test.pass_test()
diff --git a/test/Chmod.py b/test/Chmod.py
index eb0b6c1..92fa639 100644
--- a/test/Chmod.py
+++ b/test/Chmod.py
@@ -41,7 +41,9 @@ test = TestSCons.TestSCons()
# oscillate between those values.
test.write('SConstruct', """
Execute(Chmod('f1', 0666))
+Execute(Chmod(('f1-File'), 0666))
Execute(Chmod('d2', 0777))
+Execute(Chmod(Dir('d2-Dir'), 0777))
def cat(env, source, target):
target = str(target[0])
source = map(str, source)
@@ -62,8 +64,11 @@ env.Command('f7.out', 'f7.in', [Cat,
""")
test.write('f1', "f1\n")
+test.write('f1-File', "f1-File\n")
test.subdir('d2')
test.write(['d2', 'file'], "d2/file\n")
+test.subdir('d2-Dir')
+test.write(['d2-Dir', 'file'], "d2-Dir/file\n")
test.write('bar.in', "bar.in\n")
test.write('f3', "f3\n")
test.subdir('d4')
@@ -75,14 +80,21 @@ test.write('Chmod-f7.in', "Chmod-f7.in\n")
test.write('f7.out-Chmod', "f7.out-Chmod\n")
os.chmod(test.workpath('f1'), 0444)
+os.chmod(test.workpath('f1-File'), 0444)
os.chmod(test.workpath('d2'), 0555)
+os.chmod(test.workpath('d2-Dir'), 0555)
os.chmod(test.workpath('f3'), 0444)
os.chmod(test.workpath('d4'), 0555)
os.chmod(test.workpath('f5'), 0444)
os.chmod(test.workpath('Chmod-f7.in'), 0444)
os.chmod(test.workpath('f7.out-Chmod'), 0444)
-expect = test.wrap_stdout(read_str = 'Chmod("f1", 0666)\nChmod("d2", 0777)\n',
+expect = test.wrap_stdout(read_str = """\
+Chmod("f1", 0666)
+Chmod("f1-File", 0666)
+Chmod("d2", 0777)
+Chmod("d2-Dir", 0777)
+""",
build_str = """\
cat(["bar.out"], ["bar.in"])
Chmod("f3", 0666)
@@ -97,8 +109,12 @@ test.run(options = '-n', arguments = '.', stdout = expect)
s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE])
test.fail_test(s != 0444)
+s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE])
+test.fail_test(s != 0444)
s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE])
test.fail_test(s != 0555)
+s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE])
+test.fail_test(s != 0555)
test.must_not_exist('bar.out')
s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE])
test.fail_test(s != 0444)
@@ -117,8 +133,12 @@ test.run()
s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE])
test.fail_test(s != 0666)
+s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE])
+test.fail_test(s != 0666)
s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE])
test.fail_test(s != 0777)
+s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE])
+test.fail_test(s != 0777)
test.must_match('bar.out', "bar.in\n")
s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE])
test.fail_test(s != 0666)
diff --git a/test/Configure/clean.py b/test/Configure/clean.py
index 5b8e43d..a6ba7c1 100644
--- a/test/Configure/clean.py
+++ b/test/Configure/clean.py
@@ -39,7 +39,7 @@ test.write('SConstruct', """\
env = Environment()
import os
env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure(env)
+conf = Configure(env, clean=int(ARGUMENTS['clean']))
r1 = conf.CheckCHeader( 'math.h' )
r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
env = conf.Finish()
@@ -65,32 +65,16 @@ lines = [
"Checking for C header file no_std_c_header.h... "
]
-unexpected = []
+test.run(arguments = '-c clean=0')
+test.must_not_contain_lines(lines, test.stdout())
-test.run(arguments = '-c')
+test.run(arguments = '-c clean=1')
+test.must_contain_lines(lines, test.stdout())
-for line in lines:
- if string.find(test.stdout(), line) != -1:
- unexpected.append(line)
+test.run(arguments = '--clean clean=0')
+test.must_not_contain_lines(lines, test.stdout())
-if unexpected:
- print "Unexpected lines in standard output:"
- print string.join(unexpected, '\n')
- print "STDOUT ============================================================"
- print test.stdout()
- test.fail_test()
-
-test.run(arguments = '--clean')
-
-for line in lines:
- if string.find(test.stdout(), line) != -1:
- unexpected.append(line)
-
-if unexpected:
- print "Unexpected lines in standard output:"
- print string.join(unexpected, '\n')
- print "STDOUT ============================================================"
- print test.stdout()
- test.fail_test()
+test.run(arguments = '--clean clean=1')
+test.must_contain_lines(lines, test.stdout())
test.pass_test()
diff --git a/test/Configure/help.py b/test/Configure/help.py
index f79831c..32c68eb 100644
--- a/test/Configure/help.py
+++ b/test/Configure/help.py
@@ -39,7 +39,7 @@ test.write('SConstruct', """\
env = Environment()
import os
env.AppendENVPath('PATH', os.environ['PATH'])
-conf = Configure(env)
+conf = Configure(env, help=int(ARGUMENTS['help']))
r1 = conf.CheckCHeader( 'math.h' )
r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
env = conf.Finish()
@@ -65,45 +65,26 @@ lines = [
"Checking for C header file no_std_c_header.h... "
]
-unexpected = []
+# The help setting should have no effect on -H, so the -H output
+# should never contain the lines.
+test.run(arguments = '-H help=0')
+test.must_not_contain_lines(lines, test.stdout())
-test.run(arguments = '-H')
+test.run(arguments = '-H help=1')
+test.must_not_contain_lines(lines, test.stdout())
-for line in lines:
- if string.find(test.stdout(), line) != -1:
- unexpected.append(line)
+# For -h and --help, the lines appear or not depending on how Configure()
+# is initialized.
+test.run(arguments = '-h help=0')
+test.must_not_contain_lines(lines, test.stdout())
-if unexpected:
- print "Unexpected lines in standard output:"
- print string.join(unexpected, '\n')
- print "STDOUT ============================================================"
- print test.stdout()
- test.fail_test()
+test.run(arguments = '-h help=1')
+test.must_contain_lines(lines, test.stdout())
-test.run(arguments = '-h')
+test.run(arguments = '--help help=0')
+test.must_not_contain_lines(lines, test.stdout())
-for line in lines:
- if string.find(test.stdout(), line) != -1:
- unexpected.append(line)
-
-if unexpected:
- print "Unexpected lines in standard output:"
- print string.join(unexpected, '\n')
- print "STDOUT ============================================================"
- print test.stdout()
- test.fail_test()
-
-test.run(arguments = '--help')
-
-for line in lines:
- if string.find(test.stdout(), line) != -1:
- unexpected.append(line)
-
-if unexpected:
- print "Unexpected lines in standard output:"
- print string.join(unexpected, '\n')
- print "STDOUT ============================================================"
- print test.stdout()
- test.fail_test()
+test.run(arguments = '--help help=1')
+test.must_contain_lines(lines, test.stdout())
test.pass_test()
diff --git a/test/Copy.py b/test/Copy.py
index 6659d93..827b912 100644
--- a/test/Copy.py
+++ b/test/Copy.py
@@ -36,8 +36,8 @@ test = TestSCons.TestSCons()
test.write('SConstruct', """
Execute(Copy('f1.out', 'f1.in'))
-Execute(Copy('d2.out', 'd2.in'))
-Execute(Copy('d3.out', 'f3.in'))
+Execute(Copy(File('d2.out'), 'd2.in'))
+Execute(Copy('d3.out', File('f3.in')))
def cat(env, source, target):
target = str(target[0])
source = map(str, source)
diff --git a/test/Errors/preparation.py b/test/Errors/preparation.py
index 9857f99..597216a 100644
--- a/test/Errors/preparation.py
+++ b/test/Errors/preparation.py
@@ -25,8 +25,15 @@
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
"""
-Verify that we print a useful message (and exit non-zero) if an external
-error occurs while deciding if a Node is current or not.
+A currently disabled test that used to verify that we print a useful
+message (and exit non-zero) if an external error occurs while deciding
+if a Node is current or not.
+
+This behavior changed when the Big Signature Refactoring changed when
+signature calculation happens to *after* a Node has been visited (and
+therefore visiting source Nodes in turn). Creating an analogous situation
+in the new code isn't obvious, and It's not clear whether we need it
+anyway, so we're going to leave this checked in but disabled for now.
"""
import sys
@@ -35,6 +42,8 @@ import TestSCons
test = TestSCons.TestSCons()
+test.skip_test('Test not useful with current code; skipping.\n')
+
work_file_out = test.workpath('work', 'file.out')
test.subdir('install', 'work')
diff --git a/test/Fortran/SHF77COMSTR.py b/test/Fortran/SHF77COMSTR.py
index 9085570..2bedb48 100644
--- a/test/Fortran/SHF77COMSTR.py
+++ b/test/Fortran/SHF77COMSTR.py
@@ -56,7 +56,7 @@ env = Environment(SHF77COM = r'%(_python_)s myfc.py f77 $TARGET $SOURCES',
SHF77COMSTR = 'Building f77 $TARGET from $SOURCES',
SHF77PPCOM = r'%(_python_)s myfc.py f77pp $TARGET $SOURCES',
SHF77PPCOMSTR = 'Building f77pp $TARGET from $SOURCES',
- SHOBJSUFFIX='.shobj')
+ SHOBJPREFIX='', SHOBJSUFFIX='.shobj')
env.SharedObject(source = 'test01.f')
env.SharedObject(source = 'test02.F')
env.SharedObject(source = 'test03.for')
diff --git a/test/Fortran/SHF90COMSTR.py b/test/Fortran/SHF90COMSTR.py
index 9633d45..08208fa 100644
--- a/test/Fortran/SHF90COMSTR.py
+++ b/test/Fortran/SHF90COMSTR.py
@@ -56,7 +56,7 @@ env = Environment(SHF90COM = r'%(_python_)s myfc.py f90 $TARGET $SOURCES',
SHF90COMSTR = 'Building f90 $TARGET from $SOURCES',
SHF90PPCOM = r'%(_python_)s myfc.py f90pp $TARGET $SOURCES',
SHF90PPCOMSTR = 'Building f90pp $TARGET from $SOURCES',
- SHOBJSUFFIX='.shobj')
+ SHOBJPREFIX='', SHOBJSUFFIX='.shobj')
env.SharedObject(source = 'test01.f90')
env.SharedObject(source = 'test02.F90')
""" % locals())
diff --git a/test/Fortran/SHF95COMSTR.py b/test/Fortran/SHF95COMSTR.py
index eaa24ae..71a5627 100644
--- a/test/Fortran/SHF95COMSTR.py
+++ b/test/Fortran/SHF95COMSTR.py
@@ -56,7 +56,7 @@ env = Environment(SHF95COM = r'%(_python_)s myfc.py f95 $TARGET $SOURCES',
SHF95COMSTR = 'Building f95 $TARGET from $SOURCES',
SHF95PPCOM = r'%(_python_)s myfc.py f95pp $TARGET $SOURCES',
SHF95PPCOMSTR = 'Building f95pp $TARGET from $SOURCES',
- SHOBJSUFFIX='.shobj')
+ SHOBJPREFIX='', SHOBJSUFFIX='.shobj')
env.SharedObject(source = 'test01.f95')
env.SharedObject(source = 'test02.F95')
""" % locals())
diff --git a/test/Fortran/SHFORTRANCOMSTR.py b/test/Fortran/SHFORTRANCOMSTR.py
index 69a1eba..52b20c2 100644
--- a/test/Fortran/SHFORTRANCOMSTR.py
+++ b/test/Fortran/SHFORTRANCOMSTR.py
@@ -56,7 +56,7 @@ env = Environment(SHFORTRANCOM = r'%(_python_)s myfc.py fortran $TARGET $SOURCES
SHFORTRANCOMSTR = 'Building fortran $TARGET from $SOURCES',
SHFORTRANPPCOM = r'%(_python_)s myfc.py fortranpp $TARGET $SOURCES',
SHFORTRANPPCOMSTR = 'Building fortranpp $TARGET from $SOURCES',
- SHOBJSUFFIX='.shobj')
+ SHOBJPREFIX='', SHOBJSUFFIX='.shobj')
env.SharedObject(source = 'test01.f')
env.SharedObject(source = 'test02.F')
env.SharedObject(source = 'test03.for')
diff --git a/test/GetBuildFailures/option-k.py b/test/GetBuildFailures/option-k.py
new file mode 100644
index 0000000..5246f31
--- /dev/null
+++ b/test/GetBuildFailures/option-k.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+"""
+Verify that a failed build action with -j works as expected.
+"""
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+try:
+ import threading
+except ImportError:
+ # if threads are not supported, then
+ # there is nothing to test
+ TestCmd.no_result()
+ sys.exit()
+
+
+test = TestSCons.TestSCons()
+
+contents = r"""\
+import sys
+if sys.argv[0] == 'mypass.py':
+ open(sys.argv[3], 'wb').write(open(sys.argv[4], 'rb').read())
+ exit_value = 0
+elif sys.argv[0] == 'myfail.py':
+ exit_value = 1
+sys.exit(exit_value)
+"""
+
+test.write('mypass.py', contents)
+test.write('myfail.py', contents)
+
+test.write('SConstruct', """\
+Command('f3', 'f3.in', r'@%(_python_)s mypass.py - f3 $TARGET $SOURCE')
+Command('f4', 'f4.in', r'@%(_python_)s myfail.py f3 f4 $TARGET $SOURCE')
+Command('f5', 'f5.in', r'@%(_python_)s myfail.py f4 f5 $TARGET $SOURCE')
+Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE')
+
+def print_build_failures():
+ from SCons.Script import GetBuildFailures
+ bf_list = GetBuildFailures()
+ bf_list.sort(lambda a,b: cmp(a.filename, b.filename))
+ for bf in bf_list:
+ print "%%s failed: %%s" %% (bf.node, bf.errstr)
+
+try:
+ import atexit
+except ImportError:
+ import sys
+ sys.exitfunc = print_build_failures
+else:
+ atexit.register(print_build_failures)
+""" % locals())
+
+test.write('f3.in', "f3.in\n")
+test.write('f4.in', "f4.in\n")
+test.write('f5.in', "f5.in\n")
+test.write('f6.in', "f6.in\n")
+
+expect_stdout = """\
+scons: Reading SConscript files ...
+scons: done reading SConscript files.
+scons: Building targets ...
+scons: done building targets (errors occurred during build).
+f4 failed: Error 1
+f5 failed: Error 1
+""" % locals()
+
+expect_stderr = """\
+scons: *** [f4] Error 1
+scons: *** [f5] Error 1
+"""
+
+test.run(arguments = '-k .',
+ status = 2,
+ stdout = expect_stdout,
+ stderr = expect_stderr)
+
+test.must_match(test.workpath('f3'), 'f3.in\n')
+test.must_not_exist(test.workpath('f4'))
+test.must_not_exist(test.workpath('f5'))
+test.must_match(test.workpath('f6'), 'f6.in\n')
+
+
+
+test.pass_test()
diff --git a/test/GetBuildFailures/parallel.py b/test/GetBuildFailures/parallel.py
new file mode 100644
index 0000000..cfadd0d
--- /dev/null
+++ b/test/GetBuildFailures/parallel.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+"""
+Verify that a failed build action with -j works as expected.
+"""
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+try:
+ import threading
+except ImportError:
+ # if threads are not supported, then
+ # there is nothing to test
+ TestCmd.no_result()
+ sys.exit()
+
+
+test = TestSCons.TestSCons()
+
+# We want to verify that -j 4 starts all four jobs, the first and last of
+# which fail and the second and third of which succeed, and then stops
+# processing due to the build failures. To try to control the timing,
+# the created build scripts use marker directories to avoid doing their
+# processing until the previous script has finished.
+
+contents = r"""\
+import os.path
+import sys
+import time
+wait_marker = sys.argv[1] + '.marker'
+write_marker = sys.argv[2] + '.marker'
+if wait_marker != '-.marker':
+ while not os.path.exists(wait_marker):
+ time.sleep(1)
+if sys.argv[0] == 'mypass.py':
+ open(sys.argv[3], 'wb').write(open(sys.argv[4], 'rb').read())
+ exit_value = 0
+elif sys.argv[0] == 'myfail.py':
+ exit_value = 1
+if write_marker != '-.marker':
+ os.mkdir(write_marker)
+sys.exit(exit_value)
+"""
+
+test.write('mypass.py', contents)
+test.write('myfail.py', contents)
+
+test.write('SConstruct', """\
+Command('f3', 'f3.in', r'@%(_python_)s mypass.py - f3 $TARGET $SOURCE')
+Command('f4', 'f4.in', r'@%(_python_)s myfail.py f3 f4 $TARGET $SOURCE')
+Command('f5', 'f5.in', r'@%(_python_)s myfail.py f4 f5 $TARGET $SOURCE')
+Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE')
+
+def print_build_failures():
+ from SCons.Script import GetBuildFailures
+ bf_list = GetBuildFailures()
+ bf_list.sort(lambda a,b: cmp(a.filename, b.filename))
+ for bf in bf_list:
+ print "%%s failed: %%s" %% (bf.node, bf.errstr)
+
+try:
+ import atexit
+except ImportError:
+ import sys
+ sys.exitfunc = print_build_failures
+else:
+ atexit.register(print_build_failures)
+""" % locals())
+
+test.write('f3.in', "f3.in\n")
+test.write('f4.in', "f4.in\n")
+test.write('f5.in', "f5.in\n")
+test.write('f6.in', "f6.in\n")
+
+expect_stdout = """\
+scons: Reading SConscript files ...
+scons: done reading SConscript files.
+scons: Building targets ...
+scons: building terminated because of errors.
+f4 failed: Error 1
+f5 failed: Error 1
+""" % locals()
+
+expect_stderr = """\
+scons: *** [f4] Error 1
+scons: *** [f5] Error 1
+"""
+
+test.run(arguments = '-j 4 .',
+ status = 2,
+ stdout = expect_stdout,
+ stderr = expect_stderr)
+
+test.must_match(test.workpath('f3'), 'f3.in\n')
+test.must_not_exist(test.workpath('f4'))
+test.must_not_exist(test.workpath('f5'))
+test.must_match(test.workpath('f6'), 'f6.in\n')
+
+
+
+test.pass_test()
diff --git a/test/GetBuildFailures/serial.py b/test/GetBuildFailures/serial.py
new file mode 100644
index 0000000..c8205ed
--- /dev/null
+++ b/test/GetBuildFailures/serial.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+"""
+Verify that the GetBuildFailures() function returns a list of
+BuildError exceptions. Also verify printing the BuildError
+attributes we expect to be most commonly used.
+"""
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+try:
+ import threading
+except ImportError:
+ # if threads are not supported, then
+ # there is nothing to test
+ TestCmd.no_result()
+ sys.exit()
+
+
+test = TestSCons.TestSCons()
+
+contents = r"""\
+import sys
+if sys.argv[0] == 'mypass.py':
+ open(sys.argv[3], 'wb').write(open(sys.argv[4], 'rb').read())
+ exit_value = 0
+elif sys.argv[0] == 'myfail.py':
+ exit_value = 1
+sys.exit(exit_value)
+"""
+
+test.write('mypass.py', contents)
+test.write('myfail.py', contents)
+
+test.write('SConstruct', """\
+Command('f3', 'f3.in', r'@%(_python_)s mypass.py - f3 $TARGET $SOURCE')
+Command('f4', 'f4.in', r'@%(_python_)s myfail.py f3 f4 $TARGET $SOURCE')
+Command('f5', 'f5.in', r'@%(_python_)s myfail.py f4 f5 $TARGET $SOURCE')
+Command('f6', 'f6.in', r'@%(_python_)s mypass.py f5 - $TARGET $SOURCE')
+
+def print_build_failures():
+ from SCons.Script import GetBuildFailures
+ import string
+ bf_list = GetBuildFailures()
+ bf_list.sort(lambda a,b: cmp(a.filename, b.filename))
+ for bf in bf_list:
+ print "%%s failed (%%s): %%s" %% (bf.node, bf.status, bf.errstr)
+ print " %%s" %% string.join(bf.command)
+
+try:
+ import atexit
+except ImportError:
+ import sys
+ sys.exitfunc = print_build_failures
+else:
+ atexit.register(print_build_failures)
+""" % locals())
+
+test.write('f3.in', "f3.in\n")
+test.write('f4.in', "f4.in\n")
+test.write('f5.in', "f5.in\n")
+test.write('f6.in', "f6.in\n")
+
+expect_stdout = """\
+scons: Reading SConscript files ...
+scons: done reading SConscript files.
+scons: Building targets ...
+scons: building terminated because of errors.
+f4 failed (1): Error 1
+ %(_python_)s myfail.py f3 f4 "f4" "f4.in"
+""" % locals()
+
+expect_stderr = """\
+scons: *** [f4] Error 1
+"""
+
+test.run(arguments = '.',
+ status = 2,
+ stdout = expect_stdout,
+ stderr = expect_stderr)
+
+test.must_match(test.workpath('f3'), 'f3.in\n')
+test.must_not_exist(test.workpath('f4'))
+test.must_not_exist(test.workpath('f5'))
+test.must_not_exist(test.workpath('f6'))
+
+
+
+test.pass_test()
diff --git a/test/Glob/BuildDir.py b/test/Glob/BuildDir.py
new file mode 100644
index 0000000..274ca49
--- /dev/null
+++ b/test/Glob/BuildDir.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that default use of the Glob() function within a BuildDir()
+finds the local file Nodes.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('src')
+
+test.write('SConstruct', """\
+BuildDir('var1', 'src')
+BuildDir('var2', 'src')
+
+SConscript('var1/SConscript')
+SConscript('var2/SConscript')
+""")
+
+test.write(['src', 'SConscript'], """\
+env = Environment()
+
+def concatenate(target, source, env):
+ fp = open(str(target[0]), 'wb')
+ for s in source:
+ fp.write(open(str(s), 'rb').read())
+ fp.close()
+
+env['BUILDERS']['Concatenate'] = Builder(action=concatenate)
+
+f_in = Glob('f*.in')
+f_in.sort(lambda a,b: cmp(a.name, b.name))
+env.Concatenate('f.out', f_in)
+""")
+
+test.write(['src', 'f1.in'], "src/f1.in\n")
+test.write(['src', 'f2.in'], "src/f2.in\n")
+test.write(['src', 'f3.in'], "src/f3.in\n")
+
+test.run(arguments = '.')
+
+test.must_match(['var1', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n")
+test.must_match(['var2', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n")
+
+test.pass_test()
diff --git a/test/Glob/Repository.py b/test/Glob/Repository.py
new file mode 100644
index 0000000..6cef443
--- /dev/null
+++ b/test/Glob/Repository.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that the Glob() function finds files in repositories.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('work',
+ 'repository',
+ ['repository', 'src'],
+ ['repository', 'src', 'sub1'],
+ ['repository', 'src', 'sub2'])
+
+work_aaa = test.workpath('work', 'aaa')
+work_bbb = test.workpath('work', 'bbb')
+work_ccc = test.workpath('work', 'ccc')
+work_src_xxx = test.workpath('work', 'src', 'xxx')
+work_src_yyy = test.workpath('work', 'src', 'yyy')
+
+opts = "-Y " + test.workpath('repository')
+
+test.write(['repository', 'SConstruct'], """\
+def cat(env, source, target):
+ target = str(target[0])
+ source = map(str, source)
+ f = open(target, "wb")
+ for src in source:
+ f.write(open(src, "rb").read())
+ f.close()
+
+env = Environment(BUILDERS={'Build':Builder(action=cat)})
+env.Build('aaa.out', Glob('a*.in'))
+env.Build('bbb.out', Glob('b*.in'))
+env.Build('ccc.out', Glob('c*.in'))
+SConscript('src/SConscript', "env")
+""")
+
+test.write(['repository', 'aaa.in'], "repository/aaa.in\n")
+test.write(['repository', 'bbb.in'], "repository/bbb.in\n")
+test.write(['repository', 'ccc.in'], "repository/ccc.in\n")
+
+test.write(['repository', 'src', 'SConscript'], """
+Import("env")
+env.Build('xxx.out', Glob('x*.in'))
+env.Build('yyy.out', Glob('yy?.in'))
+zzz_in = Glob('*/zzz.in')
+zzz_in.sort(lambda a,b: cmp(a.abspath, b.abspath))
+env.Build('zzz.out', zzz_in)
+""")
+
+test.write(['repository', 'src', 'xxx.in'], "repository/src/xxx.in\n")
+test.write(['repository', 'src', 'yyy.in'], "repository/src/yyy.in\n")
+test.write(['repository', 'src', 'sub1', 'zzz.in'], "repository/src/sub1/zzz.in\n")
+test.write(['repository', 'src', 'sub2', 'zzz.in'], "repository/src/sub2/zzz.in\n")
+
+#
+# Make the repository non-writable,
+# so we'll detect if we try to write into it accidentally.
+test.writable('repository', 0)
+
+#
+test.run(chdir = 'work', options = opts, arguments = 'aaa.out')
+
+test.must_match(['work', 'aaa.out'], "repository/aaa.in\n")
+test.must_not_exist(test.workpath('work', 'bbb.out'))
+test.must_not_exist(test.workpath('work', 'ccc.out'))
+test.must_not_exist(test.workpath('work', 'src', 'xxx.out'))
+test.must_not_exist(test.workpath('work', 'src', 'yyy.out'))
+
+test.run(chdir = 'work', options = opts, arguments = 'bbb.out src')
+
+test.must_match(['work', 'bbb.out'], "repository/bbb.in\n")
+test.must_not_exist(test.workpath('work', 'ccc.out'))
+test.must_match(['work', 'src', 'xxx.out'], "repository/src/xxx.in\n")
+test.must_match(['work', 'src', 'yyy.out'], "repository/src/yyy.in\n")
+
+expect = """\
+repository/src/sub1/zzz.in
+repository/src/sub2/zzz.in
+"""
+
+test.must_match(['work', 'src', 'zzz.out'], expect)
+
+#
+test.run(chdir = 'work', options = opts, arguments = '.')
+
+test.must_match(['work', 'ccc.out'], "repository/ccc.in\n")
+
+#
+test.pass_test()
diff --git a/test/Glob/basic.py b/test/Glob/basic.py
new file mode 100644
index 0000000..2e7427a
--- /dev/null
+++ b/test/Glob/basic.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify basic operation of the Glob() function.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+env = Environment()
+
+def concatenate(target, source, env):
+ fp = open(str(target[0]), 'wb')
+ for s in source:
+ fp.write(open(str(s), 'rb').read())
+ fp.close()
+
+env['BUILDERS']['Concatenate'] = Builder(action=concatenate)
+
+f_in = Glob('f*.in')
+f_in.sort(lambda a,b: cmp(a.name, b.name))
+env.Concatenate('f.out', f_in)
+""")
+
+test.write('f1.in', "f1.in\n")
+test.write('f2.in', "f2.in\n")
+test.write('f3.in', "f3.in\n")
+
+test.run(arguments = '.')
+
+test.must_match('f.out', "f1.in\nf2.in\nf3.in\n")
+
+test.pass_test()
diff --git a/test/Glob/source.py b/test/Glob/source.py
new file mode 100644
index 0000000..b82e1d9
--- /dev/null
+++ b/test/Glob/source.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that use of the Glob() function within a BuildDir() returns the
+file Nodes in the source directory when the source= keyword argument is
+specified (and duplicate=0 is specified for the BuildDir()).
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('src', 'var1', 'var2')
+
+test.write('SConstruct', """\
+env = Environment()
+
+def concatenate(target, source, env):
+ fp = open(str(target[0]), 'wb')
+ for s in source:
+ fp.write(open(str(s), 'rb').read())
+ fp.close()
+
+env['BUILDERS']['Concatenate'] = Builder(action=concatenate)
+
+Export("env")
+
+BuildDir('var1', 'src', duplicate=0)
+BuildDir('var2', 'src', duplicate=0)
+
+SConscript('var1/SConscript')
+SConscript('var2/SConscript')
+""")
+
+test.write(['var1', 'SConscript'], """\
+Import("env")
+
+f_in = Glob('f[45].in', source=True)
+f_in.sort(lambda a,b: cmp(a.name, b.name))
+env.Concatenate('f.out', f_in)
+""")
+
+test.write(['var2', 'SConscript'], """\
+Import("env")
+
+f_in = Glob('f[67].in')
+f_in.sort(lambda a,b: cmp(a.name, b.name))
+env.Concatenate('f.out', f_in)
+""")
+
+test.write(['src', 'f1.in'], "src/f1.in\n")
+test.write(['src', 'f2.in'], "src/f2.in\n")
+
+test.write(['src', 'f4.in'], "src/f4.in\n")
+test.write(['src', 'f5.in'], "src/f5.in\n")
+test.write(['src', 'f6.in'], "src/f6.in\n")
+test.write(['src', 'f7.in'], "src/f7.in\n")
+
+test.run(arguments = '.')
+
+test.must_match(['var1', 'f.out'], "src/f4.in\nsrc/f5.in\n")
+test.must_match(['var2', 'f.out'], "src/f6.in\nsrc/f7.in\n")
+
+test.pass_test()
diff --git a/test/Glob/strings.py b/test/Glob/strings.py
new file mode 100644
index 0000000..d9f8ff1
--- /dev/null
+++ b/test/Glob/strings.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that use of the Glob() function with the strings= option works
+when they're used in the same SConscript file (and therefore the same
+directory) as input to a Builder call.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('src')
+
+test.write('SConstruct', """\
+BuildDir('var1', 'src')
+BuildDir('var2', 'src')
+
+SConscript('var1/SConscript')
+SConscript('var2/SConscript')
+""")
+
+test.write(['src', 'SConscript'], """\
+env = Environment()
+
+def concatenate(target, source, env):
+ fp = open(str(target[0]), 'wb')
+ for s in source:
+ fp.write(open(str(s), 'rb').read())
+ fp.close()
+
+env['BUILDERS']['Concatenate'] = Builder(action=concatenate)
+
+f_in = Glob('f*.in', strings=True)
+f_in.sort()
+env.Concatenate('f.out', f_in)
+""")
+
+test.write(['src', 'f1.in'], "src/f1.in\n")
+test.write(['src', 'f2.in'], "src/f2.in\n")
+test.write(['src', 'f3.in'], "src/f3.in\n")
+
+test.run(arguments = '.')
+
+test.must_match(['var1', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n")
+test.must_match(['var2', 'f.out'], "src/f1.in\nsrc/f2.in\nsrc/f3.in\n")
+
+test.pass_test()
diff --git a/test/Glob/subdir.py b/test/Glob/subdir.py
new file mode 100644
index 0000000..b4e89e8
--- /dev/null
+++ b/test/Glob/subdir.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that Glob() works to find Nodes underneath an explicitly-
+named subdirectory.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('subdir')
+
+test.write('SConstruct', """\
+env = Environment()
+
+def concatenate(target, source, env):
+ fp = open(str(target[0]), 'wb')
+ for s in source:
+ fp.write(open(str(s), 'rb').read())
+ fp.close()
+
+env['BUILDERS']['Concatenate'] = Builder(action=concatenate)
+
+f_in = Glob('subdir/*.in')
+f_in.sort(lambda a,b: cmp(a.name, b.name))
+env.Concatenate('f.out', f_in)
+""")
+
+test.write(['subdir', 'file.in'], "subdir/file.in\n")
+
+test.run(arguments = '.')
+
+test.must_match('f.out', "subdir/file.in\n")
+
+test.pass_test()
diff --git a/test/Glob/subst.py b/test/Glob/subst.py
new file mode 100644
index 0000000..e6aa3ca
--- /dev/null
+++ b/test/Glob/subst.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify the ability to Glob() using a pattern from a construction variable
+expansion.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+env = Environment(PATTERN = 'f*.in')
+
+def copy(target, source, env):
+ fp = open(str(target[0]), 'wb')
+ for s in source:
+ fp.write(open(str(s), 'rb').read())
+ fp.close()
+
+env['BUILDERS']['Copy'] = Builder(action=copy)
+
+f_in = env.Glob('$PATTERN')
+f_in.sort(lambda a,b: cmp(a.name, b.name))
+env.Copy('f.out', f_in)
+""")
+
+test.write('f1.in', "f1.in\n")
+test.write('f2.in', "f2.in\n")
+test.write('f3.in', "f3.in\n")
+
+test.run(arguments = '.')
+
+test.must_match('f.out', "f1.in\nf2.in\nf3.in\n")
+
+test.pass_test()
diff --git a/test/Install/Clone.py b/test/Install/Clone.py
new file mode 100644
index 0000000..65770d2
--- /dev/null
+++ b/test/Install/Clone.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that we can Install() and InstallAs() from a construction
+environment cloned from a clone.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+env1 = Environment(DESTDIR='sub1', tools=[])
+
+# Call env1.Install() but not env1.InstallAs() *before* we clone it.
+# This is to verify that re-initializing the Install() attribute on the
+# construction environment doesn't mess up the environment settings in
+# a way that leaves the InstallAs() intializer in place, which leads to
+# infinite recursion.
+env1.Install('$DESTDIR', 'foo.in')
+
+env2 = env1.Clone(DESTDIR='sub2')
+env3 = env2.Clone(DESTDIR='sub3')
+
+env2.Install('$DESTDIR', 'foo.in')
+env3.Install('$DESTDIR', 'foo.in')
+
+env1.InstallAs('$DESTDIR/foo.out', 'foo.in')
+env2.InstallAs('$DESTDIR/foo.out', 'foo.in')
+env3.InstallAs('$DESTDIR/foo.out', 'foo.in')
+""")
+
+test.write('foo.in', "foo.in\n")
+
+test.run(arguments = '.')
+
+test.must_match(['sub1', 'foo.in'], "foo.in\n")
+test.must_match(['sub2', 'foo.in'], "foo.in\n")
+test.must_match(['sub3', 'foo.in'], "foo.in\n")
+
+test.must_match(['sub1', 'foo.out'], "foo.in\n")
+test.must_match(['sub2', 'foo.out'], "foo.in\n")
+test.must_match(['sub3', 'foo.out'], "foo.in\n")
+
+test.pass_test()
diff --git a/test/LINK/SHLINKCOMSTR.py b/test/LINK/SHLINKCOMSTR.py
index cf31813..94740b8 100644
--- a/test/LINK/SHLINKCOMSTR.py
+++ b/test/LINK/SHLINKCOMSTR.py
@@ -64,6 +64,7 @@ test.write('SConstruct', """
env = Environment(SHCCCOM = r'%(_python_)s mycc.py $TARGET $SOURCES',
SHLINKCOM = r'%(_python_)s mylink.py $TARGET $SOURCES',
SHLINKCOMSTR = 'Linking shared $TARGET from $SOURCES',
+ SHOBJPREFIX = '',
SHOBJSUFFIX = '.obj',
SHLIBPREFIX = '',
SHLIBSUFFIX = '.dll')
diff --git a/test/Library.py b/test/Library.py
index 3a04b9c..4bcb2c7 100644
--- a/test/Library.py
+++ b/test/Library.py
@@ -114,7 +114,7 @@ void f3c(void);
int
main(int argc, char *argv[])
{
- argv[argc++] = "--";
+ argv[argc++] = (char *)"--";
f1();
f2a();
f2b();
diff --git a/test/MSVC/multiple-pdb.py b/test/MSVC/multiple-pdb.py
index f359fb9..feb3fd9 100644
--- a/test/MSVC/multiple-pdb.py
+++ b/test/MSVC/multiple-pdb.py
@@ -46,7 +46,7 @@ if sys.platform != 'win32':
test.skip_test(msg)
test.write('SConstruct', """\
-env = Environment(PDB = '${TARGET}.pdb')
+env = Environment(PDB = '${TARGET.base}.pdb')
env.Program('test1.cpp')
env.Program('test2.cpp')
""")
@@ -75,9 +75,9 @@ main(int argc, char *argv)
test.run(arguments = '.')
-test.must_exist('test1%s' % _exe)
-test.must_exist('test1%s.pdb' % _exe)
-test.must_exist('test2%s' % _exe)
-test.must_exist('test2%s.pdb' % _exe)
+test.must_exist('test1%s' % _exe)
+test.must_exist('test1.pdb')
+test.must_exist('test2%s' % _exe)
+test.must_exist('test2.pdb')
test.pass_test()
diff --git a/test/Mkdir.py b/test/Mkdir.py
index cbf465e..00b222b 100644
--- a/test/Mkdir.py
+++ b/test/Mkdir.py
@@ -38,6 +38,7 @@ test.subdir('work1', 'work2')
test.write(['work1', 'SConstruct'], """
Execute(Mkdir('d1'))
+Execute(Mkdir(Dir('#d1-Dir')))
def cat(env, source, target):
target = str(target[0])
source = map(str, source)
@@ -64,7 +65,7 @@ test.write(['work1', 'f2.in'], "f2.in\n")
test.write(['work1', 'f5.in'], "f5.in\n")
test.write(['work1', 'f6.in'], "f6.in\n")
-expect = test.wrap_stdout(read_str = 'Mkdir("d1")\n',
+expect = test.wrap_stdout(read_str = 'Mkdir("d1")\nMkdir("d1-Dir")\n',
build_str = """\
cat(["f2.out"], ["f2.in"])
Mkdir("d3")
@@ -79,6 +80,7 @@ Touch("%s")
test.run(chdir = 'work1', options = '-n', arguments = '.', stdout = expect)
test.must_not_exist(['work1', 'd1'])
+test.must_not_exist(['work1', 'd1-Dir'])
test.must_not_exist(['work1', 'f2.out'])
test.must_not_exist(['work1', 'd3'])
test.must_not_exist(['work1', 'd4'])
@@ -90,6 +92,7 @@ test.must_not_exist(['work1', 'f6.out-Mkdir'])
test.run(chdir = 'work1')
test.must_exist(['work1', 'd1'])
+test.must_exist(['work1', 'd1-Dir'])
test.must_match(['work1', 'f2.out'], "f2.in\n")
test.must_exist(['work1', 'd3'])
test.must_exist(['work1', 'd4'])
diff --git a/test/Move.py b/test/Move.py
index c1cdcfd..ba55581 100644
--- a/test/Move.py
+++ b/test/Move.py
@@ -34,6 +34,7 @@ test = TestSCons.TestSCons()
test.write('SConstruct', """
Execute(Move('f1.out', 'f1.in'))
+Execute(Move('File-f1.out', File('f1.in-File')))
def cat(env, source, target):
target = str(target[0])
source = map(str, source)
@@ -50,6 +51,7 @@ env.Command('f6.out', 'f6.in', [Cat, Move("Move-$TARGET", "$SOURCE-Move")])
""")
test.write('f1.in', "f1.in\n")
+test.write('f1.in-File', "f1.in-File\n")
test.write('f2.in', "f2.in\n")
test.write('f3.in', "f3.in\n")
test.write('f4.in', "f4.in\n")
@@ -57,7 +59,10 @@ test.write('f5.in', "f5.in\n")
test.write('f6.in', "f6.in\n")
test.write('f6.in-Move', "f6.in-Move\n")
-expect = test.wrap_stdout(read_str = 'Move("f1.out", "f1.in")\n',
+expect = test.wrap_stdout(read_str = """\
+Move("f1.out", "f1.in")
+Move("File-f1.out", "f1.in-File")
+""",
build_str = """\
cat(["f2.out"], ["f2.in"])
Move("f3.out", "f3.in")
@@ -69,6 +74,7 @@ Move("Move-f6.out", "f6.in-Move")
test.run(options = '-n', arguments = '.', stdout = expect)
test.must_not_exist('f1.out')
+test.must_not_exist('File-f1.out')
test.must_not_exist('f2.out')
test.must_not_exist('f3.out')
test.must_not_exist('f4.out')
@@ -79,6 +85,7 @@ test.must_not_exist('Move-f6.out')
test.run()
test.must_match('f1.out', "f1.in\n")
+test.must_match('File-f1.out', "f1.in-File\n")
test.must_match('f2.out', "f2.in\n")
test.must_not_exist('f3.in')
test.must_match('f3.out', "f3.in\n")
diff --git a/test/NodeOps.py b/test/NodeOps.py
index 7e656f7..b23a8d4 100644
--- a/test/NodeOps.py
+++ b/test/NodeOps.py
@@ -59,8 +59,8 @@ barflags = e['SHCXXFLAGS'] + ' -DBAR'
test.subdir('bld', 'src', ['src', 'subsrcdir'])
sconstruct = r"""
-foo = Environment(SHCXXFLAGS = '%(fooflags)s', WINDOWS_INSERT_DEF=1)
-bar = Environment(SHCXXFLAGS = '%(barflags)s', WINDOWS_INSERT_DEF=1)
+foo = Environment(SHOBJPREFIX='', SHCXXFLAGS = '%(fooflags)s', WINDOWS_INSERT_DEF=1)
+bar = Environment(SHOBJPREFIX='', SHCXXFLAGS = '%(barflags)s', WINDOWS_INSERT_DEF=1)
src = Dir('src')
BuildDir('bld', src, duplicate=1)
Nodes=[]
diff --git a/test/Object.py b/test/Object.py
index da945e3..108960d 100644
--- a/test/Object.py
+++ b/test/Object.py
@@ -100,7 +100,7 @@ extern "C" void f3(void);
int
main(int argc, char *argv[])
{
- argv[argc++] = "--";
+ argv[argc++] = (char *)"--";
f1();
f2();
f3();
diff --git a/test/Options/chdir.py b/test/Options/chdir.py
new file mode 100644
index 0000000..7ba85ea
--- /dev/null
+++ b/test/Options/chdir.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that we can chdir() to the directory in which an Options
+file lives by using the __name__ value.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('bin', 'subdir')
+
+test.write('SConstruct', """\
+opts = Options('../bin/opts.cfg', ARGUMENTS)
+opts.Add('VARIABLE')
+Export("opts")
+SConscript('subdir/SConscript')
+""")
+
+SConscript_contents = """\
+Import("opts")
+env = Environment()
+opts.Update(env)
+print "VARIABLE =", repr(env['VARIABLE'])
+"""
+
+test.write(['bin', 'opts.cfg'], """\
+import os
+import os.path
+os.chdir(os.path.split(__name__)[0])
+execfile('opts2.cfg')
+""")
+
+test.write(['bin', 'opts2.cfg'], """\
+VARIABLE = 'opts2.cfg value'
+""")
+
+test.write(['subdir', 'SConscript'], SConscript_contents)
+
+expect = """\
+VARIABLE = 'opts2.cfg value'
+"""
+
+test.run(arguments = '-q -Q .', stdout=expect)
+
+test.pass_test()
diff --git a/test/Options/import.py b/test/Options/import.py
new file mode 100644
index 0000000..0a3d367
--- /dev/null
+++ b/test/Options/import.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that an Options file in a different directory can import
+a module in that directory.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+workpath = test.workpath('')
+
+test.subdir('bin', 'subdir')
+
+test.write('SConstruct', """\
+opts = Options('../bin/opts.cfg', ARGUMENTS)
+opts.Add('VARIABLE')
+Export("opts")
+SConscript('subdir/SConscript')
+""")
+
+SConscript_contents = """\
+Import("opts")
+env = Environment()
+opts.Update(env)
+print "VARIABLE =", env.get('VARIABLE')
+"""
+
+test.write(['bin', 'opts.cfg'], """\
+import sys
+from local_options import VARIABLE
+""" % locals())
+
+test.write(['bin', 'local_options.py'], """\
+VARIABLE = 'bin/local_options.py'
+""")
+
+test.write(['subdir', 'SConscript'], SConscript_contents)
+
+expect = "VARIABLE = bin/local_options.py\n"
+
+test.run(arguments = '-q -Q .', stdout = expect)
+
+test.pass_test()
diff --git a/test/Parallel/duplicate-target.py b/test/Parallel/duplicate-target.py
index 5d4f5e1..43015fe 100644
--- a/test/Parallel/duplicate-target.py
+++ b/test/Parallel/duplicate-target.py
@@ -41,34 +41,58 @@ _python_ = TestSCons._python_
test = TestSCons.TestSCons()
-test.subdir('work')
+test.subdir('work', ['work', 'sub'])
tar_output = test.workpath('work.tar')
-test.write(['work', 'copy.py'], """\
+test.write(['work', 'mycopy.py'], """\
import sys
import time
time.sleep(int(sys.argv[1]))
open(sys.argv[2], 'wb').write(open(sys.argv[3], 'rb').read())
""")
+test.write(['work', 'mytar.py'], """\
+import sys
+import os.path
+
+def visit(arg, dirname, fnames):
+ fnames.sort()
+ for fn in fnames:
+ p = os.path.join(dirname, fn)
+ if os.path.isfile(p):
+ arg.write(open(p, 'rb').read())
+
+fp = open(sys.argv[1], 'wb')
+for s in sys.argv[2:]:
+ os.path.walk(s, visit, fp)
+""")
+
test.write(['work', 'SConstruct'], """\
env = Environment()
-out1 = File('f1.out')
-out2 = File('f2.out')
-env.Command([out1, out1], 'f1.in', r'%(_python_)s copy.py 3 $TARGET $SOURCE')
-env.Command([out2, out2], 'f2.in', r'%(_python_)s copy.py 3 $TARGET $SOURCE')
+out1 = File('sub/f1.out')
+out2 = File('sub/f2.out')
+env.Command([out1, out1], 'sub/f1.in',
+ r'%(_python_)s mycopy.py 3 $TARGET $SOURCE')
+env.Command([out2, out2], 'sub/f2.in',
+ r'%(_python_)s mycopy.py 3 $TARGET $SOURCE')
-env.Tar(r'%(tar_output)s', Dir('.'))
+env.Command(r'%(tar_output)s', Dir('sub'),
+ r'%(_python_)s mytar.py $TARGET $SOURCE')
""" % locals())
-test.write(['work', 'f1.in'], "work/f1.in\n")
-test.write(['work', 'f2.in'], "work/f2.in\n")
+test.write(['work', 'sub', 'f1.in'], "work/sub/f1.in\n")
+test.write(['work', 'sub', 'f2.in'], "work/sub/f2.in\n")
test.run(chdir = 'work', arguments = tar_output + ' -j2')
-test.must_match(['work', 'f1.out'], "work/f1.in\n")
-test.must_match(['work', 'f2.out'], "work/f2.in\n")
-test.must_exist(tar_output)
+test.must_match(['work', 'sub', 'f1.out'], "work/sub/f1.in\n")
+test.must_match(['work', 'sub', 'f2.out'], "work/sub/f2.in\n")
+test.must_match(tar_output, """\
+work/sub/f1.in
+work/sub/f1.in
+work/sub/f2.in
+work/sub/f2.in
+""")
test.pass_test()
diff --git a/test/Parallel/failed-build.py b/test/Parallel/failed-build.py
new file mode 100644
index 0000000..64e90c9
--- /dev/null
+++ b/test/Parallel/failed-build.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+"""
+Verify that a failed build action with -j works as expected.
+"""
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+try:
+ import threading
+except ImportError:
+ # if threads are not supported, then
+ # there is nothing to test
+ TestCmd.no_result()
+ sys.exit()
+
+
+test = TestSCons.TestSCons()
+
+# We want to verify that -j 2 starts precisely two jobs, the first of
+# which fails and the second of which succeeds, and then stops processing
+# due to the first build failure. To try to control the timing, the two
+# created build scripts use a pair of marker directories.
+#
+# The failure script waits until it sees the 'mycopy.started' directory
+# that indicates the successful script has, in fact, gotten started.
+# If we don't wait, then SCons could detect our script failure early
+# (typically if a high system load happens to delay SCons' ability to
+# start the next script) and then not start the successful script at all.
+#
+# The successful script waits until it sees the 'myfail.exiting' directory
+# that indicates the failure script has finished (with everything except
+# the final sys.exit(), that is). If we don't wait for that, then SCons
+# could detect our successful exit first (typically if a high system
+# load happens to delay the failure script) and start another job before
+# it sees the failure from the first script.
+
+test.write('myfail.py', r"""\
+import os.path
+import sys
+import time
+while not os.path.exists('mycopy.started'):
+ time.sleep(1)
+os.mkdir('myfail.exiting')
+sys.exit(1)
+""")
+
+test.write('mycopy.py', r"""\
+import os
+import sys
+import time
+os.mkdir('mycopy.started')
+open(sys.argv[1], 'wb').write(open(sys.argv[2], 'rb').read())
+while not os.path.exists('myfail.exiting'):
+ time.sleep(1)
+sys.exit(0)
+""")
+
+test.write('SConstruct', """
+MyCopy = Builder(action = r'%(_python_)s mycopy.py $TARGET $SOURCE')
+Fail = Builder(action = r'%(_python_)s myfail.py $TARGETS $SOURCE')
+env = Environment(BUILDERS = { 'MyCopy' : MyCopy, 'Fail' : Fail })
+env.Fail(target = 'f3', source = 'f3.in')
+env.MyCopy(target = 'f4', source = 'f4.in')
+env.MyCopy(target = 'f5', source = 'f5.in')
+env.MyCopy(target = 'f6', source = 'f6.in')
+""" % locals())
+
+test.write('f3.in', "f3.in\n")
+test.write('f4.in', "f4.in\n")
+test.write('f5.in', "f5.in\n")
+test.write('f6.in', "f6.in\n")
+
+test.run(arguments = '-j 2 .',
+ status = 2,
+ stderr = "scons: *** [f3] Error 1\n")
+
+test.must_not_exist(test.workpath('f3'))
+test.must_match(test.workpath('f4'), 'f4.in\n')
+test.must_not_exist(test.workpath('f5'))
+test.must_not_exist(test.workpath('f6'))
+
+
+
+test.pass_test()
diff --git a/test/Repository/variants.py b/test/Repository/variants.py
index cd4c24a..d124431 100644
--- a/test/Repository/variants.py
+++ b/test/Repository/variants.py
@@ -204,7 +204,8 @@ test.write(['repository', 'src2', 'xxx', 'main.c'], r"""
#ifdef BAR
#define MAIN_OS "BAR"
#endif
-main()
+int
+main(int argc, char *argv[])
{
printf(INCLUDE_STRING, INCLUDE_OS);
printf(XXX_STRING, XXX_OS);
diff --git a/test/Requires/basic.py b/test/Requires/basic.py
new file mode 100644
index 0000000..59cdd37
--- /dev/null
+++ b/test/Requires/basic.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify basic operation of the env.Requires() method for specifying
+order-only prerequisites.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+def append_prereq_func(target, source, env):
+ fp = open(str(target[0]), 'wb')
+ for s in map(str, source):
+ fp.write(open(s, 'rb').read())
+ fp.write(open('prereq.out', 'rb').read())
+ fp.close()
+ return None
+append_prereq = Action(append_prereq_func)
+env = Environment()
+env.Requires('file.out', 'prereq.out')
+env.Command('file.out', 'file.in', append_prereq)
+env.Command('prereq.out', 'prereq.in', Copy('$TARGET', '$SOURCES'))
+""")
+
+test.write('file.in', "file.in 1\n")
+test.write('prereq.in', "prereq.in 1\n")
+
+# First: build file.out. prereq.out should be built first, and if
+# not, we'll get an error when the build action tries to use it to
+# build file.out.
+
+test.run(arguments = 'file.out')
+
+test.must_match('prereq.out', "prereq.in 1\n")
+test.must_match('file.out', "file.in 1\nprereq.in 1\n")
+
+# Update the prereq.out file. file.out should still be up to date because
+# prereq.out is not actually a dependency, so we don't detect the
+# underlying change.
+
+test.write('prereq.out', "prereq.out 2\n")
+
+test.up_to_date(arguments = 'file.out')
+
+# Now update the prereq.in file. Trying to rebuild file.out should
+# cause prereq.out to be updated because of the change, but file.out
+# should *not* be rebuilt because, again, prereq.out isn't actually
+# a dependency that causes rebuilds.
+
+test.write('prereq.in', "prereq.in 3\n")
+
+test.run(arguments = 'file.out')
+
+test.must_match('prereq.out', "prereq.in 3\n")
+test.must_match('file.out', "file.in 1\nprereq.in 1\n")
+
+# Now update file.in, which will cause file.out to be rebuilt, picking
+# up the change(s) to prereq.out of which we were previously oblivious.
+
+test.write('file.in', 'file.in 4\n')
+
+test.run(arguments = 'file.out')
+
+test.must_match('prereq.out', "prereq.in 3\n")
+test.must_match('file.out', "file.in 4\nprereq.in 3\n")
+
+
+
+test.pass_test()
diff --git a/test/Scanner/no-Dir-node.py b/test/Scanner/no-Dir-node.py
new file mode 100644
index 0000000..b5706e3
--- /dev/null
+++ b/test/Scanner/no-Dir-node.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that use of a Scanner that searches a *PATH list doesn't create
+nodes for directories that don't exist, so they don't get picked up
+by DirScanner.
+
+Under the covers, this tests the behavior of the SCons.Node.FS.find_file()
+utility function that is used by the Scanner.Classic class to search
+directories in variables such as $CPPPATH.
+"""
+
+import os.path
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+subdir_SConscript = os.path.join('subdir', 'SConscript')
+subdir_foo = os.path.join('subdir', 'foo')
+subdir_foo_k = os.path.join('subdir', 'foo.k')
+
+test.subdir('subdir', 'inc1', 'inc2')
+
+inc2_include_h = test.workpath('inc2', 'include.h')
+
+test.write('build.py', r"""
+import os.path
+import string
+import sys
+path = string.split(sys.argv[1])
+input = open(sys.argv[2], 'rb')
+output = open(sys.argv[3], 'wb')
+
+def find_file(f):
+ if os.path.isabs(f):
+ return open(f, 'rb')
+ for dir in path:
+ p = dir + os.sep + f
+ if os.path.exists(p):
+ return open(p, 'rb')
+ return None
+
+def process(infp, outfp):
+ for line in infp.readlines():
+ if line[:8] == 'include ':
+ file = line[8:-1]
+ process(find_file(file), outfp)
+ else:
+ outfp.write(line)
+
+process(input, output)
+
+sys.exit(0)
+""")
+
+test.write('SConstruct', """\
+def foo(target, source, env):
+ children = source[0].children()
+ children.sort(lambda a,b: cmp(a.name, b.name))
+ fp = open(str(target[0]), 'wb')
+ for c in children:
+ fp.write('%s\\n' % c)
+ fp.close()
+Command('list.out', 'subdir', foo, source_scanner = DirScanner)
+SConscript('subdir/SConscript')
+""")
+
+test.write(['subdir', 'SConscript'], """\
+import SCons.Scanner
+kscan = SCons.Scanner.Classic(name = 'kfile',
+ suffixes = ['.k'],
+ path_variable = 'KPATH',
+ regex = r'^include\s+(\S+)$')
+
+env = Environment(KPATH=['.', '..'])
+env.Append(SCANNERS = kscan)
+
+env.Command('foo', 'foo.k', r'%(_python_)s build.py "$KPATH" $SOURCES $TARGET')
+""" % locals())
+
+test.write(['subdir', 'foo.k'], """\
+subdir/foo.k
+include inc1/include.h
+include %(inc2_include_h)s
+""" % locals())
+
+test.write(['inc1', 'include.h'], """\
+inc1/include.h
+""")
+
+test.write(['inc2', 'include.h'], """\
+inc2/include.h
+""")
+
+test.run(arguments = '.')
+
+test.must_match('subdir/foo', """\
+subdir/foo.k
+inc1/include.h
+inc2/include.h
+""")
+
+test.must_match('list.out', """\
+%(subdir_SConscript)s
+%(subdir_foo)s
+%(subdir_foo_k)s
+""" % locals())
+
+test.pass_test()
diff --git a/test/Touch.py b/test/Touch.py
index b41db25..6ecc3ff 100644
--- a/test/Touch.py
+++ b/test/Touch.py
@@ -36,6 +36,7 @@ test = TestSCons.TestSCons()
test.write('SConstruct', """
Execute(Touch('f1'))
+Execute(Touch(File('f1-File')))
def cat(env, source, target):
target = str(target[0])
source = map(str, source)
@@ -54,13 +55,18 @@ env.Command('f6.out', 'f6.in', [Cat,
""")
test.write('f1', "f1\n")
+test.write('f1-File', "f1-File\n")
test.write('f2.in', "f2.in\n")
test.write('f5.in', "f5.in\n")
test.write('f6.in', "f6.in\n")
-oldtime = os.path.getmtime(test.workpath('f1'))
+old_f1_time = os.path.getmtime(test.workpath('f1'))
+old_f1_File_time = os.path.getmtime(test.workpath('f1-File'))
-expect = test.wrap_stdout(read_str = 'Touch("f1")\n',
+expect = test.wrap_stdout(read_str = """\
+Touch("f1")
+Touch("f1-File")
+""",
build_str = """\
cat(["f2.out"], ["f2.in"])
Touch("f3")
@@ -74,8 +80,10 @@ test.run(options = '-n', arguments = '.', stdout = expect)
test.sleep(2)
-newtime = os.path.getmtime(test.workpath('f1'))
-test.fail_test(oldtime != newtime)
+new_f1_time = os.path.getmtime(test.workpath('f1'))
+test.fail_test(old_f1_time != new_f1_time)
+new_f1_File_time = os.path.getmtime(test.workpath('f1-File'))
+test.fail_test(old_f1_File_time != new_f1_File_time)
test.must_not_exist(test.workpath('f2.out'))
test.must_not_exist(test.workpath('f3'))
@@ -87,8 +95,10 @@ test.must_not_exist(test.workpath('f6.out-Touch'))
test.run()
-newtime = os.path.getmtime(test.workpath('f1'))
-test.fail_test(oldtime == newtime)
+new_f1_time = os.path.getmtime(test.workpath('f1'))
+test.fail_test(old_f1_time == new_f1_time)
+new_f1_File_time = os.path.getmtime(test.workpath('f1-File'))
+test.fail_test(old_f1_File_time == new_f1_File_time)
test.must_match('f2.out', "f2.in\n")
test.must_exist(test.workpath('f3'))
diff --git a/test/implicit-cache/DualTargets.py b/test/implicit-cache/DualTargets.py
new file mode 100644
index 0000000..cf41640
--- /dev/null
+++ b/test/implicit-cache/DualTargets.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test that --implicit-cache works correctly in conjonction with a
+builder that produces multiple targets.
+"""
+
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+import os.path
+
+def emitter(target, source, env):
+ tgt0 = target[0].abspath
+ base,ext = os.path.splitext(tgt0)
+ target.append(base + '.b')
+ return(target, source)
+
+
+def source_scan(node, env, path):
+ path = node.abspath
+ base,ext = os.path.splitext(path)
+ return [base + '.lib']
+
+
+env = Environment()
+env['BUILDERS']['DualTarget'] = Builder(
+ action = Action(
+ [
+ Copy( '$TARGET', '$SOURCE' ),
+ Copy( '${TARGET.base}.b', '$SOURCE' ),
+ ],
+ ),
+ suffix = '.a',
+ src_suffix = '.cpp',
+ single_source = True,
+ emitter=emitter,
+ source_scanner=Scanner(source_scan),
+ )
+
+env.Command( 'x.cpp', '', Touch('$TARGET') )
+env.Command( 'x.lib', '', Touch('$TARGET') )
+
+env.DualTarget('x.cpp')
+""" % locals())
+
+test.must_not_exist('x.cpp')
+test.must_not_exist('x.lib')
+test.must_not_exist('x.a')
+test.must_not_exist('x.b')
+
+# Build everything first.
+test.run(arguments = '.')
+test.must_exist('x.cpp')
+test.must_exist('x.lib')
+test.must_exist('x.a')
+test.must_exist('x.b')
+
+test.fail_test(string.find(test.stdout(), 'Copy') == -1)
+
+# Double check that targets are not rebuilt.
+test.run(arguments = '.')
+test.must_exist('x.cpp')
+test.must_exist('x.lib')
+test.must_exist('x.a')
+test.must_exist('x.b')
+
+test.fail_test(string.find(test.stdout(), 'Copy') != -1)
+
+# Double check that targets are not rebuilt even with --implicit-cache
+test.run(arguments = '--implicit-cache x.a')
+test.must_exist('x.cpp')
+test.must_exist('x.lib')
+test.must_exist('x.a')
+test.must_exist('x.b')
+
+test.fail_test(string.find(test.stdout(), 'Copy') != -1)
+
+# Double check that targets are not rebuilt even with --implicit-cache
+# a second time.
+test.run(arguments = '--implicit-cache x.a')
+test.must_exist('x.cpp')
+test.must_exist('x.lib')
+test.must_exist('x.a')
+test.must_exist('x.b')
+
+test.fail_test(string.find(test.stdout(), 'Copy') != -1)
+
+# Double check that targets are not rebuilt if we reran without
+# --implicit-cache
+test.run(arguments = '.')
+test.must_exist('x.cpp')
+test.must_exist('x.lib')
+test.must_exist('x.a')
+test.must_exist('x.b')
+
+test.fail_test(string.find(test.stdout(), 'Copy') != -1)
+
+# Double check again
+test.run(arguments = '.')
+test.must_exist('x.cpp')
+test.must_exist('x.lib')
+test.must_exist('x.a')
+test.must_exist('x.b')
+
+test.fail_test(string.find(test.stdout(), 'Copy') != -1)
+
+# Then only of the targets using --implicit-cache
+test.pass_test()
diff --git a/test/no-global-dependencies.py b/test/no-global-dependencies.py
new file mode 100644
index 0000000..3cdea1b
--- /dev/null
+++ b/test/no-global-dependencies.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test that files are correctly located in the build directory even when
+Scons does not have a global view of all targets.
+
+Sometimes, it might be interesting to not tell scons about every
+targets. For example, one might not read in all the SConscipts of a
+hierarchical build for a particular invocation of scons. This would be
+done to speed-up a partial rebuild when the developer knows that only
+a subset of the targets need to be rebuilt.
+"""
+
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('dir1')
+test.subdir('dir2')
+
+test.write('SConstruct', """\
+opts = Options()
+opts.AddOptions(
+ BoolOption('view_all_dependencies', 'View all dependencies', True),
+ BoolOption('duplicate', 'Duplicate sources to build dir', True)
+)
+
+env = Environment(options=opts)
+Export('env')
+
+SConscript(dirs='.', build_dir='build', duplicate=env['duplicate'])
+""" % locals())
+
+
+test.write('SConscript', """\
+Import('env')
+
+if env['view_all_dependencies']:
+ SConscript(dirs='dir1')
+
+SConscript(dirs='dir2')
+""" % locals())
+
+test.write('dir1/SConscript', """\
+Import('env')
+
+env.Command('x.cpp', '', Touch('$TARGET'))
+
+env.Object(env.File('x.cpp'))
+""" % locals())
+
+test.write('dir2/SConscript', """\
+Import('env')
+
+env.Object(env.File('#/build/dir1/x.cpp'))
+""" % locals())
+
+test.must_not_exist('build/dir1/x.cpp')
+
+
+############################################################
+#
+# Test without duplication
+#
+
+# Build everything first.
+test.run(arguments = 'duplicate=False view_all_dependencies=True .')
+test.must_exist('build/dir1/x.cpp')
+test.fail_test(string.find(test.stdout(), "`.' is up to date.") != -1)
+
+# Double check that targets are not rebuilt.
+test.run(arguments = 'duplicate=False view_all_dependencies=True .')
+test.must_exist('build/dir1/x.cpp')
+test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1)
+
+# Clean-up only the object file
+test.run(arguments = 'duplicate=False view_all_dependencies=False -c .')
+test.must_exist('build/dir1/x.cpp')
+
+# Rebuild the only object file without seeing all the dependencies.
+test.run(arguments = 'duplicate=False view_all_dependencies=False .')
+test.must_exist('build/dir1/x.cpp')
+test.fail_test(string.find(test.stdout(), "`.' is up to date.") != -1)
+
+# Double check that targets are not rebuilt without and with all the
+# dependencies.
+test.run(arguments = 'duplicate=False view_all_dependencies=False .')
+test.must_exist('build/dir1/x.cpp')
+test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1)
+
+test.run(arguments = 'duplicate=False view_all_dependencies=True .')
+test.must_exist('build/dir1/x.cpp')
+test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1)
+
+# Clean-up everything.
+test.run(arguments = 'duplicate=False view_all_dependencies=True -c .')
+test.must_not_exist('build/dir1/x.cpp')
+
+
+############################################################
+#
+# Test with duplication
+#
+# FIXME: This can not work for now because there is no way that SCons
+# can differentiate between a source that no longer exists and a file
+# that has a builder that scons does not know about because scons has
+# not parsed all the SConscript of a given project.
+#
+
+# # Build everything first.
+# test.run(arguments = 'duplicate=True view_all_dependencies=True .')
+# test.must_exist('build/dir1/x.cpp')
+# test.fail_test(string.find(test.stdout(), "`.' is up to date.") != -1)
+
+# # Double check that targets are not rebuilt.
+# test.run(arguments = 'duplicate=True view_all_dependencies=True .')
+# test.must_exist('build/dir1/x.cpp')
+# test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1)
+
+# # Clean-up only the object file
+# test.run(arguments = 'duplicate=True view_all_dependencies=False -c .')
+# test.must_exist('build/dir1/x.cpp')
+
+# # Rebuild the only object file without seeing all the dependencies.
+# test.run(arguments = 'duplicate=True view_all_dependencies=False .')
+# test.must_exist('build/dir1/x.cpp')
+# test.fail_test(string.find(test.stdout(), "`.' is up to date.") != -1)
+
+# # Double check that targets are not rebuilt without and with all the
+# # dependencies.
+# test.run(arguments = 'duplicate=True view_all_dependencies=False .')
+# test.must_exist('build/dir1/x.cpp')
+# test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1)
+
+# test.run(arguments = 'duplicate=True view_all_dependencies=True .')
+# test.must_exist('build/dir1/x.cpp')
+# test.fail_test(string.find(test.stdout(), "`.' is up to date.") == -1)
+
+# # Clean-up everything.
+# test.run(arguments = 'duplicate=True view_all_dependencies=True -c .')
+# test.must_not_exist('build/dir1/x.cpp')
+
+
+test.pass_test()
diff --git a/test/option-j.py b/test/option-j.py
index bc36f08..ffb290c 100644
--- a/test/option-j.py
+++ b/test/option-j.py
@@ -218,42 +218,5 @@ start2, finish1 = RunTest('-j 1 f1 f2', "fourth")
test.fail_test(start2 < finish1)
-# Test that a failed build with -j works properly.
-
-test.write('mycopy.py', r"""\
-import sys
-import time
-time.sleep(1)
-open(sys.argv[1], 'wb').write(open(sys.argv[2], 'rb').read())
-""")
-
-test.write('myfail.py', r"""\
-import sys
-sys.exit(1)
-""")
-
-test.write('SConstruct', """
-MyCopy = Builder(action = r'%(_python_)s mycopy.py $TARGET $SOURCE')
-Fail = Builder(action = r'%(_python_)s myfail.py $TARGETS $SOURCE')
-env = Environment(BUILDERS = { 'MyCopy' : MyCopy, 'Fail' : Fail })
-env.Fail(target = 'f3', source = 'f3.in')
-env.MyCopy(target = 'f4', source = 'f4.in')
-env.MyCopy(target = 'f5', source = 'f5.in')
-env.MyCopy(target = 'f6', source = 'f6.in')
-""" % locals())
-
-test.write('f3.in', "f3.in\n")
-test.write('f4.in', "f4.in\n")
-test.write('f5.in', "f5.in\n")
-test.write('f6.in', "f6.in\n")
-
-test.run(arguments = '-j 2 .',
- status = 2,
- stderr = "scons: *** [f3] Error 1\n")
-
-test.fail_test(os.path.exists(test.workpath('f3')))
-test.fail_test(test.read(test.workpath('f4')) != 'f4.in\n')
-test.fail_test(os.path.exists(test.workpath('f5')))
-test.fail_test(os.path.exists(test.workpath('f6')))
test.pass_test()
diff --git a/test/option/debug-dtree.py b/test/option/debug-dtree.py
index 06296b9..3ef396e 100644
--- a/test/option/debug-dtree.py
+++ b/test/option/debug-dtree.py
@@ -56,6 +56,7 @@ int main(int argc, char *argv[])
test.write('bar.c', """
#include "bar.h"
+int local = 1;
""")
test.write('foo.h', """
diff --git a/test/option/debug-includes.py b/test/option/debug-includes.py
index 52d64a9..172cbb0 100644
--- a/test/option/debug-includes.py
+++ b/test/option/debug-includes.py
@@ -56,6 +56,7 @@ int main(int argc, char *argv[])
test.write('bar.c', """
#include "bar.h"
+int local = 1;
""")
test.write('foo.h', """
diff --git a/test/option/debug-stree.py b/test/option/debug-stree.py
index d25b7fa..bf65dbb 100644
--- a/test/option/debug-stree.py
+++ b/test/option/debug-stree.py
@@ -60,6 +60,7 @@ int main(int argc, char *argv[])
test.write('bar.c', """
#include "bar.h"
+int local = 1;
""")
test.write('foo.h', """
diff --git a/test/option/debug-tree.py b/test/option/debug-tree.py
index 09cdffb..f581bc4 100644
--- a/test/option/debug-tree.py
+++ b/test/option/debug-tree.py
@@ -64,6 +64,7 @@ int main(int argc, char *argv[])
test.write('Bar.c', """
#include "Bar.h"
+int local = 1;
""")
test.write('Foo.h', """
diff --git a/test/option/tree-all.py b/test/option/tree-all.py
index 7940d47..163d286 100644
--- a/test/option/tree-all.py
+++ b/test/option/tree-all.py
@@ -64,6 +64,7 @@ int main(int argc, char *argv[])
test.write('Bar.c', """
#include "Bar.h"
+int local = 1;
""")
test.write('Foo.h', """
diff --git a/test/option/tree-derived.py b/test/option/tree-derived.py
index 3ccada8..43735f8 100644
--- a/test/option/tree-derived.py
+++ b/test/option/tree-derived.py
@@ -56,6 +56,7 @@ int main(int argc, char *argv[])
test.write('bar.c', """
#include "bar.h"
+int local = 1;
""")
test.write('foo.h', """
diff --git a/test/packaging/multiple-packages-at-once.py b/test/packaging/multiple-packages-at-once.py
index 3151c05..bbf273f 100644
--- a/test/packaging/multiple-packages-at-once.py
+++ b/test/packaging/multiple-packages-at-once.py
@@ -79,4 +79,21 @@ test.run(arguments='', stderr = None)
test.must_exist( 'src-1.0.zip' )
test.must_exist( 'src-1.0.tar.gz' )
+test.write('SConstruct', """
+Program( 'src/main.c' )
+env=Environment(tools=['default', 'packaging'])
+env.Package( PACKAGETYPE = ['src_zip', 'src_targz'],
+ NAME = "src", VERSION = "1.0",
+ PACKAGEROOT = 'test',
+ source = [ 'src/main.c', 'SConstruct' ],
+ target = 'src.zip' )
+""")
+
+test.run(arguments='', stderr = None)
+
+test.must_exist( 'src.zip' )
+test.must_exist( 'src-1.0.tar.gz' )
+
+
+
test.pass_test()
diff --git a/test/packaging/rpm/explicit-target.py b/test/packaging/rpm/explicit-target.py
index 12a6c6c..b9fcc0f 100644
--- a/test/packaging/rpm/explicit-target.py
+++ b/test/packaging/rpm/explicit-target.py
@@ -31,7 +31,6 @@ Test the ability to create a rpm package from a explicit target name.
import os
import TestSCons
-machine = TestSCons.machine
_python_ = TestSCons._python_
test = TestSCons.TestSCons()
@@ -81,15 +80,10 @@ env.Package( NAME = 'foo',
)
""" % locals())
-test.run(arguments='', stderr = None)
+expect = """
+scons: *** Setting target is not supported for rpm.
+""" + test.python_file_line(test.workpath('SConstruct'), 24)
-src_rpm = 'foo-1.2.3-0.src.rpm'
-machine_rpm = 'foo-1.2.3-0.%s.rpm' % machine
-
-test.must_exist( machine_rpm )
-test.must_exist( src_rpm )
-test.must_not_exist( 'bin/main' )
-test.fail_test( not os.popen('rpm -qpl %s' % machine_rpm).read()=='/bin/main\n')
-test.fail_test( not os.popen('rpm -qpl %s' % src_rpm).read()=='foo-1.2.3.spec\nfoo-1.2.3.tar.gz\n')
+test.run(arguments='', status=2, stderr=expect)
test.pass_test()
diff --git a/test/sconsign/ghost-entries.py b/test/sconsign/ghost-entries.py
new file mode 100644
index 0000000..45426ad
--- /dev/null
+++ b/test/sconsign/ghost-entries.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that "ghost" entries in the .sconsign file don't have Nodes
+created for them on subsequent runs (which would cause errors
+when scanning directories).
+"""
+
+import os.path
+
+d_current_txt = os.path.join('d', 'current.txt')
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+# This test case is from Morten Elo Petersen. It's harder because
+# blib-case1only actually exists in the build dir after the -c, so the
+# Dir scanner finds it and adds it to the dir's entries.
+# Unfortunately FS.py's File.exists() method checks it later and finds
+# it looks like a stale build copy of a missing source, so it deletes
+# it. And then it's later discovered to be missing since it's still
+# in the dir's entries list. The fix for this is to test for missing
+# source files in the dir scanner (Scanner/Dir.py), and delete them
+# (just like File.exists() does if they're found in the build dir
+# rather than making entries for them.
+
+test.write('SConstruct', """\
+def cat(target, source, env):
+ fp = open(str(target[0]), 'wb')
+ for s in source:
+ fp.write(open(str(s), 'rb').read())
+ fp.close()
+env=Environment()
+Export('env')
+env['BUILDERS']['Cat']=Builder(action=cat, multi=1)
+SConscript('src/SConscript',build_dir='build')
+""")
+
+test.subdir('src')
+test.write(['src', 'SConscript'], """\
+Import('env')
+if ARGUMENTS['case']=='1':
+ A=env.Cat('#build/lib/blib-case1only','src.txt')
+ B=env.Cat('#build/lib/blibB','#build/lib/blib-case1only')
+if ARGUMENTS['case']=='2':
+ A=env.Cat('case2only','src.txt')
+ B=env.Cat('#build/lib/blibB.txt','case2only')
+env.Alias('go','#build/lib')
+""")
+
+test.write(['src', 'src.txt'], "anything")
+
+test.run(arguments="-Q go case=1")
+test.must_exist('build/lib/blib-case1only')
+test.run(arguments="-Q go case=2")
+test.run(arguments="-Q go case=2 -c")
+test.run(arguments="-Q go case=2")
+
+
+#############################################################################
+# This test case is from Jason Orendorff.
+# Checking for existence before making nodes for things found in the
+# .sconsign fixes this one.
+
+test.write('SConstruct', """\
+Command("d/current.txt", [], [Touch("$TARGET")])
+if ARGUMENTS.has_key('pass') and ARGUMENTS['pass'] == '1':
+ Command("d/obsolete.txt", [], [Touch("$TARGET")])
+Command("installer.exe", ['d'], [Touch("$TARGET")])
+""")
+
+test.run(arguments='-Q pass=1')
+
+# Now delete the created files
+test.unlink(['d', 'obsolete.txt'])
+test.unlink(['d', 'current.txt'])
+test.rmdir(['d'])
+
+# Run again, as pass 2
+expect = """Touch("%(d_current_txt)s")
+Touch("installer.exe")
+""" % locals()
+
+test.run(arguments='-Q pass=2', stdout=expect)
+
+test.pass_test()
diff --git a/test/sconsign/script/Configure.py b/test/sconsign/script/Configure.py
index 8e17e95..19c8a1c 100644
--- a/test/sconsign/script/Configure.py
+++ b/test/sconsign/script/Configure.py
@@ -30,6 +30,7 @@ info in them (which have different BuildInfo entries).
"""
import os.path
+import re
import TestSCons
import TestSConsign
@@ -40,6 +41,8 @@ test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
CC = test.detect('CC', norm=1)
CC_dir, CC_file = os.path.split(CC)
+CC_dir = re.escape(os.path.normcase(CC_dir))
+CC_file = re.escape(CC_file)
# Note: We don't use os.path.join() representations of the file names
# in the expected output because paths in the .sconsign files are
diff --git a/test/sconsign/script/SConsignFile.py b/test/sconsign/script/SConsignFile.py
index 99845e3..54ecaaa 100644
--- a/test/sconsign/script/SConsignFile.py
+++ b/test/sconsign/script/SConsignFile.py
@@ -29,19 +29,61 @@ Verify that the sconsign script works with files generated when
using the signatures in an SConsignFile().
"""
-import os.path
-
+import TestSCons
import TestSConsign
-test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
+_python_ = TestSCons._python_
-CC = test.detect('CC', norm=1)
-CC_dir, CC_file = os.path.split(CC)
-LINK = test.detect('LINK', norm=1)
-if LINK is None: LINK = CC
+test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
test.subdir('sub1', 'sub2')
+test.write('fake_cc.py', r"""
+import os.path
+import re
+import string
+import sys
+
+path = string.split(sys.argv[1])
+output = open(sys.argv[2], 'wb')
+input = open(sys.argv[3], 'rb')
+
+output.write('fake_cc.py: %s\n' % sys.argv)
+
+def find_file(f):
+ for dir in path:
+ p = dir + os.sep + f
+ if os.path.exists(p):
+ return open(p, 'rb')
+ return None
+
+def process(infp, outfp):
+ for line in infp.readlines():
+ m = re.match('#include <(.*)>', line)
+ if m:
+ file = m.group(1)
+ process(find_file(file), outfp)
+ else:
+ outfp.write(line)
+
+process(input, output)
+
+sys.exit(0)
+""")
+
+test.write('fake_link.py', r"""
+import sys
+
+output = open(sys.argv[1], 'wb')
+input = open(sys.argv[2], 'rb')
+
+output.write('fake_link.py: %s\n' % sys.argv)
+
+output.write(input.read())
+
+sys.exit(0)
+""")
+
# Note: We don't use os.path.join() representations of the file names
# in the expected output because paths in the .sconsign files are
# canonicalized to use / as the separator.
@@ -55,27 +97,20 @@ sub2_inc2_h = 'sub2/inc2.h'
test.write(['SConstruct'], """\
SConsignFile()
-env1 = Environment(PROGSUFFIX = '.exe', OBJSUFFIX = '.obj')
+env1 = Environment(PROGSUFFIX = '.exe',
+ OBJSUFFIX = '.obj',
+ CCCOM = r'%(_python_)s fake_cc.py sub2 $TARGET $SOURCE',
+ LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCE')
env1.Program('sub1/hello.c')
env2 = env1.Clone(CPPPATH = ['sub2'])
env2.Program('sub2/hello.c')
-""")
+""" % locals())
-test.write(['sub1', 'hello.c'], r"""\
-#include <stdio.h>
-#include <stdlib.h>
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("sub1/hello.c\n");
- exit (0);
-}
+test.write(['sub1', 'hello.c'], r"""
+sub1/hello.c
""")
-test.write(['sub2', 'hello.c'], r"""\
-#include <stdio.h>
-#include <stdlib.h>
+test.write(['sub2', 'hello.c'], r"""
#include <inc1.h>
#include <inc2.h>
int
@@ -102,29 +137,23 @@ sig_re = r'[0-9a-fA-F]{32}'
test.run_sconsign(arguments = ".sconsign",
stdout = r"""=== .:
SConstruct: None \d+ \d+
-=== %(CC_dir)s:
-%(CC_file)s: %(sig_re)s \d+ \d+
=== sub1:
hello.c: %(sig_re)s \d+ \d+
hello.exe: %(sig_re)s \d+ \d+
%(sub1_hello_obj)s: %(sig_re)s \d+ \d+
- %(LINK)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
=== sub2:
hello.c: %(sig_re)s \d+ \d+
hello.exe: %(sig_re)s \d+ \d+
%(sub2_hello_obj)s: %(sig_re)s \d+ \d+
- %(LINK)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub2_hello_c)s: %(sig_re)s \d+ \d+
%(sub2_inc1_h)s: %(sig_re)s \d+ \d+
%(sub2_inc2_h)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
inc1.h: %(sig_re)s \d+ \d+
inc2.h: %(sig_re)s \d+ \d+
@@ -133,29 +162,23 @@ inc2.h: %(sig_re)s \d+ \d+
test.run_sconsign(arguments = "--raw .sconsign",
stdout = r"""=== .:
SConstruct: {'csig': None, 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
-=== %(CC_dir)s:
-%(CC_file)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
=== sub1:
hello.c: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
hello.exe: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sub1_hello_obj)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
- %(LINK)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sig_re)s \[.*\]
hello.obj: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sub1_hello_c)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
- %(CC)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sig_re)s \[.*\]
=== sub2:
hello.c: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
hello.exe: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sub2_hello_obj)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
- %(LINK)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sig_re)s \[.*\]
hello.obj: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sub2_hello_c)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sub2_inc1_h)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sub2_inc2_h)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
- %(CC)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sig_re)s \[.*\]
inc1.h: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
inc2.h: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
@@ -166,11 +189,6 @@ SConstruct:
csig: None
timestamp: \d+
size: \d+
-=== %(CC_dir)s:
-%(CC_file)s:
- csig: %(sig_re)s
- timestamp: \d+
- size: \d+
=== sub1:
hello.c:
csig: %(sig_re)s
@@ -185,10 +203,6 @@ hello.exe:
csig: %(sig_re)s
timestamp: \d+
size: \d+
- %(LINK)s:
- csig: %(sig_re)s
- timestamp: \d+
- size: \d+
action: %(sig_re)s \[.*\]
hello.obj:
csig: %(sig_re)s
@@ -199,10 +213,6 @@ hello.obj:
csig: %(sig_re)s
timestamp: \d+
size: \d+
- %(CC)s:
- csig: %(sig_re)s
- timestamp: \d+
- size: \d+
action: %(sig_re)s \[.*\]
=== sub2:
hello.c:
@@ -218,10 +228,6 @@ hello.exe:
csig: %(sig_re)s
timestamp: \d+
size: \d+
- %(LINK)s:
- csig: %(sig_re)s
- timestamp: \d+
- size: \d+
action: %(sig_re)s \[.*\]
hello.obj:
csig: %(sig_re)s
@@ -240,10 +246,6 @@ hello.obj:
csig: %(sig_re)s
timestamp: \d+
size: \d+
- %(CC)s:
- csig: %(sig_re)s
- timestamp: \d+
- size: \d+
action: %(sig_re)s \[.*\]
inc1.h:
csig: %(sig_re)s
@@ -261,9 +263,6 @@ test.run_sconsign(arguments = "-c -v .sconsign",
stdout = r"""=== .:
SConstruct:
csig: None
-=== %(CC_dir)s:
-%(CC_file)s:
- csig: %(sig_re)s
=== sub1:
hello.c:
csig: %(sig_re)s
@@ -288,9 +287,6 @@ test.run_sconsign(arguments = "-s -v .sconsign",
stdout = r"""=== .:
SConstruct:
size: \d+
-=== %(CC_dir)s:
-%(CC_file)s:
- size: \d+
=== sub1:
hello.c:
size: \d+
@@ -315,9 +311,6 @@ test.run_sconsign(arguments = "-t -v .sconsign",
stdout = r"""=== .:
SConstruct:
timestamp: \d+
-=== %(CC_dir)s:
-%(CC_file)s:
- timestamp: \d+
=== sub1:
hello.c:
timestamp: \d+
@@ -340,64 +333,50 @@ inc2.h:
test.run_sconsign(arguments = "-e hello.obj .sconsign",
stdout = r"""=== .:
-=== %(CC_dir)s:
=== sub1:
hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
=== sub2:
hello.obj: %(sig_re)s \d+ \d+
%(sub2_hello_c)s: %(sig_re)s \d+ \d+
%(sub2_inc1_h)s: %(sig_re)s \d+ \d+
%(sub2_inc2_h)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
""" % locals(),
- stderr = r"""sconsign: no entry `hello.obj' in `\.'
-sconsign: no entry `hello.obj' in `%(CC_dir)s'
-""" % locals())
+ stderr = r"""sconsign: no entry `hello.obj' in `\.'
+""")
test.run_sconsign(arguments = "-e hello.obj -e hello.exe -e hello.obj .sconsign",
stdout = r"""=== .:
-=== %(CC_dir)s:
=== sub1:
hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.exe: %(sig_re)s \d+ \d+
%(sub1_hello_obj)s: %(sig_re)s \d+ \d+
- %(LINK)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
=== sub2:
hello.obj: %(sig_re)s \d+ \d+
%(sub2_hello_c)s: %(sig_re)s \d+ \d+
%(sub2_inc1_h)s: %(sig_re)s \d+ \d+
%(sub2_inc2_h)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.exe: %(sig_re)s \d+ \d+
%(sub2_hello_obj)s: %(sig_re)s \d+ \d+
- %(LINK)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub2_hello_c)s: %(sig_re)s \d+ \d+
%(sub2_inc1_h)s: %(sig_re)s \d+ \d+
%(sub2_inc2_h)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
""" % locals(),
stderr = r"""sconsign: no entry `hello.obj' in `\.'
sconsign: no entry `hello.exe' in `\.'
sconsign: no entry `hello.obj' in `\.'
-sconsign: no entry `hello.obj' in `%(CC_dir)s'
-sconsign: no entry `hello.exe' in `%(CC_dir)s'
-sconsign: no entry `hello.obj' in `%(CC_dir)s'
""" % locals())
#test.run_sconsign(arguments = "-i -v .sconsign",
diff --git a/test/sconsign/script/Signatures.py b/test/sconsign/script/Signatures.py
index fc85133..27e4867 100644
--- a/test/sconsign/script/Signatures.py
+++ b/test/sconsign/script/Signatures.py
@@ -31,13 +31,12 @@ SourceSignatures() and TargetSignatures() values (timestamp and content,
respectively).
"""
+import TestSCons
import TestSConsign
-test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
+_python_ = TestSCons._python_
-CC = test.detect('CC', norm=1)
-LINK = test.detect('LINK', norm=1)
-if LINK is None: LINK = CC
+test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
# Note: We don't use os.path.join() representations of the file names
# in the expected output because paths in the .sconsign files are
@@ -46,47 +45,75 @@ if LINK is None: LINK = CC
sub1_hello_c = 'sub1/hello.c'
sub1_hello_obj = 'sub1/hello.obj'
-def re_sep(*args):
- import os.path
- import re
- return re.escape(apply(os.path.join, args))
-
test.subdir('sub1', 'sub2')
+test.write('fake_cc.py', r"""
+import os.path
+import re
+import string
+import sys
+
+path = string.split(sys.argv[1])
+output = open(sys.argv[2], 'wb')
+input = open(sys.argv[3], 'rb')
+
+output.write('fake_cc.py: %s\n' % sys.argv)
+
+def find_file(f):
+ for dir in path:
+ p = dir + os.sep + f
+ if os.path.exists(p):
+ return open(p, 'rb')
+ return None
+
+def process(infp, outfp):
+ for line in infp.readlines():
+ m = re.match('#include <(.*)>', line)
+ if m:
+ file = m.group(1)
+ process(find_file(file), outfp)
+ else:
+ outfp.write(line)
+
+process(input, output)
+
+sys.exit(0)
+""")
+
+test.write('fake_link.py', r"""
+import sys
+
+output = open(sys.argv[1], 'wb')
+input = open(sys.argv[2], 'rb')
+
+output.write('fake_link.py: %s\n' % sys.argv)
+
+output.write(input.read())
+
+sys.exit(0)
+""")
+
test.write('SConstruct', """
SConsignFile(None)
SourceSignatures('timestamp')
TargetSignatures('content')
-env1 = Environment(PROGSUFFIX = '.exe', OBJSUFFIX = '.obj')
+env1 = Environment(PROGSUFFIX = '.exe',
+ OBJSUFFIX = '.obj',
+ CCCOM = r'%(_python_)s fake_cc.py sub2 $TARGET $SOURCE',
+ LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCE')
env1.Program('sub1/hello.c')
env2 = env1.Clone(CPPPATH = ['sub2'])
env2.Program('sub2/hello.c')
-""")
+""" % locals())
test.write(['sub1', 'hello.c'], r"""\
-#include <stdio.h>
-#include <stdlib.h>
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("sub1/hello.c\n");
- exit (0);
-}
+sub1/hello.c
""")
test.write(['sub2', 'hello.c'], r"""\
-#include <stdio.h>
-#include <stdlib.h>
#include <inc1.h>
#include <inc2.h>
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("sub2/goodbye.c\n");
- exit (0);
-}
+sub2/hello.c
""")
test.write(['sub2', 'inc1.h'], r"""\
@@ -107,22 +134,18 @@ date_re = r'\S+ \S+ [ \d]\d \d\d:\d\d:\d\d \d\d\d\d'
test.run_sconsign(arguments = "-e hello.exe -e hello.obj sub1/.sconsign",
stdout = r"""hello.exe: %(sig_re)s \d+ \d+
%(sub1_hello_obj)s: %(sig_re)s \d+ \d+
- %(LINK)s: None \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: None \d+ \d+
- %(CC)s: None \d+ \d+
%(sig_re)s \[.*\]
""" % locals())
test.run_sconsign(arguments = "-e hello.exe -e hello.obj -r sub1/.sconsign",
stdout = r"""hello.exe: %(sig_re)s '%(date_re)s' \d+
%(sub1_hello_obj)s: %(sig_re)s '%(date_re)s' \d+
- %(LINK)s: None '%(date_re)s' \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s '%(date_re)s' \d+
%(sub1_hello_c)s: None '%(date_re)s' \d+
- %(CC)s: None '%(date_re)s' \d+
%(sig_re)s \[.*\]
""" % locals())
diff --git a/test/sconsign/script/no-SConsignFile.py b/test/sconsign/script/no-SConsignFile.py
index 1fcfbfd..6aede19 100644
--- a/test/sconsign/script/no-SConsignFile.py
+++ b/test/sconsign/script/no-SConsignFile.py
@@ -29,16 +29,61 @@ Verify that the sconsign script works when using an individual
.sconsign file in each directory (SConsignFile(None)).
"""
+import TestSCons
import TestSConsign
-test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
+_python_ = TestSCons._python_
-CC = test.detect('CC', norm=1)
-LINK = test.detect('LINK', norm=1)
-if LINK is None: LINK = CC
+test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
test.subdir('sub1', 'sub2')
+test.write('fake_cc.py', r"""
+import os.path
+import re
+import string
+import sys
+
+path = string.split(sys.argv[1])
+output = open(sys.argv[2], 'wb')
+input = open(sys.argv[3], 'rb')
+
+output.write('fake_cc.py: %s\n' % sys.argv)
+
+def find_file(f):
+ for dir in path:
+ p = dir + os.sep + f
+ if os.path.exists(p):
+ return open(p, 'rb')
+ return None
+
+def process(infp, outfp):
+ for line in infp.readlines():
+ m = re.match('#include <(.*)>', line)
+ if m:
+ file = m.group(1)
+ process(find_file(file), outfp)
+ else:
+ outfp.write(line)
+
+process(input, output)
+
+sys.exit(0)
+""")
+
+test.write('fake_link.py', r"""
+import sys
+
+output = open(sys.argv[1], 'wb')
+input = open(sys.argv[2], 'rb')
+
+output.write('fake_link.py: %s\n' % sys.argv)
+
+output.write(input.read())
+
+sys.exit(0)
+""")
+
# Note: We don't use os.path.join() representations of the file names
# in the expected output because paths in the .sconsign files are
# canonicalized to use / as the separator.
@@ -52,36 +97,23 @@ sub2_inc2_h = 'sub2/inc2.h'
test.write(['SConstruct'], """
SConsignFile(None)
-env1 = Environment(PROGSUFFIX = '.exe', OBJSUFFIX = '.obj')
+env1 = Environment(PROGSUFFIX = '.exe',
+ OBJSUFFIX = '.obj',
+ CCCOM = r'%(_python_)s fake_cc.py sub2 $TARGET $SOURCE',
+ LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCE')
env1.Program('sub1/hello.c')
env2 = env1.Clone(CPPPATH = ['sub2'])
env2.Program('sub2/hello.c')
-""")
+""" % locals())
test.write(['sub1', 'hello.c'], r"""\
-#include <stdio.h>
-#include <stdlib.h>
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("sub1/hello.c\n");
- exit (0);
-}
+sub1/hello.c
""")
test.write(['sub2', 'hello.c'], r"""\
-#include <stdio.h>
-#include <stdlib.h>
#include <inc1.h>
#include <inc2.h>
-int
-main(int argc, char *argv[])
-{
- argv[argc++] = "--";
- printf("sub2/goodbye.c\n");
- exit (0);
-}
+sub2/hello.c
""")
test.write(['sub2', 'inc1.h'], r"""\
@@ -99,11 +131,9 @@ sig_re = r'[0-9a-fA-F]{32}'
expect = r"""hello.c: %(sig_re)s \d+ \d+
hello.exe: %(sig_re)s \d+ \d+
%(sub1_hello_obj)s: %(sig_re)s \d+ \d+
- %(LINK)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
""" % locals()
@@ -115,11 +145,9 @@ test.run_sconsign(arguments = "--raw sub1/.sconsign",
stdout = r"""hello.c: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
hello.exe: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sub1_hello_obj)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
- %(LINK)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sig_re)s \[.*\]
hello.obj: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sub1_hello_c)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
- %(CC)s: {'csig': '%(sig_re)s', 'timestamp': \d+, 'size': \d+L?, '_version_id': 1}
%(sig_re)s \[.*\]
""" % locals())
@@ -137,10 +165,6 @@ hello.exe:
csig: %(sig_re)s
timestamp: \d+
size: \d+
- %(LINK)s:
- csig: %(sig_re)s
- timestamp: \d+
- size: \d+
action: %(sig_re)s \[.*\]
hello.obj:
csig: %(sig_re)s
@@ -151,10 +175,6 @@ hello.obj:
csig: %(sig_re)s
timestamp: \d+
size: \d+
- %(CC)s:
- csig: %(sig_re)s
- timestamp: \d+
- size: \d+
action: %(sig_re)s \[.*\]
""" % locals())
@@ -188,22 +208,18 @@ hello.obj:
test.run_sconsign(arguments = "-e hello.obj sub1/.sconsign",
stdout = r"""hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
""" % locals())
test.run_sconsign(arguments = "-e hello.obj -e hello.exe -e hello.obj sub1/.sconsign",
stdout = r"""hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.exe: %(sig_re)s \d+ \d+
%(sub1_hello_obj)s: %(sig_re)s \d+ \d+
- %(LINK)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
""" % locals())
@@ -211,13 +227,11 @@ test.run_sconsign(arguments = "sub2/.sconsign",
stdout = r"""hello.c: %(sig_re)s \d+ \d+
hello.exe: %(sig_re)s \d+ \d+
%(sub2_hello_obj)s: %(sig_re)s \d+ \d+
- %(LINK)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub2_hello_c)s: %(sig_re)s \d+ \d+
%(sub2_inc1_h)s: %(sig_re)s \d+ \d+
%(sub2_inc2_h)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
inc1.h: %(sig_re)s \d+ \d+
inc2.h: %(sig_re)s \d+ \d+
@@ -240,11 +254,9 @@ test.run_sconsign(arguments = "-e hello.obj sub2/.sconsign sub1/.sconsign",
%(sub2_hello_c)s: %(sig_re)s \d+ \d+
%(sub2_inc1_h)s: %(sig_re)s \d+ \d+
%(sub2_inc2_h)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
hello.obj: %(sig_re)s \d+ \d+
%(sub1_hello_c)s: %(sig_re)s \d+ \d+
- %(CC)s: %(sig_re)s \d+ \d+
%(sig_re)s \[.*\]
""" % locals())
diff --git a/test/subdivide.py b/test/subdivide.py
index a816957..72c7766 100644
--- a/test/subdivide.py
+++ b/test/subdivide.py
@@ -34,6 +34,8 @@ import os.path
import TestSCons
+_python_ = TestSCons._python_
+
test = TestSCons.TestSCons()
#if os.path.exists('sconsign.py'):
@@ -46,58 +48,79 @@ test = TestSCons.TestSCons()
test.subdir('src', ['src', 'sub'])
+test.write('fake_cc.py', """\
+import sys
+ofp = open(sys.argv[1], 'wb')
+ofp.write('fake_cc.py: %s\\n' % sys.argv)
+for s in sys.argv[2:]:
+ ofp.write(open(s, 'rb').read())
+""")
+
+test.write('fake_link.py', """\
+import sys
+ofp = open(sys.argv[1], 'wb')
+ofp.write('fake_link.py: %s\\n' % sys.argv)
+for s in sys.argv[2:]:
+ ofp.write(open(s, 'rb').read())
+""")
+
test.write('SConstruct', """\
SConsignFile(None)
TargetSignatures('content')
-env = Environment()
+env = Environment(PROGSUFFIX = '.exe',
+ OBJSUFFIX = '.obj',
+ CCCOM = r'%(_python_)s fake_cc.py $TARGET $SOURCES',
+ LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCES')
env.SConscript('src/SConstruct', exports=['env'])
env.Object('foo.c')
-""")
+""" % locals())
test.write(['src', 'SConstruct'], """\
SConsignFile(None)
TargetSignatures('content')
-env = Environment()
-p = env.Program('prog', ['main.c', '../foo%s', 'sub/bar.c'])
+env = Environment(PROGSUFFIX = '.exe',
+ OBJSUFFIX = '.obj',
+ CCCOM = r'%(_python_)s fake_cc.py $TARGET $SOURCES',
+ LINKCOM = r'%(_python_)s fake_link.py $TARGET $SOURCES')
+p = env.Program('prog', ['main.c', '../foo$OBJSUFFIX', 'sub/bar.c'])
env.Default(p)
-""" % TestSCons._obj)
+""" % locals())
test.write('foo.c', """\
-#include <stdio.h>
-#include <stdlib.h>
-void
-foo(void) {
- printf("foo.c\\n");
-}
+foo.c
""")
test.write(['src', 'main.c'], """\
-#include <stdio.h>
-#include <stdlib.h>
-extern void foo(void);
-extern void bar(void);
-int
-main(int argc, char *argv[]) {
- foo();
- bar();
- printf("src/main.c\\n");
- exit (0);
-}
+src/main.c
""")
test.write(['src', 'sub', 'bar.c'], """\
-#include <stdio.h>
-#include <stdlib.h>
-void
-bar(void) {
- printf("bar.c\\n");
-}
+src/sub/bar.c
""")
test.run()
-test.run(program=test.workpath('src', 'prog'),
- stdout="foo.c\nbar.c\nsrc/main.c\n")
+src_prog_exe = os.path.join('src', 'prog.exe')
+src_main_c = os.path.join('src', 'main.c')
+src_main_obj = os.path.join('src', 'main.obj')
+src_sub_bar_c = os.path.join('src', 'sub', 'bar.c')
+src_sub_bar_obj = os.path.join('src', 'sub', 'bar.obj')
+
+expect = """\
+fake_link.py: ['fake_link.py', '%(src_prog_exe)s', '%(src_main_obj)s', 'foo.obj', '%(src_sub_bar_obj)s']
+fake_cc.py: ['fake_cc.py', '%(src_main_obj)s', '%(src_main_c)s']
+src/main.c
+fake_cc.py: ['fake_cc.py', 'foo.obj', 'foo.c']
+foo.c
+fake_cc.py: ['fake_cc.py', '%(src_sub_bar_obj)s', '%(src_sub_bar_c)s']
+src/sub/bar.c
+""" % locals()
+
+if os.sep == '\\':
+ import string
+ expect = string.replace(expect, '\\', '\\\\')
+
+test.must_match(['src', 'prog.exe'], expect)
test.up_to_date(chdir='src', arguments = test.workpath())