diff options
author | Steven Knight <knight@baldmt.com> | 2005-03-05 15:25:36 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2005-03-05 15:25:36 (GMT) |
commit | 81e49da9da4df0dab0041dbc2d499048f38ed4f4 (patch) | |
tree | 6a6a9c1d857263a41a7185db0f4e5f49c35cc18e /test/BuildDir | |
parent | 7504c9d138b5a0a43c75918dc39614af12a7439a (diff) | |
download | SCons-81e49da9da4df0dab0041dbc2d499048f38ed4f4.zip SCons-81e49da9da4df0dab0041dbc2d499048f38ed4f4.tar.gz SCons-81e49da9da4df0dab0041dbc2d499048f38ed4f4.tar.bz2 |
Fix a regression in handling CPPPATH='.' when using a BuildDir with subdirectories in the search path.
Diffstat (limited to 'test/BuildDir')
-rw-r--r-- | test/BuildDir/BuildDir.py | 393 | ||||
-rw-r--r-- | test/BuildDir/CPPPATH-subdir.py | 70 | ||||
-rw-r--r-- | test/BuildDir/Sconscript-build_dir.py | 263 | ||||
-rw-r--r-- | test/BuildDir/errors.py | 171 | ||||
-rw-r--r-- | test/BuildDir/reflect.py | 136 |
5 files changed, 1033 insertions, 0 deletions
diff --git a/test/BuildDir/BuildDir.py b/test/BuildDir/BuildDir.py new file mode 100644 index 0000000..181d8aa --- /dev/null +++ b/test/BuildDir/BuildDir.py @@ -0,0 +1,393 @@ +#!/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__" + +import os.path +import string +import sys +import time +import TestSCons + +_exe = TestSCons._exe +fortran_runtime = TestSCons.fortran_lib + +test = TestSCons.TestSCons() + +fortran = test.detect('FORTRAN') + +foo11 = test.workpath('work1', 'build', 'var1', 'foo1' + _exe) +foo12 = test.workpath('work1', 'build', 'var1', 'foo2' + _exe) +foo21 = test.workpath('work1', 'build', 'var2', 'foo1' + _exe) +foo22 = test.workpath('work1', 'build', 'var2', 'foo2' + _exe) +foo31 = test.workpath('work1', 'build', 'var3', 'foo1' + _exe) +foo32 = test.workpath('work1', 'build', 'var3', 'foo2' + _exe) +foo41 = test.workpath('work1', 'build', 'var4', 'foo1' + _exe) +foo42 = test.workpath('work1', 'build', 'var4', 'foo2' + _exe) +foo51 = test.workpath('build', 'var5', 'foo1' + _exe) +foo52 = test.workpath('build', 'var5', 'foo2' + _exe) + +bar11 = test.workpath('work1', 'build', 'var1', 'bar1' + _exe) +bar12 = test.workpath('work1', 'build', 'var1', 'bar2' + _exe) +bar21 = test.workpath('work1', 'build', 'var2', 'bar1' + _exe) +bar22 = test.workpath('work1', 'build', 'var2', 'bar2' + _exe) +bar31 = test.workpath('work1', 'build', 'var3', 'bar1' + _exe) +bar32 = test.workpath('work1', 'build', 'var3', 'bar2' + _exe) +bar41 = test.workpath('work1', 'build', 'var4', 'bar1' + _exe) +bar42 = test.workpath('work1', 'build', 'var4', 'bar2' + _exe) +bar51 = test.workpath('build', 'var5', 'bar1' + _exe) +bar52 = test.workpath('build', 'var5', 'bar2' + _exe) + +test.subdir('work1', 'work2', 'work3') + +test.write(['work1', 'SConstruct'], """ +src = Dir('src') +var2 = Dir('build/var2') +var3 = Dir('build/var3') +var4 = Dir('build/var4') +var5 = Dir('../build/var5') +var6 = Dir('../build/var6') + +env = Environment(BUILD = 'build', SRC = 'src') + +BuildDir('build/var1', src) +BuildDir(var2, src) +BuildDir(var3, src, duplicate=0) +env.BuildDir("$BUILD/var4", "$SRC", duplicate=0) +BuildDir(var5, src, duplicate=0) +BuildDir(var6, src) + +env = Environment(CPPPATH='#src', FORTRANPATH='#src') +SConscript('build/var1/SConscript', "env") +SConscript('build/var2/SConscript', "env") + +env = Environment(CPPPATH=src, FORTRANPATH=src) +SConscript('build/var3/SConscript', "env") +SConscript(File('SConscript', var4), "env") + +env = Environment(CPPPATH='.', FORTRANPATH='.') +SConscript('../build/var5/SConscript', "env") +SConscript('../build/var6/SConscript', "env") +""") + +test.subdir(['work1', 'src']) +test.write(['work1', 'src', 'SConscript'], """ +import os +import os.path + +def buildIt(target, source, env): + if not os.path.exists('build'): + os.mkdir('build') + f1=open(str(source[0]), 'r') + f2=open(str(target[0]), 'w') + f2.write(f1.read()) + f2.close() + f1.close() + return 0 +Import("env") +env.Command(target='f2.c', source='f2.in', action=buildIt) +env.Program(target='foo2', source='f2.c') +env.Program(target='foo1', source='f1.c') +env.Command(target='f3.h', source='f3h.in', action=buildIt) +env.Command(target='f4.h', source='f4h.in', action=buildIt) +env.Command(target='f4.c', source='f4.in', action=buildIt) + +env2=env.Copy(CPPPATH='.') +env2.Program(target='foo3', source='f3.c') +env2.Program(target='foo4', source='f4.c') + +try: + fortran = env.subst('$FORTRAN') +except: + fortran = None + +if fortran and env.Detect(fortran): + env.Command(target='b2.f', source='b2.in', action=buildIt) + env.Copy(LIBS = %s).Program(target='bar2', source='b2.f') + env.Copy(LIBS = %s).Program(target='bar1', source='b1.f') +""" % (fortran_runtime, fortran_runtime)) + +test.write(['work1', 'src', 'f1.c'], r""" +#include "f1.h" + +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf(F1_STR); + exit (0); +} +""") + +test.write(['work1', 'src', 'f2.in'], r""" +#include "f2.h" + +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf(F2_STR); + exit (0); +} +""") + +test.write(['work1', 'src', 'f3.c'], r""" +#include "f3.h" + +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf(F3_STR); + exit (0); +} +""") + +test.write(['work1', 'src', 'f4.in'], r""" +#include "f4.h" + +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf(F4_STR); + exit (0); +} +""") + +test.write(['work1', 'src', 'f1.h'], r""" +#define F1_STR "f1.c\n" +""") + +test.write(['work1', 'src', 'f2.h'], r""" +#define F2_STR "f2.c\n" +""") + +test.write(['work1', 'src', 'f3h.in'], r""" +#define F3_STR "f3.c\n" +""") + +test.write(['work1', 'src', 'f4h.in'], r""" +#define F4_STR "f4.c\n" +""") + +test.write(['work1', 'src', 'b1.f'], r""" + PROGRAM FOO + INCLUDE 'b1.for' + STOP + END +""") + +test.write(['work1', 'src', 'b2.in'], r""" + PROGRAM FOO + INCLUDE 'b2.for' + STOP + END +""") + +test.write(['work1', 'src', 'b1.for'], r""" + PRINT *, 'b1.for' +""") + +test.write(['work1', 'src', 'b2.for'], r""" + PRINT *, 'b2.for' +""") + +# Some releases of freeBSD seem to have library complaints about +# tempnam(). Filter out these annoying messages before checking for +# error output. +def blank_output(err): + if not err: + return 1 + stderrlines = filter(lambda l: l, string.split(err, '\n')) + msg = "warning: tempnam() possibly used unsafely" + stderrlines = filter(lambda l, msg=msg: string.find(l, msg) == -1, + stderrlines) + return len(stderrlines) == 0 + +test.run(chdir='work1', arguments = '. ../build', stderr=None) + +test.fail_test(not blank_output(test.stderr())) + +test.run(program = foo11, stdout = "f1.c\n") +test.run(program = foo12, stdout = "f2.c\n") +test.run(program = foo21, stdout = "f1.c\n") +test.run(program = foo22, stdout = "f2.c\n") +test.run(program = foo31, stdout = "f1.c\n") +test.run(program = foo32, stdout = "f2.c\n") +test.run(program = foo41, stdout = "f1.c\n") +test.run(program = foo42, stdout = "f2.c\n") +test.run(program = foo51, stdout = "f1.c\n") +test.run(program = foo52, stdout = "f2.c\n") + +if fortran: + test.run(program = bar11, stdout = " b1.for\n") + test.run(program = bar12, stdout = " b2.for\n") + test.run(program = bar21, stdout = " b1.for\n") + test.run(program = bar22, stdout = " b2.for\n") + test.run(program = bar31, stdout = " b1.for\n") + test.run(program = bar32, stdout = " b2.for\n") + test.run(program = bar41, stdout = " b1.for\n") + test.run(program = bar42, stdout = " b2.for\n") + test.run(program = bar51, stdout = " b1.for\n") + test.run(program = bar52, stdout = " b2.for\n") + +test.run(chdir='work1', arguments='. ../build', stdout=test.wrap_stdout("""\ +scons: `.' is up to date. +scons: `%s' is up to date. +""" % test.workpath('build'))) + +import os +import stat +def equal_stats(x,y): + x = os.stat(x) + y = os.stat(y) + return (stat.S_IMODE(x[stat.ST_MODE]) == stat.S_IMODE(y[stat.ST_MODE]) and + x[stat.ST_MTIME] == y[stat.ST_MTIME]) + +# Make sure we did duplicate the source files in build/var2, +# and that their stats are the same: +test.must_exist(['work1', 'build', 'var2', 'f1.c']) +test.must_exist(['work1', 'build', 'var2', 'f2.in']) +test.fail_test(not equal_stats(test.workpath('work1', 'build', 'var2', 'f1.c'), test.workpath('work1', 'src', 'f1.c'))) +test.fail_test(not equal_stats(test.workpath('work1', 'build', 'var2', 'f2.in'), test.workpath('work1', 'src', 'f2.in'))) + +# Make sure we didn't duplicate the source files in build/var3. +test.must_not_exist(['work1', 'build', 'var3', 'f1.c']) +test.must_not_exist(['work1', 'build', 'var3', 'f2.in']) +test.must_not_exist(['work1', 'build', 'var3', 'b1.f']) +test.must_not_exist(['work1', 'build', 'var3', 'b2.in']) + +# Make sure we didn't duplicate the source files in build/var4. +test.must_not_exist(['work1', 'build', 'var4', 'f1.c']) +test.must_not_exist(['work1', 'build', 'var4', 'f2.in']) +test.must_not_exist(['work1', 'build', 'var4', 'b1.f']) +test.must_not_exist(['work1', 'build', 'var4', 'b2.in']) + +# Make sure we didn't duplicate the source files in build/var5. +test.must_not_exist(['build', 'var5', 'f1.c']) +test.must_not_exist(['build', 'var5', 'f2.in']) +test.must_not_exist(['build', 'var5', 'b1.f']) +test.must_not_exist(['build', 'var5', 'b2.in']) + +# verify that header files in the source directory are scanned properly: +test.write(['work1', 'src', 'f1.h'], r""" +#define F1_STR "f1.c 2\n" +""") + +test.write(['work1', 'src', 'f3h.in'], r""" +#define F3_STR "f3.c 2\n" +""") + +test.write(['work1', 'src', 'f4h.in'], r""" +#define F4_STR "f4.c 2\n" +""") + +test.run(chdir='work1', arguments = '../build/var5', stderr=None) + +test.fail_test(not blank_output(test.stderr())) + +test.run(program = foo51, stdout = "f1.c 2\n") +test.run(program = test.workpath('build', 'var5', 'foo3' + _exe), + stdout = "f3.c 2\n") +test.run(program = test.workpath('build', 'var5', 'foo4' + _exe), + stdout = "f4.c 2\n") + +test.run(chdir='work1', arguments='../build/var5', stdout=test.wrap_stdout("""\ +scons: `%s' is up to date. +""" % test.workpath('build', 'var5'))) + +# +test.write(['work2', 'SConstruct'], """\ +env = Environment() +env.Program('prog.c') +""") + +test.write(['work2', 'prog.c'], r""" +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("work2/prog.c\n"); + exit (0); +} +""") + +test.run(chdir='work2', arguments='.') + +test.up_to_date(chdir='work2', arguments='.') + +# +test.write(['work2', 'SConstruct'], """\ +env = Environment() +BuildDir('build', '.') +Export('env') +SConscript('build/SConscript') +""") + +test.write(['work2', 'SConscript'], """\ +Import('env') +env.Program('prog.c') +""") + +test.run(chdir='work2', arguments='.', stderr=None) + +test.fail_test(not blank_output(test.stderr())) + +test.run(chdir='work2', arguments='.', + stdout=test.wrap_stdout("""\ +scons: building associated BuildDir targets: build +scons: `.' is up to date. +""")) + +test.write( ['work3', 'SConstruct'], """\ +SConscriptChdir(0) +BuildDir('build', '.', duplicate=1 ) +SConscript( 'build/SConscript' ) +""") + +test.write( ['work3', 'SConscript'], """\ +import sys +headers = ['existing.h', 'non_existing.h'] +for header in headers: + h = File( header ) + contents = h.get_contents() + sys.stderr.write( '%s:%s\\n' % (header, contents)) +""") + +test.write( ['work3', 'existing.h'], """\ +/* a header file */\ +""") + +test.run(chdir='work3', + stdout=test.wrap_stdout("""\ +scons: building associated BuildDir targets: build +scons: `.' is up to date. +"""), + stderr="""\ +existing.h:/* a header file */ +non_existing.h: +""") + +test.pass_test() diff --git a/test/BuildDir/CPPPATH-subdir.py b/test/BuildDir/CPPPATH-subdir.py new file mode 100644 index 0000000..2ae50b5 --- /dev/null +++ b/test/BuildDir/CPPPATH-subdir.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__" + +""" +Test handling of the current directory (.) in CPPPATH when +the include path contains a subdirectory. + +This tests for a regression found in 0.96.90 by Chad Austin. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.subdir('src', ['src', 'glscry']) + +test.write('SConstruct', """\ +env = Environment() +Export('env') +SConscript(dirs=['src'], build_dir='build', duplicate=0) +""") + + +test.write(['src', 'SConscript'], """\ +SConscript(dirs=['glscry']) +""") + + +test.write(['src', 'glscry', 'SConscript'], """\ +Import('*') +env = env.Copy() +env.Append(CPPPATH=['.']) +env.Library('foo', 'foo.c') +""") + +test.write(['src', 'glscry', 'foo.c'], """\ +#include <foo.h> +""") + + +test.write(['src', 'glscry', 'foo.h'], "\n") + +test.run(arguments = '.', + stderr = TestSCons.noisy_ar, + match = TestSCons.match_re_dotall) + +test.pass_test() diff --git a/test/BuildDir/Sconscript-build_dir.py b/test/BuildDir/Sconscript-build_dir.py new file mode 100644 index 0000000..298eb9b --- /dev/null +++ b/test/BuildDir/Sconscript-build_dir.py @@ -0,0 +1,263 @@ +#!/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 specifying a build_dir argument to SConscript works properly. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +all1 = test.workpath('test', 'build', 'var1', 'all') +all2 = test.workpath('test', 'build', 'var2', 'all') +all3 = test.workpath('test', 'build', 'var3', 'all') +all4 = test.workpath('test', 'build', 'var4', 'all') +all5 = test.workpath('build', 'var5', 'all') +all6 = test.workpath('build', 'var6', 'all') +all7 = test.workpath('build', 'var7', 'all') +all8 = test.workpath('build', 'var8', 'all') +all9 = test.workpath('test', 'build', 'var9', 'src', 'all') + +test.subdir('test') + +test.write(['test', 'SConstruct'], """ +src = Dir('src') +alt = Dir('alt') +var1 = Dir('build/var1') +var2 = Dir('build/var2') +var3 = Dir('build/var3') +var4 = Dir('build/var4') +var5 = Dir('../build/var5') +var6 = Dir('../build/var6') +var7 = Dir('../build/var7') +var8 = Dir('../build/var8') +var9 = Dir('../build/var9') + +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={'Cat':Builder(action=cat)}, + BUILD='build') + +Export("env") + +SConscript('src/SConscript', build_dir=var1) +SConscript('src/SConscript', build_dir='build/var2', src_dir=src) + +SConscript('src/SConscript', build_dir='build/var3', duplicate=0) + +#XXX We can't support var4 and var5 yet, because our BuildDir linkage +#XXX is to an entire source directory. We haven't yet generalized our +#XXX infrastructure to be able to take the SConscript file from one source +#XXX directory, but the rest of the files from a different one. +#XXX SConscript('src/SConscript', build_dir=var4, src_dir=alt, duplicate=0) + +#XXX SConscript('src/SConscript', build_dir='../build/var5', src_dir='alt') +SConscript('src/SConscript', build_dir=var6) + +SConscript('src/SConscript', build_dir=var7, src_dir=src, duplicate=0) +env.SConscript('src/SConscript', build_dir='../$BUILD/var8', duplicate=0) + +# This tests the fact that if you specify a src_dir that is above +# the dir a SConscript is in, that we do the intuitive thing, i.e., +# we set the path of the SConscript accordingly. The below is +# equivalent to saying: +# +# BuildDir('build/var9', '.') +# SConscript('build/var9/src/SConscript') +SConscript('src/SConscript', build_dir='build/var9', src_dir='.') +""") + +test.subdir(['test', 'src'], ['test', 'alt']) + +test.write(['test', 'src', 'SConscript'], """ +Import("env") +env.Cat('aaa.out', 'aaa.in') +env.Cat('bbb.out', 'bbb.in') +env.Cat('ccc.out', 'ccc.in') +env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out']) +""") + +test.write('test/src/aaa.in', "test/src/aaa.in\n") +test.write('test/src/bbb.in', "test/src/bbb.in\n") +test.write('test/src/ccc.in', "test/src/ccc.in\n") + +test.write('test/alt/aaa.in', "test/alt/aaa.in\n") +test.write('test/alt/bbb.in', "test/alt/bbb.in\n") +test.write('test/alt/ccc.in', "test/alt/ccc.in\n") + +test.run(chdir='test', arguments = '. ../build') + +all_src = "test/src/aaa.in\ntest/src/bbb.in\ntest/src/ccc.in\n" +all_alt = "test/alt/aaa.in\ntest/alt/bbb.in\ntest/alt/ccc.in\n" + +test.must_match(all1, all_src) +test.must_match(all2, all_src) +test.must_match(all3, all_src) +#XXX We can't support var4 and var5 yet, because our BuildDir linkage +#XXX is to an entire source directory. We haven't yet generalized our +#XXX infrastructure to be able to take the SConscript file from one source +#XXX directory, but the rest of the files from a different one. +#XXX test.must_match(all4, all_alt) +#XXX test.must_match(all5, all_alt) +test.must_match(all6, all_src) +test.must_match(all7, all_src) +test.must_match(all8, all_src) +test.must_match(all9, all_src) + +import os +import stat +def equal_stats(x,y): + x = os.stat(x) + y = os.stat(y) + return (stat.S_IMODE(x[stat.ST_MODE]) == stat.S_IMODE(y[stat.ST_MODE]) and + x[stat.ST_MTIME] == y[stat.ST_MTIME]) + +# Make sure we did duplicate the source files in build/var1, +# and that their stats are the same: +for file in ['aaa.in', 'bbb.in', 'ccc.in']: + test.must_exist(test.workpath('test', 'build', 'var1', file)) + test.fail_test(not equal_stats(test.workpath('test', 'build', 'var1', file), + test.workpath('test', 'src', file))) + +# Make sure we did duplicate the source files in build/var2, +# and that their stats are the same: +for file in ['aaa.in', 'bbb.in', 'ccc.in']: + test.must_exist(test.workpath('test', 'build', 'var2', file)) + test.fail_test(not equal_stats(test.workpath('test', 'build', 'var2', file), + test.workpath('test', 'src', file))) + +# Make sure we didn't duplicate the source files in build/var3. +test.must_not_exist(test.workpath('test', 'build', 'var3', 'aaa.in')) +test.must_not_exist(test.workpath('test', 'build', 'var3', 'bbb.in')) +test.must_not_exist(test.workpath('test', 'build', 'var3', 'ccc.in')) + +#XXX We can't support var4 and var5 yet, because our BuildDir linkage +#XXX is to an entire source directory. We haven't yet generalized our +#XXX infrastructure to be able to take the SConscript file from one source +#XXX directory, but the rest of the files from a different one. +#XXX Make sure we didn't duplicate the source files in build/var4. +#XXXtest.must_not_exist(test.workpath('test', 'build', 'var4', 'aaa.in')) +#XXXtest.must_not_exist(test.workpath('test', 'build', 'var4', 'bbb.in')) +#XXXtest.must_not_exist(test.workpath('test', 'build', 'var4', 'ccc.in')) + +#XXX We can't support var4 and var5 yet, because our BuildDir linkage +#XXX is to an entire source directory. We haven't yet generalized our +#XXX infrastructure to be able to take the SConscript file from one source +#XXX directory, but the rest of the files from a different one. +#XXX Make sure we did duplicate the source files in build/var5, +#XXX and that their stats are the same: +#XXXfor file in ['aaa.in', 'bbb.in', 'ccc.in']: +#XXX test.must_exist(test.workpath('build', 'var5', file)) +#XXX test.fail_test(not equal_stats(test.workpath('build', 'var5', file), +#XXX test.workpath('test', 'src', file))) + +# Make sure we did duplicate the source files in build/var6, +# and that their stats are the same: +for file in ['aaa.in', 'bbb.in', 'ccc.in']: + test.must_exist(test.workpath('build', 'var6', file)) + test.fail_test(not equal_stats(test.workpath('build', 'var6', file), + test.workpath('test', 'src', file))) + +# Make sure we didn't duplicate the source files in build/var7. +test.must_not_exist(test.workpath('build', 'var7', 'aaa.in')) +test.must_not_exist(test.workpath('build', 'var7', 'bbb.in')) +test.must_not_exist(test.workpath('build', 'var7', 'ccc.in')) + +# Make sure we didn't duplicate the source files in build/var8. +test.must_not_exist(test.workpath('build', 'var8', 'aaa.in')) +test.must_not_exist(test.workpath('build', 'var8', 'bbb.in')) +test.must_not_exist(test.workpath('build', 'var8', 'ccc.in')) + +################### +test.subdir('test2') + +test.write(['test2', 'SConstruct'], """\ +SConscript('SConscript', build_dir='Build', src_dir='.', duplicate=0) +""") + +test.write(['test2', 'SConscript'], """\ +env = Environment() +foo_obj = env.Object('foo.c') +env.Program('foo', [foo_obj, 'bar.c']) +""") + +test.write(['test2', 'bar.c'], r""" +void +bar(void) { + printf("bar.c\n"); +} +""") + +test.write(['test2', 'foo.c'], r""" +int +main(int argc, char *argv[]) { + bar(); + printf("foo.c\n"); +} +""") + +test.run(chdir="test2") + +_obj = TestSCons._obj + +test.must_not_exist(test.workpath('test2', 'foo' + _obj)) +test.must_not_exist(test.workpath('test2', 'bar' + _obj)) +test.must_exist(test.workpath('test2', 'Build', 'foo' + _obj)) +test.must_exist(test.workpath('test2', 'Build', 'bar' + _obj)) + +################### +# Make sure that directories for subsidiary SConscript() calls +# in a build_dir get created if they don't already exist. +test.subdir('test3') + +test.subdir(['test3', 'src'], ['test3', 'src', '_glscry']) + +test.write(['test3', 'SConstruct'], """\ +SConscript(dirs=['src'], build_dir='build', duplicate=0) +""") + +test.write(['test3', 'src', 'SConscript'], """\ +SConscript(dirs=['_glscry']) +""") + +test.write(['test3', 'src', '_glscry', 'SConscript'], """\ +""") + +test.write(['test3', 'src', 'file.in'], "file.in\n") + +test.write(['test3', 'src', '_glscry', 'file.in'], "file.in\n") + +test.run(chdir='test3') + + +test.pass_test() diff --git a/test/BuildDir/errors.py b/test/BuildDir/errors.py new file mode 100644 index 0000000..93cd3ec --- /dev/null +++ b/test/BuildDir/errors.py @@ -0,0 +1,171 @@ +#!/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__" + +""" +Validate successful handling of errors when duplicating things in +BuildDirs. This is generally when the BuildDir, or something in it, +is read-only. +""" + +import os +import os.path +import stat +import sys +import TestSCons + +test = TestSCons.TestSCons() + +for dir in ['normal', 'ro-dir', 'ro-SConscript', 'ro-src']: + test.subdir(dir, [dir, 'src']) + + test.write([dir, 'SConstruct'], """\ +import os.path +BuildDir('build', 'src') +SConscript(os.path.join('build', 'SConscript')) +""") + + test.write([dir, 'src', 'SConscript'], """\ +def fake_scan(node, env, target): + # We fetch the contents here, even though we don't examine + # them, because get_contents() will cause the engine to + # try to link the source file into the build directory, + # potentially triggering a different failure case. + contents = node.get_contents() + return [] + +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)}, + SCANNERS=[Scanner(fake_scan, skeys = ['.in'])]) + +# Do some Node test operations to ensure no side-effects cause failures +File('file.in').exists() +File('file.in').is_derived() +File('file.in').is_pseudo_derived() + +env.Build('file.out', 'file.in') +""") + + test.write([dir, 'src', 'file.in'], dir + "/src/file.in\n") + +# Just verify that the normal case works fine. +test.run(chdir = 'normal', arguments = ".") + +test.fail_test(test.read(['normal', 'build', 'file.out']) != "normal/src/file.in\n") + +# Verify the error when the BuildDir itself is read-only. Don't bother +# to test this on Win32, because the ACL (I think) still allows the +# owner to create files in the directory even when it's read-only. +if sys.platform != 'win32': + dir = os.path.join('ro-dir', 'build') + test.subdir(dir) + os.chmod(dir, os.stat(dir)[stat.ST_MODE] & ~stat.S_IWUSR) + + test.run(chdir = 'ro-dir', + arguments = ".", + status = 2, + stderr = "scons: *** Cannot duplicate `%s' in `build': Permission denied. Stop.\n" % os.path.join('src', 'SConscript')) + +# Verify the error when the SConscript file within the BuildDir is +# read-only. Note that we have to make the directory read-only too, +# because otherwise our duplication logic will be able to unlink +# the read-only SConscript and duplicate the new one. +dir = os.path.join('ro-SConscript', 'build') +test.subdir(dir) +SConscript = test.workpath(dir, 'SConscript') +test.write(SConscript, '') +os.chmod(SConscript, os.stat(SConscript)[stat.ST_MODE] & ~stat.S_IWUSR) +f = open(SConscript, 'r') +os.chmod(dir, os.stat(dir)[stat.ST_MODE] & ~stat.S_IWUSR) + +test.run(chdir = 'ro-SConscript', + arguments = ".", + status = 2, + stderr = "scons: *** Cannot duplicate `%s' in `build': Permission denied. Stop.\n" % os.path.join('src', 'SConscript')) + +os.chmod('ro-SConscript', os.stat('ro-SConscript')[stat.ST_MODE] | stat.S_IWUSR) +f.close() + +test.run(chdir = 'ro-SConscript', + arguments = ".", + status = 2, + stderr = "scons: *** Cannot duplicate `%s' in `build': Permission denied. Stop.\n" % os.path.join('src', 'SConscript')) + +# Verify the error when the source file within the BuildDir is +# read-only. Note that we have to make the directory read-only too, +# because otherwise our duplication logic will be able to unlink the +# read-only source file and duplicate the new one. But because we've +# made the BuildDir read-only, we must also create a writable SConscript +# file there so it can be duplicated from the source directory. +dir = os.path.join('ro-src', 'build') +test.subdir(dir) +test.write([dir, 'SConscript'], '') +file_in = test.workpath(dir, 'file.in') +test.write(file_in, '') +os.chmod(file_in, os.stat(file_in)[stat.ST_MODE] & ~stat.S_IWUSR) +f = open(file_in, 'r') +os.chmod(dir, os.stat(dir)[stat.ST_MODE] & ~stat.S_IWUSR) + +test.run(chdir = 'ro-src', + arguments = ".", + status = 2, + stderr = """\ +scons: *** Cannot duplicate `%s' in `build': Permission denied. Stop. +""" % (os.path.join('src', 'file.in'))) + +test.run(chdir = 'ro-src', + arguments = "-k .", + status = 2, + stderr = """\ +scons: *** Cannot duplicate `%s' in `build': Permission denied. Stop. +""" % (os.path.join('src', 'file.in'))) + +f.close() + +# ensure that specifying multiple source directories for one +# build directory results in an error message, rather +# than just silently failing. +test.subdir('duplicate', ['duplicate', 'src1'], ['duplicate', 'src2']) +test.write(['duplicate', 'SConstruct'], """\ +BuildDir('build', 'src1') +BuildDir('build', 'src2') +""") + +test.run(chdir = 'duplicate', + arguments = ".", + status = 2, + stderr = """ +scons: *** 'build' already has a source directory: 'src1'. +File "SConstruct", line 2, in ? +""") + +test.pass_test() diff --git a/test/BuildDir/reflect.py b/test/BuildDir/reflect.py new file mode 100644 index 0000000..beb7df0 --- /dev/null +++ b/test/BuildDir/reflect.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__" + +""" +This test validates the correct operation of a BuildDir specification +in avoiding reflection: reflection is the case where the build_dir is +located under the corresponding source dir, and trying to use elements +in the build_dir as sources for that same build dir. + +Test based on bug #1055521 filed by Gary Oberbrunner. +""" + +import os.path +import re + +import TestSCons + +test = TestSCons.TestSCons() +python = TestSCons.python +re_python = re.escape(python) + +test.write("mycc.py", """ +print 'Compile' +""") + +test.write("mylink.py", """ +print 'Link' +""") + +sconstruct = """ +env = Environment(CC = r'%(python)s mycc.py', + LINK = r'%(python)s mylink.py', + INCPREFIX = 'INC_', + INCSUFFIX = '_CNI', + CPPPATH='%(cpppath)s') # note no leading '#' +Export("env") +SConscript('SConscript', build_dir="dir1/dir2", src_dir=".") +""" + +test.write('SConscript', """\ +Import("env") +env.Program("foo", "src1/foo.c") +Default(".") +""") + +test.write('foo.h', '#define HI_STR "hello, there!"\n') + +test.subdir('src1') + +test.write(['src1', 'foo.c'], """\ +#include <stdio.h> +#include "foo.h" +main() { printf(HI_STR);} +""") + +# Test the bad cpppath; make sure it doesn't reflect dir1/dir2/foo.h +# into dir1/dir2/dir1/dir2/foo.h, and make sure the target/message for +# builds is correct. + +cpppath = 'dir1/dir2' # note, no leading '#' +test.write('SConstruct', sconstruct % locals() ) + +targets = re.escape(os.path.join('dir1', 'dir2')) +INC_CNI = re.escape(os.path.join('INC_dir1', 'dir2', 'dir1', 'dir2_CNI')) + +# The .* after mycc\\.py below handles /nologo flags from Visual C/C++. +test.run(arguments = '', + stdout=test.wrap_stdout("""\ +scons: building associated BuildDir targets: %(targets)s +%(re_python)s mycc\\.py.* %(INC_CNI)s .+ +Compile +%(re_python)s mylink\\.py .+ +Link +""" % locals()), + match=TestSCons.match_re, + ) + +# Note that we don't check for the existence of dir1/dir2/foo.h, because +# this bad cpppath will expand to dir1/dir2/dir1/dir2, which means it +# won't pick up the srcdir copy of dir/dir2/foo.h. That's all right, +# we just need to make sure it doesn't create dir1/dir2/dir1/dir2/foo.h. +test.must_exist(['dir1', 'dir2', 'src1', 'foo.c']) +test.must_not_exist(['dir1', 'dir2', 'dir1', 'dir2', 'foo.h']) + +import shutil +shutil.rmtree('dir1', ignore_errors=1) +test.must_not_exist('dir1') + +# Now test the good cpppath and make sure everything looks right. + +cpppath = '#dir1/dir2' # note leading '#' +test.write('SConstruct', sconstruct % locals() ) + +INC_CNI = re.escape(os.path.join('INC_dir1', 'dir2_CNI')) + +# The .* after mycc\\.py below handles /nologo flags from Visual C/C++. +test.run(arguments = '', + stdout=test.wrap_stdout("""\ +scons: building associated BuildDir targets: %(targets)s +%(re_python)s mycc\\.py.* %(INC_CNI)s .+ +Compile +%(re_python)s mylink\\.py .+ +Link +""" % locals()), + match=TestSCons.match_re, + ) + +test.must_exist(['dir1', 'dir2', 'foo.h']) +test.must_exist(['dir1', 'dir2', 'src1', 'foo.c']) +test.must_not_exist(['dir1', 'dir2', 'dir1', 'dir2', 'foo.h']) + + +test.pass_test() |