Yeehaa, Yahoo, Yipee and the like! Well, there are some significant steps forward since yesterday :) Gosh, it feels good when m4 finally agrees to do what you wanted to :-) I have implemented support for $.@, which is [$1].[$2]. etc. (`.' is the separator, defaults to comma), and for $.*, which is smash($1).smash($2). etc., where `.' defaults to `:', and `smash' singles out all the white spaces. If you required no tracing format, you get `$f:$l:$n:$*', i.e., for instance: ~fu % ~ace/autotrace -m ~ace --trace AC_DEFINE ./aclocal.m4:1694:AC_DEFINE:AFS:1:Define if you have the Andrew File System. configure.in:12:AC_DEFINE:_GNU_SOURCE configure.in:22:AC_DEFINE:_ALL_SOURCE configure.in:23:AC_DEFINE:_POSIX_SOURCE:1:Define if you need to in order for `stat' and other things to work. or even: ~fu % ~ace/autotrace -m ~ace --trace 'AC_OUTPUT:With quotes: $@ without: $*' With quotes: [Makefile doc/Makefile intl/Makefile lib/Makefile man/Makefile m4/Makefile po/Makefile.in src/Makefile tests/Makefile tests/chmod/Makefile tests/cp/Makefile tests/dd/Makefile tests/dircolors/Makefile tests/install/Makefile tests/ln/Makefile tests/ls/Makefile tests/ls-2/Makefile tests/mkdir/Makefile tests/mv/Makefile tests/rm/Makefile tests/rmdir/Makefile tests/shred/Makefile tests/touch/Makefile ] without: Makefile doc/Makefile intl/Makefile lib/Makefile man/Makefile m4/Makefile po/Makefile.in src/Makefile tests/Makefile tests/chmod/Makefile tests/cp/Makefile tests/dd/Makefile tests/dircolors/Makefile tests/install/Makefile tests/ln/Makefile tests/ls/Makefile tests/ls-2/Makefile tests/mkdir/Makefile tests/mv/Makefile tests/rm/Makefile tests/rmdir/Makefile tests/shred/Makefile tests/touch/Makefile worse yet: | /tmp % cat foo | define([foo]) | foo([several | | | lines]) | | foo([a\ | big\ | token]) | /tmp % ~ace/autotrace --trace foo -m ~ace foo | foo:5:foo:several lines | foo:9:foo:abigtoken Bwahaha :) So I think we will be able to start using this in Automake, no? Well, of course there are problems. The first one being that if you trace an m4 builtin, weird things happen. This can be solved by undefining them. Akim PS/ Beware there is a literal ^Q in it, which you need if you want this to work properly. BTW, is it normal that bash does not split around ^A? I found nothing like this in the doc: | ~ace % cat -v /tmp/ifs | list="a^Qb" | IFS="^Q" | for i in $list | do | echo $i | done | | list="a^Ab" | IFS="^A" | for i in $list | do | echo $i | done | ~ace % bash /tmp/ifs | /tmp/ifs: /tmp/ifs: cannot execute binary file Naah, come on, it is not binary! | ~ace % cat -v /tmp/ifs | #! /bin/sh | | list="a^Qb" | IFS="^Q" | for i in $list | do | echo $i | done | | list="a^Ab" | IFS="^A" | for i in $list | do | echo $i | done | ~ace % bash /tmp/ifs | a | b | ab while zsh (with emulate sh) splits it properly. GNU bash, version 2.04.0(1)-beta5 (i386-pc-linux-gnu) Copyright 1999 Free Software Foundation, Inc.
#! @SHELL@ # autoconf -- create `configure' using m4 macros # Copyright (C) 1992, 93, 94, 96, 99, 2000 Free Software Foundation, Inc. # 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 2, 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # If given no args, create `configure' from template file `configure.in'. # With one arg, create a configure script on standard output from # the given template file. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: autoconf [OPTION] ... [TEMPLATE-FILE] Generate a configuration script from a TEMPLATE-FILE if given, or \`configure.in' by default. Output is sent to the standard output if TEMPLATE-FILE is given, else into \`configure'. If the option \`--trace' is used, no configuration script is created. -h, --help print this help, then exit -V, --version print version number, then exit -d, --debug don't remove temporary files -m, --macrodir=DIR directory storing Autoconf's macro files -l, --localdir=DIR directory storing the \`aclocal.m4' file -t, --trace=MACRO report the list of calls to MACRO -o, --output=FILE save output in FILE (stdout is the default) Report bugs to <[EMAIL PROTECTED]>." version="\ autoconf (GNU @PACKAGE@) @VERSION@ Written by David J. MacKenzie. Copyright (C) 1992, 93, 94, 96, 99, 2000 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." help="\ Try \`$me --help' for more information." # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # ac_LF_and_DOT # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` # An uncommon character, used as a separator. separator='' # Find GNU m4. # Handle the case that m4 has moved since we were configured. # It may have been found originally in a build directory. : ${M4=@M4@} case "$M4" in /*) test -f "$M4" || M4=m4 ;; esac # Some non-GNU m4's don't reject the --help option, so give them /dev/null. case `$M4 --help </dev/null 2>&1` in *reload-state*);; *) echo "$me: Autoconf requires GNU m4 1.4 or later" >&2; exit 1 ;; esac # Variables. : ${AC_MACRODIR=@datadir@} : ${AC_ACLOCALDIR=`(aclocal --print-ac-dir) 2>/dev/null`} : ${AWK=@AWK@} debug=false localdir= outfile= # Tasks: # - trace # Trace the first arguments of some macros # - script # Produce the configure script (default) task=script : ${TMPDIR=/tmp} tmpin=$TMPDIR/ac$$.in tmpout=$TMPDIR/ac$$.out silent_m4=$TMPDIR/silent$$.m4 trace_m4=$TMPDIR/trace$$.m4 translate_awk=$TMPDIR/trans$$.awk verbose=: # Parse command line while test $# -gt 0 ; do case "$1" in --version | --vers* | -V ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -d | --debug | --d* ) debug=:; shift ;; --localdir=* | --l*=* ) localdir=`echo "$1" | sed -e 's/^[^=]*=//'` shift ;; --localdir | --l* | -l ) shift test $# -eq 0 && { echo "$help" >&2; exit 1; } localdir="$1" shift ;; --macrodir=* | --m*=* ) AC_MACRODIR=`echo "$1" | sed -e 's/^[^=]*=//'` shift ;; --macrodir | --m* | -m ) shift test $# -eq 0 && { echo "$help" >&2; exit 1; } AC_MACRODIR="$1" shift ;; --install ) task=install shift;; --verbose | --verb* ) verbose=echo shift;; --trace | -t ) task=trace shift traces="$traces$separator$1" shift ;; --trace=* ) task=trace traces="$traces$separator"`echo "$1" | sed -e 's/^[^=]*=//;s/:.*//'` shift ;; --output | -o ) shift outfile="$1" shift ;; --output=* ) outfile=`echo "$1" | sed -e 's/^[^=]*=//'` shift ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) exec >&2 echo "$me: invalid option $1" echo "$help" exit 1 ;; * ) break ;; esac done # Running m4. if test -n "$localdir"; then use_localdir="-I$localdir -DAC_LOCALDIR=$localdir" fi run_m4="$M4 --reload $AC_MACRODIR/autoconf.m4f $use_localdir" case $# in 0) infile=configure.in test $task = script && test "x$outfile" = x && outfile=configure;; 1) infile="$1" ;; *) exec >&2 echo "$me: invalid number of arguments." echo "$help" exit 1 ;; esac $debug || trap 'rm -f $tmpin $tmpout $silent_m4 $trace_m4' 0 1 2 15 if test z$infile = z-; then infile=$tmpin cat >$infile elif test ! -r "$infile"; then echo "$me: $infile: No such file or directory" >&2 exit 1 fi # Output is produced into FD 4. Prepare it. case "x$outfile" in x- | x ) # Output to stdout exec 4>&1 ;; * ) exec 4>$outfile;; esac # Initializations are performed. Proceed to the main task. case $task in ## --------------------- ## ## Generate the script. ## ## --------------------- ## script) $run_m4 $infile > $tmpout || exit 2 # You could add your own prefixes to pattern if you wanted to check for # them too, e.g. pattern='\(AC_\|ILT_\)', except that UNIX sed doesn't do # alternation. pattern="A[CHM]_" status=0 if grep "^[^#]*$pattern" $tmpout > /dev/null 2>&1; then echo "autoconf: Undefined macros:" >&2 sed -n "s/^[^#]*\\($pattern[_A-Za-z0-9]*\\).*/\\1/p" $tmpout | while read macro; do grep -n "^[^#]*$macro" $infile /dev/null test $? -eq 1 && echo "***BUG in Autoconf--please report*** $macro" done | sort -u >&2 status=1 fi if test -n "$outfile"; then chmod +x $outfile fi # Put the real line numbers into configure to make config.log more helpful. # Because quoting can sometimes get really painful in m4, there are special # @tokens@ to substitute. sed -e 's/[ ]*$//' <$tmpout | sed -e '/^$/N;/\n$/D' | $AWK ' /__oline__/ { printf "%d:", NR + 1 } { print }' | sed ' /__oline__/s/^\([0-9][0-9]*\):\(.*\)__oline__/\2\1/ s/@BKL@/[/g s/@BKR@/]/g s/@DLR@/$/g s/@PND@/#/g ' >&4 ;; # End of the task script. ## -------------- ## ## Trace macros. ## ## -------------- ## trace) # errprint must be silent when we run `m4 --trace', otherwise there can be # warnings mixed with traces in m4's stderr. cat >$silent_m4 <<\EOF define(`errprint')dnl EOF # A program to trace m4 macros. cat >$trace_m4 <<\EOF divert(-1) changequote([, ]) define([_at], [ifelse([$#], [1], [], [$#], [2], [[[$2]]], [[[$2]][$1]_at([$1], shift(shift($@)))])]) define([_star], [ifelse([$#], [1], [], [$#], [2], [smash([$2])], [smash([$2])[$1]_star([$1], shift(shift($@)))])]) define([smash], [patsubst(patsubst(patsubst(patsubst([[[[$1]]]], [\\ ]), [[ ]+], [ ]), [^\(..\) ], [\1]), [ \(.\)$], [\1])]) define([args], [shift(shift(shift(shift(shift($@)))))]) define([at], [_at([$1], args($@))]) define([star], [_star([$1], args($@))]) EOF # A program to translate user tracing requests into m4 macros. cat >$translate_awk <<\EOF BEGIN { # File name. trans["f"] = "$1"; # Line number. trans["l"] = "$2"; # Depth. trans["d"] = "$3"; # Name (also available as $0). trans["n"] = "$4"; # Escaped dollar. trans["$"] = "$"; # $@, list of quoted effective arguments. trans["@"] = "]at([,], $@)["; # $*, list of unquoted effective arguments. trans["*"] = "]star([:], $@)["; } { res = ""; for (cp = $0; cp; cp = substr(cp, 2)) { char = substr (cp, 1, 1); if (char == "$") { if (match (cp, /^\$[0-9]+/)) { # $n -> $(n + 4) res = res "$" (substr (cp, 2, RLENGTH - 1) + 4); cp = substr (cp, RLENGTH); } else if (substr (cp, 2, 1) ~ /[fldn$@*]/) { res = res trans[substr (cp, 2, 1)]; cp = substr(cp, 2); } else if (substr (cp, 3, 1) == "@") { res = res "]at([" substr (cp, 2, 1) "], $@)["; cp = substr(cp, 3); } else if (substr (cp, 3, 1) == "*") { res = res "]star([" substr (cp, 2, 1) "], $@)["; cp = substr(cp, 3); } else { print "unrecognized escape: " substr (cp, 1, 2) >"/dev/stderr"; exit 1 } } else res = res char; } print res; } EOF # Extract both the m4 program and the m4 options from TRACES. saved_IFS=$IFS IFS=$separator for trace in $traces do test -z "$trace" && continue IFS=$saved_IFS # The request may have several lines long, hence sed has to quit. trace_opt="$trace_opt -t "`echo "$trace" | sed -e 's/:.*//;q'` case "$trace" in *:*) # The `]])' are closing the `define' which is started by sed. # This is to cope with multiple line requests. echo "$trace]])" | sed -e '1s/^\([^:]*\):\(.*\)$/define([AT_\1], [[\2/';; *) # Default request. echo "define([AT_$trace], [[\$f:\$l:\$n:\$*]])";; esac | $AWK -f $translate_awk >> $trace_m4 done echo "divert(0)dnl" >> $trace_m4 # Run m4 on the input file to get traces. # We don't use the frozen files because we want to redefine `errprint', # and because we want to be to trace AC_DEFUN and others. $M4 $trace_opt -daflq -I $AC_MACRODIR \ $silent_m4 autoconf.m4 $infile 2>&1 >/dev/null | sed -e 's/^m4trace:\([^:][^:]*\):\([0-9][0-9]*\): -\([0-9][0-9]*\)- \([^(][^(]*\)(\(.*\)$/AT_\4([\1], [\2], [\3], [\4], \5/' \ -e 's/^m4trace:\([^:][^:]*\):\([0-9][0-9]*\): -\([0-9][0-9]*\)- \(.*\)$/AT_\4([\1], [\2], [\3], [\4])/' >>$trace_m4 # Now we are ready to run m4 to process the trace file. m4 $trace_m4 >&4 ;; ## -------------------------------------------------------- ## ## Task --install. Install links to the library m4 files. ## ## -------------------------------------------------------- ## install) # An m4 program that reports what macros are requested, and where # they were defined. cat >$tmpin <<\EOF dnl Keep the definition of the old AC_DEFUN define([AC_DEFUN_OLD], defn([AC_DEFUN])) dnl Define the macro so that the first time it is expanded, it reports dnl on stderr its name, and where it was defined. define([AC_DEFUN], [AC_DEFUN_OLD([$1], [ifdef([AC_DECLARED{$1}],, [define([AC_DECLARED{$1}])errprint(]]__file__:__line__:[[ [$1] )])dnl ][$2])]) dnl All the includes must be disabled. If they are not, since people don't dnl protect the first argument of AC_DEFUN, then, if read a second time dnl this argument will be expanded, and we'll get pure junk out of m4. define([AC_INCLUDE]) EOF # Run m4 with all the library files, save its report on strderr. $verbose Running $run_m4 -dipa -t m4_include -t m4_sinclude $tmpin $localdir/*.m4 $AC_ACLOCALDIR/*.m4 $infile $run_m4 -dipa -t m4_include -t m4_sinclude $tmpin $localdir/*.m4 $AC_ACLOCALDIR/*.m4 $infile >the-script 2>$tmpout # Keep only the good lines, there may be other outputs grep '^[^: ]*:[0-9][0-9]*:[^:]*$' $tmpout >$tmpin # Extract the files that are not in the local dir, and install the links. # Save in $tmpout the list of installed links. >$tmpout $verbose "Required macros:" $verbose "`sed -e 's/^/| /' $tmpin`" cat $tmpin | while read line do file=`echo "$line" | sed -e 's/:.*//'` filename=`echo "$file" | sed -e 's,.*/,,'` macro=`echo "$line" | sed -e 's/.*:[ ]*//'` if test -f "$file" && test "x$file" != "x$infile"; then if test -f $localdir/$filename; then $verbose "$filename already installed" else $verbose "installing $file which provides $macro" ln -s "$file" "$localdir/$filename" || cp "$file" "$localdir/$filename" || { echo "$me: cannot link from $file to $localdir/$filename" >&2 exit 1 } fi echo "$localdir/$filename" >>$tmpout fi done # Now that we have installed the links, and that we know that the # user needs the FILES, check that there is an exact correspondence. # Use yourself to get the list of the included files. export AC_ACLOCALDIR export AC_MACRODIR # Not m4_s?include, because it would catch acsite and aclocal, which # we don't care of. $0 -l "$localdir" -t AC_INCLUDE $inline | sed -e 's/^[^:]*:[^:]*:[^:]*://g' | sort | uniq >$tmpin # All the included files are needed. for file in `cat $tmpin`; do if fgrep "$file" $tmpout >/dev/null 2>&1; then :; else echo "\`$file' is uselessly included" >&2 fi done # All the needed files are included. for file in `sort $tmpout | uniq`; do if fgrep "$file" $tmpin >/dev/null 2>&1; then :; else echo "\`$file' is not included" >&2 fi done ;; ## ------------ ## ## Unknown task ## ## ------------ ## *)echo "$me: internal error: unknown task: $task" >&2 exit 1 esac exit $status