From: Eric Blake Date: Mon, 17 Nov 2008 22:49:30 +0000 (-0700) Subject: Add AS_SET_STATUS, make AS_EXIT more efficient. X-Git-Tag: v2.63b~96 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=740062eb427759b1c8203004dedeab07a60cab52;p=thirdparty%2Fautoconf.git Add AS_SET_STATUS, make AS_EXIT more efficient. * lib/m4sugar/m4sh.m4 (_AS_EXIT_PREPARE, AS_SET_STATUS): New macros. (AS_EXIT): Rewrite to avoid forks. (_AS_SHELL_SANITIZE): Avoid AS_EXIT prior to shell functions. (AS_PREPARE, _AS_PREPARE): Add new preparation. * doc/autoconf.texi (Common Shell Constructs) : Document. * NEWS: Mention new macro. * tests/m4sh.at (AS@&t@_EXIT): New test. (BASENAME_TEST): Sort. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index 543ce5d96..1e56b6e93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2008-11-18 Eric Blake + Add AS_SET_STATUS, make AS_EXIT more efficient. + * lib/m4sugar/m4sh.m4 (_AS_EXIT_PREPARE, AS_SET_STATUS): New + macros. + (AS_EXIT): Rewrite to avoid forks. + (_AS_SHELL_SANITIZE): Avoid AS_EXIT prior to shell functions. + (AS_PREPARE, _AS_PREPARE): Add new preparation. + * doc/autoconf.texi (Common Shell Constructs) : + Document. + * NEWS: Mention new macro. + * tests/m4sh.at (AS@&t@_EXIT): New test. + (BASENAME_TEST): Sort. + Document Tru64 bug with 'set -e'. * doc/autoconf.texi (Limitations of Builtins) : Mention a bug in mixing 'set -e' with 'trap .. 0'. diff --git a/NEWS b/NEWS index f5f3d6e3a..b67d82ce6 100644 --- a/NEWS +++ b/NEWS @@ -30,8 +30,8 @@ GNU Autoconf NEWS - User visible changes. m4_copy m4_dumpdefs m4_rename ** The following documented m4sh macros are new: - AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_APPEND AS_VAR_ARITH - AS_VAR_COPY + AS_LINENO_PREPARE AS_ME_PREPARE AS_SET_STATUS AS_VAR_APPEND + AS_VAR_ARITH AS_VAR_COPY ** The following m4sh macros are documented now: AS_ECHO AS_ECHO_N AS_EXIT AS_LITERAL_IF AS_UNSET AS_VAR_IF diff --git a/doc/autoconf.texi b/doc/autoconf.texi index 37becc5f1..71d72f4e7 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -12052,6 +12052,14 @@ script. Also see the @code{AC_PROG_MKDIR_P} macro (@pxref{Particular Programs}). @end defmac +@defmac AS_SET_STATUS (@var{status}) +@asindex{SET_STATUS} +Emit shell code to set the value of @samp{$?} to @var{status} without +forking. However, this is not guaranteed to abort a shell running with +@code{set -e} (@pxref{Limitations of Builtins, , Limitations of Shell +Builtins}). +@end defmac + @defmac AS_TR_CPP (@var{expression}) @asindex{TR_CPP} Transform @var{expression} into a valid right-hand side for a C @code{#define}. diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4 index 4da8f3781..f056ee315 100644 --- a/lib/m4sugar/m4sh.m4 +++ b/lib/m4sugar/m4sh.m4 @@ -299,7 +299,8 @@ m4_defun([_AS_PREPARE], [m4_pushdef([AS_REQUIRE])]dnl [m4_pushdef([AS_REQUIRE_SHELL_FN], _m4_defn([_AS_REQUIRE_SHELL_FN]) )]dnl -[_AS_UNSET_PREPARE +[_AS_EXIT_PREPARE +_AS_UNSET_PREPARE _AS_VAR_APPEND_PREPARE _AS_VAR_ARITH_PREPARE @@ -331,6 +332,7 @@ AS_REQUIRE([_AS_ME_PREPARE]) AS_REQUIRE([_AS_CR_PREPARE]) AS_REQUIRE([_AS_LINENO_PREPARE]) AS_REQUIRE([_AS_ECHO_N_PREPARE]) +AS_REQUIRE([_AS_EXIT_PREPARE]) AS_REQUIRE([_AS_LN_S_PREPARE]) AS_REQUIRE([_AS_MKDIR_P_PREPARE]) AS_REQUIRE([_AS_TEST_PREPARE]) @@ -418,8 +420,11 @@ test x$exitcode = x0[]])# _AS_SHELL_FN_WORK # _AS_SHELL_SANITIZE # ------------------ -# This is the prolog that is emitted by AS_INIT and AS_INIT_GENERATED. +# This is the prolog that is emitted by AS_INIT and AS_INIT_GENERATED; +# it is executed prior to shell function definitions, hence the +# temporary redefinition of AS_EXIT. m4_defun([_AS_SHELL_SANITIZE], +[m4_pushdef([AS_EXIT], [exit m4_default([$1], 1)])]dnl [m4_text_box([M4sh Initialization.]) AS_BOURNE_COMPATIBLE @@ -470,7 +475,7 @@ export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -])# _AS_SHELL_SANITIZE +_m4_popdef([AS_EXIT])])# _AS_SHELL_SANITIZE # AS_SHELL_SANITIZE @@ -519,18 +524,34 @@ m4_defun([AS_CASE], esac])# AS_CASE -# AS_EXIT([EXIT-CODE = 1]) -# ------------------------ -# Exit and set exit code to EXIT-CODE in the way that it's seen -# within "trap 0". +# _AS_EXIT_PREPARE +# ---------------- +# Ensure AS_EXIT and AS_SET_STATUS will work. # # We cannot simply use "exit N" because some shells (zsh and Solaris sh) # will not set $? to N while running the code set by "trap 0" -# So we set $? by executing "exit N" in the subshell and then exit. +# Some shells fork even for (exit N), so we use a helper function +# to set $? prior to the exit. # Other shells don't use `$?' as default for `exit', hence just repeating # the exit value can only help improving portability. -m4_define([AS_EXIT], -[{ (exit m4_default([$1], 1)); exit m4_default([$1], 1); }]) +m4_defun([_AS_EXIT_PREPARE], +[AS_REQUIRE_SHELL_FN([as_func_set_status], + [AS_FUNCTION_DESCRIBE([as_func_set_status], [STATUS], + [Set $? to STATUS, without forking.])], [ return $[]1])]dnl +[AS_REQUIRE_SHELL_FN([as_func_exit], + [AS_FUNCTION_DESCRIBE([as_func_exit], [STATUS], + [Exit the shell with STATUS, even in a "trap 0" or "set -e" context.])], +[ set +e + as_func_set_status $[]1 + exit $[]1])])#_AS_EXIT_PREPARE + + +# AS_EXIT([EXIT-CODE = 1]) +# ------------------------ +# Exit, with status set to EXIT-CODE in the way that it's seen +# within "trap 0", and without interference from "set -e". +m4_defun([AS_EXIT], +[AS_REQUIRE([_AS_EXIT_PREPARE])[]as_func_exit m4_default([$1], 1)]) # AS_FOR(MACRO, SHELL-VAR, [LIST = "$@"], [BODY = :]) @@ -589,6 +610,13 @@ m4_map_args_pair([_$0], [_$0_ELSE], m4_shift2($@))]dnl [fi[]])# AS_IF +# AS_SET_STATUS(STATUS) +# --------------------- +# Set the shell status ($?) to STATUS, without forking. +m4_defun([AS_SET_STATUS], +[AS_REQUIRE([_AS_EXIT_PREPARE])[]as_func_set_status $1]) + + # _AS_UNSET_PREPARE # ----------------- # Define $as_unset to execute AS_UNSET, for backwards compatibility diff --git a/tests/m4sh.at b/tests/m4sh.at index 96e0452db..85ad5d8b1 100644 --- a/tests/m4sh.at +++ b/tests/m4sh.at @@ -126,6 +126,63 @@ AT_CHECK([./script]) AT_CLEANUP +## ------------- ## +## AS_BASENAME. ## +## ------------- ## + +# Strip path from file. +AT_SETUP([AS@&t@_BASENAME]) +AT_KEYWORDS([m4sh]) + +AT_DATA_M4SH([script.as], +[[AS_INIT + +m4_define([BASENAME_TEST], +[base=`AS_BASENAME([$1])` +test "$base" = "$2" || + echo "basename($1) = $base instead of $2" >&2 + +base=`_AS_BASENAME_SED([$1])` +test "$base" = "$2" || + echo "basename_sed($1) = $base instead of $2" >&2]) + +BASENAME_TEST([//1], [1]) +BASENAME_TEST([/1], [1]) +BASENAME_TEST([./1], [1]) +BASENAME_TEST([../../2], [2]) +BASENAME_TEST([//1/], [1]) +BASENAME_TEST([/1/], [1]) +BASENAME_TEST([./1/], [1]) +BASENAME_TEST([../../2], [2]) +BASENAME_TEST([//1/3], [3]) +BASENAME_TEST([/1/3], [3]) +BASENAME_TEST([./1/3], [3]) +BASENAME_TEST([../../2/3], [3]) +BASENAME_TEST([//1/3///], [3]) +BASENAME_TEST([/1/3///], [3]) +BASENAME_TEST([./1/3///], [3]) +BASENAME_TEST([../../2/3///], [3]) +BASENAME_TEST([//1//3/], [3]) +BASENAME_TEST([/1//3/], [3]) +BASENAME_TEST([./1//3/], [3]) +BASENAME_TEST([a.c], [a.c]) +BASENAME_TEST([a.c/], [a.c]) +BASENAME_TEST([/a.c/], [a.c]) +BASENAME_TEST([/1/a.c], [a.c]) +BASENAME_TEST([/1/a.c/], [a.c]) +BASENAME_TEST([/1/../a.c], [a.c]) +BASENAME_TEST([/1/../a.c/], [a.c]) +BASENAME_TEST([./1/a.c], [a.c]) +BASENAME_TEST([./1/a.c/], [a.c]) +AS_EXIT(0) +]]) + +AT_CHECK_M4SH +AT_CHECK([./script]) + +AT_CLEANUP + + ## ------------ ## ## AS_DIRNAME. ## ## ------------ ## @@ -236,59 +293,43 @@ AT_CLEANUP -## ------------- ## -## AS_BASENAME. ## -## ------------- ## +## --------- ## +## AS_EXIT. ## +## --------- ## -# Strip path from file. -AT_SETUP([AS@&t@_BASENAME]) -AT_KEYWORDS([m4sh]) +# Exit scripts with given status. +AT_SETUP([AS@&t@_EXIT]) +AT_KEYWORDS([m4sh AS@&t@_SET_STATUS]) AT_DATA_M4SH([script.as], [[AS_INIT - -m4_define([BASENAME_TEST], -[base=`AS_BASENAME([$1])` -test "$base" = "$2" || - echo "basename($1) = $base instead of $2" >&2 - -base=`_AS_BASENAME_SED([$1])` -test "$base" = "$2" || - echo "basename_sed($1) = $base instead of $2" >&2]) - -BASENAME_TEST([//1], [1]) -BASENAME_TEST([/1], [1]) -BASENAME_TEST([./1], [1]) -BASENAME_TEST([../../2], [2]) -BASENAME_TEST([//1/], [1]) -BASENAME_TEST([/1/], [1]) -BASENAME_TEST([./1/], [1]) -BASENAME_TEST([../../2], [2]) -BASENAME_TEST([//1/3], [3]) -BASENAME_TEST([/1/3], [3]) -BASENAME_TEST([./1/3], [3]) -BASENAME_TEST([../../2/3], [3]) -BASENAME_TEST([//1/3///], [3]) -BASENAME_TEST([/1/3///], [3]) -BASENAME_TEST([./1/3///], [3]) -BASENAME_TEST([../../2/3///], [3]) -BASENAME_TEST([//1//3/], [3]) -BASENAME_TEST([/1//3/], [3]) -BASENAME_TEST([./1//3/], [3]) -BASENAME_TEST([a.c], [a.c]) -BASENAME_TEST([a.c/], [a.c]) -BASENAME_TEST([/a.c/], [a.c]) -BASENAME_TEST([/1/a.c], [a.c]) -BASENAME_TEST([/1/a.c/], [a.c]) -BASENAME_TEST([/1/../a.c], [a.c]) -BASENAME_TEST([/1/../a.c/], [a.c]) -BASENAME_TEST([./1/a.c], [a.c]) -BASENAME_TEST([./1/a.c/], [a.c]) -AS_EXIT(0) +test x${1} = xa && AS_EXIT +test x${1} = xb && AS_EXIT([${2}]) +test x${1} = xc && trap 's=$?; echo $s; AS_EXIT([$s])' 0 +test x${2} = xd && set -e +AS_SET_STATUS([3]) +dnl Solaris /bin/sh 'set -e' doesn't react to failed function calls +test x${2} = xd \ + && { echo 'skipping rest of test: set -e support is lousy'; exit 77; } +AS_SET_STATUS([4]) ]]) AT_CHECK_M4SH -AT_CHECK([./script]) +AT_CHECK([./script], [4]) +AT_CHECK([./script a], [1]) +AT_CHECK([./script b], [0]) +AT_CHECK([./script b 2], [2]) +AT_CHECK([./script c], [4], [[4 +]]) +dnl If we got to this point without a FAIL, then AS_EXIT at least works. +dnl The rest of this test relies on semi-decent 'set -e' support, even +dnl though m4sh in general should not try to rely on it because of +dnl portability nightmares on what constructs are considered errors across +dnl various shells; therefore, an overall SKIP result is desirable on +dnl broken shells like Solaris /bin/sh. +AT_CHECK([./script '' d], [3]) +AT_CHECK([./script c d], [3], [[3 +]]) AT_CLEANUP