Split non-SCons-specific parts of SConf.py into a separate Conftest.py module. ...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 30 Aug 2003 07:58:08 +0000 (07:58 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 30 Aug 2003 07:58:08 +0000 (07:58 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@784 fdb21ef1-2011-0410-befe-b5e4ea1792b1

bin/files
doc/man/scons.1
src/CHANGES.txt
src/engine/MANIFEST.in
src/engine/SCons/Conftest.py [new file with mode: 0644]
src/engine/SCons/SConf.py
test/Configure.py

index 252c98f358e3565718e18aee49cac3d3018026f1..043eadbae95a716cc0b00132807a7feed6a49d4b 100644 (file)
--- 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
index 3919a6e10cbc739634585d62822f1170afe2c5bd..22cedab34cff1d575c29a6e3db69f5ef12383d16 100644 (file)
@@ -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:
index 3aad3c1d6ed9faf7ec8a3203ca479440900aeca7..7dcdaf947998f11f9997b23de969a5629e2daada 100644 (file)
@@ -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
index 4c22f1d873bc8182033208760cfcd9e05f4528e7..3c71aba3614efc9c3a7b255dea5182dbfd263116 100644 (file)
@@ -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 (file)
index 0000000..a6bedf5
--- /dev/null
@@ -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 <ctype.h> because on OSF/1 3.0 it includes <sys/types.h>
+    #   which includes <sys/select.h> 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 <assert.h>
+            %(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:
index fad2dfbd3af84198302e162968e582e725d3d952..22bcb482de6d43ffd28ea69512146fc583c5bfbc 100644 (file)
@@ -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 <assert.h>
+    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 <header.h>)
-    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 <header.h>)
-    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
+
index feaea0bb15c23ef746e6ce2fa1808338eff381fc..3bad08607a043f481dd4ee8f242379db450b5b5f 100644 (file)
@@ -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)