summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZack Weinberg <zackw@panix.com>2020-11-02 13:15:00 -0500
committerZack Weinberg <zackw@panix.com>2020-11-02 13:15:00 -0500
commitf1047b2e9656ba1cb3b672df22b2178ad0b38738 (patch)
treeae091d8ded2e8d6e07227fbd8e60bf61970379a6
parent45f1c8ba95c84a2980aa2ed3d03f1674fcc114fa (diff)
downloadautoconf-f1047b2e9656ba1cb3b672df22b2178ad0b38738.tar.gz
AC_OPENMP: Avoid clobbering ‘mp’ and/or ‘penmp’ (#110353)
Some of the compiler options that AC_OPENMP tests, mean “enable OpenMP” to one compiler, but “write output to a file named ‘mp’ or ‘penmp’” to other compilers. The author of AC_OPENMP believed that this could only happen if compilation was *successful*, but didn’t realize that one of the options means “write *preprocessed* output to a file named ‘penmp’” to SunPRO C, and that this *would* succeed on the test program. (AC_LINK_IFELSE fails anyway, because the compilation didn’t create conftest$exeext.) The option that actually means “enable OpenMP” to SunPRO C is earlier in the list than the option that means “write preprocessed output to a file named ‘penmp’”, so we might never have noticed this, but for a second bug: if you have a bad combination of Solaris operating system patches installed, it’s possible for this compiler to successfully *compile* a program that uses OpenMP, but then fail to *link* it because the OpenMP runtime library is out of sync with the core C library. AC_OPENMP doesn’t distinguish this case from “that option doesn’t mean ‘enable OpenMP’” so it goes on to other entries in the list and hits the “write preprocessed output” one. Implement four layers of defensive measures against this mess: - Use an #error directive instead of a compile-time syntax error to halt compilation when _OPENMP is not defined. - For each option that might mean “enable OpenMP”, first do an AC_COMPILE_IFELSE to find out whether it really means that, and then an AC_LINK_IFELSE to find out whether it works. If the compilation succeeds but the link fails, bail out of the loop and declare OpenMP to be unsupported. - If a file named ‘mp’ or ‘openmp’ exists in configure’s working directory when AC_OPENMP begins, error out. This means it is safe to delete any file named ‘mp’ or ‘openmp’ that exists at the *end* of AC_OPENMP. - If a file named ‘mp’ or ‘openmp’ exists in the top level of the source tree with a configure.ac that uses AC_OPENMP, have autoconf error out, too. Fixes bug #110353. Problem reported by Dagobert Michelsen. * lib/autoconf/c.m4 (_AC_LANG_OPENMP(C)): Change ‘choke me’ to ‘#error "OpenMP not supported"’. (AC_OPENMP): AC_REQUIRE _AC_OPENMP_SAFE_WD. For each option, do both a compile test and a link test; if the compile test succeeds but the link fails, don’t go on to other candidate options. Delete files named ‘mp’ and ‘penmp’ after the loop. (_AC_OPENMP_SAFE_WD): New macro, subroutine of AC_OPENMP. If files named ‘mp’ or ‘penmp’ exist, error out both at autoconf time and at configure time. * tests/torture.at (Files clobbered by AC_OPENMP): New test. * doc/autoconf.texi: Document requirement not to have files named ‘mp’ or ‘penmp’ next to a configure.ac that uses AC_OPENMP.
-rw-r--r--NEWS13
-rw-r--r--doc/autoconf.texi18
-rw-r--r--lib/autoconf/c.m4118
-rw-r--r--tests/torture.at51
4 files changed, 159 insertions, 41 deletions
diff --git a/NEWS b/NEWS
index 4e2d5a10..2608cc2e 100644
--- a/NEWS
+++ b/NEWS
@@ -164,6 +164,19 @@ GNU Autoconf NEWS - User visible changes.
Programs that use AC_FUNC_STRERROR_R should make sure to test the
preprocessor macro HAVE_DECL_STRERROR_R before using strerror_r at all.
+*** AC_OPENMP can’t be used if you have files named ‘mp’ or ‘penmp’.
+
+ Autoconf will now issue an error if AC_OPENMP is used in a configure
+ script that’s in the same directory as a file named ‘mp’ or ‘penmp’.
+ Configure scripts that use AC_OPENMP will now error out upon
+ encountering files with these names in their working directory
+ (e.g. when the build directory is separate from the source directory).
+
+ If you have files with these names at the top level of your source
+ tree, we recommend either renaming them or moving them into a
+ subdirectory. See the documentation of AC_OPENMP for further
+ explanation.
+
** New features
*** Configure scripts now support a ‘--runstatedir’ option.
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index acc290b0..2422bd67 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -7234,6 +7234,24 @@ latter.
This macro caches its result in the @code{ac_cv_prog_c_openmp},
@code{ac_cv_prog_cxx_openmp}, @code{ac_cv_prog_f77_openmp}, or
@code{ac_cv_prog_fc_openmp} variable, depending on the current language.
+
+@strong{Caution:} Some of the compiler options that @code{AC_OPENMP}
+tests, mean ``enable OpenMP'' to one compiler, but ``write output to a
+file named @file{mp} or @file{penmp}'' to other compilers. We cannot
+guarantee that the implementation of @code{AC_OPENMP} will not overwrite
+an existing file with either of these names.
+
+Therefore, as a defensive measure, a @command{configure} script that
+uses @code{AC_OPENMP} will issue an error and stop (before doing any of
+the operations that might overwrite these files) upon encountering
+either of these files in its working directory.
+@command{autoconf} will also issue an error if it finds either of
+these files in the same directory as a @file{configure.ac} that
+uses @code{AC_OPENMP}.
+
+If you have files with either of these names at the top level of your
+source tree, and you need to use @code{AC_OPENMP}, we recommend you
+either change their names or move them into a subdirectory.
@end defmac
@node C Compiler
diff --git a/lib/autoconf/c.m4 b/lib/autoconf/c.m4
index 53217077..ca63dc58 100644
--- a/lib/autoconf/c.m4
+++ b/lib/autoconf/c.m4
@@ -2125,7 +2125,7 @@ AC_DEFUN([_AC_LANG_OPENMP],
m4_define([_AC_LANG_OPENMP(C)],
[
#ifndef _OPENMP
- choke me
+#error "OpenMP not supported"
#endif
#include <omp.h>
int main (void) { return omp_get_num_threads (); }
@@ -2159,56 +2159,92 @@ m4_copy([_AC_LANG_OPENMP(Fortran 77)], [_AC_LANG_OPENMP(Fortran)])
# The options are necessary at compile time (so the #pragmas are understood)
# and at link time (so the appropriate library is linked with).
# This macro takes care to not produce redundant options if $CC $CFLAGS already
-# supports OpenMP. It also is careful to not pass options to compilers that
-# misinterpret them; for example, most compilers accept "-openmp" and create
-# an output file called 'penmp' rather than activating OpenMP support.
+# supports OpenMP.
+#
+# For each candidate option, we do a compile test first, then a link test;
+# if the compile test succeeds but the link test fails, that means we have
+# found the correct option but it doesn't work because the libraries are
+# broken. (This can happen, for instance, with SunPRO C and a bad combination
+# of operating system patches.)
+#
+# Several of the options in our candidate list can be misinterpreted by
+# compilers that don't use them to activate OpenMP support; for example,
+# many compilers understand "-openmp" to mean "write output to a file
+# named 'penmp'" rather than "enable OpenMP". We can't completely avoid
+# the possibility of clobbering files named 'penmp' or 'mp' in configure's
+# working directory; therefore, this macro will bomb out if any such file
+# already exists when it's invoked.
AC_DEFUN([AC_OPENMP],
+[AC_REQUIRE([_AC_OPENMP_SAFE_WD])]dnl
+[AC_ARG_ENABLE([openmp],
+ [AS_HELP_STRING([--disable-openmp], [do not use OpenMP])])]dnl
[
OPENMP_[]_AC_LANG_PREFIX[]FLAGS=
- AC_ARG_ENABLE([openmp],
- [AS_HELP_STRING([--disable-openmp], [do not use OpenMP])])
if test "$enable_openmp" != no; then
AC_CACHE_CHECK([for $[]_AC_CC[] option to support OpenMP],
[ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp],
- [AC_LINK_IFELSE([_AC_LANG_OPENMP],
- [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp='none needed'],
- [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp='unsupported'
- dnl Try these flags:
- dnl GCC >= 4.2 -fopenmp
- dnl SunPRO C -xopenmp
- dnl Intel C -openmp
- dnl SGI C, PGI C -mp
- dnl Tru64 Compaq C -omp
- dnl IBM XL C (AIX, Linux) -qsmp=omp
- dnl Cray CCE -homp
- dnl NEC SX -Popenmp
- dnl Lahey Fortran (Linux) --openmp
- dnl If in this loop a compiler is passed an option that it doesn't
- dnl understand or that it misinterprets, the AC_LINK_IFELSE test
- dnl will fail (since we know that it failed without the option),
- dnl therefore the loop will continue searching for an option, and
- dnl no output file called 'penmp' or 'mp' is created.
- for ac_option in -fopenmp -xopenmp -openmp -mp -omp -qsmp=omp -homp \
- -Popenmp --openmp; do
- ac_save_[]_AC_LANG_PREFIX[]FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
- _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $ac_option"
- AC_LINK_IFELSE([_AC_LANG_OPENMP],
- [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp=$ac_option])
- _AC_LANG_PREFIX[]FLAGS=$ac_save_[]_AC_LANG_PREFIX[]FLAGS
- if test "$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp" != unsupported; then
- break
- fi
- done])])
- case $ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp in #(
- "none needed" | unsupported)
- ;; #(
- *)
- OPENMP_[]_AC_LANG_PREFIX[]FLAGS=$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp ;;
- esac
+ [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp='not found'
+ dnl Try these flags:
+ dnl (on by default) ''
+ dnl GCC >= 4.2 -fopenmp
+ dnl SunPRO C -xopenmp
+ dnl Intel C -openmp
+ dnl SGI C, PGI C -mp
+ dnl Tru64 Compaq C -omp
+ dnl IBM XL C (AIX, Linux) -qsmp=omp
+ dnl Cray CCE -homp
+ dnl NEC SX -Popenmp
+ dnl Lahey Fortran (Linux) --openmp
+ for ac_option in '' -fopenmp -xopenmp -openmp -mp -omp -qsmp=omp -homp \
+ -Popenmp --openmp; do
+
+ ac_save_[]_AC_LANG_PREFIX[]FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
+ _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $ac_option"
+ AC_COMPILE_IFELSE([_AC_LANG_OPENMP],
+ [AC_LINK_IFELSE([_AC_LANG_OPENMP],
+ [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp=$ac_option],
+ [ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp='unsupported'])])
+ _AC_LANG_PREFIX[]FLAGS=$ac_save_[]_AC_LANG_PREFIX[]FLAGS
+
+ if test "$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp" != 'not found'; then
+ break
+ fi
+ done
+ if test "$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp" = 'not found'; then
+ ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp='unsupported'
+ elif test "$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp" = ''; then
+ ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp='none needed'
+ fi
+ dnl _AC_OPENMP_SAFE_WD checked that these files did not exist before we
+ dnl started probing for OpenMP support, so if they exist now, they were
+ dnl created by the probe loop and it's safe to delete them.
+ rm -f penmp mp])
+ if test "$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp" != 'unsupported' && \
+ test "$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp" != 'none needed'; then
+ OPENMP_[]_AC_LANG_PREFIX[]FLAGS="$ac_cv_prog_[]_AC_LANG_ABBREV[]_openmp"
+ fi
fi
AC_SUBST([OPENMP_]_AC_LANG_PREFIX[FLAGS])
])
+# _AC_OPENMP_SAFE_WD
+# ------------------
+# AC_REQUIREd by AC_OPENMP. Checks both at autoconf time and at
+# configure time for files that AC_OPENMP clobbers.
+AC_DEFUN([_AC_OPENMP_SAFE_WD],
+[m4_syscmd([test ! -e penmp && test ! -e mp])]dnl
+[m4_if(sysval, [0], [], [m4_fatal(m4_normalize(
+ [AC_OPENMP clobbers files named 'mp' and 'penmp'.
+ To use AC_OPENMP you must not have either of these files
+ at the top level of your source tree.]))])]dnl
+[if test -e penmp || test -e mp; then
+ AC_MSG_ERROR(m4_normalize(
+ [AC@&t@_OPENMP clobbers files named 'mp' and 'penmp'.
+ Aborting configure because one of these files already exists.]))
+fi])
+
+
+
# _AC_CXX_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST,
# ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE)
# ----------------------------------------------------------------
diff --git a/tests/torture.at b/tests/torture.at
index 76cddc65..a96af651 100644
--- a/tests/torture.at
+++ b/tests/torture.at
@@ -2061,3 +2061,54 @@ AT_CHECK([test -x build-aux/install-sh])
AT_CHECK_CONFIGURE
AT_CLEANUP
+
+## ------------------------------ ##
+## Files clobbered by AC_OPENMP. ##
+## ------------------------------ ##
+
+AT_SETUP([Files clobbered by AC_OPENMP])
+
+AT_CONFIGURE_AC(
+[[AC_PROG_CC
+AC_OPENMP
+]])
+
+AT_CHECK_AUTOHEADER
+
+# autoconf should bomb out if either 'mp' or 'openmp' exists in the
+# srcdir.
+AT_DATA([mp])
+AT_CHECK_AUTOCONF([], [1], [], [stderr])
+AT_CHECK([grep "clobbers files named 'mp' and 'penmp'" stderr],
+ [0], [ignore], [ignore])
+rm -f mp
+
+AT_DATA([penmp])
+AT_CHECK_AUTOCONF([], [1], [], [stderr])
+AT_CHECK([grep "clobbers files named 'mp' and 'penmp'" stderr],
+ [0], [ignore], [ignore])
+rm -f penmp
+
+# If neither of these files exist, autoconf should go through...
+AT_CHECK_AUTOCONF
+
+# ... but configure should bomb out, and *not* delete the files,
+# if they are added after autoconf is run.
+AT_DATA([mp])
+AT_CHECK_CONFIGURE([], [1], [], [stderr])
+AT_CHECK([test -e mp])
+AT_CHECK([grep "clobbers files named 'mp' and 'penmp'" stderr],
+ [0], [ignore], [ignore])
+rm -f mp
+
+AT_DATA([penmp])
+AT_CHECK_CONFIGURE([], [1], [], [stderr])
+AT_CHECK([test -e penmp])
+AT_CHECK([grep "clobbers files named 'mp' and 'penmp'" stderr],
+ [0], [ignore], [ignore])
+rm -f penmp
+
+AT_CHECK_CONFIGURE
+AT_CHECK_ENV
+
+AT_CLEANUP