Allow build directories outside the SConstruct tree; add a FindFile() function to...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 10 Jul 2002 22:39:00 +0000 (22:39 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 10 Jul 2002 22:39:00 +0000 (22:39 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@407 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Script/SConscript.py
src/engine/SCons/Tool/g++.py
src/engine/SCons/Tool/gcc.py
test/BuildDir.py
test/CPPFLAGS.py
test/FindFile.py [new file with mode: 0644]

index 7cd58842632d009bdf3a32b3f9a08812b9595a19..4f59835519ea954bbe52bbbd01b8ffe4bcd18875 100644 (file)
@@ -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 
index 157cb11270747a8aa93a7b652c987cbda1ead404..45a6517e3f48675c37bc7f7a036602b57dfd7e55 100644 (file)
@@ -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,
index a04790315d04eebb481b49f9f65ae8eb5b90b5ef..771ac5624d33a95fe7d66905cb88e075e247b23a 100644 (file)
@@ -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)
index 6151f2d3599d1507960597b69952a39801b42bf6..1ae121567567b61bccb97fc3da92df148f3147c9 100644 (file)
@@ -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()
index 7ae7f219aa247f34e0287a1c92e6ea4aa0849b07..0f65732329e1fcf925db7d20de6cdb51916a583a 100644 (file)
@@ -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
index a903b0a414403459b79c53a4239405078984496c..f631b0b064b5d92b8fd5b3e670159f4889a02796 100644 (file)
@@ -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']  = ''
 
index c5a1e9188ab176e881129a41c321caef09833fd1..d767b218c1244271974a9178d8bbbf28b76123bb 100644 (file)
@@ -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']  = ''
index aae3a78f79d091d679207d89bf3a0d6672a09041..14c24e24e5b7a94b8678e44133c431afc68b1515 100644 (file)
@@ -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()
index 9c0295c4fe7178256219d93ed3ff0c2bcbfd2d4d..7b272331896e5a70d13854721fdf8cfd421ac016 100644 (file)
@@ -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 (file)
index 0000000..6c3c347
--- /dev/null
@@ -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()
+