* autoconf.in ($automate): New var.
(task script): Use autom4te.
* autom4te.in (File::Spec): Use it.
(&find_file): New.
(&parse_args): --warning is -W, not -w.
Find the top level files.
(&handle_m4): Pass the warnings flags.
Don't report verbosely m4's failures, unless requested.
(&handle_output): Don't complain for forbidden tokens in comments.
Be sure to report all the forbidden tokens within a single line.
(&trace_format_to_m4): Preserve `$_'.
(&handle_traces): Sort the output macros.
(&up_to_date_p): Find the files before trying to get its time stamp.
* Status
- /*--------------------------.
- | Good for production use. |
- `--------------------------*/
+ /*----------------------------------.
+ | Don't use it for production use. |
+ `----------------------------------*/
+
+* Serious bugs
+
+** `make check' requires `make install'
+Currently autoconf requires autom4te to be installed. This is very
+bad, but will be fixed. In order to use this version of Autoconf, you
+will first have to `make install'.
+2001-07-24 Akim Demaille <akim@epita.fr>
+
+ Let autoconf use autom4te to create configure.
+
+ * autoconf.in ($automate): New var.
+ (task script): Use autom4te.
+ * autom4te.in (File::Spec): Use it.
+ (&find_file): New.
+ (&parse_args): --warning is -W, not -w.
+ Find the top level files.
+ (&handle_m4): Pass the warnings flags.
+ Don't report verbosely m4's failures, unless requested.
+ (&handle_output): Don't complain for forbidden tokens in comments.
+ Be sure to report all the forbidden tokens within a single line.
+ (&trace_format_to_m4): Preserve `$_'.
+ (&handle_traces): Sort the output macros.
+ (&up_to_date_p): Find the files before trying to get its time stamp.
+
2001-07-24 Akim Demaille <akim@epita.fr>
* Makefile.am: Ship, build and install Autom4te.
-e 's,@prefix\@,$(prefix),g' \
-e 's,@autoconf-name\@,'`echo autoconf | sed '$(transform)'`',g' \
-e 's,@autoheader-name\@,'`echo autoheader | sed '$(transform)'`',g' \
+ -e 's,@autom4te-name\@,'`echo autom4te | sed '$(transform)'`',g' \
-e 's,@M4\@,$(M4),g' \
-e 's,@AWK\@,$(AWK),g' \
-e 's,@VERSION\@,$(VERSION),g' \
MAINTAINERCLEANFILES = acversion.m4 INSTALL.txt
-edit = sed -e 's,@SHELL\@,$(SHELL),g' -e 's,@PERL\@,$(PERL),g' -e 's,@bindir\@,$(bindir),g' -e 's,@datadir\@,$(pkgdatadir),g' -e 's,@prefix\@,$(prefix),g' -e 's,@autoconf-name\@,'`echo autoconf | sed '$(transform)'`',g' -e 's,@autoheader-name\@,'`echo autoheader | sed '$(transform)'`',g' -e 's,@M4\@,$(M4),g' -e 's,@AWK\@,$(AWK),g' -e 's,@VERSION\@,$(VERSION),g' -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g'
+edit = sed -e 's,@SHELL\@,$(SHELL),g' -e 's,@PERL\@,$(PERL),g' -e 's,@bindir\@,$(bindir),g' -e 's,@datadir\@,$(pkgdatadir),g' -e 's,@prefix\@,$(prefix),g' -e 's,@autoconf-name\@,'`echo autoconf | sed '$(transform)'`',g' -e 's,@autoheader-name\@,'`echo autoheader | sed '$(transform)'`',g' -e 's,@autom4te-name\@,'`echo autom4te | sed '$(transform)'`',g' -e 's,@M4\@,$(M4),g' -e 's,@AWK\@,$(AWK),g' -e 's,@VERSION\@,$(VERSION),g' -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g'
prev_version_file = $(srcdir)/config/prev-version.txt
fi
+# We test "$dir/autom4te" in case we are in the build tree, in which case
+# the names are not transformed yet.
+for autom4te in "$AUTOM4TE" \
+ "$dir/@autom4te-name@" \
+ "$dir/autom4te" \
+ "@bindir@/@autom4te-name@"; do
+ test -f "$autom4te" && break
+done
+
+
# Variables.
: ${autoconf_dir=${AC_MACRODIR=@datadir@}}
test -z "$AC_ACLOCALDIR" &&
esac
done
-# The warnings are the concatenation of 1. application's defaults,
-# 2. $WARNINGS, $3 command line options, in that order.
-# Set them in the order expected by the M4 macros: the converse.
-alphabet='abcdefghijklmnopqrstuvwxyz'
-ALPHABET='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-NUMBERS='0123456789'
-WORDCHAR=_$alphabet$ALPHABET$NUMBERS
-
-m4_warnings=
-for warning in `IFS=,; echo syntax $WARNINGS $warnings |
- tr $ALPHABET $alphabet`
-do
- test -n $warning || continue
- m4_warnings="$warning"`test -n "$m4_warnings" && echo ",$m4_warnings"`
-done
-
-
# Trap on 0 to stop playing with `rm'.
$debug ||
{
m4f_prefiles="--reload-state=$autoconf_dir/autoconf.m4f $acsite_m4 $aclocal_m4"
run_m4="$M4 $m4_common"
+# Running autom4te.
+run_autom4te="$autom4te "\
+`$verbose "--verbose "`\
+`$debug && echo "--debug "`\
+"--include $autoconf_dir --include $localdir "\
+"--warning syntax,$warnings "\
+"autoconf.m4"`$initialization || echo f`" "\
+"$acsite_m4 "\
+"$aclocal_m4 "
+
# Find the input file.
case $# in
0)
(exit 1); exit 1
fi
-# Output is produced into FD 4. Prepare it.
-case $outfile in
- -) # Output to stdout
- exec 4>&1 ;;
- * )
- exec 4>$outfile;;
-esac
-
# Initializations are performed. Proceed to the main task.
case $task in
# M4 expansion.
: >$tmp/forbidden.rx
: >$tmp/allowed.rx
- $verbose "$me: running $run_m4 -Dm4_warnings=$m4_warnings $m4f_prefiles $infile" >&2
- $run_m4 -Dm4_warnings=$m4_warnings $m4f_prefiles $infile >$tmp/configure ||
+ $verbose "$me: running $run_autom4te $infile --output $outfile" >&2
+ $run_autom4te $infile --output $outfile ||
{ (exit 1); exit 1; }
if test "x$outfile" != x-; 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 's/^ //' >"$tmp/finalize.awk" <<EOF
- # Load the list of tokens which escape the forbidden patterns.
- BEGIN {
- # Be sure the read GAWK documentation to understand the parens
- # around \`tmp "/forbidden.rx"'.
- while ((getline pattern < (tmp "/forbidden.rx")) > 0)
- forbidden = (forbidden ? forbidden "|" : "") pattern
- close (tmp "/forbidden.rx")
- if (verbose)
- errprint("$me: forbidden: " forbidden)
-
- while ((getline pattern < (tmp "/allowed.rx")) > 0)
- allowed = (allowed ? allowed "|" : "") pattern
- if (!allowed)
- allowed = "^$"
- close (tmp "/allowed.rx")
- if (verbose)
- errprint("$me: allowed: " allowed)
- }
-
- function errprint (message)
- {
- # BAD! the pipe to 'cat >&2' doesn't work for DJGPP.
- # print message | "cat >&2"
- # Use normal redirection instead:
- print message > "$tmp/finalize.err"
- }
-
- function undefined (file, line, macro)
- {
- errprint(file ":" line ": error: possibly undefined macro: " macro)
- }
-
- # Body.
- {
- sub (/[ \t]*$/, "")
- if (\$0 == "")
- {
- if (!duplicate)
- {
- oline++
- print
- }
- duplicate = 1
- next
- }
- duplicate = 0
- oline++
- if (\$0 ~ /__oline__/)
- while (sub (/__oline__/, oline))
- continue
- while (sub (/@<:@/, "["))
- continue
- while (sub (/@:>@/, "]"))
- continue
- while (sub (/@S\|@/, "$"))
- continue
- while (sub (/@%:@/, "#"))
- continue
-
- print
-
- # Dubious feature: we tolerate macro names when commented.
- sub (/#.*/, "")
-
- # Get the tokens.
- split (\$0, tokens, /[^$WORDCHAR]*/)
-
- for (token in tokens)
- if (match (tokens[token], forbidden) &&
- !match (tokens[token], allowed))
- {
- macros [tokens [token]] = oline
- some_macros_were_not_expanded = 1
- }
- }
-
- # If there are some macros which are left unexpanded in the output,
- # try to find the input which is responsible. Otherwise, try to help.
- END {
- if (some_macros_were_not_expanded)
- {
- line = 0
- while (getline < "$infile")
- {
- line++
- for (macro in macros)
- if (index (\$0, macro))
- {
- delete macros [macro]
- undefined("$infile", line, macro)
- }
- }
- close ("$infile")
- for (macro in macros)
- undefined("$outfile", macros [macro], macro)
- exit 1
- }
- }
-EOF
- $AWK -v tmp="$tmp" \
- `$verbose "-v verbose=1"` \
- -f "$tmp/finalize.awk" <$tmp/configure >&4 ||
- { test -f "$tmp/finalize.err" && cat "$tmp/finalize.err" >&2
- (exit 1); exit 1; }
- test -f "$tmp/finalize.err" && cat "$tmp/finalize.err" >&2
;; # End of the task script.
(exit 1); exit 1
}
+ # Output is produced into FD 4. Prepare it.
+ case $outfile in
+ -) # Output to stdout
+ exec 4>&1 ;;
+ * )
+ exec 4>$outfile;;
+ esac
+
$verbose "$me: running $M4 $tmp/trace.m4" >&2
sed -f $tmp/trace2m4.sed $tmp/traces |
# Now we are ready to run m4 to process the trace file.
-include(m4sh.m4)# -*- Autoconf -*-
+changequote()changequote([, ])include(m4sh.m4)# -*- Autoconf -*-
# This file is part of Autoconf.
# Driver that loads the Autoconf macro files.
# Copyright 1994, 1999, 2000, 2001 Free Software Foundation, Inc.
use Carp;
use Getopt::Long;
use IO::File;
+use File::Spec;
use strict;
# List of requests.
my $output = '-';
my @warning;
+# M4 include path.
my @include;
+# 0 for EXIT_SUCCESS.
+my $exit_status = 0;
+
# $M4.
my $m4 = $ENV{"M4"} || '@M4@';
# Some non-GNU m4's don't reject the --help option, so give them /dev/null.
(system $command) == 0
or die ("$me: "
. (split (' ', $command))[0]
- . " failed with exit status: $?\n");
+ . " failed with exit status: "
+ . ($? >> 8)
+ . "\n");
}
+
+# $FILENAME
+# find_file ($FILENAME)
+# ---------------------
+# We match exactly the behavior of GNU m4: first look in the current
+# directory (which includes the case of absolute file names), and, if
+# the file is not absolute, just fail. Otherwise, look in the path.
+sub find_file ($)
+{
+ my ($filename) = @_;
+
+ return File::Spec->canonpath ($filename)
+ if -f $filename;
+
+ die "$me: no such for or directory: $filename\n"
+ if File::Spec->file_name_is_absolute ($filename);
+
+ foreach my $path (@include)
+ {
+ return File::Spec->canonpath (File::Spec->catfile ($path, $filename))
+ if -f File::Spec->catfile ($path, $filename)
+ }
+
+ die "$me: programming error";
+}
+
+
# print_usage ()
# --------------
# Display usage (--help).
"v|verbose" => \$verbose,
"d|debug" => \$debug,
"o|output=s" => \$output,
- "w|warnings=s" => \@warning,
+ "W|warnings=s" => \@warning,
# Library directories:
"I|include=s" => \@include,
die "$me: too few arguments
Try `$me --help' for more information.\n"
unless @ARGV;
+
+ # We don't want to depend upon m4's --include to find the top level
+ # files. Try to get a canonical name, as it's a key for caching.
+ for (my $i = 0; $i < $#ARGV; ++$i)
+ {
+ $ARGV[$i] = find_file ($ARGV[$i]);
+ }
}
# handle_m4 ($REQ, @TRACE)
# ------------------------
# Run m4 on the input files, and save the traces on the @TRACE macros.
-sub handle_m4 ($%)
+sub handle_m4 ($@)
{
my ($req, @trace) = @_;
+ # Find the files. We don't want to depend upon m4's --include.
# *.m4f files have to be reloaded.
my $files;
foreach (@ARGV)
$files .= "$_";
}
+ # The warnings are the concatenation of 1. application's defaults,
+ # 2. $WARNINGS, $3 command line options, in that order.
+ # Set them in the order expected by the M4 macros: the converse.
+ my $m4_warnings =
+ lc join (',', reverse (split (',', ($ENV{'WARNINGS'} || '')),
+ map { split /,/ } @warning));
+
# GNU m4 appends when using --error-output.
unlink ("$me.cache/" . $req->cache);
# Run m4.
- xsystem ("$m4"
- . " --define m4_tmpdir=$tmp"
- . " --define m4_warnings=" # FIXME: Pass the warnings.
- . ' --debug=aflq'
- . " --error-output=$me.cache/" . $req->cache
- . join (' --trace=', '', @trace)
- . join (' --include=', '', @include)
- . $files
- . " >$tmp/output");
+ my $command = ("$m4"
+ . " --define m4_tmpdir=$tmp"
+ . " --define m4_warnings=$m4_warnings"
+ . ' --debug=aflq'
+ . " --error-output=$me.cache/" . $req->cache
+ . join (' --trace=', '', @trace)
+ . join (' --include=', '', @include)
+ . $files
+ . " >$tmp/output");
+ verbose "running: $command";
+ system $command;
+ if ($?)
+ {
+ verbose "$m4: failed with exit status: " . ($? >> 8) . "\n";
+ exit $? >> 8;
+ }
}
print $out "$_\n";
- foreach (split ('\W+'))
+ # Don't complain in comments. Well, until we have something
+ # better, don't consider `#include' etc. are comments.
+ s/\#.*//
+ unless /^\#(if|include|endif|ifdef|ifndef|define)\b/;
+ foreach (split (/\W+/))
{
$prohibited{$_} = $oline
if /$forbidden/ && !/$allowed/;
}
}
- if (%prohibited)
+ # If no forbidden words, we're done.
+ return
+ if ! %prohibited;
+
+ # Locate the forbidden words in the last source file.
+ # This is unsatisfying but...
+ my $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
+ my $file = new IO::File ($ARGV[$#ARGV])
+ or die "$me: cannot open $ARGV[$#ARGV]: $!\n";
+ $exit_status = 1;
+
+ while ($_ = $file->getline)
{
- my $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
- my $in = new IO::File ($ARGV[$#ARGV])
- or die "$me: cannot open $ARGV[$#ARGV]: $!\n";
+ # Don't complain in comments. Well, until we have something
+ # better, don't consider `#include' etc. are comments.
+ s/\#.*//
+ unless /^\#(if|include|endif|ifdef|ifndef|define)\b/;
- while ($_ = $in->getline)
- {
- if (/$prohibited/)
- {
- warn "$ARGV[$#ARGV]: $.: undefined macro: $1\n"
- if exists $prohibited{$1};
- delete $prohibited{$1};
- }
- }
- foreach (keys %prohibited)
+ # Complain once per word, but possibly several times per line.
+ while (/$prohibited/)
{
- warn "$output: $prohibited{$_}: undefined macro: $_\n";
+ warn "$ARGV[$#ARGV]:$.: error: possibly undefined macro: $1\n";
+ delete $prohibited{$1};
+ # If we're done, exit.
+ return
+ if ! %prohibited;
+ $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
}
}
+ warn "$output:$prohibited{$_}: error: possibly undefined macro: $_\n"
+ foreach (keys %prohibited);
}
sub trace_format_to_m4 ($)
{
my ($format) = @_;
+ my ($underscore) = $_;
my %escape = (# File name.
'f' => '$1',
# Line number.
}
}
+ $_ = $underscore;
return '[[' . $res . ']]';
}
}
}
- verbose "formatting traces for `$output': ", join (', ', keys %trace);
+ verbose "formatting traces for `$output': ", join (', ', sort keys %trace);
# Processing the traces.
my $trace_m4 = new IO::File (">$tmp/traces.m4")
"## -------------------------------------- ##\n",
"\n";
print $trace_m4 "at_define([AT_$_], [at_dnl])\n"
- foreach (keys %{$req->macro});
+ foreach (sort keys %{$req->macro});
print $trace_m4 "\n";
# Implement traces for current requests (%TRACE).
"## Trace processing macros. ##\n",
"## ------------------------- ##\n",
"\n";
- foreach my $key (keys %trace)
+ foreach (sort keys %trace)
{
- print $trace_m4 "at_define([AT_$key],\n";
- print $trace_m4 trace_format_to_m4 ($trace{$key}) . ")\n\n";
+ # Trace request can be embed \n.
+ (my $comment = "Trace $_:$trace{$_}") =~ s/^/\# /;
+ print $trace_m4 "$comment\n";
+ print $trace_m4 "at_define([AT_$_],\n";
+ print $trace_m4 trace_format_to_m4 ($trace{$_}) . ")\n\n";
}
print $trace_m4 "\n";
# Single line traces, as the example above.
s{^m4trace:(.+):(\d+): -(\d+)- (.*)$}
{AT_$4([$1], [$2], [$3], [$4]};
-
print $trace_m4 "$_";
}
$trace_m4->close;
# Files may include others. We can use traces since we just checked
# if they are available.
- handle_traces ($req, "$tmp/dependencies", ('include' => '$1'));
+ # If $FILE is younger than one of its dependencies, it is outdated.
+ handle_traces ($req, "$tmp/dependencies",('include' => '$1'));
+ my $mtime = (stat ($file))[9];
my $deps = new IO::File ("$tmp/dependencies");
while ($_ = $deps->getline)
{
chop;
- push @dep, $_;
- }
-
- # If $FILE is younger than one of its dependencies, it is outdated.
- my $mtime = (stat ($file))[9];
- foreach (@dep)
- {
+ $_ = find_file ($_);
+ verbose "$file depends on $_";
if ($mtime < (stat ($_))[9])
{
verbose "$file depends on $_ which is more recent";
Request->save ("$me.cache/requests");
-exit 0;
+exit $exit_status;
fi
+# We test "$dir/autom4te" in case we are in the build tree, in which case
+# the names are not transformed yet.
+for autom4te in "$AUTOM4TE" \
+ "$dir/@autom4te-name@" \
+ "$dir/autom4te" \
+ "@bindir@/@autom4te-name@"; do
+ test -f "$autom4te" && break
+done
+
+
# Variables.
: ${autoconf_dir=${AC_MACRODIR=@datadir@}}
test -z "$AC_ACLOCALDIR" &&
esac
done
-# The warnings are the concatenation of 1. application's defaults,
-# 2. $WARNINGS, $3 command line options, in that order.
-# Set them in the order expected by the M4 macros: the converse.
-alphabet='abcdefghijklmnopqrstuvwxyz'
-ALPHABET='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-NUMBERS='0123456789'
-WORDCHAR=_$alphabet$ALPHABET$NUMBERS
-
-m4_warnings=
-for warning in `IFS=,; echo syntax $WARNINGS $warnings |
- tr $ALPHABET $alphabet`
-do
- test -n $warning || continue
- m4_warnings="$warning"`test -n "$m4_warnings" && echo ",$m4_warnings"`
-done
-
-
# Trap on 0 to stop playing with `rm'.
$debug ||
{
m4f_prefiles="--reload-state=$autoconf_dir/autoconf.m4f $acsite_m4 $aclocal_m4"
run_m4="$M4 $m4_common"
+# Running autom4te.
+run_autom4te="$autom4te "\
+`$verbose "--verbose "`\
+`$debug && echo "--debug "`\
+"--include $autoconf_dir --include $localdir "\
+"--warning syntax,$warnings "\
+"autoconf.m4"`$initialization || echo f`" "\
+"$acsite_m4 "\
+"$aclocal_m4 "
+
# Find the input file.
case $# in
0)
(exit 1); exit 1
fi
-# Output is produced into FD 4. Prepare it.
-case $outfile in
- -) # Output to stdout
- exec 4>&1 ;;
- * )
- exec 4>$outfile;;
-esac
-
# Initializations are performed. Proceed to the main task.
case $task in
# M4 expansion.
: >$tmp/forbidden.rx
: >$tmp/allowed.rx
- $verbose "$me: running $run_m4 -Dm4_warnings=$m4_warnings $m4f_prefiles $infile" >&2
- $run_m4 -Dm4_warnings=$m4_warnings $m4f_prefiles $infile >$tmp/configure ||
+ $verbose "$me: running $run_autom4te $infile --output $outfile" >&2
+ $run_autom4te $infile --output $outfile ||
{ (exit 1); exit 1; }
if test "x$outfile" != x-; 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 's/^ //' >"$tmp/finalize.awk" <<EOF
- # Load the list of tokens which escape the forbidden patterns.
- BEGIN {
- # Be sure the read GAWK documentation to understand the parens
- # around \`tmp "/forbidden.rx"'.
- while ((getline pattern < (tmp "/forbidden.rx")) > 0)
- forbidden = (forbidden ? forbidden "|" : "") pattern
- close (tmp "/forbidden.rx")
- if (verbose)
- errprint("$me: forbidden: " forbidden)
-
- while ((getline pattern < (tmp "/allowed.rx")) > 0)
- allowed = (allowed ? allowed "|" : "") pattern
- if (!allowed)
- allowed = "^$"
- close (tmp "/allowed.rx")
- if (verbose)
- errprint("$me: allowed: " allowed)
- }
-
- function errprint (message)
- {
- # BAD! the pipe to 'cat >&2' doesn't work for DJGPP.
- # print message | "cat >&2"
- # Use normal redirection instead:
- print message > "$tmp/finalize.err"
- }
-
- function undefined (file, line, macro)
- {
- errprint(file ":" line ": error: possibly undefined macro: " macro)
- }
-
- # Body.
- {
- sub (/[ \t]*$/, "")
- if (\$0 == "")
- {
- if (!duplicate)
- {
- oline++
- print
- }
- duplicate = 1
- next
- }
- duplicate = 0
- oline++
- if (\$0 ~ /__oline__/)
- while (sub (/__oline__/, oline))
- continue
- while (sub (/@<:@/, "["))
- continue
- while (sub (/@:>@/, "]"))
- continue
- while (sub (/@S\|@/, "$"))
- continue
- while (sub (/@%:@/, "#"))
- continue
-
- print
-
- # Dubious feature: we tolerate macro names when commented.
- sub (/#.*/, "")
-
- # Get the tokens.
- split (\$0, tokens, /[^$WORDCHAR]*/)
-
- for (token in tokens)
- if (match (tokens[token], forbidden) &&
- !match (tokens[token], allowed))
- {
- macros [tokens [token]] = oline
- some_macros_were_not_expanded = 1
- }
- }
-
- # If there are some macros which are left unexpanded in the output,
- # try to find the input which is responsible. Otherwise, try to help.
- END {
- if (some_macros_were_not_expanded)
- {
- line = 0
- while (getline < "$infile")
- {
- line++
- for (macro in macros)
- if (index (\$0, macro))
- {
- delete macros [macro]
- undefined("$infile", line, macro)
- }
- }
- close ("$infile")
- for (macro in macros)
- undefined("$outfile", macros [macro], macro)
- exit 1
- }
- }
-EOF
- $AWK -v tmp="$tmp" \
- `$verbose "-v verbose=1"` \
- -f "$tmp/finalize.awk" <$tmp/configure >&4 ||
- { test -f "$tmp/finalize.err" && cat "$tmp/finalize.err" >&2
- (exit 1); exit 1; }
- test -f "$tmp/finalize.err" && cat "$tmp/finalize.err" >&2
;; # End of the task script.
(exit 1); exit 1
}
+ # Output is produced into FD 4. Prepare it.
+ case $outfile in
+ -) # Output to stdout
+ exec 4>&1 ;;
+ * )
+ exec 4>$outfile;;
+ esac
+
$verbose "$me: running $M4 $tmp/trace.m4" >&2
sed -f $tmp/trace2m4.sed $tmp/traces |
# Now we are ready to run m4 to process the trace file.
use Carp;
use Getopt::Long;
use IO::File;
+use File::Spec;
use strict;
# List of requests.
my $output = '-';
my @warning;
+# M4 include path.
my @include;
+# 0 for EXIT_SUCCESS.
+my $exit_status = 0;
+
# $M4.
my $m4 = $ENV{"M4"} || '@M4@';
# Some non-GNU m4's don't reject the --help option, so give them /dev/null.
(system $command) == 0
or die ("$me: "
. (split (' ', $command))[0]
- . " failed with exit status: $?\n");
+ . " failed with exit status: "
+ . ($? >> 8)
+ . "\n");
}
+
+# $FILENAME
+# find_file ($FILENAME)
+# ---------------------
+# We match exactly the behavior of GNU m4: first look in the current
+# directory (which includes the case of absolute file names), and, if
+# the file is not absolute, just fail. Otherwise, look in the path.
+sub find_file ($)
+{
+ my ($filename) = @_;
+
+ return File::Spec->canonpath ($filename)
+ if -f $filename;
+
+ die "$me: no such for or directory: $filename\n"
+ if File::Spec->file_name_is_absolute ($filename);
+
+ foreach my $path (@include)
+ {
+ return File::Spec->canonpath (File::Spec->catfile ($path, $filename))
+ if -f File::Spec->catfile ($path, $filename)
+ }
+
+ die "$me: programming error";
+}
+
+
# print_usage ()
# --------------
# Display usage (--help).
"v|verbose" => \$verbose,
"d|debug" => \$debug,
"o|output=s" => \$output,
- "w|warnings=s" => \@warning,
+ "W|warnings=s" => \@warning,
# Library directories:
"I|include=s" => \@include,
die "$me: too few arguments
Try `$me --help' for more information.\n"
unless @ARGV;
+
+ # We don't want to depend upon m4's --include to find the top level
+ # files. Try to get a canonical name, as it's a key for caching.
+ for (my $i = 0; $i < $#ARGV; ++$i)
+ {
+ $ARGV[$i] = find_file ($ARGV[$i]);
+ }
}
# handle_m4 ($REQ, @TRACE)
# ------------------------
# Run m4 on the input files, and save the traces on the @TRACE macros.
-sub handle_m4 ($%)
+sub handle_m4 ($@)
{
my ($req, @trace) = @_;
+ # Find the files. We don't want to depend upon m4's --include.
# *.m4f files have to be reloaded.
my $files;
foreach (@ARGV)
$files .= "$_";
}
+ # The warnings are the concatenation of 1. application's defaults,
+ # 2. $WARNINGS, $3 command line options, in that order.
+ # Set them in the order expected by the M4 macros: the converse.
+ my $m4_warnings =
+ lc join (',', reverse (split (',', ($ENV{'WARNINGS'} || '')),
+ map { split /,/ } @warning));
+
# GNU m4 appends when using --error-output.
unlink ("$me.cache/" . $req->cache);
# Run m4.
- xsystem ("$m4"
- . " --define m4_tmpdir=$tmp"
- . " --define m4_warnings=" # FIXME: Pass the warnings.
- . ' --debug=aflq'
- . " --error-output=$me.cache/" . $req->cache
- . join (' --trace=', '', @trace)
- . join (' --include=', '', @include)
- . $files
- . " >$tmp/output");
+ my $command = ("$m4"
+ . " --define m4_tmpdir=$tmp"
+ . " --define m4_warnings=$m4_warnings"
+ . ' --debug=aflq'
+ . " --error-output=$me.cache/" . $req->cache
+ . join (' --trace=', '', @trace)
+ . join (' --include=', '', @include)
+ . $files
+ . " >$tmp/output");
+ verbose "running: $command";
+ system $command;
+ if ($?)
+ {
+ verbose "$m4: failed with exit status: " . ($? >> 8) . "\n";
+ exit $? >> 8;
+ }
}
print $out "$_\n";
- foreach (split ('\W+'))
+ # Don't complain in comments. Well, until we have something
+ # better, don't consider `#include' etc. are comments.
+ s/\#.*//
+ unless /^\#(if|include|endif|ifdef|ifndef|define)\b/;
+ foreach (split (/\W+/))
{
$prohibited{$_} = $oline
if /$forbidden/ && !/$allowed/;
}
}
- if (%prohibited)
+ # If no forbidden words, we're done.
+ return
+ if ! %prohibited;
+
+ # Locate the forbidden words in the last source file.
+ # This is unsatisfying but...
+ my $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
+ my $file = new IO::File ($ARGV[$#ARGV])
+ or die "$me: cannot open $ARGV[$#ARGV]: $!\n";
+ $exit_status = 1;
+
+ while ($_ = $file->getline)
{
- my $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
- my $in = new IO::File ($ARGV[$#ARGV])
- or die "$me: cannot open $ARGV[$#ARGV]: $!\n";
+ # Don't complain in comments. Well, until we have something
+ # better, don't consider `#include' etc. are comments.
+ s/\#.*//
+ unless /^\#(if|include|endif|ifdef|ifndef|define)\b/;
- while ($_ = $in->getline)
- {
- if (/$prohibited/)
- {
- warn "$ARGV[$#ARGV]: $.: undefined macro: $1\n"
- if exists $prohibited{$1};
- delete $prohibited{$1};
- }
- }
- foreach (keys %prohibited)
+ # Complain once per word, but possibly several times per line.
+ while (/$prohibited/)
{
- warn "$output: $prohibited{$_}: undefined macro: $_\n";
+ warn "$ARGV[$#ARGV]:$.: error: possibly undefined macro: $1\n";
+ delete $prohibited{$1};
+ # If we're done, exit.
+ return
+ if ! %prohibited;
+ $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
}
}
+ warn "$output:$prohibited{$_}: error: possibly undefined macro: $_\n"
+ foreach (keys %prohibited);
}
sub trace_format_to_m4 ($)
{
my ($format) = @_;
+ my ($underscore) = $_;
my %escape = (# File name.
'f' => '$1',
# Line number.
}
}
+ $_ = $underscore;
return '[[' . $res . ']]';
}
}
}
- verbose "formatting traces for `$output': ", join (', ', keys %trace);
+ verbose "formatting traces for `$output': ", join (', ', sort keys %trace);
# Processing the traces.
my $trace_m4 = new IO::File (">$tmp/traces.m4")
"## -------------------------------------- ##\n",
"\n";
print $trace_m4 "at_define([AT_$_], [at_dnl])\n"
- foreach (keys %{$req->macro});
+ foreach (sort keys %{$req->macro});
print $trace_m4 "\n";
# Implement traces for current requests (%TRACE).
"## Trace processing macros. ##\n",
"## ------------------------- ##\n",
"\n";
- foreach my $key (keys %trace)
+ foreach (sort keys %trace)
{
- print $trace_m4 "at_define([AT_$key],\n";
- print $trace_m4 trace_format_to_m4 ($trace{$key}) . ")\n\n";
+ # Trace request can be embed \n.
+ (my $comment = "Trace $_:$trace{$_}") =~ s/^/\# /;
+ print $trace_m4 "$comment\n";
+ print $trace_m4 "at_define([AT_$_],\n";
+ print $trace_m4 trace_format_to_m4 ($trace{$_}) . ")\n\n";
}
print $trace_m4 "\n";
# Single line traces, as the example above.
s{^m4trace:(.+):(\d+): -(\d+)- (.*)$}
{AT_$4([$1], [$2], [$3], [$4]};
-
print $trace_m4 "$_";
}
$trace_m4->close;
# Files may include others. We can use traces since we just checked
# if they are available.
- handle_traces ($req, "$tmp/dependencies", ('include' => '$1'));
+ # If $FILE is younger than one of its dependencies, it is outdated.
+ handle_traces ($req, "$tmp/dependencies",('include' => '$1'));
+ my $mtime = (stat ($file))[9];
my $deps = new IO::File ("$tmp/dependencies");
while ($_ = $deps->getline)
{
chop;
- push @dep, $_;
- }
-
- # If $FILE is younger than one of its dependencies, it is outdated.
- my $mtime = (stat ($file))[9];
- foreach (@dep)
- {
+ $_ = find_file ($_);
+ verbose "$file depends on $_";
if ($mtime < (stat ($_))[9])
{
verbose "$file depends on $_ which is more recent";
Request->save ("$me.cache/requests");
-exit 0;
+exit $exit_status;
-include(m4sh.m4)# -*- Autoconf -*-
+changequote()changequote([, ])include(m4sh.m4)# -*- Autoconf -*-
# This file is part of Autoconf.
# Driver that loads the Autoconf macro files.
# Copyright 1994, 1999, 2000, 2001 Free Software Foundation, Inc.
-include(m4sugar.m4)# -*- Autoconf -*-
+changequote()changequote([, ])include(m4sugar.m4)# -*- Autoconf -*-
# This file is part of Autoconf.
# M4 sugar for common shell constructs.
# Requires GNU M4 and M4sugar.
-include(m4sugar.m4)# -*- Autoconf -*-
+changequote()changequote([, ])include(m4sugar.m4)# -*- Autoconf -*-
# This file is part of Autoconf.
# M4 sugar for common shell constructs.
# Requires GNU M4 and M4sugar.