From: Eric Blake Date: Tue, 20 Jan 2009 21:22:41 +0000 (-0700) Subject: Fix out-of-order expansion with expand-before-require. X-Git-Tag: v2.63b~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=46009205a943a5f5b712cc11b72e9b017141ffeb;p=thirdparty%2Fautoconf.git Fix out-of-order expansion with expand-before-require. * lib/m4sugar/m4sugar.m4 (m4_require): Redundantly expand a required macro when issuing expand-before-require warning. * doc/autoconf.texi (Prerequisite Macros): Adjust documentation. (Expanded Before Required): New node. * tests/m4sugar.at (m4@&t@_require: nested): Adjust test. * NEWS: Mention this fix. Suggested by Bruno Haible. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index f03804cce..4ac83f563 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2009-01-21 Eric Blake + Fix out-of-order expansion with expand-before-require. + * lib/m4sugar/m4sugar.m4 (m4_require): Redundantly expand a + required macro when issuing expand-before-require warning. + * doc/autoconf.texi (Prerequisite Macros): Adjust documentation. + (Expanded Before Required): New node. + * tests/m4sugar.at (m4@&t@_require: nested): Adjust test. + * NEWS: Mention this fix. + Suggested by Bruno Haible. + Warn if macro is provided before indirectly required. * lib/m4sugar/m4sugar.m4 (m4_provide): Track the set of all macros provided since last outermost defun. diff --git a/NEWS b/NEWS index 7eff140bb..5e43abcda 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,15 @@ GNU Autoconf NEWS - User visible changes. ** The manual is now shipped under the terms of the GNU FDL 1.3. +** AC_REQUIRE now detects the case of an outer macro which first expands + then later indirectly requires the same inner macro. Previously, + this case led to silent out-of-order expansion (bug present since + 2.50); it now issues a syntax warning, and duplicates the expansion + of the inner macro to guarantee dependencies have been met. See + the manual for advice on how to refactor macros in order to avoid + the bug in earlier autoconf versions and avoid increased script + size in the current version. + ** AC_LANG_ERLANG works once again (regression introduced in 2.61a). ** AC_HEADER_ASSERT is fixed so that './configure --enable-assert' no diff --git a/doc/autoconf.texi b/doc/autoconf.texi index 69d5085df..b7e63fc13 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -617,6 +617,7 @@ Frequent Autoconf Questions, with answers * Defining Directories:: Passing @code{datadir} to program * Autom4te Cache:: What is it? Can I remove it? * Present But Cannot Be Compiled:: Compiler and Preprocessor Disagree +* Expanded Before Required:: Expanded Before Required History of Autoconf @@ -13119,61 +13120,87 @@ SOME_CHECK @end example However, this implementation can lead to another class of problems. -Since dependencies are hoisted prior to the outermost @code{AC_DEFUN} -body, but only if they have not been previously seen, it is still -possible to encounter out-of-order expansion. Given this example: +Consider the case where an outer macro first expands, then indirectly +requires, an inner macro: @example -AC_DEFUN([A], [[in A]]) -AC_DEFUN([B], [AC_REQUIRE([A])[in B]]) -AC_DEFUN([C], [AC_REQUIRE([B])[in C]]) -AC_DEFUN([OUTER], [[in OUTER] +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] A C]) OUTER @end example @noindent -observe that the expansion of @code{B} occurred prior to the expansion -of @code{OUTER}, but because the requirement for @code{B} was not -encountered until after @code{A} had already been directly expanded, -there was no reason to hoist @code{A}. Or, put another way, the fact -that @code{B} was hoisted but not @code{A} means that @code{B} occurs -before its prerequisite: +Prior to Autoconf 2.64, the implementation of @code{AC_REQUIRE} +recognized that @code{TESTB} needed to be hoisted prior to the expansion +of @code{OUTER}, but because @code{TESTA} had already been directly +expanded, it failed to hoist @code{TESTA}. Therefore, the expansion of +@code{TESTB} occurs prior to its prerequisites, leading to the following +output: @example in B +bug in OUTER in A in C @end example +@noindent +Newer Autoconf is smart enough to recognize this situation, and hoists +@code{TESTA} even though it has already been expanded, but issues a +syntax warning in the process. This is because the hoisted expansion of +@code{TESTA} defeats the purpose of using @code{AC_REQUIRE} to avoid +redundant code, and causes its own set of problems if the hoisted macro +is not idempotent: + +@example +in A +in B +in OUTER +in A +duplicate +in C +@end example + The bug is not in Autoconf, but in the macro definitions. If you ever pass a particular macro name to @code{AC_REQUIRE}, then you are implying that the macro only needs to be expanded once. But to enforce this, all uses of that macro should be through @code{AC_REQUIRE}; directly expanding the macro defeats the point of using @code{AC_REQUIRE} to eliminate redundant expansion. In the example, this rule of thumb was -violated because @code{B} requires @code{A} while @code{OUTER} directly -expands it. One way of fixing the bug is to factor @code{A} into two -macros, the portion designed for direct and repeated use (here, named -@code{A}), and the portion designed for one-shot output and used only -inside @code{AC_REQUIRE} (here, named @code{A_PREREQ}). Then, by fixing -all clients to use the correct macro according to their needs: - -@example -AC_DEFUN([A], [AC_REQUIRE([A_PREREQ])[in A]]) -AC_DEFUN([A_PREREQ], [[in A_PREREQ]]) -AC_DEFUN([B], [AC_REQUIRE([A_PREREQ])[in B]]) -AC_DEFUN([C], [AC_REQUIRE([B])[in C]]) -AC_DEFUN([OUTER], [[in OUTER] -A -C]) +violated because @code{TESTB} requires @code{TESTA} while @code{OUTER} +directly expands it. One way of fixing the bug is to factor +@code{TESTA} into two macros, the portion designed for direct and +repeated use (here, named @code{TESTA}), and the portion designed for +one-shot output and used only inside @code{AC_REQUIRE} (here, named +@code{TESTA_PREREQ}). Then, by fixing all clients to use the correct +calling convention according to their needs: + +@example +AC_DEFUN([TESTA], [AC_REQUIRE([TESTA_PREREQ])[echo in A]]) +AC_DEFUN([TESTA_PREREQ], [[echo in A_PREREQ +if test -n "$SEEN_A" ; then echo duplicate ; fi +SEEN_A=:]]) +AC_DEFUN([TESTB], [AC_REQUIRE([TESTA_PREREQ])[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]) OUTER @end example @noindent -the resulting output will then obey all dependency rules: +the resulting output will then obey all dependency rules and avoid any +syntax warnings, whether the script is built with old or new Autoconf +versions: @example in A_PREREQ @@ -22415,6 +22442,7 @@ are addressed. * Defining Directories:: Passing @code{datadir} to program * Autom4te Cache:: What is it? Can I remove it? * Present But Cannot Be Compiled:: Compiler and Preprocessor Disagree +* Expanded Before Required:: Expanded Before Required @end menu @node Distributing @@ -22803,6 +22831,48 @@ checking for pi.h... yes See @ref{Particular Headers}, for a list of headers with their prerequisites. +@node Expanded Before Required +@section Expanded Before Required + +@cindex 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 diagnosis of a syntax warning: + +@example +$ @kbd{cat configure.ac} +@result{}AC_DEFUN([TESTA], [[echo in A +@result{}if test -n "$SEEN_A" ; then echo duplicate ; fi +@result{}SEEN_A=:]]) +@result{}AC_DEFUN([TESTB], [AC_REQUIRE([TESTA])[echo in B +@result{}if test -z "$SEEN_A" ; then echo bug ; fi]]) +@result{}AC_DEFUN([TESTC], [AC_REQUIRE([TESTB])[echo in C]]) +@result{}AC_DEFUN([OUTER], [[echo in OUTER] +@result{}TESTA +@result{}TESTC]) +@result{}AC_INIT +@result{}OUTER +@result{}AC_OUTPUT +$ @kbd{autoconf} +@result{}configure.ac:11: warning: AC_REQUIRE: +@result{} `TESTA' was expanded before it was required +@result{}configure.ac:4: TESTB is expanded from... +@result{}configure.ac:6: TESTC is expanded from... +@result{}configure.ac:7: OUTER is expanded from... +@result{}configure.ac:11: the top level +@end example + +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 fix is to change all +instance of direct calls to instead go through @code{AC_REQUIRE} +(@pxref{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. + @c ===================================================== History of Autoconf. @node History diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4 index 1457aefee..3a5ce49a1 100644 --- a/lib/m4sugar/m4sugar.m4 +++ b/lib/m4sugar/m4sugar.m4 @@ -1728,8 +1728,8 @@ m4_define([m4_undivert], # inside a context that will be hoisted in front of the outermost # defun'd macro. In other words, we must be careful not to warn on: # -# | m4_defun([TEST1], [1]) -# | m4_defun([TEST2], [TEST1 REQUIRE([TEST1])]) +# | m4_defun([TEST4], [4]) +# | m4_defun([TEST5], [TEST4 REQUIRE([TEST5])]) # # The implementation of the warning involves tracking the set of # macros which have been provided since the start of the outermost @@ -1739,9 +1739,12 @@ m4_define([m4_undivert], # removed from the set; and when a macro is indirectly required (that # is, when m4_require detects a nested call), the set is checked. If # a macro is in the set, then it has been provided before it was -# required, and a warning is issued because the output will be out of -# order and the user must fix her macros to reflect the true -# dependencies. +# required, and we satisfy dependencies by expanding the macro as if +# it had never been provided; in the example given above, this means +# we now output `1 2 3 1'. Meanwhile, a warning is issued to inform +# the user that her macros trigger the bug in older autoconf versions, +# and that her outupt file now contains redundant contents (and +# possibly new problems, if the repeated macro was not idempotent). # # # 2. Keeping track of the expansion stack @@ -1984,9 +1987,10 @@ m4_define([m4_require], [m4_fatal([$0($1): cannot be used outside of an ]dnl m4_if([$0], [m4_require], [[m4_defun]], [[AC_DEFUN]])['d macro])])]dnl [m4_provide_if([$1], [m4_ifdef([_m4_require], - [m4_set_contains([_m4_provide], [$1], - [m4_warn([syntax], [$0: `$1' was expanded before it was required])])])], - [_m4_require_call([$1], [$2], _m4_divert_dump)])]) + [m4_set_contains([_m4_provide], [$1], [m4_warn([syntax], + [$0: `$1' was expanded before it was required])_m4_require_call], + [m4_ignore])], [m4_ignore])], + [_m4_require_call])([$1], [$2], _m4_divert_dump)]) # _m4_require_call(NAME-TO-CHECK, [BODY-TO-EXPAND = NAME-TO-CHECK], diff --git a/tests/m4sugar.at b/tests/m4sugar.at index a6739cf10..613a3c9b4 100644 --- a/tests/m4sugar.at +++ b/tests/m4sugar.at @@ -545,7 +545,8 @@ c post])dnl outer ]], -[[b +[[a +b pre a c