From: stevenknight Date: Tue, 21 Oct 2003 05:17:36 +0000 (+0000) Subject: Fix various SConf bugs. (Christoph Wiedemann) X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=a5144230a64beeec9caecdef2735ec4f0f473771;p=scons.git Fix various SConf bugs. (Christoph Wiedemann) git-svn-id: http://scons.tigris.org/svn/scons/trunk@825 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 22edc262..b7793236 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -168,6 +168,13 @@ RELEASE X.XX - XXX - Fix a bug in detection of Qt installed on the local system. + - Support returning Python 2.3 BooleanType values from Configure checks. + + - Provide an error message if someone mistakenly tries to call a + Configure check from within a Builder function. + + - Support calling a Builder when a Configure context is still open. + RELEASE 0.92 - Wed, 20 Aug 2003 03:45:28 -0500 diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 2ad0a329..d079feb2 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -1443,6 +1443,9 @@ class EnvironmentTestCase(unittest.TestCase): # Configure() will write to a local temporary file. test = TestCmd.TestCmd(workdir = '') save = os.getcwd() + # Configure() will test, if we are reading a SConscript file + import SCons.Script.SConscript + SCons.Script.SConscript.sconscript_reading = 1 try: os.chdir(test.workpath()) diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py index 0fbde14c..144099f8 100644 --- a/src/engine/SCons/SConf.py +++ b/src/engine/SCons/SConf.py @@ -33,7 +33,7 @@ import os import string import sys import traceback -from types import * +import types import SCons.Action import SCons.Builder @@ -70,6 +70,8 @@ def _stringSource( target, source, env ): return (target[0].get_path() + ' <- \n |' + string.replace( env['SCONF_TEXT'], "\n", "\n |" ) ) +BooleanTypes = [types.IntType] +if hasattr(types, 'BooleanType'): BooleanTypes.append(types.BooleanType) class SConf: """This is simply a class to represent a configure context. After @@ -92,6 +94,9 @@ class SConf: Note also the conf_dir and log_file arguments (you may want to build tests in the BuildDir, not in the SourceDir) """ + import SCons.Script.SConscript + if not SCons.Script.SConscript.sconscript_reading: + raise SCons.Errors.UserError, "Calling Configure from Builders is not supported." global SConfFS if not SConfFS: SConfFS = SCons.Node.FS.FS(SCons.Node.FS.default_fs.pathTop) @@ -246,6 +251,9 @@ class SConf: suff = self.env.subst( builder.builder.suffix ) target = self.confdir.File(pref + f + suff) self.env['SCONF_TEXT'] = text + self.env['PIPE_BUILD'] = 1 + self.env['PSTDOUT'] = self.logstream + self.env['PSTDERR'] = self.logstream if text != None: source = self.confdir.File(f + extension) sourceNode = self.env.SConfSourceBuilder(target=source, @@ -260,6 +268,10 @@ class SConf: nodesToBeBuilt.extend(nodes) ret = self.BuildNodes(nodesToBeBuilt) + # clean up environment + del self.env['PIPE_BUILD'] + del self.env['PSTDOUT'] + del self.env['PSTDERR'] del self.env['SCONF_TEXT'] _ac_build_counter = _ac_build_counter + 1 @@ -440,9 +452,6 @@ class SConf: # the build system not to override it with a eventually # existing file with the same name in the source directory self.logfile.dir.add_ignore( [self.logfile] ) - self.env['PIPE_BUILD'] = 1 - self.env['PSTDOUT'] = self.logstream - self.env['PSTDERR'] = self.logstream tb = traceback.extract_stack()[-3] @@ -471,10 +480,6 @@ class SConf: if self.logstream != None: self.logstream.close() self.logstream = None - # clean up environment - del self.env['PIPE_BUILD'] - del self.env['PSTDOUT'] - del self.env['PSTDERR'] # remove the SConfSourceBuilder from the environment blds = self.env['BUILDERS'] del blds['SConfSourceBuilder'] @@ -529,15 +534,15 @@ class CheckContext: 'failed'. The result is only displayed when self.did_show_result is not set. """ - if type(res) == IntType: + if type(res) in BooleanTypes: if res: text = "ok" else: text = "failed" - elif type(res) == StringType: + elif type(res) == types.StringType: text = res else: - raise TypeError, "Expected string or int" + raise TypeError, "Expected string, int or bool, got " + str(type(res)) if self.did_show_result == 0: if self.cached: @@ -578,12 +583,12 @@ class CheckContext: def BuildProg(self, text, ext): # TODO: should use self.vardict for $CC, $CPPFLAGS, etc. res = self.TryBuild(self.env.Program, text, ext) - if type(res) == IntType: + if type(res) in BooleanTypes: if res: ret = "" else: ret = "failed to build test program" - elif type(res) == StringType: + elif type(res) == types.StringType: ret = res else: raise TypeError, "Expected string or int" @@ -592,12 +597,12 @@ class CheckContext: def CompileProg(self, text, ext): # TODO: should use self.vardict for $CC, $CPPFLAGS, etc. res = self.TryBuild(self.env.Object, text, ext) - if type(res) == IntType: + if type(res) in BooleanTypes: if res: ret = "" else: ret = "failed to compile test program" - elif type(res) == StringType: + elif type(res) == types.StringType: ret = res else: raise TypeError, "Expected string or int" diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py index 78b27bd3..2028c3bd 100644 --- a/src/engine/SCons/SConfTests.py +++ b/src/engine/SCons/SConfTests.py @@ -64,6 +64,8 @@ class SConfTestCase(unittest.TestCase): # we only use SCons.Environment and SCons.SConf for these tests. import SCons.Environment import SCons.SConf + import SCons.Script.SConscript + SCons.Script.SConscript.sconscript_reading = 1 self.Environment = SCons.Environment self.SConf = SCons.SConf # and we need a new environment, cause references may point to diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py index 92cd68dd..82120615 100644 --- a/src/engine/SCons/Script/SConscript.py +++ b/src/engine/SCons/Script/SConscript.py @@ -67,6 +67,9 @@ global_exports = {} # chdir flag sconscript_chdir = 1 +# will be set to 1, if we are reading a SConscript +sconscript_reading = 0 + def _scons_add_args(alist): global arguments for arg in alist: @@ -139,6 +142,8 @@ def Return(*vars): stack[-1].retval = tuple(retval) def _SConscript(fs, *files, **kw): + global sconscript_reading + sconscript_reading = 1 top = fs.Top sd = fs.SConstruct_dir.rdir() exports = kw.get('exports', []) @@ -215,6 +220,7 @@ def _SConscript(fs, *files, **kw): f.path) finally: + sconscript_reading = 0 sys.path = old_sys_path frame = stack.pop() try: diff --git a/test/Configure.py b/test/Configure.py index 91704690..2b134dc2 100644 --- a/test/Configure.py +++ b/test/Configure.py @@ -40,32 +40,38 @@ else: # to use cygwin compilers on cmd.exe -> uncomment following line #lib = 'm' -oldPwd = os.getcwd() +work_cnt = 0 +work_dir = None python = TestSCons.python -test = None - -def reset(dot = 1): - global test, oldPwd - os.chdir( oldPwd ) - TestSCons.scons = None - test = TestSCons.TestSCons() - if dot == 1: +test = TestSCons.TestSCons() + + +def reset(match = 1): + global test, work_dir, work_cnt + work_cnt = work_cnt + 1 + work_dir='test%d' % work_cnt + test.subdir(work_dir) + if match == 0: + test.match_func = TestCmd.match_re + elif match == 1: test.match_func = TestCmd.match_re_dotall - + elif match == 2: + test.match_func = TestCmd.match_exact def checkFiles(test, files): + global work_dir for f in files: - test.fail_test( not os.path.isfile( test.workpath(f) ) ) + test.fail_test( not os.path.isfile( test.workpath(work_dir,f) ) ) def checkLog( test, logfile, numUpToDate, numCache ): - test.fail_test(not os.path.exists(test.workpath(logfile))) - log = test.read(test.workpath(logfile)) + test.fail_test(not os.path.exists(test.workpath(work_dir, logfile))) + log = test.read(test.workpath(work_dir, logfile)) try: test.fail_test( len( re.findall( "is up to date", log ) ) != numUpToDate ) test.fail_test( len( re.findall( "\(cached\): Building \S+ failed in a previous run.", log ) ) != numCache ) except: - print "contents of log ", test.workpath(logfile), "\n", log + print "contents of log ", test.workpath(work_dir, logfile), "\n", log raise @@ -73,9 +79,9 @@ try: # 1.1 if checks are ok, the cache mechanism should work - reset(dot=0) + reset(match=2) - test.write( 'SConstruct', """ + test.write([work_dir, 'SConstruct'], """ env = Environment() import os env['ENV']['PATH'] = os.environ['PATH'] @@ -102,17 +108,17 @@ Checking for C++ header file vector... yes """ % (lib, lib)) - test.run(stdout = required_stdout) + test.run(chdir=work_dir, stdout = required_stdout) checkLog(test,'config.log', 0, 0 ) - test.run(stdout = required_stdout) + test.run(chdir=work_dir, stdout = required_stdout) checkLog(test,'config.log',12, 0 ) # 1.2 if checks are not ok, the cache mechanism should work as well # (via explicit cache) - reset(dot = 0) # match exactly, "()" is a regexp thing + reset(match=2) # match exactly, "()" is a regexp thing - test.write( 'SConstruct', """ + test.write([work_dir, 'SConstruct'], """ env = Environment() import os env['ENV']['PATH'] = os.environ['PATH'] @@ -132,10 +138,10 @@ Checking for main() in C library no_c_library_SAFFDG... no """) - test.run(stdout = required_stdout) + test.run(chdir=work_dir, stdout = required_stdout) checkLog(test, 'config.log', 0, 0 ) - test.run(stdout = required_stdout) + test.run(chdir=work_dir, stdout = required_stdout) checkLog(test, 'config.log', 2, 2 ) @@ -143,7 +149,7 @@ Checking for main() in C library no_c_library_SAFFDG... no reset() - test.write( 'SConstruct', """ + test.write([work_dir, 'SConstruct'], """ env = Environment() import os env['ENV']['PATH'] = os.environ['PATH'] @@ -154,11 +160,11 @@ env = conf.Finish() Export( 'env' ) SConscript( 'SConscript' ) """) - test.write( 'SConscript', """ + test.write([work_dir, 'SConscript'], """ Import( 'env' ) env.Program( 'TestProgram', 'TestProgram.c' ) """) - test.write( 'TestProgram.c', """ + test.write([work_dir, 'TestProgram.c'], """ #include int main() { @@ -170,10 +176,10 @@ int main() { """Checking for C header file math.h... yes Checking for C header file no_std_c_header.h... no """) - test.run( stdout = required_stdout ) + test.run(chdir=work_dir, stdout = required_stdout ) checkLog( test, 'config.log', 0, 0 ) - test.run( stdout = required_stdout ) + test.run(chdir=work_dir, stdout = required_stdout ) checkLog( test, 'config.log', 3, 1 ) @@ -181,7 +187,7 @@ Checking for C header file no_std_c_header.h... no reset() - test.write( 'SConstruct', """ + test.write([work_dir, 'SConstruct'], """ env = Environment(LOGFILE='build/config.log') import os env['ENV']['PATH'] = os.environ['PATH'] @@ -194,11 +200,11 @@ Export( 'env' ) # print open( 'build/config.log' ).readlines() SConscript( 'build/SConscript' ) """) - test.write( 'SConscript', """ + test.write([work_dir, 'SConscript'], """ Import( 'env' ) env.Program( 'TestProgram', 'TestProgram.c' ) """) - test.write( 'TestProgram.c', """ + test.write([work_dir, 'TestProgram.c'], """ #include int main() { @@ -210,18 +216,18 @@ int main() { """Checking for C header file math.h... yes Checking for C header file no_std_c_header.h... no """) - test.run( stdout = required_stdout ) + test.run(chdir=work_dir, stdout = required_stdout ) checkLog( test, 'build/config.log', 0, 0 ) - test.run( stdout = required_stdout ) + test.run(chdir=work_dir, stdout = required_stdout ) checkLog( test, 'build/config.log', 3, 1 ) # 2.3 test that Configure calls in SConscript files work # even if BuildDir is set reset() - test.subdir( 'sub', ['sub', 'local'] ) - test.write( 'SConstruct', """ + test.subdir( [work_dir, 'sub'], [work_dir, 'sub', 'local'] ) + test.write([work_dir, 'SConstruct'], """ opts = Options() opts.Add('chdir') env = Environment(options=opts) @@ -232,11 +238,12 @@ else: BuildDir( 'build', '.' ) SConscript( 'build/SConscript' ) """) - test.write( 'sub/local/local_header.h', "/* Hello World */" ) - test.write( 'SConscript', """ + test.write([work_dir, 'sub', 'local', 'local_header.h'], + "/* Hello World */" ) + test.write([work_dir, 'SConscript'], """ SConscript( 'sub/SConscript' ) """) - test.write( 'sub/SConscript', """ + test.write([work_dir, 'sub', 'SConscript'], """ def CustomTest(context): context.Message('Executing Custom Test ... ') ret = context.TryCompile('#include "local_header.h"', '.c') @@ -261,10 +268,10 @@ if not conf.CustomTest(): env = conf.Finish() env.Program( 'TestProgram', 'TestProgram.c' ) """) - test.write( 'sub/TestProgram.h', """ + test.write([work_dir, 'sub', 'TestProgram.h'], """ /* Just a test header */ """) - test.write( 'sub/TestProgram.c', """ + test.write([work_dir, 'sub', 'TestProgram.c'], """ #include "TestProgram.h" #include @@ -279,22 +286,22 @@ Checking for C header file no_std_c_header.h... no Executing Custom Test ... ok """) # first with SConscriptChdir(0) - test.run(stdout = required_stdout, arguments='chdir=no') + test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=no') checkFiles( test, [".sconf_temp/.cache", "config.log"] ) checkLog( test, 'config.log', 0, 0 ) - test.run(stdout = required_stdout, arguments='chdir=no') + test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=no') checkFiles( test, [".sconf_temp/.cache", "config.log"] ) checkLog( test, 'config.log', 5, 1 ) - shutil.rmtree(test.workpath(".sconf_temp")) + shutil.rmtree(test.workpath(work_dir, ".sconf_temp")) # now with SConscriptChdir(1) - test.run(stdout = required_stdout, arguments='chdir=yes') + test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=yes') checkFiles( test, [".sconf_temp/.cache", "config.log"] ) checkLog( test, 'config.log', 0, 0 ) - test.run(stdout = required_stdout, arguments='chdir=yes') + test.run(chdir=work_dir, stdout = required_stdout, arguments='chdir=yes') checkFiles( test, [".sconf_temp/.cache", "config.log"] ) checkLog( test, 'config.log', 5, 1 ) @@ -307,8 +314,8 @@ Executing Custom Test ... ok linkFAIL = "void myFunc(); int main() { myFunc(); }" runOK = compileOK runFAIL = "int main() { return 1; }" - test.write('pyAct.py', 'import sys\nprint sys.argv[1]\nsys.exit(int(sys.argv[1]))\n') - test.write('SConstruct', """ + test.write([work_dir, 'pyAct.py'], 'import sys\nprint sys.argv[1]\nsys.exit(int(sys.argv[1]))\n') + test.write([work_dir, 'SConstruct'], """ def CheckCustom(test): test.Message( 'Executing MyTest ... ' ) retCompileOK = test.TryCompile( '%s', '.c' ) @@ -336,12 +343,49 @@ env = conf.Finish() python, python ) ) required_stdout = test.wrap_stdout(build_str='.*', read_str="Executing MyTest ... ok\n") - test.run(stdout = required_stdout) + test.run(chdir=work_dir, stdout = required_stdout) checkLog( test, 'config.log', 0, 0 ) - test.run(stdout = required_stdout) + test.run(chdir=work_dir, stdout = required_stdout) checkLog( test, 'config.log', 12, 4 ) + # 4.1 test that calling normal builders from an actual configuring + # environment works + reset() + + test.write([work_dir, 'cmd.py'], r""" +import sys +sys.stderr.write( 'Hello World on stderr\n' ) +sys.stdout.write( 'Hello World on stdout\n' ) +open(sys.argv[1], 'w').write( 'Hello World\n' ) +""") + + test.write([work_dir, 'SConstruct'], """ +env = Environment() +def CustomTest(*args): + return 0 +conf = env.Configure(custom_tests = {'MyTest' : CustomTest}) +if not conf.MyTest(): + env.Command("hello", [], "%s cmd.py $TARGET") +env = conf.Finish() +""" % python) + test.run(chdir=work_dir, stderr="Hello World on stderr\n") + + # 4.2 test that calling Configure from a builder results in a + # readable Error + reset(match=2) + + test.write([work_dir, 'SConstruct'], """ +def ConfigureAction(target, source, env): + env.Configure() + return 0 +env = Environment(BUILDERS = {'MyAction' : + Builder(action=Action(ConfigureAction))}) +env.MyAction('target', []) +""") + test.run(chdir=work_dir, status=2, + stderr="scons: *** Calling Configure from Builders is not supported.\n") + test.pass_test() finally: diff --git a/test/SConscript.py b/test/SConscript.py index d889c441..69b7a822 100644 --- a/test/SConscript.py +++ b/test/SConscript.py @@ -384,4 +384,14 @@ test.run(arguments = ".", stdout = test.wrap_stdout(read_str = "SConstruct\nsub/SConscript\nx = xxx\n", build_str = "scons: `.' is up to date.\n")) +test.write("SConstruct", """\ +def builder(target, source, env): + import SCons.Script.SConscript + assert SCons.Script.SConscript.sconscript_reading == 0 +env = Environment(BUILDERS={'builder':Builder(action=builder)}) +env.builder('test',[]) +import SCons.Script.SConscript +assert SCons.Script.SConscript.sconscript_reading == 1 +""") + test.pass_test()