]> git.ipfire.org Git - thirdparty/autoconf.git/commitdiff
AT_CHECK_MACRO: test C++ as well as C, cross as well as native
authorZack Weinberg <zackw@panix.com>
Wed, 14 Oct 2020 15:21:30 +0000 (11:21 -0400)
committerZack Weinberg <zackw@panix.com>
Mon, 30 Nov 2020 16:45:27 +0000 (11:45 -0500)
Many of the reported regressions in Autoconf 2.70 betas went unnoticed
for years because Autoconf’s bundled test suite didn’t test most of
the macros with a C++ compiler and/or in cross compilation mode.
There’s a special makefile target ‘maintainer-check-c++’ that runs all
the tests with CC=g++, but that doesn’t catch the regressions either,
because it doesn’t compare the configure results with what you’d have
gotten with a C compiler.  Also, C and C++ have diverged to the point
where setting CC to a C++ compiler doesn’t work reliably anymore.

This patch overhauls AT_CHECK_MACRO to test each macro four times:
(C compiler, C++ compiler) x (native mode, cross-compilation mode).
All four tests are expected to produce the same config.cache and
config.h, except for certain predictable differences due to running
AC_PROG_CXX instead of AC_PROG_CC, and a short list of known,
acceptable differences, maintained in mktests.pl.

There are two classes of known, acceptable differences.  Macros that
use AC_RUN_IFELSE aren’t tested in cross-compilation mode at all,
because they may crash the script (this is temporary and will be
revisited after 2.70).  Macros that correctly detect a difference
between C and C++ (e.g. AC_HEADER_STDBOOL will notice that C++ doesn’t
have the _Bool type) are annotated with the specific cache variable
and #define that varies.

mktests.pl now also has the capability to provide values for the
MACRO-USE, ADDITIONAL-COMMANDS, and AUTOCONF-FLAGS arguments to
AT_CHECK_(AU_)MACRO, on a per-macro basis, but that’s not used in this
patch.

Some of the manual uses of AT_CHECK_MACRO do not need to test C++
and/or cross compilation; for them, there is a new test helper,
AT_CHECK_CONFIGURE_AC.  Another new helper, AT_PRESERVE_CONFIG_STATUS,
is used extensively in AT_CHECK_(AU_)MACRO but may be also useful in
manual tests that need to do multiple configure runs.

This change supersedes AT_CHECK_MACRO_CROSS and
‘make maintainer-check-c++’, which are removed.

In my testing, setting CC to a C++ compiler no longer works at all,
for reasons that are impractical to fix (e.g. C++ compilers choke on
the test for C2011 features) so I have added a note to NEWS saying
that this is not supported anymore.

 * tests/local.at (AT_CHECK_MACRO): Default behavior is now to test
   the macro in both native and cross-compilation mode, and expect the
   results to be identical.  If the macro transitively required
   AC_PROG_CC, and a C++ compiler is available, then test it twice
   more with AC_LANG([C++]) in effect, and again expect the results to
   be identical.  New fifth argument TEST-PARAMETERS can modify this
   behavior.
   (_AT_FILTER_CXX_CV_VARIES, _AT_FILTER_CXX_DEFINE_VARIES): New,
   subroutines of AT_CHECK_MACRO.

   (AT_CHECK_MACRO_CROSS): Remove, subsumed by new AT_CHECK_MACRO
   behavior.
   (AT_CHECK_AU_MACRO): Forward to AT_CHECK_MACRO for the basic test;
   then do the same autoupdate test as before, as a separate test group.

   (at_check_env): Also ignore OPENMP_CXXFLAGS.
   (AT_CONFIG_CMP): Add third argument EXTRA-VARIANCE that specifies
   additional variables that are expected to vary in a particular test.
   (_AT_CONFIG_CMP_PRUNE): New, subroutine of AT_CONFIG_CMP.
   (AT_DEFINES_CMP): New helper macro that compares config.h headers,
   with the ability to ignore variation in specific defines.
   (_AT_DEFINES_CMP_PRUNE): New, subroutine of AT_DEFINES_CMP.

   (AT_PRESERVE_CONFIG_STATUS): New helper that makes copies of
   config.h, config.log, config.status, and state-env.after under
   names that won’t be clobbered by a subsequent run of configure.

   (AT_CHECK_CONFIGURE_AC): New helper that defines a complete test
   group consisting of a single invocation of _AT_CHECK_AC_MACRO;
   effectively what AT_CHECK_MACRO used to be.
   (_AT_CHECK_AC_MACRO): Correct documentation comment; the PRE-TESTS
   argument has always been optional.

 * tests/mktests.pl (test_parameters): New global data object giving
   extra arguments to pass to AT_CHECK_MACRO/AT_CHECK_AU_MACRO on a
   per-macro basis.
   (emit_test): New function that handles emitting calls to
   AT_CHECK_(AU_)MACRO with the desired arguments.
   (scan_m4_files): Use emit_test.

   (au_exclude_list): Add AC_HAVE_LIBRARY, AC_COMPILE_CHECK,
   AC_TRY_CPP, AC_TRY_COMPILE, AC_TRY_LINK, and AC_TRY_RUN.

 * tests/semantics.at (AC_CHECK_LIB, AC_SEARCH_LIBS): Rewrite test
   using symbols from zlib instead of libm, to get consistent behavior
   from C and C++.
   (AC_SEARCH_LIBS (none needed)): Revise to clarify what is being tested.
   (AC_CHECK_DECLS): Use _AC_LANG_ABBREV when inspecting cache variables.
   (AC_CHECK_ALIGNOF, AC_CHECK_ALIGNOF struct)
   (AC_CHECK_SIZEOF, AC_CHECK_SIZEOF struct)
   No need for AT_CHECK_MACRO_CROSS.
   (AC_CHECK_FILES): Switch to AT_CHECK_CONFIGURE_AC.
   (AC_SYS_RESTARTABLE_SYSCALLS, AC_FUNC_WAIT3): Do not test in cross
   compilation mode.
   (AC_TRY_CPP, AC_TRY_COMPILE, AC_TRY_LINK, AC_TRY_RUN)
   (AC_COMPILE_CHECK, AC_HAVE_LIBRARY): New manual AT_CHECK_AU_MACRO tests.

 * tests/c.at (Extensions, C keywords, AC_PROG_CPP requires AC_PROG_CC)
   (AC_NO_EXECUTABLES (working linker), AC_NO_EXECUTABLES (broken linker)):
   Switch to AT_CHECK_CONFIGURE_AC. Also convert case statements to AS_CASE.
   (Broken/missing compilers): Pass CC=no-such-compiler on the command
   line instead of hardwiring it in the configure script.

 * tests/local.mk (maintainer-check-c++): Remove target.
   (maintainer-check): Run the ordinary ‘make check’ as well as
   ‘make maintainer-check-posix’.

NEWS
tests/c.at
tests/local.at
tests/local.mk
tests/mktests.pl
tests/semantics.at

diff --git a/NEWS b/NEWS
index 4cad963b1e09552f8904b803a5ab0d45677e70fa..16849cf71cf10c51e50f9bfb0fc68a6102e82ffb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -69,6 +69,18 @@ GNU Autoconf NEWS - User visible changes.
   See the “Input” section of the manual for more detail, including
   where to get the auxiliary scripts that may be needed by autoconf macros.
 
+*** Setting CC to a C++ compiler is no longer supported.
+
+  The C and C++ languages have diverged enough that we can no longer
+  guarantee that test C programs will be processed as intended by a
+  C++ compiler.  In this release, configure will proceed anyway, but
+  many test results will be incorrect.  In a future release, we may
+  make AC_PROG_CC error out if it detects that CC is a C++ compiler.
+
+  See the “Language Choice” section of the manual for instructions on
+  how to write configure scripts for C++ programs, and for programs
+  with code in more than one language.
+
 *** Older versions of automake and aclocal (< 1.8) are no longer supported.
 
 *** AC_CONFIG_SUBDIRS no longer directly supports Cygnus configure.
index 1ae678d10e8ff5126259fe13c82fb7b899b806f8..40720fe42f6e215a3c5359135a746627ecb9f36b 100644 (file)
@@ -28,22 +28,24 @@ AT_BANNER([C low level compiling/preprocessing macros.])
 ## Extensions.  ##
 ## ------------ ##
 
