From: stevenknight Date: Wed, 10 Jul 2002 22:39:00 +0000 (+0000) Subject: Allow build directories outside the SConstruct tree; add a FindFile() function to... X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=cc30de45788ad0dc08d68d8c3c4c15212afd608e;p=scons.git Allow build directories outside the SConstruct tree; add a FindFile() function to search for files with a specified name; add to the shared-object g++ and gcc command lines. (Charles Crain) git-svn-id: http://scons.tigris.org/svn/scons/trunk@407 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 7cd58842..4f598355 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -560,7 +560,7 @@ Works exactly the same way as the option except for the way default targets are handled. When this option is used and no targets are specified on the command line, all default targets that are defined in the SConscript(s) in the current -directory are built, regardless of what directory the resulant targets end +directory are built, regardless of what directory the resultant targets end up in. .TP @@ -817,7 +817,7 @@ executable program (on POSIX systems) or .B bar.exe -(on Windows sytems) +(on Windows systems) from the bar.c source file: .ES @@ -1336,7 +1336,7 @@ General options passed to the assembler. The command line used to assemble an assembly-language source file into an object file after first running the file through the C preprocessor. -Any options specified in the $CPPFLAGS construction variable +Any options specified in the $ASFLAGS and $CPPFLAGS construction variables are included on this command line. .IP BUILDERS @@ -1352,6 +1352,8 @@ The C compiler. .IP CCCOM The command line used to compile a C source file to a (static) object file. +Any options specified in the $CCFLAGS and $CPPFLAGS construction variables +are included on this command line. .IP CCFLAGS General options that are passed to the C compiler. @@ -1372,7 +1374,8 @@ as C files. .IP CPPFLAGS C preprocessor options. These will be included in any command that uses the C preprocessor, -inluding not just compilation of C and C++ source files, +including not just compilation of C and C++ source files +via the $CCCOM, $SHCCCOM, $CXXCOM and $SHCXXCOM command lines, but also the $F77PPCOM command line used to compile a Fortran source file, and the $ASPPCOM command line @@ -1456,6 +1459,8 @@ as C++ files. .IP CXXCOM The command line used to compile a C++ source file to an object file. +Any options specified in the $CXXFLAGS and $CPPFLAGS construction variables +are included on this command line. .IP CXXFLAGS General options that are passed to the C++ compiler. @@ -1583,7 +1588,7 @@ env = Environment(F77COM="my_compiler $_F77INCFLAGS -c -o $TARGET $SOURCE") .IP F77PPCOM The command line used to compile a Fortran source file to an object file after first running the file through the C preprocessor. -Any options specified in the $CPPFLAGS construction variable +Any options specified in the $F77FLAGS and $CPPFLAGS construction variables are included on this command line. .IP INCPREFIX @@ -1798,6 +1803,8 @@ The C compiler used for generating shared-library objects. .IP SHCCCOM The command line used to compile a C source file to a shared-library object file. +Any options specified in the $SHCCFLAGS and $CPPFLAGS construction variables +are included on this command line. .IP SHCCFLAGS Options that are passed to the C compiler @@ -1809,6 +1816,8 @@ The C++ compiler used for generating shared-library objects. .IP SHCXXCOM The command line used to compile a C++ source file to a shared-library object file. +Any options specified in the $SHCXXFLAGS and $CPPFLAGS construction variables +are included on this command line. .IP SHCXXFLAGS Options that are passed to the C++ compiler @@ -1829,7 +1838,7 @@ to generated shared-library objects. The command line used to compile a Fortran source file to a shared-library object file after first running the file through the C preprocessor. -Any options specified in the $CPPFLAGS construction variable +Any options specified in the $SHF77FLAGS and $CPPFLAGS construction variables are included on this command line. .IP SHLIBPREFIX @@ -1941,6 +1950,13 @@ normally be built under .IR src_dir . Multiple build directories can be set up for multiple build variants, for example. +.I src_dir +must be underneath the SConstruct file's directory, +and +.I build_dir +may not be underneath the +.I src_dir . + .B scons will link or copy (depending on the platform) all the source files into the build directory if @@ -1990,6 +2006,9 @@ can be a relative or absolute path. .I directory is an optional directory that will be used as the parent directory. +.TP +.RI FindFile( file ", " + .TP .RI Export( vars ) This tells diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 157cb112..45a6517e 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -40,6 +40,13 @@ RELEASE 0.08 - - Fix handling file names with multiple dots. + - Allow a build directory to be outside of the SConstruct tree. + + - Add a FindFile() function that searches for a file node with a + specified name. + + - Add $CPPFLAGS to the shared-object command lines for g++ and gcc. + From Charles Crain and Steven Knight: - Add a "tools=" keyword argument to Environment instantiation, diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index a0479031..771ac562 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -289,8 +289,8 @@ class FS: if not isinstance(build_dir, SCons.Node.Node): build_dir = self.Dir(build_dir) build_dir.duplicate = duplicate - if not src_dir.is_under(self.Top) or not build_dir.is_under(self.Top): - raise UserError, "Both source and build directories must be under top of build tree." + if not src_dir.is_under(self.Top): + raise UserError, "Source directory must be under top of build tree." if src_dir.is_under(build_dir): raise UserError, "Source directory cannot be under build directory." build_dir.link(src_dir, duplicate) diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 6151f2d3..1ae12156 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -94,6 +94,14 @@ class BuildDirTestCase(unittest.TestCase): assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath assert f2.srcpath == os.path.normpath('src/test1'), f2.srcpath + fs = SCons.Node.FS.FS() + fs.BuildDir('../var1', 'src') + fs.BuildDir('../var2', 'src') + f1 = fs.File('../var1/test1') + f2 = fs.File('../var2/test1') + assert f1.srcpath == os.path.normpath('src/test1'), f1.srcpath + assert f2.srcpath == os.path.normpath('src/test1'), f2.srcpath + fs = SCons.Node.FS.FS() fs.BuildDir('build/var1', 'src', duplicate=0) fs.BuildDir('build/var2', 'src') @@ -126,14 +134,6 @@ class BuildDirTestCase(unittest.TestCase): assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \ stat.S_IMODE(st[stat.ST_MODE]) - exc_caught = 0 - try: - fs = SCons.Node.FS.FS() - fs.BuildDir('/test/foo', '.') - except UserError: - exc_caught = 1 - assert exc_caught, "Should have caught a UserError." - exc_caught = 0 try: fs = SCons.Node.FS.FS() diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py index 7ae7f219..0f657323 100644 --- a/src/engine/SCons/Script/SConscript.py +++ b/src/engine/SCons/Script/SConscript.py @@ -220,6 +220,10 @@ def GetBuildPath(files): return ret[0] return ret +def FindFile(file, dirs): + nodes = SCons.Node.arg2nodes(dirs, SCons.Node.FS.default_fs.Dir) + return SCons.Node.FS.find_file(file, nodes) + def Export(*vars): try: for var in vars: @@ -256,6 +260,7 @@ def BuildDefaultGlobals(): globals['Environment'] = SCons.Environment.Environment globals['Export'] = Export globals['File'] = SCons.Node.FS.default_fs.File + globals['FindFile'] = FindFile globals['GetBuildPath'] = GetBuildPath globals['GetCommandHandler'] = SCons.Action.GetCommandHandler globals['Help'] = Help diff --git a/src/engine/SCons/Tool/g++.py b/src/engine/SCons/Tool/g++.py index a903b0a4..f631b0b0 100644 --- a/src/engine/SCons/Tool/g++.py +++ b/src/engine/SCons/Tool/g++.py @@ -55,7 +55,7 @@ def generate(env, platform): env['CXXCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' env['SHCXX'] = '$CXX' env['SHCXXFLAGS'] = '$CXXFLAGS -fPIC' - env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' + env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' env['INCPREFIX'] = '-I' env['INCSUFFIX'] = '' diff --git a/src/engine/SCons/Tool/gcc.py b/src/engine/SCons/Tool/gcc.py index c5a1e918..d767b218 100644 --- a/src/engine/SCons/Tool/gcc.py +++ b/src/engine/SCons/Tool/gcc.py @@ -55,7 +55,7 @@ def generate(env, platform): env['CCCOM'] = '$CC $CCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' env['SHCC'] = '$CC' env['SHCCFLAGS'] = '$CCFLAGS -fPIC' - env['SHCCCOM'] = '$SHCC $SHCCFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' + env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' env['INCPREFIX'] = '-I' env['INCSUFFIX'] = '' diff --git a/test/BuildDir.py b/test/BuildDir.py index aae3a78f..14c24e24 100644 --- a/test/BuildDir.py +++ b/test/BuildDir.py @@ -36,34 +36,36 @@ else: test = TestSCons.TestSCons() -foo11 = test.workpath('build', 'var1', 'foo1' + _exe) -foo12 = test.workpath('build', 'var1', 'foo2' + _exe) -foo21 = test.workpath('build', 'var2', 'foo1' + _exe) -foo22 = test.workpath('build', 'var2', 'foo2' + _exe) -foo31 = test.workpath('build', 'var3', 'foo1' + _exe) -foo32 = test.workpath('build', 'var3', 'foo2' + _exe) -foo41 = test.workpath('build', 'var4', 'foo1' + _exe) -foo42 = test.workpath('build', 'var4', 'foo2' + _exe) +foo11 = test.workpath('test', 'build', 'var1', 'foo1' + _exe) +foo12 = test.workpath('test', 'build', 'var1', 'foo2' + _exe) +foo21 = test.workpath('test', 'build', 'var2', 'foo1' + _exe) +foo22 = test.workpath('test', 'build', 'var2', 'foo2' + _exe) +foo31 = test.workpath('test', 'build', 'var3', 'foo1' + _exe) +foo32 = test.workpath('test', 'build', 'var3', 'foo2' + _exe) +foo41 = test.workpath('test', 'build', 'var4', 'foo1' + _exe) +foo42 = test.workpath('test', 'build', 'var4', 'foo2' + _exe) foo51 = test.workpath('build', 'var5', 'foo1' + _exe) foo52 = test.workpath('build', 'var5', 'foo2' + _exe) -bar11 = test.workpath('build', 'var1', 'bar1' + _exe) -bar12 = test.workpath('build', 'var1', 'bar2' + _exe) -bar21 = test.workpath('build', 'var2', 'bar1' + _exe) -bar22 = test.workpath('build', 'var2', 'bar2' + _exe) -bar31 = test.workpath('build', 'var3', 'bar1' + _exe) -bar32 = test.workpath('build', 'var3', 'bar2' + _exe) -bar41 = test.workpath('build', 'var4', 'bar1' + _exe) -bar42 = test.workpath('build', 'var4', 'bar2' + _exe) +bar11 = test.workpath('test', 'build', 'var1', 'bar1' + _exe) +bar12 = test.workpath('test', 'build', 'var1', 'bar2' + _exe) +bar21 = test.workpath('test', 'build', 'var2', 'bar1' + _exe) +bar22 = test.workpath('test', 'build', 'var2', 'bar2' + _exe) +bar31 = test.workpath('test', 'build', 'var3', 'bar1' + _exe) +bar32 = test.workpath('test', 'build', 'var3', 'bar2' + _exe) +bar41 = test.workpath('test', 'build', 'var4', 'bar1' + _exe) +bar42 = test.workpath('test', 'build', 'var4', 'bar2' + _exe) bar51 = test.workpath('build', 'var5', 'bar1' + _exe) bar52 = test.workpath('build', 'var5', 'bar2' + _exe) -test.write('SConstruct', """ +test.subdir('test') + +test.write('test/SConstruct', """ src = Dir('src') var2 = Dir('build/var2') var3 = Dir('build/var3') var4 = Dir('build/var4') -var5 = Dir('build/var5') +var5 = Dir('../build/var5') BuildDir('build/var1', src) @@ -81,11 +83,11 @@ SConscript('build/var3/SConscript', "env") SConscript(File('SConscript', var4), "env") env = Environment(CPPPATH='.', F77PATH='.') -SConscript('build/var5/SConscript', "env") +SConscript('../build/var5/SConscript', "env") """) -test.subdir('src') -test.write(['src', 'SConscript'], """ +test.subdir(['test', 'src']) +test.write(['test', 'src', 'SConscript'], """ import os import os.path @@ -108,7 +110,7 @@ env.Copy(LIBS = 'g2c').Program(target='bar2', source='b2.f') env.Copy(LIBS = 'g2c').Program(target='bar1', source='b1.f') """) -test.write('src/f1.c', r""" +test.write('test/src/f1.c', r""" #include "f1.h" int @@ -120,7 +122,7 @@ main(int argc, char *argv[]) } """) -test.write('src/f2.in', r""" +test.write('test/src/f2.in', r""" #include "f2.h" int @@ -132,37 +134,37 @@ main(int argc, char *argv[]) } """) -test.write('src/f1.h', r""" +test.write('test/src/f1.h', r""" #define F1_STR "f1.c\n" """) -test.write('src/f2.h', r""" +test.write('test/src/f2.h', r""" #define F2_STR "f2.c\n" """) -test.write(['src', 'b1.f'], r""" +test.write(['test', 'src', 'b1.f'], r""" PROGRAM FOO INCLUDE 'b1.for' STOP END """) -test.write(['src', 'b2.in'], r""" +test.write(['test', 'src', 'b2.in'], r""" PROGRAM FOO INCLUDE 'b2.for' STOP END """) -test.write(['src', 'b1.for'], r""" +test.write(['test', 'src', 'b1.for'], r""" PRINT *, 'b1.for' """) -test.write(['src', 'b2.for'], r""" +test.write(['test', 'src', 'b2.for'], r""" PRINT *, 'b2.for' """) -test.run(arguments = '.') +test.run(chdir='test', arguments = '. ../build') test.run(program = foo11, stdout = "f1.c\n") test.run(program = foo12, stdout = "f2.c\n") @@ -187,16 +189,16 @@ test.run(program = bar51, stdout = " b1.for\n") test.run(program = bar52, stdout = " b2.for\n") # Make sure we didn't duplicate the source files in build/var3. -test.fail_test(os.path.exists(test.workpath('build', 'var3', 'f1.c'))) -test.fail_test(os.path.exists(test.workpath('build', 'var3', 'f2.in'))) -test.fail_test(os.path.exists(test.workpath('build', 'var3', 'b1.f'))) -test.fail_test(os.path.exists(test.workpath('build', 'var3', 'b2.in'))) +test.fail_test(os.path.exists(test.workpath('test', 'build', 'var3', 'f1.c'))) +test.fail_test(os.path.exists(test.workpath('test', 'build', 'var3', 'f2.in'))) +test.fail_test(os.path.exists(test.workpath('test', 'build', 'var3', 'b1.f'))) +test.fail_test(os.path.exists(test.workpath('test', 'build', 'var3', 'b2.in'))) # Make sure we didn't duplicate the source files in build/var4. -test.fail_test(os.path.exists(test.workpath('build', 'var4', 'f1.c'))) -test.fail_test(os.path.exists(test.workpath('build', 'var4', 'f2.in'))) -test.fail_test(os.path.exists(test.workpath('build', 'var4', 'b1.f'))) -test.fail_test(os.path.exists(test.workpath('build', 'var4', 'b2.in'))) +test.fail_test(os.path.exists(test.workpath('test', 'build', 'var4', 'f1.c'))) +test.fail_test(os.path.exists(test.workpath('test', 'build', 'var4', 'f2.in'))) +test.fail_test(os.path.exists(test.workpath('test', 'build', 'var4', 'b1.f'))) +test.fail_test(os.path.exists(test.workpath('test', 'build', 'var4', 'b2.in'))) # Make sure we didn't duplicate the source files in build/var5. test.fail_test(os.path.exists(test.workpath('build', 'var5', 'f1.c'))) @@ -204,5 +206,4 @@ test.fail_test(os.path.exists(test.workpath('build', 'var5', 'f2.in'))) test.fail_test(os.path.exists(test.workpath('build', 'var5', 'b1.f'))) test.fail_test(os.path.exists(test.workpath('build', 'var5', 'b2.in'))) - test.pass_test() diff --git a/test/CPPFLAGS.py b/test/CPPFLAGS.py index 9c0295c4..7b272331 100644 --- a/test/CPPFLAGS.py +++ b/test/CPPFLAGS.py @@ -74,7 +74,7 @@ else: import getopt import os import sys -opts, args = getopt.getopt(sys.argv[1:], 'o:') +opts, args = getopt.getopt(sys.argv[1:], 'o:s:') for opt, arg in opts: if opt == '-o': out = arg outfile = open(out, 'wb') @@ -92,7 +92,7 @@ import os import sys compiler = sys.argv[1] clen = len(compiler) + 1 -opts, args = getopt.getopt(sys.argv[2:], 'co:x') +opts, args = getopt.getopt(sys.argv[2:], 'co:xf:') for opt, arg in opts: if opt == '-o': out = arg elif opt == '-x': open('mygcc.out', 'ab').write(compiler + "\n") @@ -140,4 +140,43 @@ test.fail_test(test.read('foo' + _exe) != "test1.c\ntest2.cpp\ntest3.F\n") test.fail_test(test.read('mygcc.out') != "cc\nc++\ng77\n") +test.write('SConstruct', """ +env = Environment(CPPFLAGS = '-x', + SHLINK = r'%s mylink.py', + CC = r'%s mygcc.py cc', + CXX = r'%s mygcc.py c++', + F77 = r'%s mygcc.py g77') +env.SharedLibrary(target = File('foo.bar'), + source = Split('test1.c test2.cpp test3.F')) +""" % (python, python, python, python)) + +test.write('test1.c', r"""test1.c +#cc +#link +""") + +test.write('test2.cpp', r"""test2.cpp +#c++ +#link +""") + +test.write('test3.F', r"""test3.F +#g77 +#link +""") + +test.unlink('mygcc.out') + +test.run(arguments = '.', stderr = None) + +test.fail_test(test.read('test1' + _obj) != "test1.c\n#link\n") + +test.fail_test(test.read('test2' + _obj) != "test2.cpp\n#link\n") + +test.fail_test(test.read('test3' + _obj) != "test3.F\n#link\n") + +test.fail_test(test.read('foo.bar') != "test1.c\ntest2.cpp\ntest3.F\n") + +test.fail_test(test.read('mygcc.out') != "cc\nc++\ng77\n") + test.pass_test() diff --git a/test/FindFile.py b/test/FindFile.py new file mode 100644 index 00000000..6c3c3479 --- /dev/null +++ b/test/FindFile.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# +# Copyright (c) 2001, 2002 Steven Knight +# +# 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 TestSCons + +test = TestSCons.TestSCons() + +test.subdir('foo') +test.subdir('bar') +test.subdir(['bar', 'baz']) + +test.write('testfile1', 'test 1\n') +test.write(['foo', 'testfile2'], 'test 2\n') +test.write(['bar', 'testfile1'], 'test 3\n') +test.write(['bar', 'baz', 'testfile2'], 'test 4\n') + +test.write('SConstruct', """ +file1 = FindFile('testfile1', [ 'foo', '.', 'bar', 'bar/baz' ]) +print open(str(file1), 'r').read() +file2 = FindFile('testfile1', [ 'bar', 'foo', '.', 'bar/baz' ]) +print open(str(file2), 'r').read() +file3 = FindFile('testfile2', [ 'foo', '.', 'bar', 'bar/baz' ]) +print open(str(file3), 'r').read() +file4 = FindFile('testfile2', [ 'bar/baz', 'foo', '.', 'bar' ]) +print open(str(file4), 'r').read() +""") + +expect = """test 1 + +test 3 + +test 2 + +test 4 + +""" + +test.run(stdout = expect) + +test.pass_test() +