mirror of
git://git.savannah.gnu.org/libtool.git
synced 2024-12-09 06:40:24 +08:00
78385ffd8a
Dash shipped with Ubutu-11.10 as /bin/sh, among others, still has a crippled echo builtin that mis-handles backslashes. * build-aux/options-parser (bs_echo): Adopt the autoconf echo normalization code to find a suitable replacement for buggy echo commands. Adjust all uses of echo to $bs_echo. * build-aux/extract-trace (func_extract_trace, func_main): Likewise. * bootstrap: To retain some execution speed on platforms with buggy builtin echo, replace most occurrences of `echo' with `$bs_echo' - except where its arguments will obviously never contain backslashes or be overly long. Reported by Reuben Thomas. Signed-off-by: Gary V. Vaughan <gary@gnu.org>
408 lines
13 KiB
Bash
Executable File
408 lines
13 KiB
Bash
Executable File
#! /bin/sh
|
|
|
|
# Make sure we've evaluated the option-parser library.
|
|
test -n "$progpath" || . `echo "$0" |${SED-sed} 's|[^/]*$||'`/options-parser
|
|
|
|
# Set a version string.
|
|
scriptversion=2011-11-21.10; # UTC
|
|
|
|
# Extract macro arguments from autotools input with GNU M4.
|
|
# Written by Gary V. Vaughan, 2010
|
|
#
|
|
# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
|
|
# This is free software; see the source for copying conditions. There is NO
|
|
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
#
|
|
##### PLEASE CHECK `--version' WORKS AFTER EDITING THE ABOVE COPYRIGHT #####
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
## ------ ##
|
|
## Usage. ##
|
|
## ------ ##
|
|
|
|
# Run `./extract-trace --help' for help with using this script from the
|
|
# command line.
|
|
#
|
|
# Or source first `options-parser' and then this file into your own
|
|
# scripts in order to make use of the function and variable framework
|
|
# they define, and also to avoid the overhead of forking to run this
|
|
# script in its own process on every call.
|
|
|
|
|
|
## -------------- ##
|
|
## Configuration. ##
|
|
## -------------- ##
|
|
|
|
usage='$progname MACRO_NAME FILE [...]'
|
|
|
|
long_help_message='
|
|
The first argument to this program is the name of an autotools macro
|
|
whose arguments you want to extract by examining the files listed in the
|
|
remaining arguments using the same tool that Autoconf and Automake use,
|
|
GNU M4.
|
|
|
|
The arguments are returned separated by colons, with each traced call
|
|
on a separate line.'
|
|
|
|
|
|
|
|
## ------------------##
|
|
## Helper functions. ##
|
|
## ------------------##
|
|
|
|
# This section contains the helper functions used by the rest of
|
|
# `extract-trace'.
|
|
|
|
|
|
# func_autoconf_configure MAYBE-CONFIGURE-FILE
|
|
# --------------------------------------------
|
|
# Ensure that MAYBE-CONFIGURE-FILE is the name of a file in the current
|
|
# directory which contains an uncommented call to AC_INIT.
|
|
func_autoconf_configure ()
|
|
{
|
|
$debug_cmd
|
|
|
|
_G_sed_no_comment='s|#.*$||; s|^dnl .*$||; s| dnl .*$||;'
|
|
_G_ac_init=
|
|
|
|
# If we were passed a genuine file, make sure it calls AC_INIT.
|
|
test -f "$1" \
|
|
&& _G_ac_init=`$SED "$_G_sed_no_comment" "$1" |grep AC_INIT`
|
|
|
|
# Otherwise it is not a genuine Autoconf input file.
|
|
test -n "$_G_ac_init"
|
|
_G_status=$?
|
|
|
|
test 0 -ne "$_G_status" \
|
|
&& func_verbose "\`$1' not using Autoconf"
|
|
|
|
(exit $_G_status)
|
|
}
|
|
|
|
|
|
# func_find_tool ENVVAR NAMES...
|
|
# ------------------------------
|
|
# Search for a required program. Use the value of ENVVAR, if set,
|
|
# otherwise find the first of the NAMES that can be run (i.e.,
|
|
# supports --version). If found, set ENVVAR to the program name,
|
|
# die otherwise.
|
|
func_find_tool ()
|
|
{
|
|
$debug_cmd
|
|
|
|
_G_find_tool_envvar=$1
|
|
shift
|
|
_G_find_tool_names=$@
|
|
eval "_G_find_tool_res=\$$_G_find_tool_envvar"
|
|
if test -n "$_G_find_tool_res"; then
|
|
_G_find_tool_error_prefix="\$$find_tool_envvar: "
|
|
else
|
|
for _G_prog
|
|
do
|
|
if func_tool_version_output $_G_prog >/dev/null; then
|
|
_G_find_tool_res=$_G_prog
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
if test -n "$_G_find_tool_res"; then
|
|
func_tool_version_output >/dev/null $_G_find_tool_res "\
|
|
${_G_find_tool_error_prefix}Cannot run \`$_G_find_tool_res --version'"
|
|
|
|
# Make sure the result is exported to the environment for children
|
|
# to use.
|
|
eval "$_G_find_tool_envvar=\$_G_find_tool_res"
|
|
eval "export $_G_find_tool_envvar"
|
|
else
|
|
func_error "\
|
|
One of these is required:
|
|
$_G_find_tool_names"
|
|
fi
|
|
}
|
|
|
|
|
|
# func_tool_version_output CMD [FATAL-ERROR-MSG]
|
|
# ----------------------------------------------
|
|
# Attempt to run `CMD --version', discarding errors. The output can be
|
|
# ignored by redirecting stdout, and this function used simply to test
|
|
# whether the command exists and exits normally when passed a
|
|
# `--version' argument.
|
|
# When FATAL-ERROR-MSG is given, then this function will display the
|
|
# message and exit if running `CMD --version' returns a non-zero exit
|
|
# status.
|
|
func_tool_version_output ()
|
|
{
|
|
$debug_cmd
|
|
|
|
_G_cmd=$1
|
|
_G_fatal_error_msg=$2
|
|
|
|
# Some tools, like `git2cl' produce thousands of lines of output
|
|
# unless stdin is /dev/null - in that case we want to return
|
|
# successfully without saving all of that output. Other tools,
|
|
# such as `help2man' exit with a non-zero status when stdin comes
|
|
# from /dev/null, so we re-execute without /dev/null if that
|
|
# happens. This means that occasionally, the output from both calls
|
|
# ends up in the result, but the alternative would be to discard the
|
|
# output from one call, and hope the other produces something useful.
|
|
{ $_G_cmd --version </dev/null || $_G_cmd --version; } 2>/dev/null
|
|
_G_status=$?
|
|
|
|
test 0 -ne "$_G_status" && test -n "$_G_fatal_error_msg" \
|
|
&& func_fatal_error "$_G_fatal_error_msg"
|
|
|
|
(exit $_G_status)
|
|
}
|
|
|
|
|
|
## -------------------- ##
|
|
## Resource management. ##
|
|
## -------------------- ##
|
|
|
|
# This section contains definitions for functions that each ensure a
|
|
# particular resource (a file, or a non-empty configuration variable for
|
|
# example) is available, and if appropriate to extract default values
|
|
# from pertinent package files. Where a variable already has a non-
|
|
# empty value (as set by the package's `bootstrap.conf'), that value is
|
|
# used in preference to deriving the default. Call them using their
|
|
# associated `require_*' variable to ensure that they are executed, at
|
|
# most, once.
|
|
#
|
|
# It's entirely deliberate that calling these functions can set
|
|
# variables that don't obey the namespace limitations obeyed by the rest
|
|
# of this file, in order that that they be as useful as possible to
|
|
# callers.
|
|
|
|
|
|
# require_configure_ac
|
|
# --------------------
|
|
# Ensure that there is a `configure.ac' or `configure.in' file in the
|
|
# current directory which contains an uncommented call to AC_INIT, and
|
|
# that `$configure_ac' contains its name.
|
|
require_configure_ac=func_require_configure_ac
|
|
func_require_configure_ac ()
|
|
{
|
|
$debug_cmd
|
|
|
|
test -z "$configure_ac" \
|
|
&& func_autoconf_configure configure.ac && configure_ac=configure.ac
|
|
test -z "$configure_ac" \
|
|
&& func_autoconf_configure configure.in && configure_ac=configure.in
|
|
test -z "$configure_ac" \
|
|
|| func_verbose "found \`$configure_ac'"
|
|
|
|
require_configure_ac=:
|
|
}
|
|
|
|
|
|
# require_gnu_m4
|
|
# --------------
|
|
# Search for GNU M4, and export it in $M4.
|
|
require_gnu_m4=func_require_gnu_m4
|
|
func_require_gnu_m4 ()
|
|
{
|
|
$debug_cmd
|
|
|
|
test -n "$M4" || {
|
|
# Find the first m4 binary that responds to --version.
|
|
func_find_tool M4 gm4 gnum4 m4
|
|
}
|
|
|
|
test -n "$M4" || func_fatal_error "\
|
|
Please install GNU M4, or \`export M4=/path/to/gnu/m4'."
|
|
|
|
func_verbose "export M4='$M4'"
|
|
|
|
# Make sure the search result is visible to subshells
|
|
export M4
|
|
|
|
require_gnu_m4=:
|
|
}
|
|
|
|
|
|
## --------------- ##
|
|
## Core functions. ##
|
|
## --------------- ##
|
|
|
|
# This section contains the high level functions used when calling this
|
|
# file as a script. `func_extract_trace' is probably the only one that you
|
|
# won't want to replace if you source this file into your own script.
|
|
|
|
|
|
# func_extract_trace MACRO_NAMES [FILENAME]...
|
|
# --------------------------------------------
|
|
# set `$func_extract_trace_result' to a colon delimited list of arguments
|
|
# to any of the comma separated list of MACRO_NAMES in FILENAME. If no
|
|
# FILENAME is given, then `$configure_ac' is assumed.
|
|
func_extract_trace ()
|
|
{
|
|
$debug_cmd
|
|
|
|
$require_configure_ac
|
|
$require_gnu_m4
|
|
|
|
_G_m4_traces=`$bs_echo "--trace=$1" |$SED 's%,% --trace=%g'`
|
|
_G_re_macros=`$bs_echo "($1)" |$SED 's%,%|%g'`
|
|
_G_macros="$1"; shift
|
|
test $# -gt 0 || {
|
|
set dummy $configure_ac
|
|
shift
|
|
}
|
|
|
|
# Generate an error if the first file is missing
|
|
<"$1"
|
|
|
|
# Sadly, we can't use `autom4te' tracing to extract macro arguments,
|
|
# because it complains about things we want to ignore at bootstrap
|
|
# time - like missing m4_include files; AC_PREREQ being newer than
|
|
# the installed autoconf; and returns nothing when tracing
|
|
# `AM_INIT_AUTOMAKE' when aclocal hasn't been generated yet.
|
|
#
|
|
# The following tries to emulate a less persnickety version of (and
|
|
# due to not having to wait for Perl startup on every invocation,
|
|
# it's probably faster too):
|
|
#
|
|
# autom4te --language=Autoconf --trace=$my_macro:\$% "$@"
|
|
#
|
|
# First we give a minimal set of macro declarations to M4 to prime
|
|
# it for reading Autoconf macros, while still providing some of the
|
|
# functionality generally used at m4-time to supply dynamic
|
|
# arguments to Autocof functions, but without following
|
|
# `m4_s?include' files.
|
|
_G_mini='
|
|
# Initialisation.
|
|
m4_changequote([,])
|
|
m4_define([m4_copy], [m4_define([$2], m4_defn([$1]))])
|
|
m4_define([m4_rename], [m4_copy([$1], [$2])m4_undefine([$1])])
|
|
|
|
# Disable these macros.
|
|
m4_undefine([m4_dnl])
|
|
m4_undefine([m4_include])
|
|
m4_undefine([m4_m4exit])
|
|
m4_undefine([m4_m4wrap])
|
|
m4_undefine([m4_maketemp])
|
|
|
|
# Copy and rename macros not handled by "m4 --prefix".
|
|
m4_define([dnl], [m4_builtin([dnl])])
|
|
m4_copy([m4_define], [m4_defun])
|
|
m4_rename([m4_ifelse], [m4_if])
|
|
m4_ifdef([m4_mkstemp], [m4_undefine([m4_mkstemp])])
|
|
m4_rename([m4_patsubst], [m4_bpatsubst])
|
|
m4_rename([m4_regexp], [m4_bregexp])
|
|
|
|
# "m4sugar.mini" - useful m4-time macros for dynamic arguments.
|
|
# If we discover packages that need more m4 macros defined in
|
|
# order to bootstrap correctly, add them here:
|
|
m4_define([m4_bmatch],
|
|
[m4_if([$#], 0, [], [$#], 1, [], [$#], 2, [$2],
|
|
[m4_if(m4_bregexp([$1], [$2]), -1,
|
|
[$0([$1], m4_shift3($@))], [$3])])])
|
|
m4_define([m4_ifndef], [m4_ifdef([$1], [$3], [$2])])
|
|
m4_define([m4_ifset],
|
|
[m4_ifdef([$1], [m4_ifval(m4_defn([$1]), [$2], [$3])], [$3])])
|
|
m4_define([m4_require], [$1])
|
|
m4_define([m4_shift3], [m4_shift(m4shift(m4shift($@)))])
|
|
|
|
# "autoconf.mini" - things from autoconf macros we care about.
|
|
m4_copy([m4_defun], [AC_DEFUN])
|
|
|
|
# Dummy definitions for the macros we want to trace.
|
|
# AM_INIT_AUTOMAKE at least produces no trace without this.
|
|
'
|
|
|
|
_G_save=$IFS
|
|
IFS=,
|
|
for _G_macro in $_G_macros; do
|
|
IFS=$_G_save
|
|
func_append _G_mini "AC_DEFUN([$_G_macro])$nl"
|
|
done
|
|
IFS=$_G_save
|
|
|
|
# We discard M4's stdout, but the M4 trace output from reading our
|
|
# "autoconf.mini" followed by any other files passed to this
|
|
# function is then scanned by sed to transform it into a colon
|
|
# delimited argument list assigned to a shell variable.
|
|
_G_transform='s|#.*$||; s|^dnl .*$||; s| dnl .*$||;'
|
|
|
|
# Unfortunately, alternation in regexp addresses doesn't work in at
|
|
# least BSD (and hence Mac OS X) sed, so we have to append a capture
|
|
# and print block for each traced macro to the sed transform script.
|
|
_G_save=$IFS
|
|
IFS=,
|
|
for _G_macro in $_G_macros; do
|
|
IFS=$_G_save
|
|
func_append _G_transform '
|
|
/^m4trace: -1- '"$_G_macro"'/ {
|
|
s|^m4trace: -1- '"$_G_macro"'[([]*||
|
|
s|], [[]|:|g
|
|
s|[])]*$|:|
|
|
s|\(.\):$|\1|
|
|
p
|
|
}'
|
|
done
|
|
IFS=$_G_save
|
|
|
|
# Save the command pipeline results for further use by callers of
|
|
# this function.
|
|
func_extract_trace_result=`$bs_echo "$_G_mini" \
|
|
|$M4 -daq --prefix $_G_m4_traces - "$@" 2>&1 1>/dev/null \
|
|
|$SED -n -e "$_G_transform"`
|
|
}
|
|
|
|
|
|
# func_main [ARG]...
|
|
# ------------------
|
|
func_main ()
|
|
{
|
|
$debug_cmd
|
|
|
|
# Option processing.
|
|
func_options "$@"
|
|
eval set dummy "$func_options_result"; shift
|
|
|
|
# Validate remaining non-option arguments.
|
|
test $# -gt 1 \
|
|
|| func_fatal_help "not enough arguments"
|
|
|
|
# Pass non-option arguments to extraction function.
|
|
func_extract_trace "$@"
|
|
|
|
# Display results.
|
|
test -n "$func_extract_trace_result" \
|
|
&& $bs_echo "$func_extract_trace_result"
|
|
|
|
# The End.
|
|
exit $EXIT_SUCCESS
|
|
}
|
|
|
|
|
|
## --------------------------- ##
|
|
## Actually perform the trace. ##
|
|
## --------------------------- ##
|
|
|
|
# Only call `func_main' if this script was called directly.
|
|
test extract-trace = "$progname" && func_main "$@"
|
|
|
|
# Local variables:
|
|
# mode: shell-script
|
|
# sh-indentation: 2
|
|
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
|
# time-stamp-start: "scriptversion="
|
|
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
|
# time-stamp-time-zone: "UTC"
|
|
# time-stamp-end: "; # UTC"
|
|
# End:
|