diff options
author | Zack Weinberg <zackw@panix.com> | 2020-11-02 13:15:00 -0500 |
---|---|---|
committer | Zack Weinberg <zackw@panix.com> | 2020-11-02 13:15:00 -0500 |
commit | f1047b2e9656ba1cb3b672df22b2178ad0b38738 (patch) | |
tree | ae091d8ded2e8d6e07227fbd8e60bf61970379a6 | |
parent | 45f1c8ba95c84a2980aa2ed3d03f1674fcc114fa (diff) | |
download | autoconf-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-- | NEWS | 13 | ||||
-rw-r--r-- | doc/autoconf.texi | 18 | ||||
-rw-r--r-- | lib/autoconf/c.m4 | 118 | ||||
-rw-r--r-- | tests/torture.at | 51 |
4 files changed, 159 insertions, 41 deletions
@@ -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 |