+AT_CHECK_CONFIGURE_AC([Object file extensions],
+[[AC_PROG_CC
+
 # As far as we know only `foo', `foo.exe' are possible executable,
 # and `foo.o', `foo.obj' are possible object files.  Autoconf must not
 # know that, but it is OK for the test suite to take this into account.
-AT_CHECK_MACRO([Extensions],
-[[AC_PROG_CC
-case $ac_exeext in
-  '' | '.exe' ) ;;
-  * ) AC_MSG_ERROR([suspicious executable suffix: $ac_exeext]);;
-esac
+AS@&t@_CASE([$ac_exeext],
+  ['' | '.exe'],
+    [],
+    [AC_MSG_ERROR([suspicious executable suffix: $ac_exeext])])
 
-case $ac_objext in
-  'o' | 'obj' ) ;;
-  * ) AC_MSG_ERROR([suspicious object suffix: $ac_objext]);;
-esac
-]])
+AS@&t@_CASE([$ac_objext],
+  ['o' | 'obj'],
+    [],
+    [AC_MSG_ERROR([suspicious object suffix: $ac_objext])])
 
+AC_OUTPUT
+]])
 
 
 ## -------------------------- ##
@@ -58,13 +60,12 @@ AT_SETUP([Broken/missing compilers])
 
 AT_DATA([configure.ac],
 [[AC_INIT
-CC=no-such-compiler
 AC_PROG_CC
 AC_OUTPUT
 ]])
 
 AT_CHECK_AUTOCONF
-AT_CHECK_CONFIGURE([], 77, ignore, ignore)
+AT_CHECK_CONFIGURE([CC=no-such-compiler], 77, ignore, ignore)
 
 AT_CLEANUP
 
@@ -73,12 +74,15 @@ AT_CLEANUP
 ## C keywords.  ##
 ## ------------ ##
 
-# GCC supports `const', `typeof', and `volatile'.
-AT_CHECK_MACRO([C keywords],
+AT_CHECK_CONFIGURE_AC([C keywords],
 [[AC_PROG_CC
+
 AC_C_CONST
 AC_C_TYPEOF
 AC_C_VOLATILE
+
+# If the C compiler is GCC, AC_C_{CONST,TYPEOF,VOLATILE} ought to all
+# detect support for their respective keyword.
 case $GCC,$ac_cv_c_const,$ac_cv_c_typeof,$ac_cv_c_volatile in
  yes,*no*)
    AC_MSG_ERROR([failed to detect `const', `typeof', or `volatile' support]);;
@@ -86,20 +90,20 @@ esac
 ]])
 
 
-
 ## --------------------------------- ##
 ## AC_PROG_CPP requires AC_PROG_CC.  ##
 ## --------------------------------- ##
 
-# Must invoke AC_PROG_CC.
-AT_CHECK_MACRO([AC_PROG_CPP requires AC_PROG_CC],
+AT_CHECK_CONFIGURE_AC([AC_PROG_CPP requires AC_PROG_CC],
 [[AC_PROG_CPP
-test -z "$CC" &&
+
+# AC_PROG_CPP should have AC_REQUIREd AC_PROG_CC.
+if test -z "$CC"; then
    AC_MSG_ERROR([looked for a C preprocessor without looking for a compiler])
+fi
 ]])
 
 
-
 ## --------------------------- ##
 ## AC_PROG_CPP with warnings.  ##
 ## --------------------------- ##
@@ -232,21 +236,21 @@ AT_CLEANUP
 ## AC_NO_EXECUTABLES (working linker).  ##
 ## ------------------------------------ ##
 
-AT_CHECK_MACRO([AC_NO_EXECUTABLES (working linker)],
-[AC_NO_EXECUTABLES
+AT_CHECK_CONFIGURE_AC([AC_NO_EXECUTABLES (working linker)],
+[[AC_NO_EXECUTABLES
 AC_PROG_CC
-])
+]])
 
 
 ## ----------------------------------- ##
 ## AC_NO_EXECUTABLES (broken linker).  ##
 ## ----------------------------------- ##
 
-AT_CHECK_MACRO([AC_NO_EXECUTABLES (broken linker)],
-[LDFLAGS=-lnosuchlibrary
+AT_CHECK_CONFIGURE_AC([AC_NO_EXECUTABLES (broken linker)],
+[[LDFLAGS=-lnosuchlibrary
 AC_NO_EXECUTABLES
 AC_PROG_CC
-])
+]])
 
 
 ## -------------------------- ##
index 374e530cfa3cd0e13c05dc5e2bde209ac6540dd9..e32c3d472a575fd117a5b700064330d9dbdab774 100644 (file)
@@ -363,7 +363,7 @@ if test -f state-env.before && test -f state-env.after; then
       [ERLANG_INSTALL_LIB_DIR_.*|ERLANG_ERTS_VER|OBJC|OBJCPP|OBJCFLAGS],
       [OBJCXX|OBJCXXCPP|OBJCXXFLAGS],
       [GOC|GOFLAGS],
-      [OPENMP_CFLAGS],
+      [OPENMP_(C|CXX)FLAGS],
       [LIBS|LIB@&t@OBJS|LTLIBOBJS|LDFLAGS],
       [INSTALL(_(DATA|PROGRAM|SCRIPT))?],
       [EXEEXT|OBJEXT],
@@ -394,8 +394,8 @@ fi
 } [#]at_check_env])
 
 
-# AT_CONFIG_CMP(VAR-FILE-A, VAR-FILE-B)
-# -------------------------------------
+# AT_CONFIG_CMP(VAR-FILE-A, VAR-FILE-B, [EXTRA-VARIANCE])
+# -------------------------------------------------------
 # Check the outcomes of two configure runs for equality by comparing dumps of
 # their shell variables.  VAR-FILE-A and VAR-FILE-B are two `set'-style shell
 # variable space dumps.
@@ -419,6 +419,22 @@ fi
 #   - BASH_ARGV [bash]
 #   - LINENO [Posix]
 #   - _AST_FEATURES [ksh93]
+# - Optionally, variables that are expected to vary in a particular test.
+#   This is controlled by the EXTRA-VARIANCE argument, which is a
+#   whitespace-separated sequence of tokens.  Each token means to ignore
+#   one or more additional variables and/or rename some variables, as follows:
+#
+#   cross: ignore cross_compiling
+#   cxx: ignore all of:
+#     - CC, CPP, CCC, CXX, CXXCPP, CFLAGS, CXXFLAGS, GCC, GXX
+#     - ac_cv_env_(any of the above)_(set|value)
+#     - ac_cv_c_compiler_gnu, ac_cv_cxx_compiler_gnu
+#     - ac_cv_c_decl_report, ac_cv_cxx_decl_report
+#     - ac_cv_prog_c_*, ac_cv_prog_cxx_*, ac_cv_prog_ac_ct_(CC|CXX)
+#     - ac_cv_prog_CPP, ac_cv_prog_CXXCPP
+#     + other ac_cv_c_* are renamed to ac_cv_cxx_*
+#     + OPENMP_CFLAGS is renamed to OPENMP_CXXFLAGS
+#   vary:NAME (where NAME is any identifier): ignore ac_cv_NAME
 #
 # Furthermore, it is okay for a non-cache variable initialized to empty in one
 # run to be unset in another run.  This happens when, for example, cache update
@@ -429,14 +445,14 @@ fi
 #
 # Lines that do not look like `foo=bar' are probably latter lines of
 # multiline values; trim them.
-#
 m4_define([AT_CONFIG_CMP],
 [for act_file in $1 $2
 do
-  $SED '/^ac_cv_/ b
+  $SED '/^ac_cv_/ b skip
        /^m4_defn([m4_re_word])=./ !d
        /^[[^=]]*='\'''\''$/ d
        /^a[[cs]]_/ d
+       : skip
        /^OLDPWD=/ d
        /^PPID=/ d
        /^RANDOM=/ d
@@ -450,11 +466,124 @@ do
        /^BASH_ARGV=/ d
        /^LINENO=/ d
        /^_AST_FEATURES=/ d
-       ' $act_file >at_config_vars-$act_file
+m4_map_args_w([$3], [_AT_CONFIG_CMP_PRUNE(], [)])dnl
+' < $act_file > at_config_vars-$act_file
 done
 AT_CMP([at_config_vars-$1], [at_config_vars-$2])[]dnl
 ])# AT_CONFIG_CMP
 
+# _AT_CONFIG_CMP_PRUNE(TOKEN)
+# ---------------------------
+# Subroutine of AT_CONFIG_CMP which implements the extra-variance rules
+# described above.  Expands to additional sed commands to be inserted in
+# the program above.
+# Note for future readers: not all sed implementations allow alternations
+# in regexes (e.g. /^ac_cv_env_CC_\(set\|value\)=/ would not be portable).
+m4_define([_AT_CONFIG_CMP_PRUNE],
+[m4_bmatch([$1],
+  [^cross$],
+[      /^cross_compiling=/ d
+],
+  [^cxx$],
+[      /^CC=/ d
+       /^CPP=/ d
+       /^CCC=/ d
+       /^CXX=/ d
+       /^CXXCPP=/ d
+       /^CFLAGS=/ d
+       /^CXXFLAGS=/ d
+       /^GCC=/ d
+       /^GXX=/ d
+       /^ac_cv_env_CC_set=/ d
+       /^ac_cv_env_CC_value=/ d
+       /^ac_cv_env_CPP_set=/ d
+       /^ac_cv_env_CPP_value=/ d
+       /^ac_cv_env_CFLAGS_set=/ d
+       /^ac_cv_env_CFLAGS_value=/ d
+       /^ac_cv_env_GCC_set=/ d
+       /^ac_cv_env_GCC_value=/ d
+       /^ac_cv_env_CCC_set=/ d
+       /^ac_cv_env_CCC_value=/ d
+       /^ac_cv_env_CXX_set=/ d
+       /^ac_cv_env_CXX_value=/ d
+       /^ac_cv_env_CXXCPP_set=/ d
+       /^ac_cv_env_CXXCPP_value=/ d
+       /^ac_cv_env_CXXFLAGS_set=/ d
+       /^ac_cv_env_CXXFLAGS_value=/ d
+       /^ac_cv_env_GXX_set=/ d
+       /^ac_cv_env_GXX_value=/ d
+       /^ac_cv_prog_ac_ct_CC=/ d
+       /^ac_cv_prog_ac_ct_CXX=/ d
+       /^ac_cv_prog_CPP=/ d
+       /^ac_cv_prog_CXXCPP=/ d
+       /^ac_cv_c_compiler_gnu=/ d
+       /^ac_cv_cxx_compiler_gnu=/ d
+       /^ac_cv_c_decl_report=/ d
+       /^ac_cv_cxx_decl_report=/ d
+       /^ac_cv_prog_c_@<:@^=@:>@*=/ d
+       /^ac_cv_prog_cc_@<:@^=@:>@*=/ d
+       /^ac_cv_prog_cxx_@<:@^=@:>@*=/ d
+       s/^ac_cv_c_/ac_cv_cxx_/
+       s/^OPENMP_CFLAGS=/OPENMP_CXXFLAGS=/
+],
+  [^vary:],
+[      /^ac_cv_]m4_bpatsubsts([$1], [\<vary:], [])[=/ d
+],
+  [m4_fatal([unrecognized AT_CONFIG_CMP variance token: "$1"])])])
+
+
+# AT_DEFINES_CMP(CONFIG-H-A, CONFIG-H-B, [EXTRA-VARIANCE])
+# --------------------------------------------------------
+# Check the outcomes of two configure runs for equality by comparing the
+# config.h headers they produced.  Optionally, ignore changes to particular
+# defines, under the control of the EXTRA-VARIANCE argument, which is a
+# whitespace-separated sequence of tokens. Each token means to ignore
+# one or more additional defines, as follows:
+#   vary:NAME (where NAME is any identifier): ignore #define/#undef NAME
+m4_define([AT_DEFINES_CMP],
+[m4_ifblank([$3], [AT_CMP([$1], [$2])],
+[for act_file in $1 $2
+do
+  $SED '
+m4_map_args_w([$3], [_AT_DEFINES_CMP_PRUNE(], [)])
+' < $act_file > at_defines-$act_file
+done
+AT_CMP([at_defines-$1], [at_defines-$2])[]dnl
+])])# AT_DEFINES_CMP
+
+
+# _AT_DEFINES_CMP_PRUNE(TOKEN)
+# ---------------------------
+# Subroutine of AT_DEFINES_CMP which implements the extra-variance rules
+# described above.  Expands to one or more sed commands.
+# After quadrigraph replacement, each sed command group will be
+#   /#define macro_name[ (]/ d ;#)
+#   /#undef macro_name[ (]/ d ;#)
+# AC_DEFINE never emits tabs or puts whitespace between '#' and
+# 'define' or 'undef', so this is sufficient.
+m4_define([_AT_DEFINES_CMP_PRUNE],
+[m4_bmatch([$1],
+  [^vary:],
+[      /@%:@define ]m4_bpatsubsts([$1], [\<vary:], [])dnl
+[@<:@ @{:@@:>@/ d ;@%:@@:}@
+       /@%:@undef ]m4_bpatsubsts([$1], [\<vary:], [])dnl
+[@<:@ @{:@@:>@/ d ;@%:@@:}@
+],
+  [m4_fatal([unrecognized AT_DEFINES_CMP variance token: "$1"])])])
+
+
+# AT_PRESERVE_CONFIG_STATUS(SUFFIX)
+# ---------------------------------
+# Copy the files 'state-env.after', 'config.h', 'config.log', and
+# 'config.status' to names ending with SUFFIX, so they are not
+# clobbered by a subsequent run of configure.
+m4_define([AT_PRESERVE_CONFIG_STATUS],
+[cp -f state-env.after state-env.$1
+cp -f config.h config-h.$1
+cp -f config.log config-log.$1
+cp -f config.status config-status.$1
+])
+
 
 # AT_CHECK_DEFINES(CONTENT)
 # -------------------------
@@ -510,8 +639,8 @@ dnl pacify editors that don't understand sh case: ((
 ])
 
 
