Discussion:
Call the AC_CHECK_HEADER macro on a condition
YuGiOhJCJ Mailing-List
2016-04-12 09:38:21 UTC
Permalink
Hello,

This is my configure.ac file:
AC_INIT([my-project], [20160412])
AM_INIT_AUTOMAKE
AM_PROG_CC_C_O
AC_CHECK_HEADER([avr/io.h], [], [AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [], [AC_MSG_ERROR([missing header: util/delay.h])])
AC_CHECK_HEADER([stdio.h], [], [AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [], [AC_MSG_ERROR([missing header: time.h])])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

The two first header checks must be called only when host is "avr" whereas the two last checks must be called in other cases.

Currently, if I call my configure script with host set to "avr" that's what happens:
$ ./configure --host=avr
checking for a BSD-compatible install... /bin/ginstall -c
checking whether build environment is sane... yes
checking for avr-strip... avr-strip
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for style of include used by make... GNU
checking for avr-gcc... avr-gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... yes
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether avr-gcc accepts -g... yes
checking for avr-gcc option to accept ISO C89... none needed
checking dependency style of avr-gcc... gcc3
checking whether avr-gcc and cc understand -c and -o together... yes
checking how to run the C preprocessor... avr-gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... no
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... no
checking for strings.h... no
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking avr/io.h usability... yes
checking avr/io.h presence... yes
checking for avr/io.h... yes
checking util/delay.h usability... yes
checking util/delay.h presence... yes
checking for util/delay.h... yes
checking stdio.h usability... yes
checking stdio.h presence... yes
checking for stdio.h... yes
checking time.h usability... yes
checking time.h presence... yes
checking for time.h... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands

As you can see the :
AC_CHECK_HEADER([stdio.h], [], [AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [], [AC_MSG_ERROR([missing header: time.h])])
calls are done whereas it is useless for my project when host is "avr".

And you can guess what happens when I call my configure script with host not set:
$ ./configure
checking for a BSD-compatible install... /bin/ginstall -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking dependency style of gcc... gcc3
checking whether gcc and cc understand -c and -o together... yes
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking avr/io.h usability... no
checking avr/io.h presence... no
checking for avr/io.h... no
configure: error: missing header: avr/io.h

Here, the:
AC_CHECK_HEADER([avr/io.h], [], [AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [], [AC_MSG_ERROR([missing header: util/delay.h])])
calls are done whereas when host is my linux machine, these checks should not be done.

So, I would like to call the AC_CHECK_HEADER macro on a condition:
AC_INIT([my-project], [20160412])
AM_INIT_AUTOMAKE
AM_PROG_CC_C_O
if test "x$host" == xavr; then
AC_CHECK_HEADER([avr/io.h], [], [AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [], [AC_MSG_ERROR([missing header: util/delay.h])])
else
AC_CHECK_HEADER([stdio.h], [], [AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [], [AC_MSG_ERROR([missing header: time.h])])
fi
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

With this new configure.ac file, if I call my configure script with host set to "avr" that's what happens:
$ ./configure --host=avr
checking for a BSD-compatible install... /bin/ginstall -c
checking whether build environment is sane... yes
checking for avr-strip... avr-strip
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for style of include used by make... GNU
checking for avr-gcc... avr-gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... yes
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether avr-gcc accepts -g... yes
checking for avr-gcc option to accept ISO C89... none needed
checking dependency style of avr-gcc... gcc3
checking whether avr-gcc and cc understand -c and -o together... yes
checking how to run the C preprocessor... avr-gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... no
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... no
checking for strings.h... no
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking avr/io.h usability... yes
checking avr/io.h presence... yes
checking for avr/io.h... yes
checking util/delay.h usability... yes
checking util/delay.h presence... yes
checking for util/delay.h... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands

It seems to do the job.
The:
AC_CHECK_HEADER([stdio.h], [], [AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [], [AC_MSG_ERROR([missing header: time.h])])
calls are not anymore done.

And that's what happens when I call my configure script with host not set:
$ ./configure
checking for a BSD-compatible install... /bin/ginstall -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking dependency style of gcc... gcc3
checking whether gcc and cc understand -c and -o together... yes
checking stdio.h usability... yes
checking stdio.h presence... no
configure: WARNING: stdio.h: accepted by the compiler, rejected by the preprocessor!
configure: WARNING: stdio.h: proceeding with the compiler's result
checking for stdio.h... yes
checking time.h usability... yes
checking time.h presence... no
configure: WARNING: time.h: accepted by the compiler, rejected by the preprocessor!
configure: WARNING: time.h: proceeding with the compiler's result
checking for time.h... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands

As you can see, the good thing is that the:
AC_CHECK_HEADER([avr/io.h], [], [AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [], [AC_MSG_ERROR([missing header: util/delay.h])])
calls are not anymore done.
However, the bad thing is that I got some warnings:
[...]
configure: WARNING: stdio.h: accepted by the compiler, rejected by the preprocessor!
configure: WARNING: stdio.h: proceeding with the compiler's result
[...]
configure: WARNING: time.h: accepted by the compiler, rejected by the preprocessor!
configure: WARNING: time.h: proceeding with the compiler's result
[...]

So, I guess my configure.ac file is wrong.

How to do the things correctly please to call the AC_CHECK_HEADER macro on a condition?

Thank you.
Best regards.
Nick Bowler
2016-04-12 15:05:51 UTC
Permalink
Hi,

On 2016-04-12, YuGiOhJCJ Mailing-List <yugiohjcj-***@laposte.net>
wrote:
[snip exposition]
Post by YuGiOhJCJ Mailing-List
AC_INIT([my-project], [20160412])
AM_INIT_AUTOMAKE
AM_PROG_CC_C_O
if test "x$host" == xavr; then
AC_CHECK_HEADER([avr/io.h], [], [AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [], [AC_MSG_ERROR([missing header: util/delay.h])])
else
AC_CHECK_HEADER([stdio.h], [],
[AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [],
[AC_MSG_ERROR([missing header: time.h])])
fi
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
The basic problem with the above is that AC_PROG_CPP is not
called properly in your configure.ac. Because (simplifying
a bit) AC_CHECK_HEADER requires a the preprocessor, it expands

AC_REQUIRE([AC_PROG_CPP]).

Loosely, this means that the first expansion of AC_CHECK_HEADER
will expand AC_PROG_CPP, if it was not already done. In your
original version, these expansions were unconditional and things
worked fine.

But in your second instance, the first expansion of AC_CHECK_HEADER
expands AC_PROG_CPP inside an "if". The result is that no preprocessor
is checked in the "else" case. You can see this in the configure output,
the following line is only printed in the avr case:

checking how to run the C preprocessor... avr-gcc -E

There are several basic solutions:

- First, you can just expand AC_PROG_CPP directly and unconditionally
before your if. This will ensure the macro is available in both cases.

- Second is to rewrite your condition using AS_IF, which automatically
"hoists" the dependency AC_PROG_CPP (and any other dependencies)
outside of the if condition. For example:

AS_IF([test x"$host" = x"avr"],
[AC_CHECK_HEADER([avr/io.h], [],
[AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [],
[AC_MSG_ERROR([missing header: util/delay.h])])],

[AC_CHECK_HEADER([stdio.h], [],
[AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [],
[AC_MSG_ERROR([missing header: time.h])])])

- Third, you can make the checks unconditional but the hard
failures conditional, e.g.:

AC_CHECK_HEADER([avr/io.h], [],
[if test x"$host" = x"avr"; then
AC_MSG_ERROR([missing header: avr/io.h])
fi])

Normally I would go with AS_IF.

Hope that helps,
Nick
Eric Blake
2016-04-12 15:24:21 UTC
Permalink
Post by Nick Bowler
But in your second instance, the first expansion of AC_CHECK_HEADER
expands AC_PROG_CPP inside an "if". The result is that no preprocessor
is checked in the "else" case. You can see this in the configure output,
checking how to run the C preprocessor... avr-gcc -E
- First, you can just expand AC_PROG_CPP directly and unconditionally
before your if. This will ensure the macro is available in both cases.
- Second is to rewrite your condition using AS_IF, which automatically
"hoists" the dependency AC_PROG_CPP (and any other dependencies)
AS_IF([test x"$host" = x"avr"],
[AC_CHECK_HEADER([avr/io.h], [],
[AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [],
[AC_MSG_ERROR([missing header: util/delay.h])])],
[AC_CHECK_HEADER([stdio.h], [],
[AC_MSG_ERROR([missing header: stdio.h])])
Also, checking for <stdio.h> is pointless these days. You can portably
assume a C89 compiler (and these days, often a C99 compiler), which
guarantees <stdio.h> is present.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Earnie
2016-04-18 14:26:18 UTC
Permalink
Post by Eric Blake
Also, checking for <stdio.h> is pointless these days. You can portably
assume a C89 compiler (and these days, often a C99 compiler), which
guarantees <stdio.h> is present.
But removing that check would thwart the purpose of autoconf being able
to provide legacy support, would it not? I suppose there comes a point
in time when legacy needs a maximum age but I think that requires some
acknowledgement from the users of autoconf.
--
Earnie
Paul Eggert
2016-04-18 14:43:30 UTC
Permalink
Post by Eric Blake
Also, checking for <stdio.h> is pointless these days. You can portably
assume a C89 compiler (and these days, often a C99 compiler), which
guarantees <stdio.h> is present.
Although it's safe to assume C89ish (or even C99ish) these days, there
is the possibility that it's a freestanding C implementation, where the
C standard does not require <stdio.h>. This might happen in a
bootloader, say, where no operating system is available.
YuGiOhJCJ Mailing-List
2016-04-13 00:22:29 UTC
Permalink
On Tue, 12 Apr 2016 11:05:51 -0400
Post by Nick Bowler
Hi,
[snip exposition]
Post by YuGiOhJCJ Mailing-List
AC_INIT([my-project], [20160412])
AM_INIT_AUTOMAKE
AM_PROG_CC_C_O
if test "x$host" == xavr; then
AC_CHECK_HEADER([avr/io.h], [], [AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [], [AC_MSG_ERROR([missing header: util/delay.h])])
else
AC_CHECK_HEADER([stdio.h], [],
[AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [],
[AC_MSG_ERROR([missing header: time.h])])
fi
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
The basic problem with the above is that AC_PROG_CPP is not
called properly in your configure.ac. Because (simplifying
a bit) AC_CHECK_HEADER requires a the preprocessor, it expands
AC_REQUIRE([AC_PROG_CPP]).
Loosely, this means that the first expansion of AC_CHECK_HEADER
will expand AC_PROG_CPP, if it was not already done. In your
original version, these expansions were unconditional and things
worked fine.
But in your second instance, the first expansion of AC_CHECK_HEADER
expands AC_PROG_CPP inside an "if". The result is that no preprocessor
is checked in the "else" case. You can see this in the configure output,
checking how to run the C preprocessor... avr-gcc -E
- First, you can just expand AC_PROG_CPP directly and unconditionally
before your if. This will ensure the macro is available in both cases.
- Second is to rewrite your condition using AS_IF, which automatically
"hoists" the dependency AC_PROG_CPP (and any other dependencies)
AS_IF([test x"$host" = x"avr"],
[AC_CHECK_HEADER([avr/io.h], [],
[AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [],
[AC_MSG_ERROR([missing header: util/delay.h])])],
[AC_CHECK_HEADER([stdio.h], [],
[AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [],
[AC_MSG_ERROR([missing header: time.h])])])
- Third, you can make the checks unconditional but the hard
AC_CHECK_HEADER([avr/io.h], [],
[if test x"$host" = x"avr"; then
AC_MSG_ERROR([missing header: avr/io.h])
fi])
Normally I would go with AS_IF.
Hope that helps,
Nick
It is a very useful answer with explanations.
I am using AS_IF now and it works perfectly.
Thank you.
Thomas Petazzoni
2016-04-19 13:40:00 UTC
Permalink
Hello,
Post by Nick Bowler
- First, you can just expand AC_PROG_CPP directly and unconditionally
before your if. This will ensure the macro is available in both cases.
- Second is to rewrite your condition using AS_IF, which automatically
"hoists" the dependency AC_PROG_CPP (and any other dependencies)
AS_IF([test x"$host" = x"avr"],
[AC_CHECK_HEADER([avr/io.h], [],
[AC_MSG_ERROR([missing header: avr/io.h])])
AC_CHECK_HEADER([util/delay.h], [],
[AC_MSG_ERROR([missing header: util/delay.h])])],
[AC_CHECK_HEADER([stdio.h], [],
[AC_MSG_ERROR([missing header: stdio.h])])
AC_CHECK_HEADER([time.h], [],
[AC_MSG_ERROR([missing header: time.h])])])
- Third, you can make the checks unconditional but the hard
AC_CHECK_HEADER([avr/io.h], [],
[if test x"$host" = x"avr"; then
AC_MSG_ERROR([missing header: avr/io.h])
fi])
I just wanted to thank you for this explanation. I was not affected by
the original issue, but your answer was very useful. Until now, I
thought AS_IF() was just a stupid wrapper around the shell's if clause,
but your answer makes it clear that it is a lot smarter than that.

Thanks!

Thomas
--
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
Julien ÉLIE
2016-04-19 20:40:49 UTC
Permalink
Hi all,
Post by Thomas Petazzoni
Post by Nick Bowler
- Second is to rewrite your condition using AS_IF, which automatically
"hoists" the dependency AC_PROG_CPP (and any other dependencies)
outside of the if condition.
I just wanted to thank you for this explanation. I was not affected by
the original issue, but your answer was very useful. Until now, I
thought AS_IF() was just a stupid wrapper around the shell's if clause,
but your answer makes it clear that it is a lot smarter than that.
So did I!

Incidentally, I am aware of AS_IF and AS_CASE constructions, as
described in
<https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Common-Shell-Constructs.html>.
Is it planned to add other macros like AS_FOR, AS_WHILE...?

One may consider doing something like:

for header in $LIST ; do AC_CHECK_HEADER([$header]) ; done

If I understand well, in case $LIST happens to be empty, AC_PROG_CPP
will never be run, and subsequent calls to AC_CHECK_HEADER in the
configure script will fail.
--
Julien ÉLIE

« Je sens que ma dernière hure est proche ! » (Astérix)
Loading...