[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: AS_MESSAGE_FD
From: |
Eric Blake |
Subject: |
Re: AS_MESSAGE_FD |
Date: |
Sat, 22 Nov 2008 00:06:59 +0000 (UTC) |
User-agent: |
Loom/3.14 (http://gmane.org/) |
Eric Blake <ebb9 <at> byu.net> writes:
> > +AT_SETUP([AS@&t <at> _INIT_GENERATED])
> > +
> > +AT_DATA_M4SH([script.as], [[dnl
> > +m4_define([AS_MESSAGE_FD], [1])
>
> By the way, this test points out another m4sh flaw that needs fixing - we
> should consider providing default values for AS_MESSAGE_FD (1) and
> AS_MESSAGE_LOG_FD (empty), which can be changed by clients, so that
AS_MESSAGE
> works if the client doesn't touch these macros. The manual documents that
they
> exist, but is silent on whether the users may/must redefine them (and
> AS_INIT_GENERATED currently doesn't work if the user does not redefine
them).
What do you think of this patch?
From: Eric Blake <address@hidden>
Date: Fri, 21 Nov 2008 15:50:37 -0700
Subject: [PATCH] Clean up AS_MESSAGE_LOG_FD usage.
* lib/m4sugar/m4sh.m4 (AS_MESSAGE_FD, AS_MESSAGE_LOG_FD)
(AS_ORIGINAL_STDIN_FD): Provide default M4sh values.
(_AS_ECHO_LOG, AS_MESSAGE, _AS_ERROR_PREPARE, AS_ERROR): Simplify
usage.
(AS_INIT_GENERATED): Don't shuffle an unchanged AS_MESSAGE_FD.
* tests/m4sh.at (AS@&address@hidden): Update test.
(AS@&address@hidden): New test.
* doc/autoconf.texi (Initialization Macros) <AS_INIT_GENERATED>:
Give more details about fd manipulation.
(File Descriptor Macros): Describe M4sh defaults for the fds.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 14 ++++++++
doc/autoconf.texi | 35 +++++++++++++++------
lib/m4sugar/m4sh.m4 | 46 +++++++++++++++++++++-------
tests/m4sh.at | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 157 insertions(+), 22 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index ec79176..d72ad1f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2008-11-21 Eric Blake <address@hidden>
+ Clean up AS_MESSAGE_LOG_FD usage.
+ * lib/m4sugar/m4sh.m4 (AS_MESSAGE_FD, AS_MESSAGE_LOG_FD)
+ (AS_ORIGINAL_STDIN_FD): Provide default M4sh values.
+ (_AS_ECHO_LOG, AS_MESSAGE, _AS_ERROR_PREPARE, AS_ERROR): Simplify
+ usage.
+ (AS_INIT_GENERATED): Don't shuffle an unchanged AS_MESSAGE_FD.
+ * tests/m4sh.at (AS@&address@hidden): Update test.
+ (AS@&address@hidden): New test.
+ * doc/autoconf.texi (Initialization Macros) <AS_INIT_GENERATED>:
+ Give more details about fd manipulation.
+ (File Descriptor Macros): Describe M4sh defaults for the fds.
+
+2008-11-21 Eric Blake <address@hidden>
+
Use shell function for AS_ERROR.
* lib/m4sugar/m4sh.m4 (_AS_ERROR_PREPARE): New macro, defining a
new shell function.
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index e8cab41..957b8be 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -12500,15 +12500,21 @@ Initialization Macros
(thus, the emitted code is equivalent in effect, but more efficient,
than the code output by @code{AS_INIT}, @code{AS_BOURNE_COMPATIBLE}, and
@code{AS_SHELL_SANITIZE}). If present, @var{comment} is output near the
-beginning of the child, prior to the shell initialization code. The
+beginning of the child, prior to the shell initialization code, and is
+subject to parameter expansion, command substitution, and backslash
+quote removal. The
parent script should check the exit status after this macro, in case
@var{file} could not be properly created (for example, if the disk was
full). If successfully created, the parent script can then proceed to
append additional M4sh constructs into the child script.
-Note that the child script starts life without a log file open, so you
+Note that the child script starts life without a log file open, so if
+the parent script uses logging (@pxref{AS_MESSAGE_LOG_FD}), you
must temporarily disable any attempts to use the log file until after
-emitting code to open a log within the child. Currently, the suggested
+emitting code to open a log within the child. On the other hand, if the
+parent script has @code{AS_MESSAGE_FD} redirected somewhere besides
address@hidden, then the child script already has code that copies stdout to
+that descriptor. Currently, the suggested
idiom for writing a M4sh shell script from within another script is:
@example
@@ -12583,27 +12589,36 @@ File Descriptor Macros
@defmac AS_MESSAGE_FD
@asindex{MESSAGE_FD}
The file descriptor for @samp{checking for...} messages and results.
-Normally this directs messages to the standard output, however when
address@hidden is run with the @option{-q} option, messages sent to
address@hidden are discarded.
+By default, @code{AS_INIT} sets this to @samp{1} for standalone M4sh
+clients. However, @code{AC_INIT} shuffles things around to another file
+descriptor, in order to allow the @option{-q} option of
address@hidden to choose whether messages should go to the script's
+standard output or be discarded.
If you want to display some messages, consider using one of the printing
macros (@pxref{Printing Messages}) instead. Copies of messages output
via these macros are also recorded in @file{config.log}.
@end defmac
address@hidden
@defmac AS_MESSAGE_LOG_FD
@asindex{MESSAGE_LOG_FD}
-
-The file descriptor for messages logged to @file{config.log}. Macros
-that run tools, like @code{AC_COMPILE_IFELSE} (@pxref{Running the
+This must either be empty, or expand to a file descriptor for log
+messages. By default, @code{AS_INIT} sets this macro to the empty
+string for standalone M4sh clients, thus disabling logging. However,
address@hidden shuffles things around so that both @command{configure}
+and @command{config.status} use @file{config.log} for log messages.
+Macros that run tools, like @code{AC_COMPILE_IFELSE} (@pxref{Running the
Compiler}), redirect all output to this descriptor. You may want to do
so if you develop such a low-level macro.
@end defmac
@defmac AS_ORIGINAL_STDIN_FD
@asindex{ORIGINAL_STDIN_FD}
-The file descriptor for the original standard input.
+This must expand to a file descriptor for the original standard input.
+By default, @code{AS_INIT} sets this macro to @samp{0} for standalone
+M4sh clients. However, @code{AC_INIT} shuffles things around for
+safety.
When @command{configure} runs, it may accidentally execute an
interactive command that has the same name as the non-interactive meant
diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4
index f3dc4ac..67eb9ff 100644
--- a/lib/m4sugar/m4sh.m4
+++ b/lib/m4sugar/m4sh.m4
@@ -658,8 +658,30 @@ m4_defun([AS_UNSET],
## 3. Error and warnings at the shell level. ##
## ------------------------------------------ ##
-# If AS_MESSAGE_LOG_FD is defined, shell messages are duplicated there
-# too.
+
+# AS_MESSAGE_FD
+# -------------
+# Must expand to the fd where messages will be sent. Defaults to 1,
+# although a script may reassign this value and use exec to either
+# copy stdout to the new fd, or open the new fd on /dev/null.
+m4_define([AS_MESSAGE_FD], [1])
+
+# AS_MESSAGE_LOG_FD
+# -----------------
+# Must expand to either the empty string (when no logging is
+# performed), or to the fd of a log file. Defaults to empty, although
+# a script may reassign this value and use exec to open a log. When
+# not empty, messages to AS_MESSAGE_FD are duplicated to the log,
+# along with a LINENO reference.
+m4_define([AS_MESSAGE_LOG_FD])
+
+
+# AS_ORIGINAL_STDIN_FD
+# --------------------
+# Must expand to the fd of the script's original stdin. Defaults to
+# 0, although the script may reassign this value and use exec to
+# shuffle fd's.
+m4_define([AS_ORIGINAL_STDIN_FD], [0])
# AS_ESCAPE(STRING, [CHARS = $"`\])
@@ -730,7 +752,7 @@ m4_define([_AS_ECHO],
# Log the string to AS_MESSAGE_LOG_FD.
m4_defun_init([_AS_ECHO_LOG],
[AS_REQUIRE([_AS_LINENO_PREPARE])],
-[_AS_ECHO([$as_me:${as_lineno-$LINENO}: $1], [AS_MESSAGE_LOG_FD])])
+[_AS_ECHO([$as_me:${as_lineno-$LINENO}: $1], AS_MESSAGE_LOG_FD)])
# _AS_ECHO_N_PREPARE
@@ -765,10 +787,11 @@ m4_define([_AS_ECHO_N],
# AS_MESSAGE(STRING, [FD = AS_MESSAGE_FD])
# ----------------------------------------
-# Output "`basename $0`: "STRING to the open file FD.
+# Output "`basename $0`: STRING" to the open file FD, and if logging
+# is enabled, copy it to the log with a reference to LINENO.
m4_defun_init([AS_MESSAGE],
[AS_REQUIRE([_AS_ME_PREPARE])],
-[m4_ifset([AS_MESSAGE_LOG_FD],
+[m4_ifval(AS_MESSAGE_LOG_FD,
[{ _AS_ECHO_LOG([$1])
_AS_ECHO([$as_me: $1], [$2]);}],
[_AS_ECHO([$as_me: $1], [$2])])[]])
@@ -792,15 +815,15 @@ m4_define([AS_WARN],
# otherwise, assume the entire script does not do logging.
m4_define([_AS_ERROR_PREPARE],
[AS_REQUIRE_SHELL_FN([as_fn_error],
- [AS_FUNCTION_DESCRIBE([as_fn_error], [ERROR]m4_ifset([AS_MESSAGE_LOG_FD],
+ [AS_FUNCTION_DESCRIBE([as_fn_error], [ERROR]m4_ifval(AS_MESSAGE_LOG_FD,
[[ [[LINENO LOG_FD]]]]),
[Output "`basename @S|@0`: error: ERROR" to stderr.]
-m4_ifset([AS_MESSAGE_LOG_FD],
+m4_ifval(AS_MESSAGE_LOG_FD,
[[If LINENO and LOG_FD are provided, also output the error to LOG_FD,
referencing LINENO.]])
[Then exit the script with status $?, using 1 if that was 0.])],
[ as_status=$?; test $as_status -eq 0 && as_status=1
-m4_ifset([AS_MESSAGE_LOG_FD],
+m4_ifval(AS_MESSAGE_LOG_FD,
[m4_pushdef([AS_MESSAGE_LOG_FD], [$[3]])dnl
if test "$[3]"; then
AS_LINENO_PUSH([$[2]])
@@ -819,7 +842,7 @@ m4_defun_init([AS_ERROR],
[m4_append_uniq([_AS_CLEANUP],
[m4_divert_text([M4SH-INIT-FN], [_AS_ERROR_PREPARE[]])])],
[m4_ifvaln([$2], [{ AS_SET_STATUS([$2])])]dnl
-[as_fn_error "_AS_QUOTE([$1])"m4_ifset([AS_MESSAGE_LOG_FD],
+[as_fn_error "_AS_QUOTE([$1])"m4_ifval([AS_MESSAGE_LOG_FD],
[ "$LINENO" AS_MESSAGE_LOG_FD])[]m4_ifval([$2], [; }])])
@@ -1986,8 +2009,9 @@ _ASEOF
cat >>$1 <<\_ASEOF || as_write_fail=1
_AS_SHELL_SANITIZE
_AS_PREPARE
-exec AS_MESSAGE_FD>&1
-m4_text_box([Main body of $1 script.])
+m4_if(AS_MESSAGE_FD, [1], [], [exec AS_MESSAGE_FD>&1
+])]dnl
+[m4_text_box([Main body of $1 script.])
_ASEOF
test $as_write_fail = 0 && chmod +x $1[]dnl
_m4_popdef([AS_MESSAGE_LOG_FD])])# AS_INIT_GENERATED
diff --git a/tests/m4sh.at b/tests/m4sh.at
index e85aabe..0c575de 100644
--- a/tests/m4sh.at
+++ b/tests/m4sh.at
@@ -1259,9 +1259,10 @@ AT_CLEANUP
## ------------------- ##
AT_SETUP([AS@&address@hidden)
+AT_KEYWORDS([AS@&address@hidden AS@&address@hidden)
+dnl First run, no logging, tests shell selection
AT_DATA_M4SH([script.as], [[dnl
-m4_define([AS_MESSAGE_FD], [1])
AS_INIT
AS_INIT_GENERATED([child], [echo hello from child])
cat >>child <<\EOF
@@ -1286,4 +1287,85 @@ AT_CHECK([grep 'SHELL=.' stdout], [0], [ignore])
sed s/parent/child/ <stdout >expout
AT_CHECK([./child], [0], [expout])
+
+dnl Second run, with logging from parent and child, tests fd handling
+AT_DATA_M4SH([script.as], [[dnl
+AS_INIT
+child=${1-child}
+m4_define([AS_MESSAGE_LOG_FD], [5])
+exec AS_MESSAGE_LOG_FD>log
+AS_INIT_GENERATED([$child], [echo hello1 from $child]) || AS_EXIT([1])
+cat >>$child <<\EOF
+m4_pushdef([AS_MESSAGE_LOG_FD])
+AS_MESSAGE([hello2 from ${child}child])
+m4_popdef([AS_MESSAGE_LOG_FD])
+exec AS_MESSAGE_LOG_FD>>log
+AS_MESSAGE([hello3 from child])
+EOF
+AS_MESSAGE([hello from parent])
+dnl close log in parent before spawning child, for mingw
+exec AS_MESSAGE_LOG_FD>-
+./$child
+]])
+
+AT_CHECK_M4SH
+AT_CHECK([./script], [0], [[script: hello from parent
+hello1 from child
+child: hello2 from child
+child: hello3 from child
+]])
+AT_CHECK([[sed 's,:[0-9][0-9]*:,:0:,' log]], [0],
+[[script:0: hello from parent
+child:0: hello3 from child
+]])
+
+# Force write error creating a file on stdout
+if test -w /dev/full && test -c /dev/full; then
+ AT_CHECK([./script /dev/full], [1], [ignore], [ignore])
+fi
+
+AT_CLEANUP
+
+
+## --------------- ##
+## AS_MESSAGE_FD. ##
+## --------------- ##
+
+AT_SETUP([AS@&address@hidden)
+AT_KEYWORDS([AS@&address@hidden AS@&address@hidden AS@&t_ORIGINAL_STDIN_FD])
+AT_KEYWORDS([AS@&address@hidden)
+
+AT_DATA_M4SH([script.as], [[dnl
+AS_INIT
+m4_define([AS_ORIGINAL_STDIN_FD], [5])
+m4_define([AS_MESSAGE_LOG_FD], [6])
+m4_define([AS_MESSAGE_FD], [7])
+exec AS_ORIGINAL_STDIN_FD<&0 </dev/null AS_MESSAGE_LOG_FD>log
+if test $[#] -gt 0; then
+ exec AS_MESSAGE_FD>/dev/null
+else
+ exec AS_MESSAGE_FD>&1
+fi
+AS_LINENO_PUSH([100])
+cat # tests that stdin is neutralized
+AS_MESSAGE([hello world])
+cat <&AS_ORIGINAL_STDIN_FD
+]])
+
+AT_CHECK_M4SH
+AT_CHECK([echo goodbye | ./script], [0],
+[[script: hello world
+goodbye
+]])
+AT_CHECK([cat log], [0],
+[[script:100: hello world
+]])
+rm log
+AT_CHECK([echo goodbye | ./script silent], [0],
+[[goodbye
+]])
+AT_CHECK([cat log], [0],
+[[script:100: hello world
+]])
+
AT_CLEANUP
--
1.6.0.4
- Re: [PATCH] Pass CONFIG_SHELL down if provided, Ralf Wildenhues, 2008/11/11
- Re: [PATCH] Pass CONFIG_SHELL down if provided, Eric Blake, 2008/11/11
- Re: [PATCH] Pass CONFIG_SHELL down if provided, Ralf Wildenhues, 2008/11/11
- Re: [PATCH] Pass CONFIG_SHELL down if provided, Paolo Bonzini, 2008/11/12
- Re: [PATCH] Pass CONFIG_SHELL down if provided, Eric Blake, 2008/11/12
- Re: [PATCH] Pass CONFIG_SHELL down if provided, Paolo Bonzini, 2008/11/12
- Re: [PATCH] Pass CONFIG_SHELL down if provided, Eric Blake, 2008/11/12
- Re: [PATCH] Pass CONFIG_SHELL down if provided, Eric Blake, 2008/11/12
- AS_MESSAGE_FD [was: [PATCH] Pass CONFIG_SHELL down if provided], Eric Blake, 2008/11/12
- Re: AS_MESSAGE_FD,
Eric Blake <=
- Re: AS_MESSAGE_FD, Eric Blake, 2008/11/22
- Re: AS_MESSAGE_FD, Ralf Wildenhues, 2008/11/22
- Re: AS_MESSAGE_FD, Eric Blake, 2008/11/22
- Re: AS_MESSAGE_FD, Ralf Wildenhues, 2008/11/23
- Re: AS_MESSAGE_FD, Eric Blake, 2008/11/23
- Re: AS_MESSAGE_FD, Eric Blake, 2008/11/24
Re: [PATCH] Pass CONFIG_SHELL down if provided, Paolo Bonzini, 2008/11/12