Older versions of Autoconf silently built files with incorrect ordering between dependent macros if an outer macro first expanded, then later indirectly required, an inner macro. Starting with Autoconf 2.64, this situation no longer generates out-of-order code, but results in duplicate output and a syntax warning:
$ cat configure.ac ⇒AC_DEFUN([TESTA], [[echo in A ⇒if test -n "$SEEN_A" ; then echo duplicate ; fi ⇒SEEN_A=:]]) ⇒AC_DEFUN([TESTB], [AC_REQUIRE([TESTA])[echo in B ⇒if test -z "$SEEN_A" ; then echo bug ; fi]]) ⇒AC_DEFUN([TESTC], [AC_REQUIRE([TESTB])[echo in C]]) ⇒AC_DEFUN([OUTER], [[echo in OUTER] ⇒TESTA ⇒TESTC]) ⇒AC_INIT ⇒OUTER ⇒AC_OUTPUT $ autoconf ⇒configure.ac:11: warning: AC_REQUIRE: ⇒ `TESTA' was expanded before it was required ⇒configure.ac:4: TESTB is expanded from... ⇒configure.ac:6: TESTC is expanded from... ⇒configure.ac:7: OUTER is expanded from... ⇒configure.ac:11: the top level
To avoid this warning, decide what purpose the macro in question serves.
If it only needs to be expanded once (for example, if it provides
initialization text used by later macros), then the simplest fix is to
change the macro to be declared with AC_DEFUN_ONCE
(see One-Shot Macros), although this only works in Autoconf 2.64 and
newer. A more portable fix is to change all
instances of direct calls to instead go through AC_REQUIRE
(see Prerequisite Macros). If, instead, the macro is parameterized
by arguments or by the current definition of other macros in the m4
environment, then the macro should always be directly expanded instead
of required.
For another case study, consider this example trimmed down from an actual package. Originally, the package contained shell code and multiple macro invocations at the top level of configure.ac:
AC_DEFUN([FOO], [AC_COMPILE_IFELSE([...])]) foobar= AC_PROG_CC FOO
but that was getting complex, so the author wanted to offload some of the text into a new macro in another file included via aclocal.m4. The naïve approach merely wraps the text in a new macro:
AC_DEFUN([FOO], [AC_COMPILE_IFELSE([...])]) AC_DEFUN([BAR], [ foobar= AC_PROG_CC FOO ]) BAR
With older versions of Autoconf, the setting of ‘foobar=’ occurs
before the single compiler check, as the author intended. But with
Autoconf 2.64, this issues the “expanded before it was required”
warning for AC_PROG_CC
, and outputs two copies of the compiler
check, one before ‘foobar=’, and one after. To understand why this
is happening, remember that the use of AC_COMPILE_IFELSE
includes
a call to AC_REQUIRE([AC_PROG_CC])
under the hood. According to
the documented semantics of AC_REQUIRE
, this means that
AC_PROG_CC
must occur before the body of the outermost
AC_DEFUN
, which in this case is BAR
, thus preceeding the
use of ‘foobar=’. The older versions of Autoconf were broken with
regards to the rules of AC_REQUIRE
, which explains why the code
changed from one over to two copies of AC_PROG_CC
when upgrading
autoconf. In other words, the author was unknowingly relying on a bug
exploit to get the desired results, and that exploit broke once the bug
was fixed.
So, what recourse does the author have, to restore their intended
semantics of setting ‘foobar=’ prior to a single compiler check,
regardless of whether Autoconf 2.63 or 2.64 is used? One idea is to
remember that only AC_DEFUN
is impacted by AC_REQUIRE
;
there is always the possibility of using the lower-level
m4_define
:
AC_DEFUN([FOO], [AC_COMPILE_IFELSE([...])]) m4_define([BAR], [ foobar= AC_PROG_CC FOO ]) BAR
This works great if everything is in the same file. However, it does
not help in the case where the author wants to have aclocal
find the definition of BAR
from its own file, since
aclocal requires the use of AC_DEFUN
. In this case, a
better fix is to recognize that if BAR
also uses
AC_REQUIRE
, then there will no longer be direct expansion prior
to a subsequent require. Then, by creating yet another helper macro,
the author can once again guarantee a single invocation of
AC_PROG_CC
, which will still occur after foobar=
. The
author can also use AC_BEFORE
to make sure no other macro
appearing before BAR
has triggered an unwanted expansion of
AC_PROG_CC
.
AC_DEFUN([FOO], [AC_COMPILE_IFELSE([...])]) AC_DEFUN([BEFORE_CC], [ foobar= ]) AC_DEFUN([BAR], [ AC_BEFORE([$0], [AC_PROG_CC])dnl AC_REQUIRE([BEFORE_CC])dnl AC_REQUIRE([AC_PROG_CC])dnl FOO ]) BAR