-# _AT_CHECK_AC_MACRO(AC-BODY, PRE-TESTS, [AUTOCONF-FLAGS])
-# --------------------------------------
+# _AT_CHECK_AC_MACRO(AC-BODY, [PRE-TESTS], [AUTOCONF-FLAGS])
+# ----------------------------------------------------------
 # Create a minimalist configure.ac running the macro named
 # NAME-OF-THE-MACRO, check that autoconf runs on that script,
 # and that the generated configure script runs without error.
@@ -524,97 +653,267 @@ AT_CHECK_CONFIGURE
 AT_CHECK_ENV
 ])# _AT_CHECK_AC_MACRO
 
+# AT_CHECK_CONFIGURE_AC(NAME, AC-BODY, [AUTOCONF-FLAGS],
+#                       [PRE-TESTS], [POST-TESTS])
+# -----------------------------------------------------
+# Shorthand for a complete test "group" consisting of a single
+# invocation of _AT_CHECK_AC_MACRO, possibly with some additional
+# tests executed before and after.
+m4_define([AT_CHECK_CONFIGURE_AC],
+[AT_SETUP([$1])
+_AT_CHECK_AC_MACRO([$2], [$4], [$3])
+$5
+AT_CLEANUP
+])
 
 # AT_CHECK_MACRO(MACRO, [MACRO-USE], [ADDITIONAL-CMDS],
-#                [AUTOCONF-FLAGS])
+#                [AUTOCONF-FLAGS], [TEST-PARAMETERS])
 # -----------------------------------------------------
-# Create a minimalist configure.ac running the macro named
-# NAME-OF-THE-MACRO, check that autoconf runs on that script,
+# Create a minimalist configure.ac running the macro named MACRO
+# (using the code in MACRO-USE if that argument is not empty,
+# otherwise a bare invocation of MACRO with no arguments),
+# check that autoconf runs on that script,
 # and that the generated configure script runs without error.
