From f98a2dabc8603592c74f02674a8dc551533382b6 Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Wed, 10 Jul 2002 22:39:00 +0000 Subject: 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) --- doc/man/scons.1 | 31 +++++++++++--- src/CHANGES.txt | 7 ++++ src/engine/SCons/Node/FS.py | 4 +- src/engine/SCons/Node/FSTests.py | 16 +++---- src/engine/SCons/Script/SConscript.py | 5 +++ src/engine/SCons/Tool/g++.py | 2 +- src/engine/SCons/Tool/gcc.py | 2 +- test/BuildDir.py | 79 ++++++++++++++++++----------------- test/CPPFLAGS.py | 43 ++++++++++++++++++- test/FindFile.py | 64 ++++++++++++++++++++++++++++ 10 files changed, 194 insertions(+), 59 deletions(-) create mode 100644 test/FindFile.py diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 7cd5884..4f59835 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 @@ -1991,6 +2007,9 @@ can be a relative or absolute path. is an optional directory that will be used as the parent directory. .TP +.RI FindFile( file ", " + +.TP .RI Export( vars ) This tells .B scons diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 157cb11..45a6517 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 a047903..771ac56 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 6151f2d..1ae1215 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -95,6 +95,14 @@ class BuildDirTestCase(unittest.TestCase): 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') f1 = fs.File('build/var1/test1') @@ -129,14 +137,6 @@ class BuildDirTestCase(unittest.TestCase): 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() fs.BuildDir('build', '/test/foo') except UserError: exc_caught = 1 diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py index 7ae7f21..0f65732 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 a903b0a..f631b0b 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 c5a1e91..d767b21 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 aae3a78..14c24e2 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 9c0295c..7b27233 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 0000000..6c3c347 --- /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() + -- cgit v0.12