20.8 Expanded Before Required

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 preceding 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