-#
-# We run `configure' twice, both times with a cache, and compare
-# the environment after each run to detect inconsistencies.
+# AUTOCONF-FLAGS are passed to all invocations of autoconf.
+#
+# We always generate two variants of the minimalist configure.ac,
+# with and without forcing the script into cross-compilation mode
+# before executing MACRO-USE.  If a C++ compiler is available, we
+# generate two more variants in which MACRO-USE is invoked while
+# AC_LANG([C++]) is in effect; as before, one forces the script into
+# cross-compilation mode and the other doesn't.  All variants of the
+# generated configure script are run twice, once with an empty cache,
+# and once with a cache primed by the previous run.
+#
+# All four (or eight, if C++ is available) runs are expected to
+# produce the same results, except for the value of 'cross_compiling'
+# and differences due to running AC_PROG_CXX instead of AC_PROG_CC.
+# (See AT_CONFIG_CMP for details.)
+#
+# If ADDITIONAL-CMDS are present, they are executed after the first
+# pair of tests (with the C compiler, in native mode).
+#
+# If TEST-PARAMETERS are present, they should be a space-separated
+# list of modifiers to how the test is carried out.  Currently
+# the following modifiers are defined:
+#
+#   - `no-cross': Don't test this macro in cross-compilation mode.
+#     This is for macros that use AC_RUN_IFELSE, and therefore, when
+#     cross-compiling, they either crash or give a `best guess' answer
+#     that may be wrong.
+#
+#   - `cxx_cv_varies:NAME': The value of the cache variable ac_cv_NAME
+#     may legitimately vary between the C tests and the C++ tests.
+#
+#   - `cxx_define_varies:NAME' The value of the AC_DEFINEd macro NAME
+#     may legitimately vary between the C tests and the C++ tests.
 m4_define([AT_CHECK_MACRO],
 [AT_SETUP([$1])
 
+# C compiler, native mode.
 AT_CONFIGURE_AC([m4_default([$2], [$1])])
-
 AT_CHECK_AUTOCONF([$4])
 AT_CHECK_AUTOHEADER([$4], [ignore])
 
-for at_run in r1 r2
-do
-    AT_CHECK_CONFIGURE([-C])
-    cp -f state-env.after state-env.$at_run
-    cp -f config.h config-h.$at_run
-    cp -f config.log config-log.$at_run
-    cp -f config.status config-status.$at_run
-    AT_CHECK_ENV
-done
+cp -f configure.ac configure-ac.c-native
+cp -f configure configure.c-native
+cp -f config.hin config-hin.c-native
 
-AT_CMP([config-h.r1], [config-h.r2])
-AT_CONFIG_CMP([state-env.r1], [state-env.r2])
+AT_CHECK_CONFIGURE([-C])
+AT_PRESERVE_CONFIG_STATUS([c-native-r1])
+AT_CHECK_ENV
+AT_CHECK_CONFIGURE([-C])
+AT_PRESERVE_CONFIG_STATUS([c-native-r2])
+AT_CHECK_ENV
 
-$3
+AT_DEFINES_CMP([config-h.c-native-r1], [config-h.c-native-r2])
+AT_CONFIG_CMP([state-env.c-native-r1], [state-env.c-native-r2])
 
-AT_CLEANUP[]dnl
+m4_n([$3])dnl
+m4_bmatch([$5], [\<no-cross\>], [], [dnl
+
+# C compiler, cross-compilation mode.
+rm -rf config.cache autom4te.cache
+AT_CONFIGURE_AC(
+[cross_compiling=yes
+ac_tool_warned=yes
+m4_default([$2], [$1])])
+AT_CHECK_AUTOCONF([$4])
+AT_CHECK_AUTOHEADER([$4], [ignore])
+
+cp -f configure.ac configure-ac.c-cross
+cp -f configure configure.c-cross
+cp -f config.hin config-hin.c-cross
+
+AT_CHECK_CONFIGURE([-C])
+AT_PRESERVE_CONFIG_STATUS([c-cross-r1])
+AT_CHECK_ENV
+AT_DEFINES_CMP([config-h.c-native-r1], [config-h.c-cross-r1])
+AT_CONFIG_CMP([state-env.c-native-r1], [state-env.c-cross-r1], [cross])
+
+AT_CHECK_CONFIGURE([-C])
+AT_PRESERVE_CONFIG_STATUS([c-cross-r2])
+AT_CHECK_ENV
+AT_DEFINES_CMP([config-h.c-native-r1], [config-h.c-cross-r2])
+AT_CONFIG_CMP([state-env.c-native-r1], [state-env.c-cross-r2], [cross])
+])dnl
+
+# To save time, skip the C++-mode tests for any macro that did not
+# transitively require AC_PROG_CC; it won't make any difference.
+if grep '^CC=' state-env.c-native-r1 > /dev/null 2>&1; then
+
+  # C++ compiler, native mode.
+  rm -rf config.cache autom4te.cache
+  AT_CONFIGURE_AC(
+  [AC_LANG([C++])
+  m4_default([$2], [$1])])
+
+  # Autoconf may fail here because of an AC_LANG_ASSERT([C]); this
+  # means the macro is specific to C and should not be tested with the
+  # C++ compiler.
+  AT_CHECK_AUTOCONF([$4], [ignore], [ignore], [stderr])
+  if test -s stderr; then
+    AT_CHECK([grep 'error: AC_LANG_ASSERT: current language is not C' stderr],
+             [0], [ignore], [ignore])
+  else
+    AT_CHECK_AUTOHEADER([$4], [ignore])
+
+    cp -f configure.ac configure-ac.cxx-native
+    cp -f configure configure.cxx-native
+    cp -f config.hin config-hin.cxx-native
+
+    # If this configure pass fails with code 77, that means there is no
+    # C++ compiler available; don't mark the entire test group skipped,
+    # just skip the rest of the C++ testing.
+    AT_CHECK_CONFIGURE([-C;
+      status=$?
+      if test $status -eq 77; then
+        touch at-no-cxx
+        exit 0
+      else
+        exit $status
+      fi
+    ])
+    if test ! -f at-no-cxx; then
+      AT_PRESERVE_CONFIG_STATUS([cxx-native-r1])
+      AT_CHECK_ENV
+      AT_DEFINES_CMP([config-h.c-native-r1], [config-h.cxx-native-r1],
+                     _AT_FILTER_CXX_DEFINE_VARIES([$5]))
+      AT_CONFIG_CMP([state-env.c-native-r1], [state-env.cxx-native-r1],
+                    [cxx ]_AT_FILTER_CXX_CV_VARIES([$5]))
+
+      AT_CHECK_CONFIGURE([-C])
+      AT_PRESERVE_CONFIG_STATUS([cxx-native-r2])
+      AT_CHECK_ENV
+      AT_DEFINES_CMP([config-h.cxx-native-r1], [config-h.cxx-native-r2])
+      AT_CONFIG_CMP([state-env.cxx-native-r1], [state-env.cxx-native-r2])
+m4_bmatch([$5], [\<no-cross\>], [], [dnl
+
+      # Fourth run: C++ compiler, cross-compilation mode.
+
+      rm -rf config.cache autom4te.cache
+      AT_CONFIGURE_AC(
+      [cross_compiling=yes
+      ac_tool_warned=yes
+      AC_LANG([C++])
+      m4_default([$2], [$1])])
+      AT_CHECK_AUTOCONF([$4])
+      AT_CHECK_AUTOHEADER([$4], [ignore])
+
+      cp -f configure.ac configure-ac.cxx-cross
+      cp -f configure configure.cxx-cross
+      cp -f config.hin config-hin.cxx-cross
+
+      AT_CHECK_CONFIGURE([-C])
+      AT_PRESERVE_CONFIG_STATUS([cxx-cross-r1])
+      AT_CHECK_ENV
+      AT_DEFINES_CMP([config-h.cxx-native-r1], [config-h.cxx-cross-r1])
+      AT_CONFIG_CMP([state-env.cxx-native-r1], [state-env.cxx-cross-r1],
+                    [cross])
+
+      AT_CHECK_CONFIGURE([-C])
+      AT_PRESERVE_CONFIG_STATUS([cxx-cross-r2])
+      AT_CHECK_ENV
+      AT_DEFINES_CMP([config-h.cxx-cross-r1], [config-h.cxx-cross-r2])
+      AT_CONFIG_CMP([state-env.cxx-cross-r1], [state-env.cxx-cross-r2])
+])dnl
+    fi # C++ compiler available
+  fi # macro can be used with C++
+fi # C++ makes a difference
+
+AT_CLEANUP
 ])# AT_CHECK_MACRO
 
 
