http://invisible-island.net/autoconf/
Copyright © 2014,2015 by Thomas E. Dickey
The X/Open documentation is a consensus based on documentation
and the contributor's experience. Often it lacks precision.
Sometimes there is no consensus. The echo
command is
an example.
Referring to IEEE Std 1003.1, 2004 Edition, Under OPTIONS:
and under OPERANDS:
If the first operand is -n, or if any of the operands contain a backslash ( '\' ) character, the results are implementation-defined.
On XSI-conformant systems, if the first operand is -n, it shall be treated as a string, not an option. The following character sequences shall be recognized on XSI-conformant systems within any of the arguments:.
It goes on to list escapes (operands containing a backslash).
Some readers do not notice that the two statements in OPERANDS are mutually exclusive. The standard only describes the behavior of “XSI-conformant” systems. Other possibilities are alluded to, but not specified.
Reading between the lines, there are some comments about the non-conformant systems:
they may have options,
in particular, “-n
” is a
well-known (but non-conforming) case,
systems accepting “-n
” are likely
to differ in their treatment of escapes,
there may be other escapes supported (or even ignored) by the non-conformant system, and
there may be other options which are recognized by the non-conformant system, but they are not worth mentioning.
The differences between conformant and non-conformant systems are interesting for autoconf scripts because the generated scripts try to show the beginning and end of
There are historically two main implementations of
echo
to consider:
BSD accepts a “-n
” option to
suppress a trailing newline, while
SystemV accepts a “\c
” escape to
do this.
Doing that using a shell script would involve checking for which feature was supported, and setting shell variables to reuse the test results.
Here is a short history of how this shell feature evolved in autoconf (also see repository):
The underlying shell (echo) feature test was originally
added in
1994 before autoconf 2.0 by David J. MacKenzie as
“AC_PROG_ECHO_N”. The feature set shell variables
ac_c
, ac_n
and ac_t
to
denote the pieces corresponding to
Later, in
February 2000, Akim Demaille apparently disagreed that
AC_PROG_ECHO should be an autoconf feature.
He renamed it to “_AC_PROG_ECHO_N”, implying that
it was an
internal feature.
At the same time, he renamed MacKenzie's variables to
ECHO_C
, ECHO_N
and
ECHO_T
—and documented those variables.
Here is the resulting feature test in acspecific.m4, from autoconf 2.52:
# _AC_PROG_ECHO
# -------------
# Check whether to use -n, \c, or newline-tab to separate
# checking messages from result messages.
# Don't try to cache, since the results of this macro are needed to
# display the checking message. In addition, caching something used once
# has little interest.
# Idea borrowed from dist 3.0. Use `*c*,', not `*c,' because if `\c'
# failed there is also a new-line to match.
m4_define([_AC_PROG_ECHO],
[case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
*c*,-n*) ECHO_N= ECHO_C='
' ECHO_T=' ' ;;
*c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
*) ECHO_N= ECHO_C='\c' ECHO_T= ;;
esac
AC_SUBST(ECHO_C)dnl
AC_SUBST(ECHO_N)dnl
AC_SUBST(ECHO_T)dnl
])# _AC_PROG_ECHO
With autoconf 2.53, the feature test moved to lib/m4sugar/m4sh.m4, without change other than some m4-syntax.
Later, in
2005, Paul Eggert changed the feature test to separate
the “\c
” and
“-n
” parts to eliminate a repeated
newline,
documented in a separate commit as a bug report by Stepan
Kasal, e.g.,
this posting in February. The resulting script looked
like this:
# _AS_ECHO_N_PREPARE
# ------------------
# Check whether to use -n, \c, or newline-tab to separate
# checking messages from result messages.
# Don't try to cache, since the results of this macro are needed to
# display the checking message. In addition, caching something used once
# has little interest.
# Idea borrowed from dist 3.0. Use `*c*,', not `*c,' because if `\c'
# failed there is also a newline to match.
m4_defun([_AS_ECHO_N_PREPARE],
[ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in
-n*)
case `echo 'x\c'` in
*c*) ECHO_T=' ';; # ECHO_T is single tab character.
*) ECHO_C='\c';;
esac;;
*)
ECHO_N='-n';;
esac
])# _AS_ECHO_N_PREPARE
Eggert's followup comment said “the usual case where echo -n works”, which was a reference to the relative popularity of Linux and the BSDs versus the SVR4-based Unix systems.
In short, the feature was added early in autoconf's development, existed unchanged for eleven years before it was changed for cosmetic reasons. There was no functional requirement for this change; there were no shells which failed to produce the expected result.
Referring to config.status
files which I capture
as part of my build process (see the save-XXX scripts), I
can see that the usual case is as I
stated above:
\c
”.-n
”.-n
”.More to the point, none of the systems for which I have data would have exercised the case mentioned by Kasal. He did not cite a configuration for which this would occur; it may have been hypothetical.
However, one of the nice features about standards is that people can misread them, to find whatever they want the standard to say. My attention was drawn to this recently by Gentoo bug report #531244. That report points to a Gentoo patch for dash, which (see comment #15):
See patch [1] which was applied to dash-0.5.8.1-r2 in Gentoo. It changes echo behavior as follows: - disable interpretation of escape sequences; - drop support for '-n' option. So the following shell code doesn't work in any way with that version of dash (and it is really not portable): echo $ECHO_N "Some text $ECHO_C" autoconf >=2.62 uses AS_ECHO macro which works fine.
Actually, "portable" is something different from the ability
to work around defective software. That is exactly what happens
when one applies the
patch mentioned. In particular, note that the reason for the
bug report was that the ECHO_C
variable was a
newline, which broke the sed script in
config.status
. None of the platforms to which any of
my programs have been ported in the last fifteen years produced
that result. Otherwise, there would have been a build
failure—and bug report.
The patch cites two other Gentoo bug reports:
The relevant part of the patch removes the interpretation of
escape sequences from the “echo
” command
(as well as “-n
”). As noted in comment
#3 of the more recent report, upstream rejected the patch.
Gentoo went ahead and tried to use it, echoing the comment in the
patch about size/speed.
Because most of the logic dealing with escapes in
dash is shared by echo
and
printf
, there is little possible saving for size.
Likewise, the comment about speed is pointless (it only slows
dash down when there are escapes to
process).
Gentoo might fix the bug which was introduced into dash. I put a workaround in autoconf-252, which coincidentally gives a similar result to the mainstream version:
--- acspecific.m4 2010/08/14 22:07:16 1.5
+++ acspecific.m4 2014/12/04 01:28:50 1.6
@@ -65,9 +65,9 @@
# Idea borrowed from dist 3.0. Use `*c*,', not `*c,' because if `\c'
# failed there is also a new-line to match.
m4_define([_AC_PROG_ECHO],
-[case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
- *c*,-n*) ECHO_N= ECHO_C='
-' ECHO_T=' ' ;;
+[case `echo "testing\c" 2>/dev/null; echo 1,2,3`,`echo -n testing 2>/dev/null; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C= # newlines do not sed ;-) only broken shells would use this case anyway
+ ECHO_T=' ' ;;
*c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
*) ECHO_N= ECHO_C='\c' ECHO_T= ;;
esac