libtool-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 6/6] use printf as $ECHO


From: Paolo Bonzini
Subject: Re: [PATCH 6/6] use printf as $ECHO
Date: Mon, 10 Nov 2008 12:07:12 +0100
User-agent: Thunderbird 2.0.0.17 (Macintosh/20080914)

>>>> +if test "X`printf %s $ECHO`" = "X$ECHO"; then
>>>> +  ECHO='printf %s\n'
>>> Just for safety, shouldn't the test use '%s\n' rather than bare %s (in 
>>> other 
>>> words, make our test match our usage pattern)?
>> _AS_ECHO_PREPARE does the same...
> 
> Here's a chance to fix both at once.  :-)

To be more precise, Autoconf also needs an "echo -n" emulation, so it
does use "printf %s" too.  I just copied the assumption that if one
works, the other does too.

> Esp., I'm quite sure that we need the cat here-document fallback;
> [...] I am quite concerned that this patch will break
> some of the older systems.

[warning: the rest of this message is pretty dense!]

There are two possible objections to the patch:

1) portability.  I looked again at Sven Mascheck's pages, and you're
probably thinking of http://www.in-ulm.de/~mascheck/various/uuoc/ where
he says:

   Here documents [used with cat] force `as-is' output, if there are
   character sequences which are special to echo(1), and if printf(1) is
   not available".

   cat<<EOF
   $VARIABLE
   EOF

And this actually tells me: if we don't find an easy printf (either
builtin or the first in the path) that works, there is no need to search
*all* printf and *all* shells, we could use a shell function like

   func_fallback_echo()
   {
     cat <<_LTEOF
   $1 (or $*)
   _LTEOF
   }

It would definitely cost less than the fallback echo of Libtool HEAD,
and it would be as portable; it would even make a smaller patch.  I
attach a diff to apply after 6/6.  It hasn't finished testing with the
fallback, but it's going well so far.

2) performance.  Autoconf currently tries to use in order "printf" (may
fork), "/usr/ucb/echo -n" (will fork once), and "expr" (will fork
twice).  The patch I sent last Friday is a little better: it tries to
use in order "printf" (may fork), "/path/to/good/printf" (will fork
once), and another shell's builtin printf (will fork once).  It is
indeed less safe, so it is indeed better to switch to `cat' -- it does
not change much in terms of performance, but it also forks only once if
there is no builtin printf and it could be a little better because "cat"
has a lower startup time than any shell, of course.  So the attached
patch is a win-win for both portability and performance compared to the
patch I sent last Friday.  Thanks for pointing out that this use of
"cat" is indeed useful.

Note that there is one other possibility that does not fork, namely to
check if the builtin "echo -n" prints "echo -n -n abc\t" as "-n abc\t".
 I didn't do this because ksh (the only shell I have here that has no
builtin printf) fully parses "echo -n -n abc" and even "print -R -n -n
abc"; I suppose zsh 3.x does the same (I checked zsh 4.x, which however
has builtin printf).  ash/dash support the trick, but has builtin printf
and they're rejected anyway before we reach the test, because they do
not support $LINENO.

The difference with Libtool HEAD is twofold.  First, I removed the
re-execute path, because I believe that having two re-execute paths in
M4sh and in Libtool is unmaintainable, and the presence of hacks such as
ORIGINAL_CONFIG_SHELL only reinforces my belief.  Second, I removed
fallbacks that didn't fully solve the issue (leading to the need for
$Xsed), including this one: :-)

            # Oops.  We lost completely, so just stick with echo.
            ECHO=echo

The resulting code is simpler, at least for Autoconf >= 2.60 has no
performance penalty, removes the need for compounding hack-over-hack,
and removes some forks in the fallback case of using cat.  I say that
for Autoconf >= 2.60, there should be no performance penalty because the
shell detection code will usually find a bash somewhere in the PATH, and
so a builtin printf.  When dash starts implementing $LINENO, it will
also be accepted on systems that install dash as /bin/sh.

For Autoconf < 2.60, the performance penalty affects systems where the
first shell that supports $LINENO (because of Autoconf's requests) has
no builtin printf.  This happens when /bin/sh does not support $LINENO,
and there is a /bin/ksh but not /bin/bash, or a /usr/bin/ksh but not
/usr/bin/bash.


Given all this, here are three questions:

1) I don't have access to systems that are old or weird enough to check
if the performance penalty will happen often.  What do you think?

2) If ksh had a way to print without interpreting escapes *and dashes*,
I'd be glad to add it; do you know one?

3) I wonder if the _AS_DETECT_SUGGESTED shouldn't be added to Autoconf
too.  Opinions?


A meta question is, would you prefer that I resubmit the attached patch
separately, basing it on top of HEAD?

Paolo
diff --git a/libltdl/config/ltmain.m4sh b/libltdl/config/ltmain.m4sh
index e3627b0..28f50cd 100644
--- a/libltdl/config/ltmain.m4sh
+++ b/libltdl/config/ltmain.m4sh
@@ -92,8 +92,13 @@ fi
 BIN_SH=xpg4; export BIN_SH # for Tru64
 DUALCASE=1; export DUALCASE # for MKS sh
 
-# In case there is no working printf in the path
-eval "$lt_func_ECHO"
+# A function that is used when printf is not a builtin.
+func_fallback_echo ()
+{
+  cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF
+}
 
 # NLS nuisances: We save the old values to restore during execute mode.
 # Only set LANG and LC_ALL to C if already set.