-# AT_CHECK_MACRO_CROSS(MACRO, [MACRO-USE], [ADDITIONAL-CMDS],
-#                      [AUTOCONF-FLAGS])
-# -----------------------------------------------------------
-# Like the previous one, but creates two checks: for native
-# compile and for cross-compile.
-m4_define([AT_CHECK_MACRO_CROSS],
-[AT_CHECK_MACRO($@)
-AT_CHECK_MACRO([$1 (cross compile)],
-  [AT_KEYWORDS([cross])
-  # Exercise the code used when cross-compiling.
-  cross_compiling=yes
-  ac_tool_warned=yes
-  m4_default([$2], [$1])],
-  [$3], [$4])
-])
+# _AT_FILTER_CXX_CV_VARIES(TEST-PARAMETERS)
+# ---------------------------------------------
+# Subroutine of AT_CHECK_MACRO that expands to a sequence of
+# zero or more `vary:NAME' tokens, one for each occurrence of
+# `cxx_cv_varies:NAME' in TEST-PARAMETERS.
+m4_define([_AT_FILTER_CXX_CV_VARIES],
+[m4_map_args_w([$1], [_AT_FILTER_CXX_CV_VARY(], [)], [ ])])
+
+m4_define([_AT_FILTER_CXX_CV_VARY],
+[m4_bmatch([$1], [^cxx_cv_varies:],
+  [m4_bpatsubsts([$1], [\<cxx_cv_varies:], [vary:])])])
 
 
-# AT_CHECK_AU_MACRO(MACRO)
+# _AT_FILTER_CXX_DEFINE_VARIES(TEST-PARAMETERS)
+# ---------------------------------------------
+# Subroutine of AT_CHECK_MACRO that expands to a sequence of
+# zero or more `vary:NAME' tokens, one for each occurrence of
+# `cxx_define_varies:NAME' in TEST-PARAMETERS.
+m4_define([_AT_FILTER_CXX_DEFINE_VARIES],
+[m4_map_args_w([$1], [_AT_FILTER_CXX_DEFINE_VARY(], [)], [ ])])
+
+m4_define([_AT_FILTER_CXX_DEFINE_VARY],
+[m4_bmatch([$1], [^cxx_define_varies:],
+  [m4_bpatsubsts([$1], [\<cxx_define_varies:], [vary:])])])
+
+
+# AT_CHECK_AU_MACRO(MACRO, [MACRO-USE], [ADDITIONAL-CMDS],
+#                   [AUTOCONF-FLAGS], [TEST-PARAMETERS])
 # ------------------------
-# Create a minimalist configure.ac running the macro named
-# NAME-OF-THE-MACRO, check that autoconf runs on that script,
-# and that the generated configure script runs without error.
-#
-# Then run autoupdate on that script, and check that NAME-OF-THE-MACRO
-# no longer appears in configure.ac, autoconf runs on the updated
-# script, the configure script still runs without error, and the
-# result is unchanged.
-#
-# On the first pass, check for a -Wobsolete warning naming
-# NAME-OF-THE-MACRO.  On the second pass, *don't* check for the
-# absence of -Wobsolete warnings, because many of autoupdate's edits
-# leave the configure.ac author with some manual work to do, and
-# indicate this by inserting an m4_warn message to be removed
-# after the manual work is complete.
+# Do all the tests that AT_CHECK_MACRO(...) would do.
+#
+# In addition, run autoupdate on configure.ac; afterward, verify that
+# MACRO no longer appears in configure.ac, autoconf runs on the
+# updated script, the configure script still runs without error, and
+# the result of configuration is unchanged.
+#
+# Before running autoupdate, check for a -Wobsolete warning naming
+# MACRO from configure.  After running autoupdate, *don't* check for
+# the absence of -Wobsolete warnings, because many of autoupdate's
+# edits leave the configure.ac author with some manual work to do, and
+# indicate this by inserting an m4_warn message to be removed after
+# the manual work is complete.
 m4_define([AT_CHECK_AU_MACRO],
-[AT_SETUP([$1])
+[AT_CHECK_MACRO([$1], [$2], [$3], [-Wno-obsolete $4], [$5])
+
+AT_SETUP([autoupdating $1])
 AT_KEYWORDS([autoupdate])
 
-AT_CONFIGURE_AC([$1])
+AT_CONFIGURE_AC([m4_default([$2], [$1])])
 
-AT_CHECK_AUTOCONF([], 0, [], [stderr])
+AT_CHECK_AUTOCONF([$4], 0, [], [stderr])
 AT_CHECK([grep 'macro .$1. is obsolete' stderr], 0, [ignore], [ignore])
-AT_CHECK_AUTOHEADER([-Wno-obsolete], [ignore])
+AT_CHECK_AUTOHEADER([-Wno-obsolete $4], [ignore])
 AT_CHECK_CONFIGURE
 AT_CHECK_ENV
+AT_PRESERVE_CONFIG_STATUS([before-au])
 
 rm config.hin
 AT_CHECK_AUTOUPDATE([], 0, [], ignore)
 AT_CHECK([grep '^$1$' configure.ac], 1)
 
-AT_CHECK_AUTOCONF([-Wno-obsolete])
-AT_CHECK_AUTOHEADER([-Wno-obsolete], [ignore])
+AT_CHECK_AUTOCONF([-Wno-obsolete $4])
+AT_CHECK_AUTOHEADER([-Wno-obsolete $4], [ignore])
 AT_CHECK_CONFIGURE
 AT_CHECK_ENV
+AT_PRESERVE_CONFIG_STATUS([after-au])
+
+AT_CMP([config-h.before-au], [config-h.after-au])
+AT_CONFIG_CMP([state-env.before-au], [state-env.after-au])
 
 AT_CLEANUP[]dnl
 ])# AT_CHECK_AU_MACRO
index 3b8688cf5a3bdc6be5d77f76d387c7035b1bbf78..f712b5317fcdfb6fa08e5da89256ad8f564756bc 100644 (file)
@@ -210,10 +210,10 @@ CLEANFILES += tests/mktests.tmp tests/mktests.stamp
 
 ## maintainer-check ##
 
-# These cannot be run in parallel.
+# The test suite cannot be run in parallel with itself.
 maintainer-check:
+       $(MAKE) $(AM_MAKEFLAGS) check
        $(MAKE) $(AM_MAKEFLAGS) maintainer-check-posix
-       $(MAKE) $(AM_MAKEFLAGS) maintainer-check-c++
 
 # The hairy heredoc is more robust than using echo.
 CLEANFILES += expr
@@ -234,7 +234,3 @@ expr:
 maintainer-check-posix: expr
        POSIXLY_CORRECT=yes $(MAKE) $(AM_MAKEFLAGS) check
        rm expr
-
-# Try using G++ as a C compiler.
-maintainer-check-c++:
-       CC=g++ $(MAKE) $(AM_MAKEFLAGS) check
index 2571ef21fea173e491bff445b1cd17ab4ec1a269..63920897ef0bcb6e3be46fe4684f134c52c21856 100644 (file)
@@ -27,7 +27,7 @@ use warnings FATAL => 'all';
 # Not every macro can be run without arguments, and some are already
 # tested elsewhere.
 my @ac_exclude_list = (
-  # Internal macros are used elsewhere.
+  # Internal macros should not be invoked directly from a configure.ac.
   qr/^_?_AC_/,
 
   # Used in many places.
@@ -128,11 +128,88 @@ my @au_exclude_list = (
   qr/^AC_(DIAGNOSE|FATAL|OBSOLETE|WARNING)$/,
   qr/^AC_(FOREACH|LINK_FILES|PREREQ)$/,
 
+  # Need arguments.  Tested in semantics.at.
+  qr/^AC_HAVE_LIBRARY$/,
+  qr/^AC_COMPILE_CHECK$/,
+  qr/^AC_TRY_(COMPILE|CPP|LINK|RUN)$/,
+
   # Not macros, just mapping from old variable name to a new one.
   qr/^ac_cv_prog_(gcc|gxx|g77)$/,
 );
 
 
+# test_parameters
+# ---------------
+# Extra arguments to pass to the test macro for particular macros.
+# Keys are macro names, values are records containing one or more
+# of the possible optional arguments to AT_CHECK_(AU_)MACRO:
+# macro_use, additional_commands, autoconf_flags, test_parameters => '...'.
+# Entries in this hash are grouped by common situations, and sorted
+# alphabetically within each group.
+# Note that you must provide M4 quotation; emit_test will not quote
+# the arguments for you.  (This is so you can _not_ quote the arguments
+# when that's useful.)
+
+my %test_parameters = (
+  # Uses AC_RUN_IFELSE, cross-compilation test fails.
+  AC_FC_CHECK_BOUNDS      => { test_parameters => '[no-cross]' },
+  AC_FUNC_CHOWN           => { test_parameters => '[no-cross]' },
+  AC_FUNC_FNMATCH         => { test_parameters => '[no-cross]' },
+  AC_FUNC_FORK            => { test_parameters => '[no-cross]' },
+  AC_FUNC_GETGROUPS       => { test_parameters => '[no-cross]' },
+  AC_FUNC_LSTAT           => { test_parameters => '[no-cross]' },
+  AC_FUNC_MALLOC          => { test_parameters => '[no-cross]' },
+  AC_FUNC_MEMCMP          => { test_parameters => '[no-cross]' },
+  AC_FUNC_MKTIME          => { test_parameters => '[no-cross]' },
+  AC_FUNC_MMAP            => { test_parameters => '[no-cross]' },
+  AC_FUNC_REALLOC         => { test_parameters => '[no-cross]' },
+  AC_FUNC_STAT            => { test_parameters => '[no-cross]' },
+  AC_FUNC_STRCOLL         => { test_parameters => '[no-cross]' },
+  AC_FUNC_STRNLEN         => { test_parameters => '[no-cross]' },
+  AC_FUNC_STRTOD          => { test_parameters => '[no-cross]' },
+
+  # Different result with a C++ compiler than a C compiler:
+  # C++ compilers may or may not support these features from C1999 and later.
+  AC_C_RESTRICT => {
+    test_parameters => ('[cxx_define_varies:restrict' .
+                        ' cxx_cv_varies:cxx_restrict]')
+  },
+  AC_C_TYPEOF => {
+    test_parameters => ('[cxx_define_varies:typeof' .
+                        ' cxx_define_varies:HAVE_TYPEOF' .
+                        ' cxx_cv_varies:cxx_typeof]')
+  },
+  AC_C__GENERIC => {
+    test_parameters => ('[cxx_define_varies:HAVE_C__GENERIC' .
+                        ' cxx_cv_varies:cxx__Generic]')
+  },
+  AC_C_VARARRAYS => {
+    test_parameters => ('[cxx_define_varies:HAVE_C_VARARRAYS' .
+                        ' cxx_define_varies:__STDC_NO_VLA__' .
+                        ' cxx_cv_varies:cxx_vararrays]')
+  },
+
+  # stdbool.h is supposed to be includeable from C++, per C++2011
+  # [support.runtime], but the type _Bool was not added to the C++
+  # standard, so it may or may not be present depending on how much
+  # the C++ compiler cares about C source compatibility.
+  AC_CHECK_HEADER_STDBOOL => {
+    test_parameters => ('[cxx_define_varies:HAVE__BOOL' .
+                        ' cxx_cv_varies:type__Bool]')
+  },
+  AC_HEADER_STDBOOL => {
+    test_parameters => ('[cxx_define_varies:HAVE__BOOL' .
+                        ' cxx_cv_varies:type__Bool]')
+  },
+
+  # G++ forces -D_GNU_SOURCE which, with some versions of GNU libc,
+  # changes the declaration of strerror_r.  Blech.
+  AC_FUNC_STRERROR_R => {
+    test_parameters => ('[cxx_define_varies:STRERROR_R_CHAR_P' .
+                        ' cxx_cv_varies:func_strerror_r_char_p]')
+  },
+);
+
 # skip_macro MACRO, EXCLUDE-LIST
 # ------------------------------
 # Returns truthy if any of the regexes in EXCLUDE-LIST match MACRO.
@@ -147,6 +224,35 @@ sub skip_macro
 }
 
 
+# emit_test FH, TEST-MACRO, MACRO
+# --------------------------------
+# Emit code to FH to test MACRO using TEST-MACRO.
+# TEST-MACRO is expected to be either AT_CHECK_MACRO or AT_CHECK_AU_MACRO;
+# see local.at.
+sub emit_test
+{
+  my ($fh, $test_macro, $macro) = @_;
+  my $params = $test_parameters{$macro} || {};
+  my $macro_use           = ${$params}{macro_use}           || '';
+  my $additional_commands = ${$params}{additional_commands} || '';
+  my $autoconf_flags      = ${$params}{autoconf_flags}      || '';
+  my $test_parameters     = ${$params}{test_parameters}     || '';
+
+  $autoconf_flags = '[]'
+    if $autoconf_flags eq '' && $test_parameters ne '';
+  $additional_commands = '[]'
+    if $additional_commands eq '' && $autoconf_flags ne '';
+  $macro_use = '[]'
+    if $macro_use eq '' && $additional_commands ne '';
+
+  print $fh "$test_macro([$macro]";
+  print $fh ", $autoconf_flags" if $autoconf_flags ne '';
+  print $fh ", $additional_commands" if $additional_commands ne '';
+  print $fh ", $autoconf_flags" if $autoconf_flags ne '';
+  print $fh ", $test_parameters" if $test_parameters ne '';
+  print $fh ")\n";
+}
+
 # scan_m4_files
 # -------------
 # Scan all of the Autoconf source files and produce lists of macros
@@ -267,12 +373,14 @@ EOF
           if (@$ac_macros)
             {
               print $fh "\n# Modern macros.\n";
-              print $fh "AT_CHECK_MACRO([$_])\n" for sort @$ac_macros;
+              emit_test ($fh, 'AT_CHECK_MACRO', $_)
+                for sort @$ac_macros;
             }
           if (@$au_macros)
             {
               print $fh "\n# Obsolete macros.\n";
-              print $fh "AT_CHECK_AU_MACRO([$_])\n" for sort @$au_macros;
+              emit_test ($fh, 'AT_CHECK_AU_MACRO', $_)
+                for sort @$au_macros;
             }
         }
       else
