mirror of
git://git.sv.gnu.org/autoconf
synced 2024-11-21 01:01:48 +08:00
AS_IF: Handle else clause being empty after macro expansion (#110369)
AS_IF can emit a syntactically invalid shell if-then-else, if CONDITION then : # ... else fi when its IF-FALSE argument consists of macros that don’t produce any shell code. This was a documented limitation in AS_IF, but it’s a bad limitation to have, because macros that *used* to expand to shell commands might start expanding to nothing in future releases. For instance, this broke the libzmq configure script, which did AC_PROG_CC AX_CHECK_COMPILE_FLAG([-std=gnu11], [CFLAGS+=" -std=gnu11"], [AC_PROG_CC_C99]) Perfectly valid in 2.69, but in 2.70 AC_PROG_CC_C99 doesn’t produce any shell code and the script crashes. We had that limitation for good reason: we can’t just put ‘:’ at the beginning of the else-clause, like we do for the then-clause, because that would clobber $? and the IF-FALSE commands might want to inspect it. (This doesn’t matter for the then-clause, because $? is always zero at the beginning of a then-clause anyway.) The simplest and least inefficient shell construct I can find that works in this context is a shell function that does ‘return $?’. Due to awkward M4sh initialization ordering constraints (AS_IF gets used before we can safely use shell functions) an indirection through a shell variable is necessary. The structure of a m4sh script is now #! /bin/sh ## M4sh Initialization as_nop=: ... ## M4sh Shell Functions as_fn_nop () { return $?; } as_nop=as_fn_nop ... and AS_IF emits if CONDITION then : # ... else $as_nop # ... fi The uses of AS_IF that appear before the beginning of the M4sh Shell Functions section are all under our control and they don’t need to look at $?. If anyone has a better idea for how to make this work I will be glad to hear it. Fixes bug #110369. * lib/m4sugar/m4sh.m4 (_AS_IF_ELSE): When $1 is nonempty, invoke _AS_EMPTY_ELSE_PREPARE. Emit $as_nop at beginning of else clause. (_AS_BOURNE_COMPATIBLE): Initialize as_nop to ‘:’. (_AS_EMPTY_ELSE_PREPARE): New macro which emits a definition of as_fn_nop and resets as_nop to as_fn_nop. (AS_PREPARE, _AS_PREPARE): Invoke _AS_EMPTY_ELSE_PREPARE. (_AS_UNSET_PREPARE): Tweak white space. * tests/m4sh.at (AS_IF and AS_CASE): Test AS_IF’s IF-FALSE argument being empty after macro expansion. * doc/autoconf.texi (AS_IF): Remove warning about use with ‘run-if-false’ argument empty after macro expansion.
This commit is contained in:
parent
996f608165
commit
fd633e92cb
6
NEWS
6
NEWS
@ -387,6 +387,12 @@ GNU Autoconf NEWS - User visible changes.
|
||||
This means configure scripts will no longer check repeatedly for the
|
||||
C compiler under some combinations of macro use.
|
||||
|
||||
*** AS_IF’s if-false argument may be empty after macro expansion.
|
||||
|
||||
This long-standing limitation broke configure scripts that used
|
||||
macros in this position that emitted shell code in 2.69 but no
|
||||
longer do, so we have lifted it.
|
||||
|
||||
*** AC_HEADER_MAJOR detects the location of the major, minor, and
|
||||
makedev macros correctly under glibc 2.25 and later.
|
||||
|
||||
|
@ -13972,13 +13972,6 @@ AS_IF([test "x$foo" = xyes], [HANDLE_FOO([yes])],
|
||||
ensures any required macros of @code{HANDLE_FOO}
|
||||
are expanded before the first test.
|
||||
|
||||
The @var{run-if-false} argument should either consist entirely of
|
||||
blanks, or expand to a nonempty shell command. For example,
|
||||
@code{AS_IF([:], [:], [[]])} is invalid because its @var{run-if-false}
|
||||
argument contains the nonblank characters @code{[]} which expand to
|
||||
nothing. This restriction on @var{run-if-false} also applies to other
|
||||
macros with ``if-false'' arguments denoting shell commands.
|
||||
|
||||
This macro should be used instead of plain @samp{if} in code
|
||||
outside of an @code{AC_DEFUN} macro, when the contents of the @samp{if}
|
||||
use @code{AC_REQUIRE} directly or indirectly (@pxref{Prerequisite Macros}).
|
||||
|
@ -98,9 +98,10 @@ _$0
|
||||
# _AS_BOURNE_COMPATIBLE
|
||||
# ---------------------
|
||||
# This is the part of AS_BOURNE_COMPATIBLE which has to be repeated inside
|
||||
# each instance.
|
||||
# each instance. See _AS_EMPTY_ELSE_PREPARE for explanation of as_nop.
|
||||
m4_define([_AS_BOURNE_COMPATIBLE],
|
||||
[AS_IF([test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1],
|
||||
[as_nop=:
|
||||
AS_IF([test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1],
|
||||
[emulate sh
|
||||
NULLCMD=:
|
||||
[#] Pre-4.2 versions of Zsh do word splitting on ${1+"$[@]"}, which
|
||||
@ -351,7 +352,8 @@ m4_defun([_AS_PREPARE],
|
||||
[m4_pushdef([AS_MESSAGE_LOG_FD], [-1])]dnl
|
||||
[_AS_ERROR_PREPARE
|
||||
_m4_popdef([AS_MESSAGE_LOG_FD])]dnl
|
||||
[_AS_EXIT_PREPARE
|
||||
[_AS_EMPTY_ELSE_PREPARE
|
||||
_AS_EXIT_PREPARE
|
||||
_AS_UNSET_PREPARE
|
||||
_AS_VAR_APPEND_PREPARE
|
||||
_AS_VAR_ARITH_PREPARE
|
||||
@ -387,6 +389,7 @@ AS_REQUIRE([_AS_CR_PREPARE])
|
||||
AS_REQUIRE([_AS_LINENO_PREPARE])
|
||||
AS_REQUIRE([_AS_ECHO_N_PREPARE])
|
||||
AS_REQUIRE([_AS_EXIT_PREPARE])
|
||||
AS_REQUIRE([_AS_EMPTY_ELSE_PREPARE])
|
||||
AS_REQUIRE([_AS_LN_S_PREPARE])
|
||||
AS_REQUIRE([_AS_MKDIR_P_PREPARE])
|
||||
AS_REQUIRE([_AS_TEST_PREPARE])
|
||||
@ -669,14 +672,27 @@ done[]_m4_popdef([$1])])
|
||||
# | fi
|
||||
# with simplifications when IF-TRUE1 and/or IF-FALSE are empty.
|
||||
#
|
||||
# Note: IF-TRUEn and IF_FALSE may be nonempty but, after further macro
|
||||
# expansion, leave no actual shell code. We can't detect this, so we
|
||||
# include a no-op statement in each clause to prevent it becoming a shell
|
||||
# syntax error. For the IF-TRUEn this can simply be `:' at the beginning of
|
||||
# the clause. IF-FALSE is harder because it must preserve the value of $?
|
||||
# from the conditional expression. The most practical way to do this is
|
||||
# with a shell function whose body is `return $?' but AS_IF is used before
|
||||
# it's safe to use shell functions. To deal with *that*, there is a shell
|
||||
# variable $as_fn_nop that expands to `:' before the nop shell function is
|
||||
# defined, and invokes the nop shell function afterward. Early uses of
|
||||
# AS_IF (which are all under our control) must not use the value of $? from
|
||||
# the conditional expression in an else clause.
|
||||
m4_define([_AS_IF],
|
||||
[elif $1
|
||||
then :
|
||||
$2
|
||||
])
|
||||
m4_define([_AS_IF_ELSE],
|
||||
m4_defun([_AS_IF_ELSE],
|
||||
[m4_ifnblank([$1],
|
||||
[else
|
||||
[m4_append_uniq([_AS_CLEANUP], [AS_REQUIRE([_AS_EMPTY_ELSE_PREPARE])])]dnl
|
||||
[else $as_nop
|
||||
$1
|
||||
])])
|
||||
|
||||
@ -687,6 +703,16 @@ then :
|
||||
m4_map_args_pair([_$0], [_$0_ELSE], m4_shift2($@))]dnl
|
||||
[fi[]])# AS_IF
|
||||
|
||||
m4_defun([_AS_EMPTY_ELSE_PREPARE],
|
||||
[m4_divert_text([M4SH-INIT-FN],
|
||||
[AS_FUNCTION_DESCRIBE([as_fn_nop], [],
|
||||
[Do nothing but, unlike ":", preserve the value of $][?.])
|
||||
as_fn_nop ()
|
||||
{
|
||||
return $[]?
|
||||
}
|
||||
as_nop=as_fn_nop])])
|
||||
|
||||
|
||||
# AS_SET_STATUS(STATUS)
|
||||
# ---------------------
|
||||
@ -705,7 +731,8 @@ as_fn_unset ()
|
||||
{
|
||||
AS_UNSET([$[1]])
|
||||
}
|
||||
as_unset=as_fn_unset])
|
||||
as_unset=as_fn_unset
|
||||
])
|
||||
|
||||
|
||||
# AS_UNSET(VAR)
|
||||
|
@ -1320,13 +1320,11 @@ dnl Handle blank arguments.
|
||||
AS_IF([false], [:], [ ]) && AS_CASE([foo], [foo], []
|
||||
) && echo seventeen
|
||||
m4_define([empty])AS_IF([:], [empty]
|
||||
) && AS_CASE([foo], [foo], [empty]) && echo eighteen
|
||||
) && AS_IF([false], [], [empty]
|
||||
) || AS_CASE([foo], [foo], [empty]) && echo eighteen
|
||||
dnl Allow for users that don't know to avoid trailing whitespace
|
||||
AS_IF([:
|
||||
], [echo nineteen])
|
||||
dnl We can't handle AS_IF([false], [:], [empty]) unless m4_expand is
|
||||
dnl taught how to handle m4_require. The user is responsible for
|
||||
dnl avoiding the syntax error in that case.
|
||||
|
||||
# check that require works correctly
|
||||
m4_for([n], 1, 9, [],
|
||||
|
Loading…
Reference in New Issue
Block a user