From bfc84b0f38ad74bd181df2b0938f0bd94e774cd4 Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Sat, 30 Aug 2003 07:58:08 +0000 Subject: Split non-SCons-specific parts of SConf.py into a separate Conftest.py module. (Bram Moolenaar) --- bin/files | 1 + doc/man/scons.1 | 62 +++++- src/CHANGES.txt | 5 + src/engine/MANIFEST.in | 1 + src/engine/SCons/Conftest.py | 483 +++++++++++++++++++++++++++++++++++++++++++ src/engine/SCons/SConf.py | 242 +++++++++++----------- test/Configure.py | 34 +-- 7 files changed, 685 insertions(+), 143 deletions(-) create mode 100644 src/engine/SCons/Conftest.py diff --git a/bin/files b/bin/files index 252c98f..043eadb 100644 --- a/bin/files +++ b/bin/files @@ -1,5 +1,6 @@ ./SCons/Action.py ./SCons/Builder.py +./SCons/Conftest.py ./SCons/Defaults.py ./SCons/Environment.py ./SCons/Errors.py diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 3919a6e..22cedab 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -3739,38 +3739,70 @@ The following Checks are predefined. goes by and developers contribute new useful tests.) .TP -.RI Configure.CheckCHeader( self ", " header ", [" include_quotes ]) +.RI Configure.CheckHeader( self ", " header ", [" include_quotes ", " language ]) Checks if .I header -is usable in the C-language. The optional argument +is usable in the specified language. +The optional argument .I include_quotes must be a two character string, where the first character denotes the opening quote and the second character denotes the closing quote (both default to \N'34') +The optional argument +.I language +should be either +.B C +or +.B C++ +and selects the compiler to be used for the check. +Returns 1 on success and 0 on failure. + +.TP +.RI Configure.CheckCHeader( self ", " header ", [" include_quotes ]) +This is a wrapper around +.B Configure.CheckHeader +which checks if +.I header +is usable in the C language. The optional argument +.I include_quotes +must be +a two character string, where the first character denotes the opening +quote and the second character denotes the closing quote (both default +to \N'34'). Returns 1 on success and 0 on failure. .TP .RI Configure.CheckCXXHeader( self ", " header ", [" include_quotes ]) -Checks if +This is a wrapper around +.B Configure.CheckHeader +which checks if .I header is usable in the C++ language. The optional argument .I include_quotes must be a two character string, where the first character denotes the opening quote and the second character denotes the closing quote (both default -to \N'34') +to \N'34'). Returns 1 on success and 0 on failure. .TP -.RI Configure.CheckFunc( self ", " function_name ) +.RI Configure.CheckFunc( self ", " function_name ", [" language ]) Checks if the specified C or C+++ function is available. .I function_name is the name of the function to check for. +The optional +.I language +argument should be +.B C +or +.B C++ +and selects the compiler to be used for the check; +the default is "C". .TP -.RI Configure.CheckLib( self ", [" library ", " symbol ", " autoadd ]) +.RI Configure.CheckLib( self ", [" library ", " symbol ", " header ", " language ", " autoadd ]) Checks if .I library provides @@ -3791,6 +3823,14 @@ is "main", which just check if you can link against the specified .IR library . +The optional +.I language +argument should be +.B C +or +.B C++ +and selects the compiler to be used for the check; +the default is "C". The default value for .I autoadd is 1. @@ -3817,7 +3857,7 @@ specifies whether to add the library to the environment (only if the check succeeds). This method returns 1 on success and 0 on error. .TP -.RI Configure.CheckType( self ", " type_name ", [" includes ]) +.RI Configure.CheckType( self ", " type_name ", [" includes ", " language ]) Checks for the existence of a type defined by .BR typedef . .I type_name @@ -3827,6 +3867,14 @@ is a string containing one or more .B #include lines that will be inserted into the program that will be run to test for the existence of the type. +The optional +.I language +argument should be +.B C +or +.B C++ +and selects the compiler to be used for the check; +the default is "C". .EE Example of a typical Configure usage: diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 3aad3c1..7dcdaf9 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -30,6 +30,11 @@ RELEASE X.XX - XXX - Accomodate alphanumeric version strings in EnsurePythonVersion(). + From Bram Moolenaar: + + - Split the non-SCons-specific functionality from SConf.py to a new, + re-usable Conftest.py module. + RELEASE 0.92 - Wed, 20 Aug 2003 03:45:28 -0500 diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in index 4c22f1d..3c71aba 100644 --- a/src/engine/MANIFEST.in +++ b/src/engine/MANIFEST.in @@ -1,6 +1,7 @@ SCons/__init__.py SCons/Action.py SCons/Builder.py +SCons/Conftest.py SCons/Defaults.py SCons/Environment.py SCons/Errors.py diff --git a/src/engine/SCons/Conftest.py b/src/engine/SCons/Conftest.py new file mode 100644 index 0000000..a6bedf5 --- /dev/null +++ b/src/engine/SCons/Conftest.py @@ -0,0 +1,483 @@ +"""SCons.Conftest + +Autoconf-like configuration support; low level implementation of tests. +""" + +# +# Copyright (c) 2003 Stichting NLnet Labs +# Copyright (c) 2001, 2002, 2003 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. +# + +# +# The purpose of this module is to define how a check is to be performed. +# Use one of the Check...() functions below. +# + +# +# A context class is used that defines functions for carrying out the tests, +# logging and messages. The following methods and members must be present: +# +# context.Display(msg) Function called to print messages that are normally +# displayed for the user. Newlines are explicitly used. +# The text should also be written to the logfile! +# +# context.Log(msg) Function called to write to a log file. +# +# context.BuildProg(text, ext) +# Function called to build a program, using "ext" for the +# file extention. Must return an empty string for +# success, an error message for failure. +# For reliable test results building should be done just +# like an actual program would be build, using the same +# command and arguments (including configure results so +# far). +# +# context.CompileProg(text, ext) +# Function called to compile a program, using "ext" for +# the file extention. Must return an empty string for +# success, an error message for failure. +# For reliable test results compiling should be done just +# like an actual source file would be compiled, using the +# same command and arguments (including configure results +# so far). +# +# context.AppendLIBS(lib_name_list) +# Append "lib_name_list" to the value of LIBS. +# "lib_namelist" is a list of strings. +# Return the value of LIBS before changing it (any type +# can be used, it is passed to SetLIBS() later. +# +# context.SetLIBS(value) +# Set LIBS to "value". The type of "value" is what +# AppendLIBS() returned. +# Return the value of LIBS before changing it (any type +# can be used, it is passed to SetLIBS() later. +# +# context.headerfilename +# Name of file to append configure results to, usually +# "confdefs.h". +# The file must not exist or be empty when starting. +# Empty or None to skip this (some tests will not work!). +# +# context.vardict Dictionary holding variables used for the tests and +# stores results from the tests, used for the build +# commands. +# Normally contains "CC", "LIBS", "CPPFLAGS", etc. +# +# context.havedict Dictionary holding results from the tests that are to +# be used inside a program. +# Names often start with "HAVE_". These are zero +# (feature not present) or one (feature present). Other +# variables may have any value, e.g., "PERLVERSION" can +# be a number and "SYSTEMNAME" a string. +# + +import string +from types import IntType + +# +# PUBLIC FUNCTIONS +# + +# Generic remarks: +# - When a language is specified which is not supported the test fails. The +# message is a bit different, because not all the arguments for the normal +# message are available yet (chicken-egg problem). + + +def CheckBuilder(context, text = None, language = None): + """ + Configure check to see if the compiler works. + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + "text" may be used to specify the code to be build. + Returns an empty string for success, an error message for failure. + """ + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("%s\n" % msg) + return msg + + if not text: + text = """ + int main() { + return 0; + }\n\n""" + + context.Display("Checking if building a %s file works... " % lang) + ret = context.BuildProg(text, suffix) + _YesNoResult(context, ret, None, text) + return ret + + +def CheckFunc(context, function_name, header = None, language = None): + """ + Configure check for a function "function_name". + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + Optional "header" can be defined to define a function prototype, include a + header file or anything else that comes before main(). + Sets HAVE_function_name in context.havedict according to the result. + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. + Returns an empty string for success, an error message for failure. + """ + + # Remarks from autoconf: + # - Don't include because on OSF/1 3.0 it includes + # which includes which contains a prototype for select. + # Similarly for bzero. + # - assert.h is included to define __stub macros and hopefully few + # prototypes, which can conflict with char $1(); below. + # - Override any gcc2 internal prototype to avoid an error. + # - We use char for the function declaration because int might match the + # return type of a gcc2 builtin and then its argument prototype would + # still apply. + # - The GNU C library defines this for functions which it implements to + # always fail with ENOSYS. Some functions are actually named something + # starting with __ and the normal name is an alias. + + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + if not header: + header = """ + #ifdef __cplusplus + extern "C" + #endif + char %s();""" % function_name + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for %s(): %s\n" % (function_name, msg)) + return msg + + text = """ + %(include)s + #include + %(hdr)s + + int main() { + #if defined (__stub_%(name)s) || defined (__stub___%(name)s) + fail fail fail + #else + %(name)s(); + #endif + + return 0; + }\n\n""" % { 'name': function_name, + 'include': includetext, + 'hdr': header } + + context.Display("Checking for %s function %s()... " % (lang, function_name)) + ret = context.BuildProg(text, suffix) + _YesNoResult(context, ret, "HAVE_" + function_name, text) + return ret + + +def CheckHeader(context, header_name, header = None, language = None, + include_quotes = None): + """ + Configure check for a C or C++ header file "header_name". + Optional "header" can be defined to do something before including the + header file (unusual, supported for consistency). + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + Sets HAVE_header_name in context.havedict according to the result. + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS and $CPPFLAGS are set correctly. + Returns an empty string for success, an error message for failure. + """ + # Why compile the program instead of just running the preprocessor? + # It is possible that the header file exists, but actually using it may + # fail (e.g., because it depends on other header files). Thus this test is + # more strict. It may require using the "header" argument. + # + # Use <> by default, because the check is normally used for system header + # files. SCons passes '""' to overrule this. + + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"\n' % context.headerfilename + else: + includetext = '' + if not header: + header = "" + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for header file %s: %s\n" + % (header_name, msg)) + return msg + + if not include_quotes: + include_quotes = "<>" + + text = "%s%s\n#include %s%s%s\n\n" % (includetext, header, + include_quotes[0], header_name, include_quotes[1]) + + context.Display("Checking for %s header file %s... " % (lang, header_name)) + ret = context.CompileProg(text, suffix) + _YesNoResult(context, ret, "HAVE_" + header_name, text) + return ret + + +def CheckType(context, type_name, fallback = None, + header = None, language = None): + """ + Configure check for a C or C++ type "type_name". + Optional "header" can be defined to include a header file. + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + Sets HAVE_type_name in context.havedict according to the result. + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. + Returns an empty string for success, an error message for failure. + """ + + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + if not header: + header = "" + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for %s type: %s\n" % (type_name, msg)) + return msg + + # Remarks from autoconf about this test: + # - Grepping for the type in include files is not reliable (grep isn't + # portable anyway). + # - Using "TYPE my_var;" doesn't work for const qualified types in C++. + # Adding an initializer is not valid for some C++ classes. + # - Using the type as parameter to a function either fails for K&$ C or for + # C++. + # - Using "TYPE *my_var;" is valid in C for some types that are not + # declared (struct something). + # - Using "sizeof(TYPE)" is valid when TYPE is actually a variable. + # - Using the previous two together works reliably. + text = """ + %(include)s + %(header)s + + int main() { + if ((%(name)s *) 0) + return 0; + if (sizeof (%(name)s)) + return 0; + }\n\n""" % { 'include': includetext, + 'header': header, + 'name': type_name } + + context.Display("Checking for %s type %s... " % (lang, type_name)) + ret = context.BuildProg(text, suffix) + _YesNoResult(context, ret, "HAVE_" + type_name, text) + if ret and fallback and context.headerfilename: + f = open(context.headerfilename, "a") + f.write("typedef %s %s;\n" % (fallback, type_name)) + f.close() + + return ret + + +def CheckLib(context, lib_name, func_name, header = None, + extra_libs = None, call = None, language = None, autoadd = 1): + """ + Configure check for a C or C++ library "lib_name". + Tests if "func_name" or "call" exists in the library. Note: if it exists + in another library the test succeeds anyway! + Optional "header" can be defined to include a header file. If not given a + default prototype for "func_name" is added. + Optional "extra_libs" is a list of library names to be added after + "lib_name" in the build command. To be used for libraries that "lib_name" + depends on. + Optional "call" replaces the call to "func_name" in the test code. It must + consist of complete C statements, including a trailing ";". + There must either be a "func_name" or a "call" argument (or both). + "language" should be "C" or "C++" and is used to select the compiler. + Default is "C". + Note that this uses the current value of compiler and linker flags, make + sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. + Returns an empty string for success, an error message for failure. + """ + # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. + if context.headerfilename: + includetext = '#include "%s"' % context.headerfilename + else: + includetext = '' + if not header: + header = "" + + lang, suffix, msg = _lang2suffix(language) + if msg: + context.Display("Cannot check for library %s: %s\n" % (lib_name, msg)) + return msg + + text = """ + %s + %s """ % (includetext, header) + + # Add a function declaration if needed. + if func_name and func_name != "main" and not header: + text = text + """ + #ifdef __cplusplus + extern "C" + #endif + char %s();""" % func_name + + # The actual test code. + if not call: + call = "%s();" % func_name + text = text + """ + int + main() { + %s + return 0; + } + \n\n""" % call + + i = string.find(call, "\n") + if i > 0: + calltext = call[:i] + ".." + elif call[-1] == ';': + calltext = call[:-1] + else: + calltext = call + + context.Display("Checking for %s in %s library %s... " + % (calltext, lang, lib_name)) + if lib_name: + l = [ lib_name ] + if extra_libs: + l.extend(extra_libs) + oldLIBS = context.AppendLIBS(l) + sym = "HAVE_LIB" + lib_name + else: + oldLIBS = -1 + sym = None + + ret = context.BuildProg(text, suffix) + + _YesNoResult(context, ret, sym, text) + if oldLIBS != -1 and (ret or not autoadd): + context.SetLIBS(oldLIBS) + + return ret + + +# +# END OF PUBLIC FUNCTIONS +# + +def _YesNoResult(context, ret, key, text): + """ + Handle the result of a test with a "yes" or "no" result. + "ret" is the return value: empty if OK, error message when not. + "key" is the name of the symbol to be defined (HAVE_foo). + "text" is the source code of the program used for testing. + """ + if key: + _Have(context, key, not ret) + if ret: + context.Display("no\n") + _LogFailed(context, text, ret) + else: + context.Display("yes\n") + + +def _Have(context, key, have): + """ + Store result of a test in context.havedict and context.headerfilename. + "key" is a "HAVE_abc" name. It is turned into all CAPITALS and ":./" are + replaced by an underscore. + The value of "have" can be: + 1 - Feature is defined, add "#define key". + 0 - Feature is not defined, add "/* #undef key */". + Adding "undef" is what autoconf does. Not useful for the + compiler, but it shows that the test was done. + number - Feature is defined to this number "#define key have". + Doesn't work for 0 or 1, use a string then. + string - Feature is defined to this string "#define key have". + Give "have" as is should appear in the header file, include quotes + when desired and escape special characters! + """ + key_up = string.upper(key) + key_up = string.replace(key_up, ':', '_') + key_up = string.replace(key_up, '.', '_') + key_up = string.replace(key_up, '/', '_') + key_up = string.replace(key_up, ' ', '_') + context.havedict[key_up] = have + if context.headerfilename: + f = open(context.headerfilename, "a") + if have == 1: + f.write("#define %s\n" % key_up) + elif have == 0: + f.write("/* #undef %s */\n" % key_up) + elif type(have) == IntType: + f.write("#define %s %d\n" % (key_up, have)) + else: + f.write("#define %s %s\n" % (key_up, str(have))) + f.close() + + +def _LogFailed(context, text, msg): + """ + Write to the log about a failed program. + Add line numbers, so that error messages can be understood. + """ + context.Log("Failed program was:\n") + lines = string.split(text, '\n') + if len(lines) and lines[-1] == '': + lines = lines[:-1] # remove trailing empty line + n = 1 + for line in lines: + context.Log("%d: %s\n" % (n, line)) + n = n + 1 + context.Log("Error message: %s\n" % msg) + + +def _lang2suffix(lang): + """ + Convert a language name to a suffix. + When "lang" is empty or None C is assumed. + Returns a tuple (lang, suffix, None) when it works. + For an unrecognized language returns (None, None, msg). + Where: + lang = the unified language name + suffix = the suffix, including the leading dot + msg = an error message + """ + if not lang or lang in ["C", "c"]: + return ("C", ".c", None) + if lang in ["c++", "C++", "cpp", "CXX", "cxx"]: + return ("C++", ".cpp", None) + + return None, None, "Unsupported language: %s" % lang + + +# vim: set sw=4 et sts=4 tw=79 fo+=l: diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py index fad2dfb..22bcb48 100644 --- a/src/engine/SCons/SConf.py +++ b/src/engine/SCons/SConf.py @@ -30,7 +30,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import cPickle import os -import shutil import sys import traceback from types import * @@ -42,6 +41,7 @@ import SCons.Node.FS import SCons.Taskmaster import SCons.Util import SCons.Warnings +import SCons.Conftest # First i thought of using a different filesystem as the default_fs, # but it showed up that there are too many side effects in doing that. @@ -503,7 +503,12 @@ class CheckContext: """Constructor. Pass the corresponding SConf instance.""" self.sconf = sconf self.cached = 0 - self.show_result = 0 + self.did_show_result = 0 + + # for Conftest.py: + self.vardict = {} + self.havedict = {} + self.headerfilename = None # XXX may cause trouble! def Message(self, text): """Inform about what we are doing right now, e.g. @@ -513,29 +518,33 @@ class CheckContext: if self.sconf.logstream != None: self.sconf.logstream.write(text + '\n') sys.stdout.write(text) - self.show_result = 0 + self.did_show_result = 0 - def Result(self, res ): + def Result(self, res): """Inform about the result of the test. res may be an integer or a string. In case of an integer, the written text will be 'ok' or 'failed'. + The result is only displayed when self.did_show_result is not set. """ - if( type(res) == IntType ): + if type(res) == IntType: if res: text = "ok" else: text = "failed" - elif( type(res) == StringType ): + elif type(res) == StringType: text = res else: raise TypeError, "Expected string or int" - if( self.cached ): - text = text + " (cached)" - if self.show_result == 0: + + if self.did_show_result == 0: + if self.cached: + text = text + " (cached)" + + # Didn't show result yet, do it now. if self.sconf.logstream != None: self.sconf.logstream.write("Result: " + text + "\n\n") sys.stdout.write(text + "\n") - self.show_result = 1 + self.did_show_result = 1 def TryBuild(self, *args, **kw): @@ -561,110 +570,126 @@ class CheckContext: else: raise AttributeError, "CheckContext instance has no attribute '%s'" % attr -def _header_prog( header, include_quotes ): - return "#include %s%s%s\n\n" % (include_quotes[0], - header, - include_quotes[1]) + #### Stuff used by Conftest.py (look there for explanations). -def CheckFunc(context, function_name): - context.Message("Checking for %s... " % function_name) + 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 res: + ret = "" + else: + ret = "failed to build test program" + elif type(res) == StringType: + ret = res + else: + raise TypeError, "Expected string or int" + return ret - ret = context.TryBuild(context.env.Program, """ - #include + 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 res: + ret = "" + else: + ret = "failed to compile test program" + elif type(res) == StringType: + ret = res + else: + raise TypeError, "Expected string or int" + return ret - #ifdef __cplusplus - extern "C" - #endif - char %(name)s(); + def AppendLIBS(self, lib_name_list): + oldLIBS = self.env.get( 'LIBS', [] ) + self.env.Append(LIBS = lib_name_list) + return oldLIBS - int main() { - #if defined (__stub_%(name)s) || defined (__stub___%(name)s) - fail fail fail - #else - %(name)s(); - #endif + def SetLIBS(self, val): + oldLIBS = self.env.get( 'LIBS', [] ) + self.env.Replace(LIBS = val) + return oldLIBS - return 0; - }\n\n""" % { 'name': function_name }, ".cpp") - context.Result(ret) + def Display(self, msg): + sys.stdout.write(msg) + self.Log(msg) - return ret + def Log(self, msg): + if self.sconf.logstream != None: + self.sconf.logstream.write(msg) -def CheckType(context, type_name, includes = ""): - context.Message("Checking for %s..." % type_name) + #### End of stuff used by Conftest.py. - ret = context.TryBuild(context.env.Program, """ - %(includes)s - int main() { - if ((%(name)s *) 0) - return 0; - if (sizeof (%(name)s)) - return 0; - }\n\n""" % { 'name': type_name, 'includes': includes }, ".cpp") - context.Result(ret) +def CheckFunc(context, function_name, language = None): + res = SCons.Conftest.CheckFunc(context, function_name, language = language) + context.did_show_result = 1 + if not res: + return 1 # Ok + return 0 # Failed - return ret -def CheckCHeader(test, header, include_quotes='""'): +def CheckType(context, type_name, includes = "", language = None): + res = SCons.Conftest.CheckType(context, type_name, + header = includes, language = language) + context.did_show_result = 1 + if not res: + return 1 # Ok + return 0 # Failed + + +def CheckHeader(context, header, include_quotes = '<>', language = None): """ - A test for a c header file. + A test for a C or C++ header file. """ # ToDo: Support also system header files (i.e. #include ) - test.Message("Checking for C header %s ... " % header) - ret = test.TryCompile(_header_prog(header, include_quotes), ".c") - test.Result( ret ) - return ret + res = SCons.Conftest.CheckHeader(context, header, language = language, + include_quotes = include_quotes) + context.did_show_result = 1 + if not res: + return 1 # Ok + return 0 # Failed -def CheckCXXHeader(test, header, include_quotes='""'): +# Bram: Make this function obsolete? CheckHeader() is more generic. + +def CheckCHeader(context, header, include_quotes = '""'): """ - A test for a c++ header file. + A test for a C header file. """ - # ToDo: Support also system header files (i.e. #include ) - test.Message("Checking for C++ header %s ... " % header) - ret = test.TryCompile(_header_prog(header, include_quotes), ".cpp") - test.Result( ret ) - return ret + return CheckHeader(context, header, include_quotes, language = "C") -def CheckLib(test, library=None, symbol="main", autoadd=1): + +# Bram: Make this function obsolete? CheckHeader() is more generic. + +def CheckCXXHeader(context, header, include_quotes = '""'): + """ + A test for a C++ header file. + """ + return CheckHeader(context, header, include_quotes, language = "C++") + + +def CheckLib(context, library = None, symbol = "main", autoadd = 1, + header = None, language = None): """ A test for a library. See also CheckLibWithHeader. Note that library may also be None to test whether the given symbol compiles without flags. """ # ToDo: accept path for the library - test.Message("Checking for %s in library %s ... " % (symbol, library)) - oldLIBS = test.env.get( 'LIBS', [] ) - - # NOTE: we allow this at in the case that we don't know what the - # library is called like when we get --libs from a configure script - if library != None: - test.env.Append(LIBS = [ library ]) - - text = "" - if symbol != "main": - text = text + """ -#ifdef __cplusplus -extern "C" -#endif -char %s();""" % symbol - text = text + """ -int -main() { -%s(); -return 0; -} -\n\n""" % symbol - - ret = test.TryLink( text, ".c" ) - if not autoadd or not ret: - test.env.Replace(LIBS=oldLIBS) - - test.Result(ret) - return ret - -def CheckLibWithHeader(test, library, header, language, call="main();", autoadd=1): + res = SCons.Conftest.CheckLib(context, library, symbol, header = header, + language = language, autoadd = autoadd) + context.did_show_result = 1 + if not res: + return 1 # Ok + return 0 # Failed + + +# XXX +# Bram: Can only include one header and can't use #ifdef HAVE_HEADER_H. + +def CheckLibWithHeader(context, library, header, language, + call = "main();", autoadd = 1): # ToDo: accept path for library. Support system header files. """ Another (more sophisticated) test for a library. @@ -673,33 +698,12 @@ def CheckLibWithHeader(test, library, header, language, call="main();", autoadd= As in CheckLib, we support library=None, to test if the call compiles without extra link flags. """ - test.Message("Checking for %s in library %s (header %s) ... " % - (call, library, header)) - oldLIBS= test.env.get( 'LIBS', [] ) - - # NOTE: we allow this at in the case that we don't know what the - # library is called like when we get --libs from a configure script - if library != None: - test.env.Append(LIBS = [ library ]) - - text = """\ -#include "%s" -int main() { - %s - return 0; -} -""" % (header, call) - - if language in ["C", "c"]: - extension=".c" - elif language in ["CXX", "cxx", "C++", "c++"]: - extension=".cpp" - else: - raise SCons.Errors.UserError, "Unknown language!" - - ret = test.TryLink( text, extension) - if not autoadd or not ret: - test.env.Replace( LIBS = oldLIBS ) - - test.Result(ret) - return ret + + res = SCons.Conftest.CheckLib(context, library, "main", + header = '#include "%s"' % header, + call = call, language = language, autoadd = autoadd) + context.did_show_result = 1 + if not res: + return 1 # Ok + return 0 # Failed + diff --git a/test/Configure.py b/test/Configure.py index feaea0b..3bad086 100644 --- a/test/Configure.py +++ b/test/Configure.py @@ -93,14 +93,15 @@ if not (r1 and r2 and r3 and r4 and r5 and r6): required_stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n", read_str= - """Checking for main(); in library %s (header math.h) ... ok -Checking for main(); in library None (header math.h) ... ok -Checking for main in library %s ... ok -Checking for main in library None ... ok -Checking for C header math.h ... ok -Checking for C++ header vector ... ok + """Checking for main() in C library %s... yes +Checking for main() in C library None... yes +Checking for main() in C library %s... yes +Checking for main() in C library None... yes +Checking for C header file math.h... yes +Checking for C++ header file vector... yes """ % (lib, lib)) + test.run(stdout = required_stdout) checkLog(test,'config.log', 0, 0 ) @@ -109,8 +110,7 @@ Checking for C++ header vector ... ok # 1.2 if checks are not ok, the cache mechanism should work as well # (via explicit cache) - reset() - + reset(dot = 0) # match exactly, "()" is a regexp thing test.write( 'SConstruct', """ env = Environment() @@ -127,10 +127,11 @@ if not (not r1 and not r2): required_stdout = test.wrap_stdout(build_str="scons: `.' is up to date.\n", read_str= - """Checking for C header no_std_c_header.h ... failed -Checking for main in library no_c_library_SAFFDG ... failed + """Checking for C header file no_std_c_header.h... no +Checking for main() in C library no_c_library_SAFFDG... no """) + test.run(stdout = required_stdout) checkLog(test, 'config.log', 0, 0 ) @@ -164,11 +165,10 @@ int main() { printf( "Hello\\n" ); } """) - test.match_func = TestCmd.match_re_dotall required_stdout = test.wrap_stdout(build_str='.*', read_str= - """Checking for C header math.h ... ok -Checking for C header no_std_c_header.h ... failed + """Checking for C header file math.h... yes +Checking for C header file no_std_c_header.h... no """) test.run( stdout = required_stdout ) checkLog( test, 'config.log', 0, 0 ) @@ -207,8 +207,8 @@ int main() { """) required_stdout = test.wrap_stdout(build_str='.*', read_str= - """Checking for C header math.h ... ok -Checking for C header no_std_c_header.h ... failed + """Checking for C header file math.h... yes +Checking for C header file no_std_c_header.h... no """) test.run( stdout = required_stdout ) checkLog( test, 'build/config.log', 0, 0 ) @@ -270,8 +270,8 @@ int main() { """) required_stdout = test.wrap_stdout(build_str='.*', read_str= - """Checking for C header math.h ... ok -Checking for C header no_std_c_header.h ... failed + """Checking for C header file math.h... yes +Checking for C header file no_std_c_header.h... no Executing Custom Test ... ok """) # first with SConscriptChdir(0) -- cgit v0.12