@@ -2340,16 +2345,18 @@ if test \"\$libtool_install_magic\" = \"$magic\"; then
 else
   # When we are sourced in execute mode, \$file and \$ECHO are already set.
   if test \"\$libtool_execute_magic\" != \"$magic\"; then
-    file=\"\$0\"
-    # Make sure echo works."
+    file=\"\$0\""
 
-    qlt_cmd_ECHO=`$ECHO "X$lt_cmd_ECHO" | $Xsed -e "$sed_quote_subst"`
-    qlt_func_ECHO=`$ECHO "X$lt_func_ECHO" | $Xsed -e "$sed_quote_subst"`
     qECHO=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"`
-       $ECHO "\
-    lt_cmd_ECHO=\"$qlt_cmd_ECHO\"
-    lt_func_ECHO=\"$qlt_func_ECHO\"
-    eval \"\$lt_func_ECHO\"
+    $ECHO "\
+
+# A function that is used when printf is not a builtin.
+func_fallback_echo ()
+{
+  cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF
+}
     ECHO=\"$qECHO\"
   fi\
 
diff --git a/libltdl/m4/libtool.m4 b/libltdl/m4/libtool.m4
index 4c4aa0b..b221749 100644
--- a/libltdl/m4/libtool.m4
+++ b/libltdl/m4/libtool.m4
@@ -526,7 +526,13 @@ LTCC='$LTCC'
 LTCFLAGS='$LTCFLAGS'
 compiler='$compiler_DEFAULT'
 
-eval "\$lt_func_ECHO"
+# Used when printf is not a builtin.
+func_fallback_echo ()
+{
+  cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF
+}
 
 # Quote evaled strings.
 for var in lt_decl_all_varnames([[ \
@@ -1069,74 +1075,37 @@ m4_define([_LT_SHELL_INIT],
 ])])# _LT_SHELL_INIT
 
 
-# _LT_DETECT_ECHO_BACKSLASH
-# -----------------------------
-# Find a working printf (either a program or a shell builtin)
-# that can be used to print values without interpreting backslashes
-# or strings with a leading `-'.
-m4_defun([_LT_DETECT_ECHO_BACKSLASH],
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
 
[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
 ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
 ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
 
-AC_MSG_CHECKING([for a working printf])
+AC_MSG_CHECKING([how to print strings])
 if test "X`printf %s $ECHO`" = "X$ECHO"; then
   ECHO='printf %s\n'
-
 else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-  for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-  do
-    IFS=$as_save_IFS
-    test "x$as_dir" = x && continue
-    test -f "$as_dir/printf" || test -f "$as_dir/printf.exe" || continue
-    test "X`$as_dir/printf %s $ECHO`" = "X$ECHO" &&
-      { ECHO=$as_dir/printf' %s\n' ; break; }
-  done
-  case "$ECHO" in
-    */printf*) ;;
-    *) 
-      lt_cmd_ECHO="printf %s\\\\n \"\$[]1\""
-      as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-      for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-      do
-        IFS=$as_save_IFS
-        test "x$as_dir" = x && continue
-        for as_base in sh bash ksh zsh sh5; do
-          as_shell=$as_dir/$as_base
-          test -f "$as_shell" || test -f "$as_shell.exe" || continue
-         lt_func_ECHO='func_do_echo () { '$as_shell' -c "$lt_cmd_ECHO" x 
"$[]1";}'
-          (lt_out=`$as_shell -c "
-               PATH=/tmp/nonexistent; export PATH;
-               FPATH=/tmp/nonexistent; export FPATH;
-               printf %s \"\\$[]1\"" lt_echo "$ECHO"`
-          test "X$lt_out" = "X$ECHO") &&
-            { eval "$lt_func_ECHO"; ECHO=func_do_echo; break 2; }
-        done
-      done
-  esac
+  # Used when printf is not a builtin.
+  func_fallback_echo ()
+  {
+    cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF
+  }
+  ECHO='func_fallback_echo'
 fi
 
 case "$ECHO" in
-  printf*) AC_MSG_RESULT([shell builtin]) ;;
-  */printf*) AC_MSG_RESULT([$as_dir/printf]) ;;
-  func_do_echo) AC_MSG_RESULT([$as_shell builtin]) ;;
-  *) AC_MSG_RESULT([not found])
-    AC_MSG_ERROR([cannot find a working printf]) ;;
+  printf*) AC_MSG_RESULT([printf]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
 esac
 
-_LT_DECL([], [lt_cmd_ECHO], [1], [Used if there is no working printf in the 
path])
-_LT_DECL([], [lt_func_ECHO], [1], [Used if there is no working printf in the 
path])
-])
-
-# _LT_PROG_ECHO_BACKSLASH
-# -----------------------
-# Add some code to the start of the generated configure script which
-# will find a printf which doesn't interpret backslashes, and
-# which we can use as an echo command.  If possible, find a builtin.
-m4_defun([_LT_PROG_ECHO_BACKSLASH],
-[m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DETECT_ECHO_BACKSLASH])dnl
 m4_ifdef([_AS_DETECT_SUGGESTED],
 [_AS_DETECT_SUGGESTED([
   
ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'

reply via email to

[Prev in Thread] Current Thread [Next in Thread]