More robust AC_COMPILE_IFELSE feature testing?
Asked Answered
H

1

7

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.

Hallam answered 7/11, 2017 at 14:40 Comment(2)
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.Kile
Thanks @Kile - Yeah, that would probably be the most complete test. I'd settle for something that catches the illegal option and invalid option messages.Hallam
R
4

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.

Rainfall answered 10/11, 2017 at 14:24 Comment(9)
Thanks Stefan. How would I port my non-Autoconf checking into Autoconf? I had to use it already, but its an ugly wart that is effectively copy/paste: configure.ac. I'm OK with checking $?, but the machinery has to check for complaints like illegal option and unrecognized option.Hallam
Thanks again Stefan. "I'm not a fan of AC_LANG_WERROR..." - Yeah, I'm not hacking that bullshit in. It seems like it is trading one set of defective tests for another set of defective tests. First, I doubt it works for all the compilers we support. Second, I'm not sure one can make the leap that a compiler diagnostic (or lack of one) is the right way to determine success. I'm would wager there are some diagnostics that are benign and I don't care about. We know the strings that tell us something is wrong, so we should use them.Hallam
I added an error-grepping example you might find useful.Rainfall
Thanks Stefan. Its going to take a little time for me to test it. Forgive my ignorance... Another (dumb) question: how do I get the Autoconf tests to use it? Can we undef the existing [broken] macro, and define it to your improved macro?Hallam
I'd avoid redefining existing macros, you might not always be aware of the updated semantics. AC_DEFUN can overwrite existing macros, but using the original macro inside is not trivial afaict. MY_COMPILE_CLEAN_IFELSE should be able to replace normal AC_COMPILE_IFELSE calls like MY_COMPILE_CLEAN_IFELSE([AC_LANG_PROGRAM()], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])Rainfall
Thanks again @Stefan. Forgive my ignorance (again)... I read 10 Writing Autoconf Macros from the manual. Where, exactly, is MY_COMPILE_CLEAN_IFELSE placed? We have configure.ac and Makefile.am. Does that mean it goes in configure.ac? Sorry to ask. The closest I found to an example is 10.6 Coding Style, but it does not state where to place a macro.Hallam
@Hallam configure.ac is fine (just not before AC_INIT). autotools.io/autoconf/macros.html documents other ways.Rainfall
Thanks again Stefan.Hallam
I know this is an old post... There are two retval=1 and no retval=0.Hallam

© 2022 - 2024 — McMap. All rights reserved.