7
votes

Autoconf's AC_COMPILE_IFELSE is misdetecting features for us under different compilers, like Sun's C++ compiler and IBM's xlC compiler. AC_COMPILE_IFELSE appears to check return values, but some compilers don't bother to set it or set it to unexpected values. Later, we use options that are not available.

In my non-Autoconf build scripts I use "fatal|error|illegal|unrecognized|not found|not exist" to detect a compiler or linker complaint. It is more robust than just checking $?. The test looks like:

# infile and outfile are temp files that allow testing a feature
SH_ERROR=$($CXX -Wl,--enable-new-dtags -o "$outfile" "$infile" 2>&1 | $EGREP -i -c -E 'fatal|error|illegal|unrecognized|not found|not exist')
if [[ "$SH_ERROR" -eq "0" ]]; then
    CXXFLAGS+="-Wl,--enable-new-dtags"
fi

The Autoconf documentation for AC_COMPILE_IFELSE is at 6.4 Running the Compiler, but it does not discuss the subject matter. In fact, the document does not even define what it means for AC_COMPILE_IFELSE to be "success[ful]".

My first question is, are compiler return values standardized somewhere?

My second question is, what does Autoconf use to determine "success"?

My third question is, how do we do the same in Autoconf? Is there something else to use besides AC_COMPILE_IFELSE?

A related question is (based on Stefan's answer), how do we get Autoconf to use an improved AC_COMPILE_IFELSE? Is it possible to undef the current AC_COMPILE_IFELSE and define it to the more robust version?

Thanks in advance.

1
TBH the only robust test would be to check if the compiler creates an executable which does what it should do. I.e. the test code should include a std::cout << "A-128-bits-GUID\n", and the test should only pass if there's an executable generated which echoes back that string. Of course, that is a slight challenge for cross-compiles.MSalters
Thanks @MSalters - Yeah, that would probably be the most complete test. I'd settle for something that catches the illegal option and invalid option messages.jww

1 Answers

4
votes

My first question is, are compiler return values standardized somewhere?

I'm pretty sure there is no standard defining what compilers for any language should return, apart from the obvious standard for all programs that exit code 0 means success and everything else failure, see posix on the exit function:

A value of zero (or EXIT_SUCCESS, which is required to be zero) for the argument status conventionally indicates successful termination. This corresponds to the specification for exit() in the ISO C standard. The convention is followed by utilities such as make and various shells, which interpret a zero status from a child process as success. For this reason, applications should not call exit(0) or _exit(0) when they terminate unsuccessfully; for example, in signal-catching functions.


My second question is, what does Autoconf use to determine "success"?

The latest autoconf release is 2.69 (from 2012), and although some things might have changed, I'm going to base my answer on it.

AC_COMPILE_IFELSE is successful, iff the compiler has a successful exit code (i.e. 0) and the object file is not empty (test -s conftest.$ac_objext; it is removed before running the compiler). If AC_LANG_WERROR was used for the current language it also makes sure the stderr output of the compiler is empty (apart from shell trace log lines).


My third question is, how do we do the same in Autoconf? Is there something else to use besides AC_COMPILE_IFELSE?

Keep in mind, that although the autoconf sources look like magic, they are not - you can build your own macros as long as you know what you want them to do :) But maybe AC_LANG_WERROR is an option, apart from telling the vendor to suck it and fix their crap.

I'm not a fan of AC_LANG_WERROR: I had to use /etc/ld.so.preload on a multiarch system to fix problems with flashplayer some years ago, and running binaries from the other arch would always print an error it couldn't load it, although there was nothing wrong with it - AC_LANG_WERROR breaks horribly in such environment

As an example of a custom compile check macro take a look at this:

# MY_COMPILE_CLEAN_IFELSE(PROGRAM, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
# ---------------------------------------------------------------
# Try to compile PROGRAM.
AC_DEFUN([MY_COMPILE_CLEAN_IFELSE],
[AC_REQUIRE([AC_PROG_EGREP])
AC_COMPILE_IFELSE([$1],[retval=0
if $EGREP -i -c -E 'fatal|error|unrecognized|not found|not exist' conftest.err >/dev/null; then retval=1; fi
],[retval=1])
AS_IF([test $retval = 0],[$2],[$3])])

conftest.err is deleted after AC_COMPILE_IFELSE is done, so you need to check it in the inner actions.