index d14e57131f1111091e4c9aa7117e284ef3acc463..8e218355d425e06951966ed41fb6c3ca3fd27a1f 100644 (file)
@@ -26,81 +26,177 @@ AT_BANNER([Semantics.])
 
 # AC_CHECK_LIB
 # ------------
-# Well, I can't imagine a system where `cos' is neither in libc, nor
-# in libm.  Nor can I imagine a lib more likely to exists than libm.
-# But there are systems without libm, on which we don't want to have
-# this test fail, so exit successfully if `cos' is in libc.
-AT_CHECK_MACRO([AC_CHECK_LIB],
-[AC_TRY_LINK_FUNC(cos,
-                 [AC_MSG_ERROR([`cos' is in `libc'], 77)])
+# Test for symbols in a library that is very likely to be available
+# and can be used from both C and C++: zlib, which we assume is
+# available unless <zlib.h> doesn't exist.
+# We used to use math library symbols for this, but that no longer
+# works, because some C++ compilers pull in libm by default when the
+# matching C compiler doesn't, breaking AT_CHECK_MACRO's expectations.
+AT_CHECK_MACRO([AC_CHECK_LIB], [[
+AC_CHECK_HEADER([zlib.h], [], [
+  AC_MSG_NOTICE([zlib not available, skipping test])
+  AS_EXIT(77)
+])
 
-AC_CHECK_LIB(m, cos,,
-            [AC_MSG_ERROR([cannot find `cos' in `libm'])])
+# Using : for the ACTION-IF-FOUND in each call to AC_CHECK_LIB
+# prevents LIBS from accumulating copies of "-lz".
 
-# No kidding, using variables was broken in 2.50 :(
-ac_sin=sin
-AC_CHECK_LIB(m, $ac_sin,,
-      [AC_MSG_ERROR([cannot find `\$ac_sin' (= `$ac_sin') in `libm'])])
-
-AS_UNSET([ac_cv_lib_m_acos])
-ac_m=m
-AC_CHECK_LIB($ac_m, acos,,
-      [AC_MSG_ERROR([cannot find `acos' in `\$ac_m' (= `$ac_m')])])
-if test "${ac_cv_lib_m_acos+set}" != set; then
-  AC_MSG_ERROR([ac_cv_lib_m_acos not set])
+AC_CHECK_LIB([z], [zlibVersion], [:], [
+  AC_MSG_ERROR([cannot find zlibVersion in libz])
+])
+if test "${ac_cv_lib_z_zlibVersion+set}" != set; then
+  AC_MSG_ERROR([ac_cv_lib_z_zlibVersion not set])
 fi
 
-ac_asin=asin
-AC_CHECK_LIB($ac_m, $ac_asin,,
-      [AC_MSG_ERROR([cannot find `\$ac_asin' (= `$ac_asin') in `\$ac_m' (= `$ac_m')])])
 
-# But if the bug is in the caching mechanism, then be sure we
-# correctly detect failures.
+# No kidding, using variables was broken in 2.50 :(
+ac_deflate=deflate
+AC_CHECK_LIB([z], [$ac_deflate], [:], [
+  AC_MSG_ERROR([cannot find \$ac_deflate (= $ac_deflate) in libz])
+])
+if test "${ac_cv_lib_z_deflate+set}" != set; then
+  AC_MSG_ERROR([ac_cv_lib_z_deflate not set])
+fi
 
-AC_CHECK_LIB(m, cossack,
-            [AC_MSG_ERROR([found `cossack' in `libm'])])
+ac_z=z
+AC_CHECK_LIB([$ac_z], [deflateEnd], [:], [
+  AC_MSG_ERROR([cannot find deflateEnd in lib\$ac_z (= lib$ac_z)])
+])
+if test "${ac_cv_lib_z_deflateEnd+set}" != set; then
+  AC_MSG_ERROR([ac_cv_lib_z_deflateEnd not set])
+fi
 
-# No kidding, using variables was broken in 2.50 :(
-ac_sinner=sinner
-AC_CHECK_LIB(m, $ac_sinner,
-      [AC_MSG_ERROR([found `\$ac_sinner' (= `$ac_sinner') in `libm'])])
+ac_inflate=inflate
+AC_CHECK_LIB([$ac_z], [$ac_inflate], [:], [
+  AC_MSG_ERROR(
+    [cannot find \$ac_inflate (= $ac_inflate) in lib\$ac_z (= lib$ac_z)])
+])
+if test "${ac_cv_lib_z_inflate+set}" != set; then
+  AC_MSG_ERROR([ac_cv_lib_z_inflate not set])
+fi
 
-ac_m=m
-AC_CHECK_LIB($ac_m, acossack,
-      [AC_MSG_ERROR([found `acossack' in `\$ac_m' (= `$ac_m')])])
+# Also test for symbols that don't (well, shouldn't) exist.
+# These should still set their cache variables!
+AC_CHECK_LIB([z], [deflagrate], [
+  AC_MSG_ERROR([found deflagrate in libz])
+], [:])
+if test "${ac_cv_lib_z_deflagrate+set}" != set; then
+  AC_MSG_ERROR([ac_cv_lib_z_zlibVersion not set])
+fi
 
-ac_asinner=asinner
-AC_CHECK_LIB($ac_m, $ac_asinner,
-      [AC_MSG_ERROR([found `\$ac_asinner' (= `$ac_asinner') in `\$ac_m' (= `$ac_m')])])
+ac_defenestrate=defenestrate
+AC_CHECK_LIB([z], [$ac_defenestrate], [
+  AC_MSG_ERROR([found \$ac_defenestrate (= $ac_defenestrate) in libz])
+], [:])
+if test "${ac_cv_lib_z_defenestrate+set}" != set; then
+  AC_MSG_ERROR([ac_cv_lib_z_defenestrate not set])
+fi
 
-])
+AC_CHECK_LIB([$ac_z], [defoliate], [
+  AC_MSG_ERROR([found defoliate in lib\$ac_z (= lib$ac_z)])
+], [:])
+if test "${ac_cv_lib_z_defoliate+set}" != set; then
+  AC_MSG_ERROR([ac_cv_lib_z_defoliate not set])
+fi
+
+ac_infiltrate=infiltrate
+AC_CHECK_LIB([$ac_z], [$ac_infiltrate], [
+  AC_MSG_ERROR(
+    [found \$ac_infiltrate (= $ac_infiltrate) in lib\$ac_z (= lib$ac_z)])
+], [:])
+if test "${ac_cv_lib_z_infiltrate+set}" != set; then
+  AC_MSG_ERROR([ac_cv_lib_z_infiltrate not set])
+fi
+]])
 
 
 # AC_SEARCH_LIBS
 # --------------
-AT_CHECK_MACRO([AC_SEARCH_LIBS],
-[
-AC_SEARCH_LIBS(cos, oser m ust,,
-            [AC_MSG_ERROR([cannot find `cos'])])
-
-case "$ac_cv_search_cos" in
-  -loser|-lust) AC_MSG_ERROR([jeez, $ac_cv_search_cos must be a cool library!]) ;;
-esac
+# Like AC_CHECK_LIBS, we use zlib here because we need the behavior to
+# be consistent between the C and C++ compilers.
+AT_CHECK_MACRO([AC_SEARCH_LIBS (needed)], [[
+AC_CHECK_HEADER([zlib.h], [], [
+  AC_MSG_NOTICE([zlib not available, skipping test])
+  AS_EXIT(77)
 ])
 
+# Unlike AC_CHECK_LIBS, AC_SEARCH_LIBS sets $LIBS *even if*
+# ACTION-IF-FOUND is given, so we need to reset it after each test.
+ac_at_save_LIBS="$LIBS"
+
+AC_SEARCH_LIBS([zlibVersion], [z], [:], [:])
+if test x"$ac_cv_search_zlibVersion" != x-lz; then
+  AC_MSG_ERROR([wrong zlibVersion search result: $ac_cv_search_zlibVersion])
+fi
+LIBS="$ac_at_save_LIBS"
+
+# No kidding, using variables was broken in 2.50 :(
+ac_deflate=deflate
+AC_SEARCH_LIBS([$ac_deflate], [z], [:], [:])
+if test x"$ac_cv_search_deflate" != x-lz; then
+  AC_MSG_ERROR([wrong deflate search result: $ac_cv_search_deflate])
+fi
+LIBS="$ac_at_save_LIBS"
+
+ac_z=z
+AC_SEARCH_LIBS([deflateEnd], [$ac_z], [:], [:])
+if test x"$ac_cv_search_deflateEnd" != x-lz; then
+  AC_MSG_ERROR([wrong deflateEnd search result: $ac_cv_search_deflateEnd])
+fi
+LIBS="$ac_at_save_LIBS"
+
+ac_inflate=inflate
+AC_SEARCH_LIBS([$ac_inflate], [$ac_z], [:], [:])
+if test x"$ac_cv_search_inflate" != x-lz; then
+  AC_MSG_ERROR([wrong inflate search result: $ac_cv_search_inflate])
+fi
+LIBS="$ac_at_save_LIBS"
+
+# Also test for symbols that don't (well, shouldn't) exist.
+# These should still set their cache variables!
+AC_SEARCH_LIBS([deflagrate], [z], [:], [:])
+if test x"$ac_cv_search_deflagrate" != xno; then
+  AC_MSG_ERROR([wrong deflagrate search result: $ac_cv_search_deflagrate])
+fi
+LIBS="$ac_at_save_LIBS"
+
+ac_defenestrate=defenestrate
+AC_SEARCH_LIBS([$ac_defenestrate], [z], [:], [:])
+if test x"$ac_cv_search_defenestrate" != xno; then
+  AC_MSG_ERROR([wrong defenestrate search result: $ac_cv_search_defenestrate])
+fi
+LIBS="$ac_at_save_LIBS"
+
+AC_SEARCH_LIBS([defoliate], [$ac_z], [:], [:])
+if test x"$ac_cv_search_defoliate" != xno; then
+  AC_MSG_ERROR([wrong defoliate search result: $ac_cv_search_defoliate])
+fi
+LIBS="$ac_at_save_LIBS"
+
+ac_infiltrate=infiltrate
+AC_SEARCH_LIBS([$ac_infiltrate], [$ac_z], [:], [:])
+if test x"$ac_cv_search_infiltrate" != xno; then
+  AC_MSG_ERROR([wrong infiltrate search result: $ac_cv_search_infiltrate])
+fi
+LIBS="$ac_at_save_LIBS"
+]])
+
 
 # AC_SEARCH_LIBS (none needed)
 # ----------------------------
-AT_CHECK_MACRO([AC_SEARCH_LIBS (none needed)],
-[
-AC_SEARCH_LIBS(printf, oser c ust,,
-            [AC_MSG_ERROR([cannot find `printf'])])
-
-case "$ac_cv_search_printf" in
-  -loser|-lust) AC_MSG_ERROR([jeez, $ac_cv_search_printf must be a cool library!]) ;;
-  -lc) AC_MSG_ERROR([huh, you need to give -lc?])
-esac
-])
+# This test doesn't need to be nearly as thorough as the above; its
+# purpose is simply to ensure that when no library is needed,
+# AC_SEARCH_LIBS really does produce "none needed" as its result.
+AT_CHECK_MACRO([AC_SEARCH_LIBS (none needed)], [[
+# No library should be required to link with printf, but we throw
+# -lc in the search list so that it includes both libraries that
+# don't exist and libraries that probably do.
+AC_SEARCH_LIBS([printf], [oser c ust], [:], [:])
+
+if test x"$ac_cv_search_printf" != "xnone required"; then
+  AC_MSG_ERROR([wrong printf search result: $ac_cv_search_printf])
+fi
+]])
 
 
 # AC_CHECK_DECLS
@@ -145,8 +241,8 @@ AT_CHECK_MACRO([AC_CHECK_DECLS],
                ]])
   AC_LANG_WERROR
   AC_CHECK_DECL([undeclared (char *)], [AS_EXIT([1])],, [[]])
-  if test -z "$ac_c_werror_flag"; then
-    AC_MSG_ERROR([ac_c_werror_flag overwritten])
+  if test -z "$ac_[]_AC_LANG_ABBREV[]_werror_flag"; then
+    AC_MSG_ERROR([ac_]_AC_LANG_ABBREV[_werror_flag overwritten])
   fi
 ]],
 [AT_CHECK_DEFINES(
@@ -390,7 +486,7 @@ AT_CHECK([grep 'yes.*member of.*yes_s' config.h], [], [ignore])
 
 # AC_CHECK_ALIGNOF
 # ----------------
-AT_CHECK_MACRO_CROSS([AC_CHECK_ALIGNOF],
+AT_CHECK_MACRO([AC_CHECK_ALIGNOF],
 [[AC_CHECK_ALIGNOF(char)
 AC_CHECK_ALIGNOF(charchar,
 [[#include <stddef.h>
@@ -407,7 +503,7 @@ AC_CHECK_ALIGNOF(charcharchar)
 
 # AC_CHECK_ALIGNOF struct
 # -----------------------
-AT_CHECK_MACRO_CROSS([AC_CHECK_ALIGNOF struct],
+AT_CHECK_MACRO([AC_CHECK_ALIGNOF struct],
 [[AC_CHECK_ALIGNOF([struct { char c; }])
 AC_CHECK_ALIGNOF([struct nosuchstruct])
 ]],
@@ -419,7 +515,7 @@ AT_CHECK([[grep "#define ALIGNOF_STRUCT_NOSUCHSTRUCT 0" config.h]],
 
 # AC_CHECK_SIZEOF
 # ---------------
-AT_CHECK_MACRO_CROSS([AC_CHECK_SIZEOF],
+AT_CHECK_MACRO([AC_CHECK_SIZEOF],
 [[AC_CHECK_SIZEOF(char)
 AC_CHECK_SIZEOF(charchar,,
 [[#include <stdio.h>
@@ -435,7 +531,7 @@ AC_CHECK_SIZEOF(charcharchar)
 
 # AC_CHECK_SIZEOF struct
 # ----------------------
-AT_CHECK_MACRO_CROSS([AC_CHECK_SIZEOF struct],
+AT_CHECK_MACRO([AC_CHECK_SIZEOF struct],
 [[AC_C_CONST
 AC_CHECK_SIZEOF([struct x], [], [struct x { char c; int x; };])
 AC_CHECK_SIZEOF([const struct x], [], [struct x { const char *p; int x; };])
@@ -510,12 +606,16 @@ AT_CLEANUP
 # --------------
 # FIXME: To really test HAVE_AC_EXISTS2 and HAVE_AC_MISSING2 we need to
 # open AH_TEMPLATE to `configure.ac', which is not yet the case.
-AT_CHECK_MACRO([AC_CHECK_FILES],
-[touch at-exists1 at-exists2
+# Don't use AT_CHECK_MACRO for this one because AC_CHECK_FILES can't be
+# used when cross compiling.
+
+AT_CHECK_CONFIGURE_AC([AC_CHECK_FILES],
+[[touch at-exists1 at-exists2
 ac_exists2=at-exists2
 ac_missing2=at-missing2
 AC_CHECK_FILES(at-exists1 at-missing1 $ac_exists2 $ac_missing2)
-rm at-exists1 at-exists2],
+rm at-exists1 at-exists2]],
+[], [],
 [AT_CHECK_DEFINES(
 [#define HAVE_AT_EXISTS1 1
 /* #undef HAVE_AT_MISSING1 */
@@ -803,9 +903,100 @@ AT_CLEANUP
 ## ------------------------------- ##
 
 
-AT_CHECK_MACRO([AC_SYS_RESTARTABLE_SYSCALLS], , ,[-W no-obsolete])
+AT_CHECK_MACRO([AC_SYS_RESTARTABLE_SYSCALLS], , ,[-W no-obsolete], [no-cross])
 AT_CHECK_MACRO([AC_FUNC_SETVBUF_REVERSED], , ,[-W no-obsolete])
-AT_CHECK_MACRO([AC_FUNC_WAIT3], , ,[-W no-obsolete])
+AT_CHECK_MACRO([AC_FUNC_WAIT3], , ,[-W no-obsolete], [no-cross])
+
+
+## ------------------------------------- ##
+## Obsolete macros requiring arguments.  ##
+## ------------------------------------- ##
+
+# These all wrap the macro under test in an AC_CACHE_CHECK and an
+# AC_DEFINE so the full verification machinery of AT_CHECK_MACRO is
+# effective.  Caution: AT_CHECK_AU_MACRO expects that after an
+# autoupdate run, a naive grep will not find the old macro name
+# anywhere in the updated configure.ac, not even as part of a
+# longer identifier.  (But it's case sensitive.)
+
+AT_CHECK_AU_MACRO([AC_TRY_CPP],
+[[AC_CACHE_CHECK([working ac_try_cpp], [ac_cv_ac_try_cpp_works], [
+  AC_TRY_CPP([
+    @%:@if 2 + 2 != 4
+    @%:@error "SEVEN!"  /* in memory of Stanislaw Lem */
+    @%:@endif
+  ], [ac_cv_ac_try_cpp_works=yes],
+     [ac_cv_ac_try_cpp_works=no])
+])
+if test $ac_cv_ac_try_cpp_works = yes; then
+  AC_DEFINE([ac_try_cpp_works], [1], [label])
+fi
+]])
+
+
+AT_CHECK_AU_MACRO([AC_TRY_COMPILE],
+[[AC_CACHE_CHECK([working ac_try_compile], [ac_cv_ac_try_compile_works], [
+  AC_TRY_COMPILE([int variable;], [return variable;],
+    [ac_cv_ac_try_compile_works=yes],
+    [ac_cv_ac_try_compile_works=no])
+])
+if test $ac_cv_ac_try_compile_works = yes; then
+  AC_DEFINE([ac_try_compile_works], [1], [label])
+fi
+]])
+
+
+AT_CHECK_AU_MACRO([AC_TRY_LINK],
+[[AC_CACHE_CHECK([working ac_try_link], [ac_cv_ac_try_link_works], [
+  AC_TRY_LINK([@%:@include <stdio.h>], [return !feof(stdin);],
+    [ac_cv_ac_try_link_works=yes],
+    [ac_cv_ac_try_link_works=no])
+])
+if test $ac_cv_ac_try_link_works = yes; then
+  AC_DEFINE([ac_try_link_works], [1], [label])
+fi
+]])
+
+
+# Oddly enough, AC_COMPILE_CHECK was shorthand for AC_MSG_CHECKING +
+# AC_TRY_LINK, not AC_TRY_COMPILE.  When not cached, this will print
+#   checking for working ac_compile_check... checking for feof ... yes
+# but whatever.
+AT_CHECK_AU_MACRO([AC_COMPILE_CHECK],
+[[AC_CACHE_CHECK([working ac_compile_check], [ac_cv_ac_compile_check_works], [
+  AC_COMPILE_CHECK([feof], [@%:@include <stdio.h>], [return !feof(stdin);],
+    [ac_cv_ac_compile_check_works=yes],
+    [ac_cv_ac_compile_check_works=no])
+])
+if test $ac_cv_ac_compile_check_works = yes; then
+  AC_DEFINE([ac_compile_check_works], [1], [label])
+fi
+]])
+
+
+AT_CHECK_AU_MACRO([AC_TRY_RUN],
+[[AC_CACHE_CHECK([working ac_try_run], [ac_cv_ac_try_run_works], [
+  AC_TRY_RUN([int main(void) { return 0; }],
+    [ac_cv_ac_try_run_works=yes],
+    [ac_cv_ac_try_run_works=no],
+    [ac_cv_ac_try_run_works=yes]) # cross compile, assume it works
+])
+if test $ac_cv_ac_try_run_works = yes; then
+  AC_DEFINE([ac_try_run_works], [1], [label])
+fi
+]])
+
+
+# For purpose of this test, we don't care whether these libraries
+# exist (as long as the result is consistent between C and C++)
+# but we _do_ need to make sure that autoupdate correctly handles
+# AC_HAVE_LIBRARY's acceptance of "-lfoo" and "libfoo.a" as the
+# LIBRARY argument, where AC_CHECK_LIB only takes "foo".
+AT_CHECK_AU_MACRO([AC_HAVE_LIBRARY],
+[[AC_HAVE_LIBRARY([alice])
+AC_HAVE_LIBRARY([-lbob])
+AC_HAVE_LIBRARY([libmallory.a])
+]])
 
 
 ## ----------------------------------------- ##