| 1 | #! @PERL@ -w
|
|---|
| 2 | # -*- perl -*-
|
|---|
| 3 | # @configure_input@
|
|---|
| 4 |
|
|---|
| 5 | eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
|
|---|
| 6 | if 0;
|
|---|
| 7 |
|
|---|
| 8 | # autom4te - Wrapper around M4 libraries.
|
|---|
| 9 | # Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
|
|---|
| 10 |
|
|---|
| 11 | # This program is free software; you can redistribute it and/or modify
|
|---|
| 12 | # it under the terms of the GNU General Public License as published by
|
|---|
| 13 | # the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 14 | # any later version.
|
|---|
| 15 |
|
|---|
| 16 | # This program is distributed in the hope that it will be useful,
|
|---|
| 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 19 | # GNU General Public License for more details.
|
|---|
| 20 |
|
|---|
| 21 | # You should have received a copy of the GNU General Public License
|
|---|
| 22 | # along with this program; if not, write to the Free Software
|
|---|
| 23 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|---|
| 24 | # 02110-1301, USA.
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 | BEGIN
|
|---|
| 28 | {
|
|---|
| 29 | my $datadir = $ENV{'autom4te_perllibdir'} || '@datadir@';
|
|---|
| 30 | $datadir =~ s/\/\@unixroot/$ENV{'UNIXROOT'}/; # The EMX built perl doesn't know @unixroot.
|
|---|
| 31 | unshift @INC, $datadir;
|
|---|
| 32 |
|
|---|
| 33 | # Override SHELL. On DJGPP SHELL may not be set to a shell
|
|---|
| 34 | # that can handle redirection and quote arguments correctly,
|
|---|
| 35 | # e.g.: COMMAND.COM. For DJGPP always use the shell that configure
|
|---|
| 36 | # has detected.
|
|---|
| 37 | $ENV{'SHELL'} = '@SHELL@' if ($^O eq 'dos');
|
|---|
| 38 | }
|
|---|
| 39 |
|
|---|
| 40 | use Autom4te::C4che;
|
|---|
| 41 | use Autom4te::ChannelDefs;
|
|---|
| 42 | use Autom4te::Channels;
|
|---|
| 43 | use Autom4te::FileUtils;
|
|---|
| 44 | use Autom4te::General;
|
|---|
| 45 | use Autom4te::XFile;
|
|---|
| 46 | use File::Basename;
|
|---|
| 47 | use strict;
|
|---|
| 48 |
|
|---|
| 49 | # Data directory.
|
|---|
| 50 | my $datadir = $ENV{'AC_MACRODIR'} || '@datadir@';
|
|---|
| 51 | $datadir =~ s/\/\@unixroot/$ENV{'UNIXROOT'}/; # The EMX built perl doesn't know @unixroot.
|
|---|
| 52 |
|
|---|
| 53 | # $LANGUAGE{LANGUAGE} -- Automatic options for LANGUAGE.
|
|---|
| 54 | my %language;
|
|---|
| 55 |
|
|---|
| 56 | my $output = '-';
|
|---|
| 57 |
|
|---|
| 58 | # Mode of the output file except for traces.
|
|---|
| 59 | my $mode = "0666";
|
|---|
| 60 |
|
|---|
| 61 | # If melt, don't use frozen files.
|
|---|
| 62 | my $melt = 0;
|
|---|
| 63 |
|
|---|
| 64 | # Names of the cache directory, cache directory index, trace cache
|
|---|
| 65 | # prefix, and output cache prefix. And the IO objet for the index.
|
|---|
| 66 | my $cache;
|
|---|
| 67 | my $icache;
|
|---|
| 68 | my $tcache;
|
|---|
| 69 | my $ocache;
|
|---|
| 70 | my $icache_file;
|
|---|
| 71 |
|
|---|
| 72 | # The macros to trace mapped to their format, as specified by the
|
|---|
| 73 | # user.
|
|---|
| 74 | my %trace;
|
|---|
| 75 |
|
|---|
| 76 | # The macros the user will want to trace in the future.
|
|---|
| 77 | # We need `include' to get the included file, `m4_pattern_forbid' and
|
|---|
| 78 | # `m4_pattern_allow' to check the output.
|
|---|
| 79 | #
|
|---|
| 80 | # FIXME: What about `sinclude'?
|
|---|
| 81 | my @preselect = ('include',
|
|---|
| 82 | 'm4_pattern_allow', 'm4_pattern_forbid',
|
|---|
| 83 | '_m4_warn');
|
|---|
| 84 |
|
|---|
| 85 | # M4 include path.
|
|---|
| 86 | my @include;
|
|---|
| 87 |
|
|---|
| 88 | # Do we freeze?
|
|---|
| 89 | my $freeze = 0;
|
|---|
| 90 |
|
|---|
| 91 | # $M4.
|
|---|
| 92 | my $m4 = $ENV{"M4"} || '@M4@';
|
|---|
| 93 | $m4 =~ s/\/\@unixroot/$ENV{'UNIXROOT'}/; # The EMX built perl doesn't know @unixroot.
|
|---|
| 94 | # Some non-GNU m4's don't reject the --help option, so give them /dev/null.
|
|---|
| 95 | fatal "need GNU m4 1.4 or later: $m4"
|
|---|
| 96 | if system "$m4 --help </dev/null 2>&1 | grep reload-state >/dev/null";
|
|---|
| 97 |
|
|---|
| 98 | # Set some high recursion limit as the default limit, 250, has already
|
|---|
| 99 | # been hit with AC_OUTPUT. Don't override the user's choice.
|
|---|
| 100 | $m4 .= ' --nesting-limit=1024'
|
|---|
| 101 | if " $m4 " !~ / (--nesting-limit(=[0-9]+)?|-L[0-9]*) /;
|
|---|
| 102 |
|
|---|
| 103 |
|
|---|
| 104 | # @M4_BUILTIN -- M4 builtins and a useful comment.
|
|---|
| 105 | my @m4_builtin = `echo dumpdef | $m4 2>&1 >/dev/null`;
|
|---|
| 106 | map { s/:.*//;s/\W// } @m4_builtin;
|
|---|
| 107 |
|
|---|
| 108 |
|
|---|
| 109 | # %M4_BUILTIN_ALTERNATE_NAME
|
|---|
| 110 | # --------------------------
|
|---|
| 111 | # The builtins are renamed, e.g., `define' is renamed `m4_define'.
|
|---|
| 112 | # So map `define' to `m4_define' and conversely.
|
|---|
| 113 | # Some macros don't follow this scheme: be sure to properly map to their
|
|---|
| 114 | # alternate name too.
|
|---|
| 115 | #
|
|---|
| 116 | # This is because GNU M4 1.4's tracing of builtins is buggy. When run on
|
|---|
| 117 | # this input:
|
|---|
| 118 | #
|
|---|
| 119 | # | divert(-1)
|
|---|
| 120 | # | changequote([, ])
|
|---|
| 121 | # | define([m4_eval], defn([eval]))
|
|---|
| 122 | # | eval(1)
|
|---|
| 123 | # | m4_eval(2)
|
|---|
| 124 | # | undefine([eval])
|
|---|
| 125 | # | m4_eval(3)
|
|---|
| 126 | #
|
|---|
| 127 | # it behaves this way:
|
|---|
| 128 | #
|
|---|
| 129 | # | % m4 input.m4 -da -t eval
|
|---|
| 130 | # | m4trace: -1- eval(1)
|
|---|
| 131 | # | m4trace: -1- m4_eval(2)
|
|---|
| 132 | # | m4trace: -1- m4_eval(3)
|
|---|
| 133 | # | %
|
|---|
| 134 | #
|
|---|
| 135 | # Conversely:
|
|---|
| 136 | #
|
|---|
| 137 | # | % m4 input.m4 -da -t m4_eval
|
|---|
| 138 | # | %
|
|---|
| 139 | #
|
|---|
| 140 | # So we will merge them, i.e. tracing `BUILTIN' or tracing
|
|---|
| 141 | # `m4_BUILTIN' will be the same: tracing both, but honoring the
|
|---|
| 142 | # *last* trace specification.
|
|---|
| 143 | #
|
|---|
| 144 | # FIXME: This is not enough: in the output `$0' will be `BUILTIN'
|
|---|
| 145 | # sometimes and `m4_BUILTIN' at others. We should return a unique name,
|
|---|
| 146 | # the one specified by the user.
|
|---|
| 147 | #
|
|---|
| 148 | # FIXME: To be absolutely rigorous, I would say that given that we
|
|---|
| 149 | # _redefine_ divert (instead of _copying_ it), divert and the like
|
|---|
| 150 | # should not be part of this list.
|
|---|
| 151 | my %m4_builtin_alternate_name;
|
|---|
| 152 | @m4_builtin_alternate_name{"$_", "m4_$_"} = ("m4_$_", "$_")
|
|---|
| 153 | foreach (grep { !/m4wrap|m4exit|dnl|ifelse|__.*__/ } @m4_builtin);
|
|---|
| 154 | @m4_builtin_alternate_name{"ifelse", "m4_if"} = ("m4_if", "ifelse");
|
|---|
| 155 | @m4_builtin_alternate_name{"m4exit", "m4_exit"} = ("m4_exit", "m4exit");
|
|---|
| 156 | @m4_builtin_alternate_name{"m4wrap", "m4_wrap"} = ("m4_wrap", "m4wrap");
|
|---|
| 157 |
|
|---|
| 158 |
|
|---|
| 159 | # $HELP
|
|---|
| 160 | # -----
|
|---|
| 161 | $help = "Usage: $0 [OPTION] ... [FILES]
|
|---|
| 162 |
|
|---|
| 163 | Run GNU M4 on the FILES, avoiding useless runs. Output the traces if tracing,
|
|---|
| 164 | the frozen file if freezing, otherwise the expansion of the FILES.
|
|---|
| 165 |
|
|---|
| 166 | If some of the FILES are named \`FILE.m4f\' they are considered to be M4
|
|---|
| 167 | frozen files of all the previous files (which are therefore not loaded).
|
|---|
| 168 | If \`FILE.m4f\' is not found, then \`FILE.m4\' will be used, together with
|
|---|
| 169 | all the previous files.
|
|---|
| 170 |
|
|---|
| 171 | Some files may be optional, i.e., will only be processed if found in the
|
|---|
| 172 | include path, but then must end in \`.m4?\'; the question mark is not part of
|
|---|
| 173 | the actual file name.
|
|---|
| 174 |
|
|---|
| 175 | Operation modes:
|
|---|
| 176 | -h, --help print this help, then exit
|
|---|
| 177 | -V, --version print version number, then exit
|
|---|
| 178 | -v, --verbose verbosely report processing
|
|---|
| 179 | -d, --debug don\'t remove temporary files
|
|---|
| 180 | -o, --output=FILE save output in FILE (defaults to \`-\', stdout)
|
|---|
| 181 | -f, --force don\'t rely on cached values
|
|---|
| 182 | -W, --warnings=CATEGORY report the warnings falling in CATEGORY
|
|---|
| 183 | -l, --language=LANG specify the set of M4 macros to use
|
|---|
| 184 | -C, --cache=DIRECTORY preserve results for future runs in DIRECTORY
|
|---|
| 185 | --no-cache disable the cache
|
|---|
| 186 | -m, --mode=OCTAL change the non trace output file mode (0666)
|
|---|
| 187 | -M, --melt don\'t use M4 frozen files
|
|---|
| 188 |
|
|---|
| 189 | Languages include:
|
|---|
| 190 | \`Autoconf\' create Autoconf configure scripts
|
|---|
| 191 | \`Autotest\' create Autotest test suites
|
|---|
| 192 | \`M4sh\' create M4sh shell scripts
|
|---|
| 193 | \`M4sugar\' create M4sugar output
|
|---|
| 194 |
|
|---|
| 195 | " . Autom4te::ChannelDefs::usage . "
|
|---|
| 196 |
|
|---|
| 197 | The environment variables \`M4\' and \`WARNINGS\' are honored.
|
|---|
| 198 |
|
|---|
| 199 | Library directories:
|
|---|
| 200 | -B, --prepend-include=DIR prepend directory DIR to search path
|
|---|
| 201 | -I, --include=DIR append directory DIR to search path
|
|---|
| 202 |
|
|---|
| 203 | Tracing:
|
|---|
| 204 | -t, --trace=MACRO report the MACRO invocations
|
|---|
| 205 | -p, --preselect=MACRO prepare to trace MACRO in a future run
|
|---|
| 206 |
|
|---|
| 207 | Freezing:
|
|---|
| 208 | -F, --freeze produce an M4 frozen state file for FILES
|
|---|
| 209 |
|
|---|
| 210 | Report bugs to <bug-autoconf\@gnu.org>.
|
|---|
| 211 | ";
|
|---|
| 212 |
|
|---|
| 213 | # $VERSION
|
|---|
| 214 | # --------
|
|---|
| 215 | $version = <<"EOF";
|
|---|
| 216 | autom4te (@PACKAGE_NAME@) @VERSION@
|
|---|
| 217 | Copyright (C) 2006 Free Software Foundation, Inc.
|
|---|
| 218 | This is free software. You may redistribute copies of it under the terms of
|
|---|
| 219 | the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
|
|---|
| 220 | There is NO WARRANTY, to the extent permitted by law.
|
|---|
| 221 |
|
|---|
| 222 | Written by Akim Demaille.
|
|---|
| 223 | EOF
|
|---|
| 224 |
|
|---|
| 225 |
|
|---|
| 226 | ## ---------- ##
|
|---|
| 227 | ## Routines. ##
|
|---|
| 228 | ## ---------- ##
|
|---|
| 229 |
|
|---|
| 230 |
|
|---|
| 231 | # $OPTION
|
|---|
| 232 | # files_to_options (@FILE)
|
|---|
| 233 | # ------------------------
|
|---|
| 234 | # Transform Autom4te conventions (e.g., using foo.m4f to designate a frozen
|
|---|
| 235 | # file) into a suitable command line for M4 (e.g., using --reload-state).
|
|---|
| 236 | sub files_to_options (@)
|
|---|
| 237 | {
|
|---|
| 238 | my (@file) = @_;
|
|---|
| 239 | my @res;
|
|---|
| 240 | foreach my $file (@file)
|
|---|
| 241 | {
|
|---|
| 242 | if ($file =~ /\.m4f$/)
|
|---|
| 243 | {
|
|---|
| 244 | push @res, "--reload-state=$file";
|
|---|
| 245 | }
|
|---|
| 246 | else
|
|---|
| 247 | {
|
|---|
| 248 | push @res, $file;
|
|---|
| 249 | }
|
|---|
| 250 | }
|
|---|
| 251 | return join ' ', @res;
|
|---|
| 252 | }
|
|---|
| 253 |
|
|---|
| 254 |
|
|---|
| 255 | # load_configuration ($FILE)
|
|---|
| 256 | # --------------------------
|
|---|
| 257 | # Load the configuration $FILE.
|
|---|
| 258 | sub load_configuration ($)
|
|---|
| 259 | {
|
|---|
| 260 | my ($file) = @_;
|
|---|
| 261 | use Text::ParseWords;
|
|---|
| 262 |
|
|---|
| 263 | my $cfg = new Autom4te::XFile ($file);
|
|---|
| 264 | my $lang;
|
|---|
| 265 | while ($_ = $cfg->getline)
|
|---|
| 266 | {
|
|---|
| 267 | chomp;
|
|---|
| 268 | # Comments.
|
|---|
| 269 | next
|
|---|
| 270 | if /^\s*(\#.*)?$/;
|
|---|
| 271 | s/\/\@unixroot/$ENV{'UNIXROOT'}/; # The EMX built perl doesn't know @unixroot.
|
|---|
| 272 | my @words = shellwords ($_);
|
|---|
| 273 | my $type = shift @words;
|
|---|
| 274 | if ($type eq 'begin-language:')
|
|---|
| 275 | {
|
|---|
| 276 | fatal "$file:$.: end-language missing for: $lang"
|
|---|
| 277 | if defined $lang;
|
|---|
| 278 | $lang = lc $words[0];
|
|---|
| 279 | }
|
|---|
| 280 | elsif ($type eq 'end-language:')
|
|---|
| 281 | {
|
|---|
| 282 | error "$file:$.: end-language mismatch: $lang"
|
|---|
| 283 | if $lang ne lc $words[0];
|
|---|
| 284 | $lang = undef;
|
|---|
| 285 | }
|
|---|
| 286 | elsif ($type eq 'args:')
|
|---|
| 287 | {
|
|---|
| 288 | fatal "$file:$.: no current language"
|
|---|
| 289 | unless defined $lang;
|
|---|
| 290 | push @{$language{$lang}}, @words;
|
|---|
| 291 | }
|
|---|
| 292 | else
|
|---|
| 293 | {
|
|---|
| 294 | error "$file:$.: unknown directive: $type";
|
|---|
| 295 | }
|
|---|
| 296 | }
|
|---|
| 297 | }
|
|---|
| 298 |
|
|---|
| 299 |
|
|---|
| 300 | # parse_args ()
|
|---|
| 301 | # -------------
|
|---|
| 302 | # Process any command line arguments.
|
|---|
| 303 | sub parse_args ()
|
|---|
| 304 | {
|
|---|
| 305 | # We want to look for the early options, which should not be found
|
|---|
| 306 | # in the configuration file. Prepend to the user arguments.
|
|---|
| 307 | # Perform this repeatedly so that we can use --language in language
|
|---|
| 308 | # definitions. Beware that there can be several --language
|
|---|
| 309 | # invocations.
|
|---|
| 310 | my @language;
|
|---|
| 311 | do {
|
|---|
| 312 | @language = ();
|
|---|
| 313 | use Getopt::Long;
|
|---|
| 314 | Getopt::Long::Configure ("pass_through", "permute");
|
|---|
| 315 | GetOptions ("l|language=s" => \@language);
|
|---|
| 316 |
|
|---|
| 317 | foreach (@language)
|
|---|
| 318 | {
|
|---|
| 319 | error "unknown language: $_"
|
|---|
| 320 | unless exists $language{lc $_};
|
|---|
| 321 | unshift @ARGV, @{$language{lc $_}};
|
|---|
| 322 | }
|
|---|
| 323 | } while @language;
|
|---|
| 324 |
|
|---|
| 325 | # --debug is useless: it is parsed below.
|
|---|
| 326 | if (exists $ENV{'AUTOM4TE_DEBUG'})
|
|---|
| 327 | {
|
|---|
| 328 | print STDERR "$me: concrete arguments:\n";
|
|---|
| 329 | foreach my $arg (@ARGV)
|
|---|
| 330 | {
|
|---|
| 331 | print STDERR "| $arg\n";
|
|---|
| 332 | }
|
|---|
| 333 | }
|
|---|
| 334 |
|
|---|
| 335 | # Process the arguments for real this time.
|
|---|
| 336 | my @trace;
|
|---|
| 337 | my @prepend_include;
|
|---|
| 338 | parse_WARNINGS;
|
|---|
| 339 | getopt
|
|---|
| 340 | (
|
|---|
| 341 | # Operation modes:
|
|---|
| 342 | "o|output=s" => \$output,
|
|---|
| 343 | "W|warnings=s" => \&parse_warnings,
|
|---|
| 344 | "m|mode=s" => \$mode,
|
|---|
| 345 | "M|melt" => \$melt,
|
|---|
| 346 |
|
|---|
| 347 | # Library directories:
|
|---|
| 348 | "B|prepend-include=s" => \@prepend_include,
|
|---|
| 349 | "I|include=s" => \@include,
|
|---|
| 350 |
|
|---|
| 351 | # Tracing:
|
|---|
| 352 | # Using a hash for traces is seducing. Unfortunately, upon `-t FOO',
|
|---|
| 353 | # instead of mapping `FOO' to undef, Getopt maps it to `1', preventing
|
|---|
| 354 | # us from distinguishing `-t FOO' from `-t FOO=1'. So let's do it
|
|---|
| 355 | # by hand.
|
|---|
| 356 | "t|trace=s" => \@trace,
|
|---|
| 357 | "p|preselect=s" => \@preselect,
|
|---|
| 358 |
|
|---|
| 359 | # Freezing.
|
|---|
| 360 | "F|freeze" => \$freeze,
|
|---|
| 361 |
|
|---|
| 362 | # Caching.
|
|---|
| 363 | "C|cache=s" => \$cache,
|
|---|
| 364 | "no-cache" => sub { $cache = undef; },
|
|---|
| 365 | );
|
|---|
| 366 |
|
|---|
| 367 | fatal "too few arguments
|
|---|
| 368 | Try `$me --help' for more information."
|
|---|
| 369 | unless @ARGV;
|
|---|
| 370 |
|
|---|
| 371 | # Freezing:
|
|---|
| 372 | # We cannot trace at the same time (well, we can, but it sounds insane).
|
|---|
| 373 | # And it implies melting: there is risk not to update properly using
|
|---|
| 374 | # old frozen files, and worse yet: we could load a frozen file and
|
|---|
| 375 | # refreeze it! A sort of caching :)
|
|---|
| 376 | fatal "cannot freeze and trace"
|
|---|
| 377 | if $freeze && @trace;
|
|---|
| 378 | $melt = 1
|
|---|
| 379 | if $freeze;
|
|---|
| 380 |
|
|---|
| 381 | # Names of the cache directory, cache directory index, trace cache
|
|---|
| 382 | # prefix, and output cache prefix. If the cache is not to be
|
|---|
| 383 | # preserved, default to a temporary directory (automatically removed
|
|---|
| 384 | # on exit).
|
|---|
| 385 | $cache = $tmp
|
|---|
| 386 | unless $cache;
|
|---|
| 387 | $icache = "$cache/requests";
|
|---|
| 388 | $tcache = "$cache/traces.";
|
|---|
| 389 | $ocache = "$cache/output.";
|
|---|
| 390 |
|
|---|
| 391 | # Normalize the includes: the first occurrence is enough, several is
|
|---|
| 392 | # a pain since it introduces a useless difference in the path which
|
|---|
| 393 | # invalidates the cache. And strip `.' which is implicit and always
|
|---|
| 394 | # first.
|
|---|
| 395 | @include = grep { !/^\.$/ } uniq (reverse(@prepend_include), @include);
|
|---|
| 396 |
|
|---|
| 397 | # Convert @trace to %trace, and work around the M4 builtins tracing
|
|---|
| 398 | # problem.
|
|---|
| 399 | # The default format is `$f:$l:$n:$%'.
|
|---|
| 400 | foreach (@trace)
|
|---|
| 401 | {
|
|---|
| 402 | /^([^:]+)(?::(.*))?$/ms;
|
|---|
| 403 | $trace{$1} = defined $2 ? $2 : '$f:$l:$n:$%';
|
|---|
| 404 | $trace{$m4_builtin_alternate_name{$1}} = $trace{$1}
|
|---|
| 405 | if exists $m4_builtin_alternate_name{$1};
|
|---|
| 406 | }
|
|---|
| 407 |
|
|---|
| 408 | # Work around the M4 builtins tracing problem for @PRESELECT.
|
|---|
| 409 | push (@preselect,
|
|---|
| 410 | map { $m4_builtin_alternate_name{$_} }
|
|---|
| 411 | grep { exists $m4_builtin_alternate_name{$_} } @preselect);
|
|---|
| 412 |
|
|---|
| 413 | # If we find frozen files, then all the files before it are
|
|---|
| 414 | # discarded: the frozen file is supposed to include them all.
|
|---|
| 415 | #
|
|---|
| 416 | # We don't want to depend upon m4's --include to find the top level
|
|---|
| 417 | # files, so we use `find_file' here. Try to get a canonical name,
|
|---|
| 418 | # as it's part of the key for caching. And some files are optional
|
|---|
| 419 | # (also handled by `find_file').
|
|---|
| 420 | my @argv;
|
|---|
| 421 | foreach (@ARGV)
|
|---|
| 422 | {
|
|---|
| 423 | if (/\.m4f$/)
|
|---|
| 424 | {
|
|---|
| 425 | # Frozen files are optional => pass a `?' to `find_file'.
|
|---|
| 426 | my $file = find_file ("$_?", @include);
|
|---|
| 427 | if (!$melt && $file)
|
|---|
| 428 | {
|
|---|
| 429 | @argv = ($file);
|
|---|
| 430 | }
|
|---|
| 431 | else
|
|---|
| 432 | {
|
|---|
| 433 | s/\.m4f$/.m4/;
|
|---|
| 434 | push @argv, find_file ($_, @include);
|
|---|
| 435 | }
|
|---|
| 436 | }
|
|---|
| 437 | else
|
|---|
| 438 | {
|
|---|
| 439 | my $file = find_file ($_, @include);
|
|---|
| 440 | push @argv, $file
|
|---|
| 441 | if $file;
|
|---|
| 442 | }
|
|---|
| 443 | }
|
|---|
| 444 | @ARGV = @argv;
|
|---|
| 445 | }
|
|---|
| 446 |
|
|---|
| 447 |
|
|---|
| 448 | # handle_m4 ($REQ, @MACRO)
|
|---|
| 449 | # ------------------------
|
|---|
| 450 | # Run m4 on the input files, and save the traces on the @MACRO.
|
|---|
| 451 | sub handle_m4 ($@)
|
|---|
| 452 | {
|
|---|
| 453 | my ($req, @macro) = @_;
|
|---|
| 454 |
|
|---|
| 455 | # GNU m4 appends when using --debugfile/--error-output.
|
|---|
| 456 | unlink ($tcache . $req->id . "t");
|
|---|
| 457 |
|
|---|
| 458 | # Run m4.
|
|---|
| 459 | #
|
|---|
| 460 | # We don't output directly to the cache files, to avoid problems
|
|---|
| 461 | # when we are interrupted (that leaves corrupted files).
|
|---|
| 462 | xsystem ("$m4"
|
|---|
| 463 | . join (' --include=', '', @include)
|
|---|
| 464 | . ' --debug=aflq'
|
|---|
| 465 | . (!exists $ENV{'AUTOM4TE_NO_FATAL'} ? ' --fatal-warning' : '')
|
|---|
| 466 | . " @M4_DEBUGFILE@=$tcache" . $req->id . "t"
|
|---|
| 467 | . join (' --trace=', '', sort @macro)
|
|---|
| 468 | . " " . files_to_options (@ARGV)
|
|---|
| 469 | . " >$ocache" . $req->id . "t");
|
|---|
| 470 |
|
|---|
| 471 | # Everything went ok: preserve the outputs.
|
|---|
| 472 | foreach my $file (map { $_ . $req->id } ($tcache, $ocache))
|
|---|
| 473 | {
|
|---|
| 474 | use File::Copy;
|
|---|
| 475 | move ("${file}t", "$file")
|
|---|
| 476 | or fatal "cannot rename ${file}t as $file: $!";
|
|---|
| 477 | }
|
|---|
| 478 | }
|
|---|
| 479 |
|
|---|
| 480 |
|
|---|
| 481 | # warn_forbidden ($WHERE, $WORD, %FORBIDDEN)
|
|---|
| 482 | # ------------------------------------------
|
|---|
| 483 | # $WORD is forbidden. Warn with a dedicated error message if in
|
|---|
| 484 | # %FORBIDDEN, otherwise, a simple `error: possibly undefined macro'
|
|---|
| 485 | # will do.
|
|---|
| 486 | my $first_warn_forbidden = 1;
|
|---|
| 487 | sub warn_forbidden ($$%)
|
|---|
| 488 | {
|
|---|
| 489 | my ($where, $word, %forbidden) = @_;
|
|---|
| 490 | my $message;
|
|---|
| 491 |
|
|---|
| 492 | for my $re (sort keys %forbidden)
|
|---|
| 493 | {
|
|---|
| 494 | if ($word =~ $re)
|
|---|
| 495 | {
|
|---|
| 496 | $message = $forbidden{$re};
|
|---|
| 497 | last;
|
|---|
| 498 | }
|
|---|
| 499 | }
|
|---|
| 500 | $message ||= "possibly undefined macro: $word";
|
|---|
| 501 | warn "$where: error: $message\n";
|
|---|
| 502 | if ($first_warn_forbidden)
|
|---|
| 503 | {
|
|---|
| 504 | warn <<EOF;
|
|---|
| 505 | If this token and others are legitimate, please use m4_pattern_allow.
|
|---|
| 506 | See the Autoconf documentation.
|
|---|
| 507 | EOF
|
|---|
| 508 | $first_warn_forbidden = 0;
|
|---|
| 509 | }
|
|---|
| 510 | }
|
|---|
| 511 |
|
|---|
| 512 |
|
|---|
| 513 | # handle_output ($REQ, $OUTPUT)
|
|---|
| 514 | # -----------------------------
|
|---|
| 515 | # Run m4 on the input files, perform quadrigraphs substitution, check for
|
|---|
| 516 | # forbidden tokens, and save into $OUTPUT.
|
|---|
| 517 | sub handle_output ($$)
|
|---|
| 518 | {
|
|---|
| 519 | my ($req, $output) = @_;
|
|---|
| 520 |
|
|---|
| 521 | verb "creating $output";
|
|---|
| 522 |
|
|---|
| 523 | # Load the forbidden/allowed patterns.
|
|---|
| 524 | handle_traces ($req, "$tmp/patterns",
|
|---|
| 525 | ('m4_pattern_forbid' => 'forbid:$1:$2',
|
|---|
| 526 | 'm4_pattern_allow' => 'allow:$1'));
|
|---|
| 527 | my @patterns = new Autom4te::XFile ("$tmp/patterns")->getlines;
|
|---|
| 528 | chomp @patterns;
|
|---|
| 529 | my %forbidden =
|
|---|
| 530 | map { /^forbid:([^:]+):.+$/ => /^forbid:[^:]+:(.+)$/ } @patterns;
|
|---|
| 531 | my $forbidden = join ('|', map { /^forbid:([^:]+)/ } @patterns) || "^\$";
|
|---|
| 532 | my $allowed = join ('|', map { /^allow:([^:]+)/ } @patterns) || "^\$";
|
|---|
| 533 |
|
|---|
| 534 | verb "forbidden tokens: $forbidden";
|
|---|
| 535 | verb "forbidden token : $_ => $forbidden{$_}"
|
|---|
| 536 | foreach (sort keys %forbidden);
|
|---|
| 537 | verb "allowed tokens: $allowed";
|
|---|
| 538 |
|
|---|
| 539 | # Read the (cached) raw M4 output, produce the actual result. We
|
|---|
| 540 | # have to use the 2nd arg to have Autom4te::XFile honor the third, but then
|
|---|
| 541 | # stdout is to be handled by hand :(. Don't use fdopen as it means
|
|---|
| 542 | # we will close STDOUT, which we already do in END.
|
|---|
| 543 | my $out = new Autom4te::XFile;
|
|---|
| 544 | if ($output eq '-')
|
|---|
| 545 | {
|
|---|
| 546 | $out->open (">$output");
|
|---|
| 547 | }
|
|---|
| 548 | else
|
|---|
| 549 | {
|
|---|
| 550 | $out->open($output, O_CREAT | O_WRONLY | O_TRUNC, oct ($mode));
|
|---|
| 551 | }
|
|---|
| 552 | fatal "cannot create $output: $!"
|
|---|
| 553 | unless $out;
|
|---|
| 554 | my $in = new Autom4te::XFile ($ocache . $req->id);
|
|---|
| 555 |
|
|---|
| 556 | my %prohibited;
|
|---|
| 557 | my $res;
|
|---|
| 558 | while ($_ = $in->getline)
|
|---|
| 559 | {
|
|---|
| 560 | s/\s+$//;
|
|---|
| 561 | s/__oline__/$./g;
|
|---|
| 562 | s/\@<:\@/[/g;
|
|---|
| 563 | s/\@:>\@/]/g;
|
|---|
| 564 | s/\@S\|\@/\$/g;
|
|---|
| 565 | s/\@%:\@/#/g;
|
|---|
| 566 |
|
|---|
| 567 | $res = $_;
|
|---|
| 568 |
|
|---|
| 569 | # Don't complain in comments. Well, until we have something
|
|---|
| 570 | # better, don't consider `#include' etc. are comments.
|
|---|
| 571 | s/\#.*//
|
|---|
| 572 | unless /^\#\s*(if|include|endif|ifdef|ifndef|define)\b/;
|
|---|
| 573 | foreach (split (/\W+/))
|
|---|
| 574 | {
|
|---|
| 575 | $prohibited{$_} = $.
|
|---|
| 576 | if !/^$/ && /$forbidden/o && !/$allowed/o && ! exists $prohibited{$_};
|
|---|
| 577 | }
|
|---|
| 578 |
|
|---|
| 579 | # Performed *last*: the empty quadrigraph.
|
|---|
| 580 | $res =~ s/\@&t\@//g;
|
|---|
| 581 |
|
|---|
| 582 | print $out "$res\n";
|
|---|
| 583 | }
|
|---|
| 584 |
|
|---|
| 585 | # If no forbidden words, we're done.
|
|---|
| 586 | return
|
|---|
| 587 | if ! %prohibited;
|
|---|
| 588 |
|
|---|
| 589 | # Locate the forbidden words in the last input file.
|
|---|
| 590 | # This is unsatisfying but...
|
|---|
| 591 | my $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
|
|---|
| 592 | my $file = new Autom4te::XFile ($ARGV[$#ARGV]);
|
|---|
| 593 | $exit_code = 1;
|
|---|
| 594 |
|
|---|
| 595 | while ($_ = $file->getline)
|
|---|
| 596 | {
|
|---|
| 597 | # Don't complain in comments. Well, until we have something
|
|---|
| 598 | # better, don't consider `#include' etc. are comments.
|
|---|
| 599 | s/\#.*//
|
|---|
| 600 | unless /^\#(if|include|endif|ifdef|ifndef|define)\b/;
|
|---|
| 601 |
|
|---|
| 602 | # Complain once per word, but possibly several times per line.
|
|---|
| 603 | while (/$prohibited/)
|
|---|
| 604 | {
|
|---|
| 605 | my $word = $1;
|
|---|
| 606 | warn_forbidden ("$ARGV[$#ARGV]:$.", $word, %forbidden);
|
|---|
| 607 | delete $prohibited{$word};
|
|---|
| 608 | # If we're done, exit.
|
|---|
| 609 | return
|
|---|
| 610 | if ! %prohibited;
|
|---|
| 611 | $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
|
|---|
| 612 | }
|
|---|
| 613 | }
|
|---|
| 614 | warn_forbidden ("$output:$prohibited{$_}", $_, %forbidden)
|
|---|
| 615 | foreach (sort { $prohibited{$a} <=> $prohibited{$b} } keys %prohibited);
|
|---|
| 616 | }
|
|---|
| 617 |
|
|---|
| 618 |
|
|---|
| 619 | ## --------------------- ##
|
|---|
| 620 | ## Handling the traces. ##
|
|---|
| 621 | ## --------------------- ##
|
|---|
| 622 |
|
|---|
| 623 |
|
|---|
| 624 | # $M4_MACRO
|
|---|
| 625 | # trace_format_to_m4 ($FORMAT)
|
|---|
| 626 | # ----------------------------
|
|---|
| 627 | # Convert a trace $FORMAT into a M4 trace processing macro's body.
|
|---|
| 628 | sub trace_format_to_m4 ($)
|
|---|
| 629 | {
|
|---|
| 630 | my ($format) = @_;
|
|---|
| 631 | my $underscore = $_;
|
|---|
| 632 | my %escape = (# File name.
|
|---|
| 633 | 'f' => '$1',
|
|---|
| 634 | # Line number.
|
|---|
| 635 | 'l' => '$2',
|
|---|
| 636 | # Depth.
|
|---|
| 637 | 'd' => '$3',
|
|---|
| 638 | # Name (also available as $0).
|
|---|
| 639 | 'n' => '$4',
|
|---|
| 640 | # Escaped dollar.
|
|---|
| 641 | '$' => '$');
|
|---|
| 642 |
|
|---|
| 643 | my $res = '';
|
|---|
| 644 | $_ = $format;
|
|---|
| 645 | while ($_)
|
|---|
| 646 | {
|
|---|
| 647 | # $n -> $(n + 4)
|
|---|
| 648 | if (s/^\$(\d+)//)
|
|---|
| 649 | {
|
|---|
| 650 | $res .= "\$" . ($1 + 4);
|
|---|
| 651 | }
|
|---|
| 652 | # $x, no separator given.
|
|---|
| 653 | elsif (s/^\$([fldn\$])//)
|
|---|
| 654 | {
|
|---|
| 655 | $res .= $escape{$1};
|
|---|
| 656 | }
|
|---|
| 657 | # $.x or ${sep}x.
|
|---|
| 658 | elsif (s/^\$\{([^}]*)\}([@*%])//
|
|---|
| 659 | || s/^\$(.?)([@*%])//)
|
|---|
| 660 | {
|
|---|
| 661 | # $@, list of quoted effective arguments.
|
|---|
| 662 | if ($2 eq '@')
|
|---|
| 663 | {
|
|---|
| 664 | $res .= ']at_at([' . ($1 ? $1 : ',') . '], $@)[';
|
|---|
| 665 | }
|
|---|
| 666 | # $*, list of unquoted effective arguments.
|
|---|
| 667 | elsif ($2 eq '*')
|
|---|
| 668 | {
|
|---|
| 669 | $res .= ']at_star([' . ($1 ? $1 : ',') . '], $@)[';
|
|---|
| 670 | }
|
|---|
| 671 | # $%, list of flattened unquoted effective arguments.
|
|---|
| 672 | elsif ($2 eq '%')
|
|---|
| 673 | {
|
|---|
| 674 | $res .= ']at_percent([' . ($1 ? $1 : ':') . '], $@)[';
|
|---|
| 675 | }
|
|---|
| 676 | }
|
|---|
| 677 | elsif (/^(\$.)/)
|
|---|
| 678 | {
|
|---|
| 679 | error "invalid escape: $1";
|
|---|
| 680 | }
|
|---|
| 681 | else
|
|---|
| 682 | {
|
|---|
| 683 | s/^([^\$]+)//;
|
|---|
| 684 | $res .= $1;
|
|---|
| 685 | }
|
|---|
| 686 | }
|
|---|
| 687 |
|
|---|
| 688 | $_ = $underscore;
|
|---|
| 689 | return '[[' . $res . ']]';
|
|---|
| 690 | }
|
|---|
| 691 |
|
|---|
| 692 |
|
|---|
| 693 | # handle_traces($REQ, $OUTPUT, %TRACE)
|
|---|
| 694 | # ------------------------------------
|
|---|
| 695 | # We use M4 itself to process the traces. But to avoid name clashes when
|
|---|
| 696 | # processing the traces, the builtins are disabled, and moved into `at_'.
|
|---|
| 697 | # Actually, all the low level processing macros are in `at_' (and `_at_').
|
|---|
| 698 | # To avoid clashes between user macros and `at_' macros, the macros which
|
|---|
| 699 | # implement tracing are in `AT_'.
|
|---|
| 700 | #
|
|---|
| 701 | # Having $REQ is needed to neutralize the macros which have been traced,
|
|---|
| 702 | # but are not wanted now.
|
|---|
| 703 | sub handle_traces ($$%)
|
|---|
| 704 | {
|
|---|
| 705 | my ($req, $output, %trace) = @_;
|
|---|
| 706 |
|
|---|
| 707 | verb "formatting traces for `$output': " . join (', ', sort keys %trace);
|
|---|
| 708 |
|
|---|
| 709 | # Processing the traces.
|
|---|
| 710 | my $trace_m4 = new Autom4te::XFile (">$tmp/traces.m4");
|
|---|
| 711 |
|
|---|
| 712 | $_ = <<'EOF';
|
|---|
| 713 | divert(-1)
|
|---|
| 714 | changequote([, ])
|
|---|
| 715 | # _at_MODE(SEPARATOR, ELT1, ELT2...)
|
|---|
| 716 | # ----------------------------------
|
|---|
| 717 | # List the elements, separating then with SEPARATOR.
|
|---|
| 718 | # MODE can be:
|
|---|
| 719 | # `at' -- the elements are enclosed in brackets.
|
|---|
| 720 | # `star' -- the elements are listed as are.
|
|---|
| 721 | # `percent' -- the elements are `flattened': spaces are singled out,
|
|---|
| 722 | # and no new line remains.
|
|---|
| 723 | define([_at_at],
|
|---|
| 724 | [at_ifelse([$#], [1], [],
|
|---|
| 725 | [$#], [2], [[[$2]]],
|
|---|
| 726 | [[[$2]][$1]$0([$1], at_shift(at_shift($@)))])])
|
|---|
| 727 |
|
|---|
| 728 | define([_at_percent],
|
|---|
| 729 | [at_ifelse([$#], [1], [],
|
|---|
| 730 | [$#], [2], [at_flatten([$2])],
|
|---|
| 731 | [at_flatten([$2])[$1]$0([$1], at_shift(at_shift($@)))])])
|
|---|
| 732 |
|
|---|
| 733 | define([_at_star],
|
|---|
| 734 | [at_ifelse([$#], [1], [],
|
|---|
| 735 | [$#], [2], [[$2]],
|
|---|
| 736 | [[$2][$1]$0([$1], at_shift(at_shift($@)))])])
|
|---|
| 737 |
|
|---|
| 738 | # FLATTEN quotes its result.
|
|---|
| 739 | # Note that the second pattern is `newline, tab or space'. Don't lose
|
|---|
| 740 | # the tab!
|
|---|
| 741 | define([at_flatten],
|
|---|
| 742 | [at_patsubst(at_patsubst(at_patsubst(at_patsubst([[[[$1]]]], [\\\n]),
|
|---|
| 743 | [[\n\t ]+], [ ]),
|
|---|
| 744 | [ *\(.\)$], [\1]),
|
|---|
| 745 | [^ *\(.*\)], [[\1]])])
|
|---|
| 746 |
|
|---|
| 747 | define([at_args], [at_shift(at_shift(at_shift(at_shift(at_shift($@)))))])
|
|---|
| 748 | define([at_at], [_$0([$1], at_args($@))])
|
|---|
| 749 | define([at_percent], [_$0([$1], at_args($@))])
|
|---|
| 750 | define([at_star], [_$0([$1], at_args($@))])
|
|---|
| 751 |
|
|---|
| 752 | EOF
|
|---|
| 753 | s/^ //mg;s/\\t/\t/mg;s/\\n/\n/mg;
|
|---|
| 754 | print $trace_m4 $_;
|
|---|
| 755 |
|
|---|
| 756 | # If you trace `define', then on `define([m4_exit], defn([m4exit])' you
|
|---|
| 757 | # will produce
|
|---|
| 758 | #
|
|---|
| 759 | # AT_define([m4sugar.m4], [115], [1], [define], [m4_exit], <m4exit>)
|
|---|
| 760 | #
|
|---|
| 761 | # Since `<m4exit>' is not quoted, the outer m4, when processing
|
|---|
| 762 | # `trace.m4' will exit prematurely. Hence, move all the builtins to
|
|---|
| 763 | # the `at_' name space.
|
|---|
| 764 |
|
|---|
| 765 | print $trace_m4 "# Copy the builtins.\n";
|
|---|
| 766 | map { print $trace_m4 "define([at_$_], defn([$_]))\n" } @m4_builtin;
|
|---|
| 767 | print $trace_m4 "\n";
|
|---|
| 768 |
|
|---|
| 769 | print $trace_m4 "# Disable them.\n";
|
|---|
| 770 | map { print $trace_m4 "at_undefine([$_])\n" } @m4_builtin;
|
|---|
| 771 | print $trace_m4 "\n";
|
|---|
| 772 |
|
|---|
| 773 |
|
|---|
| 774 | # Neutralize traces: we don't want traces of cached requests (%REQUEST).
|
|---|
| 775 | print $trace_m4
|
|---|
| 776 | "## -------------------------------------- ##\n",
|
|---|
| 777 | "## By default neutralize all the traces. ##\n",
|
|---|
| 778 | "## -------------------------------------- ##\n",
|
|---|
| 779 | "\n";
|
|---|
| 780 | print $trace_m4 "at_define([AT_$_], [at_dnl])\n"
|
|---|
| 781 | foreach (sort keys %{$req->macro});
|
|---|
| 782 | print $trace_m4 "\n";
|
|---|
| 783 |
|
|---|
| 784 | # Implement traces for current requests (%TRACE).
|
|---|
| 785 | print $trace_m4
|
|---|
| 786 | "## ------------------------- ##\n",
|
|---|
| 787 | "## Trace processing macros. ##\n",
|
|---|
| 788 | "## ------------------------- ##\n",
|
|---|
| 789 | "\n";
|
|---|
| 790 | foreach (sort keys %trace)
|
|---|
| 791 | {
|
|---|
| 792 | # Trace request can be embed \n.
|
|---|
| 793 | (my $comment = "Trace $_:$trace{$_}") =~ s/^/\# /;
|
|---|
| 794 | print $trace_m4 "$comment\n";
|
|---|
| 795 | print $trace_m4 "at_define([AT_$_],\n";
|
|---|
| 796 | print $trace_m4 trace_format_to_m4 ($trace{$_}) . ")\n\n";
|
|---|
| 797 | }
|
|---|
| 798 | print $trace_m4 "\n";
|
|---|
| 799 |
|
|---|
| 800 | # Reenable output.
|
|---|
| 801 | print $trace_m4 "at_divert(0)at_dnl\n";
|
|---|
| 802 |
|
|---|
| 803 | # Transform the traces from m4 into an m4 input file.
|
|---|
| 804 | # Typically, transform:
|
|---|
| 805 | #
|
|---|
| 806 | # | m4trace:configure.ac:3: -1- AC_SUBST([exec_prefix], [NONE])
|
|---|
| 807 | #
|
|---|
| 808 | # into
|
|---|
| 809 | #
|
|---|
| 810 | # | AT_AC_SUBST([configure.ac], [3], [1], [AC_SUBST], [exec_prefix], [NONE])
|
|---|
| 811 | #
|
|---|
| 812 | # Pay attention that the file name might include colons, if under DOS
|
|---|
| 813 | # for instance, so we don't use `[^:]+'.
|
|---|
| 814 | my $traces = new Autom4te::XFile ($tcache . $req->id);
|
|---|
| 815 | while ($_ = $traces->getline)
|
|---|
| 816 | {
|
|---|
| 817 | # Trace with arguments, as the example above. We don't try
|
|---|
| 818 | # to match the trailing parenthesis as it might be on a
|
|---|
| 819 | # separate line.
|
|---|
| 820 | s{^m4trace:(.+):(\d+): -(\d+)- ([^(]+)\((.*)$}
|
|---|
| 821 | {AT_$4([$1], [$2], [$3], [$4], $5};
|
|---|
| 822 | # Traces without arguments, always on a single line.
|
|---|
| 823 | s{^m4trace:(.+):(\d+): -(\d+)- ([^)]*)\n$}
|
|---|
| 824 | {AT_$4([$1], [$2], [$3], [$4])\n};
|
|---|
| 825 | print $trace_m4 "$_";
|
|---|
| 826 | }
|
|---|
| 827 | $trace_m4->close;
|
|---|
| 828 |
|
|---|
| 829 | my $in = new Autom4te::XFile ("$m4 $tmp/traces.m4 |");
|
|---|
| 830 | my $out = new Autom4te::XFile (">$output");
|
|---|
| 831 |
|
|---|
| 832 | # This is dubious: should we really transform the quadrigraphs in
|
|---|
| 833 | # traces? It might break balanced [ ] etc. in the output. The
|
|---|
| 834 | # consensus seeems to be that traces are more useful this way.
|
|---|
| 835 | while ($_ = $in->getline)
|
|---|
| 836 | {
|
|---|
| 837 | # It makes no sense to try to transform __oline__.
|
|---|
| 838 | s/\@<:\@/[/g;
|
|---|
| 839 | s/\@:>\@/]/g;
|
|---|
| 840 | s/\@S\|\@/\$/g;
|
|---|
| 841 | s/\@%:\@/#/g;
|
|---|
| 842 | s/\@&t\@//g;
|
|---|
| 843 | print $out $_;
|
|---|
| 844 | }
|
|---|
| 845 | }
|
|---|
| 846 |
|
|---|
| 847 |
|
|---|
| 848 | # $BOOL
|
|---|
| 849 | # up_to_date ($REQ)
|
|---|
| 850 | # -----------------
|
|---|
| 851 | # Are the cache files of $REQ up to date?
|
|---|
| 852 | # $REQ is `valid' if it corresponds to the request and exists, which
|
|---|
| 853 | # does not mean it is up to date. It is up to date if, in addition,
|
|---|
| 854 | # its files are younger than its dependencies.
|
|---|
| 855 | sub up_to_date ($)
|
|---|
| 856 | {
|
|---|
| 857 | my ($req) = @_;
|
|---|
| 858 |
|
|---|
| 859 | return 0
|
|---|
| 860 | if ! $req->valid;
|
|---|
| 861 |
|
|---|
| 862 | my $tfile = $tcache . $req->id;
|
|---|
| 863 | my $ofile = $ocache . $req->id;
|
|---|
| 864 |
|
|---|
| 865 | # We can't answer properly if the traces are not computed since we
|
|---|
| 866 | # need to know what other files were included. Actually, if any of
|
|---|
| 867 | # the cache files is missing, we are not up to date.
|
|---|
| 868 | return 0
|
|---|
| 869 | if ! -f $tfile || ! -f $ofile;
|
|---|
| 870 |
|
|---|
| 871 | # The youngest of the cache files must be older than the oldest of
|
|---|
| 872 | # the dependencies.
|
|---|
| 873 | my $tmtime = mtime ($tfile);
|
|---|
| 874 | my $omtime = mtime ($ofile);
|
|---|
| 875 | my ($file, $mtime) = ($tmtime < $omtime
|
|---|
| 876 | ? ($ofile, $omtime) : ($tfile, $tmtime));
|
|---|
| 877 |
|
|---|
| 878 | # We depend at least upon the arguments.
|
|---|
| 879 | my @dep = @ARGV;
|
|---|
| 880 |
|
|---|
| 881 | # Files may include others. We can use traces since we just checked
|
|---|
| 882 | # if they are available.
|
|---|
| 883 | handle_traces ($req, "$tmp/dependencies",
|
|---|
| 884 | ('include' => '$1',
|
|---|
| 885 | 'm4_include' => '$1'));
|
|---|
| 886 | my $deps = new Autom4te::XFile ("$tmp/dependencies");
|
|---|
| 887 | while ($_ = $deps->getline)
|
|---|
| 888 | {
|
|---|
| 889 | chomp;
|
|---|
| 890 | my $file = find_file ("$_?", @include);
|
|---|
| 891 | # If a file which used to be included is no longer there, then
|
|---|
| 892 | # don't say it's missing (it might no longer be included). But
|
|---|
| 893 | # of course, that cause the output to be outdated (as if the
|
|---|
| 894 | # time stamp of that missing file was newer).
|
|---|
| 895 | return 0
|
|---|
| 896 | if ! $file;
|
|---|
| 897 | push @dep, $file;
|
|---|
| 898 | }
|
|---|
| 899 |
|
|---|
| 900 | # If $FILE is younger than one of its dependencies, it is outdated.
|
|---|
| 901 | return up_to_date_p ($file, @dep);
|
|---|
| 902 | }
|
|---|
| 903 |
|
|---|
| 904 |
|
|---|
| 905 | ## ---------- ##
|
|---|
| 906 | ## Freezing. ##
|
|---|
| 907 | ## ---------- ##
|
|---|
| 908 |
|
|---|
| 909 | # freeze ($OUTPUT)
|
|---|
| 910 | # ----------------
|
|---|
| 911 | sub freeze ($)
|
|---|
| 912 | {
|
|---|
| 913 | my ($output) = @_;
|
|---|
| 914 |
|
|---|
| 915 | # When processing the file with diversion disabled, there must be no
|
|---|
| 916 | # output but comments and empty lines.
|
|---|
| 917 | my $result = xqx ("$m4"
|
|---|
| 918 | . ' --fatal-warning'
|
|---|
| 919 | . join (' --include=', '', @include)
|
|---|
| 920 | . ' --define=divert'
|
|---|
| 921 | . " " . files_to_options (@ARGV)
|
|---|
| 922 | . ' </dev/null');
|
|---|
| 923 | $result =~ s/#.*\n//g;
|
|---|
| 924 | $result =~ s/^\n//mg;
|
|---|
| 925 |
|
|---|
| 926 | fatal "freezing produced output:\n$result"
|
|---|
| 927 | if $result;
|
|---|
| 928 |
|
|---|
| 929 | # If freezing produces output, something went wrong: a bad `divert',
|
|---|
| 930 | # or an improper paren etc.
|
|---|
| 931 | xsystem ("$m4"
|
|---|
| 932 | . ' --fatal-warning'
|
|---|
| 933 | . join (' --include=', '', @include)
|
|---|
| 934 | . " --freeze-state=$output"
|
|---|
| 935 | . " " . files_to_options (@ARGV)
|
|---|
| 936 | . ' </dev/null');
|
|---|
| 937 | }
|
|---|
| 938 |
|
|---|
| 939 | ## -------------- ##
|
|---|
| 940 | ## Main program. ##
|
|---|
| 941 | ## -------------- ##
|
|---|
| 942 |
|
|---|
| 943 | mktmpdir ('am4t');
|
|---|
| 944 | load_configuration ($ENV{'AUTOM4TE_CFG'} || "$datadir/autom4te.cfg");
|
|---|
| 945 | load_configuration ("$ENV{'HOME'}/.autom4te.cfg")
|
|---|
| 946 | if exists $ENV{'HOME'} && -f "$ENV{'HOME'}/.autom4te.cfg";
|
|---|
| 947 | load_configuration (".autom4te.cfg")
|
|---|
| 948 | if -f ".autom4te.cfg";
|
|---|
| 949 | parse_args;
|
|---|
| 950 |
|
|---|
| 951 | # Freezing does not involve the cache.
|
|---|
| 952 | if ($freeze)
|
|---|
| 953 | {
|
|---|
| 954 | freeze ($output);
|
|---|
| 955 | exit $exit_code;
|
|---|
| 956 | }
|
|---|
| 957 |
|
|---|
| 958 | # We need our cache directory.
|
|---|
| 959 | if (! -d "$cache")
|
|---|
| 960 | {
|
|---|
| 961 | mkdir "$cache", 0755
|
|---|
| 962 | or fatal "cannot create $cache: $!";
|
|---|
| 963 | }
|
|---|
| 964 |
|
|---|
| 965 | # Open the index for update, and lock it. autom4te handles several
|
|---|
| 966 | # files, but the index is the first and last file to be update, so
|
|---|
| 967 | # locking it is sufficient.
|
|---|
| 968 | $icache_file = new Autom4te::XFile $icache, O_RDWR|O_CREAT;
|
|---|
| 969 | $icache_file->lock (LOCK_EX);
|
|---|
| 970 |
|
|---|
| 971 | # Read the cache index if available and older than autom4te itself.
|
|---|
| 972 | # If autom4te is younger, then some structures such as C4che, might
|
|---|
| 973 | # have changed, which would corrupt its processing.
|
|---|
| 974 | Autom4te::C4che->load ($icache_file)
|
|---|
| 975 | if -f $icache && mtime ($icache) > mtime ($0);
|
|---|
| 976 |
|
|---|
| 977 | # Add the new trace requests.
|
|---|
| 978 | my $req = Autom4te::C4che->request ('input' => \@ARGV,
|
|---|
| 979 | 'path' => \@include,
|
|---|
| 980 | 'macro' => [keys %trace, @preselect]);
|
|---|
| 981 |
|
|---|
| 982 | # If $REQ's cache files are not up to date, or simply if the user
|
|---|
| 983 | # discarded them (-f), declare it invalid.
|
|---|
| 984 | $req->valid (0)
|
|---|
| 985 | if $force || ! up_to_date ($req);
|
|---|
| 986 |
|
|---|
| 987 | # We now know whether we can trust the Request object. Say it.
|
|---|
| 988 | verb "the trace request object is:\n" . $req->marshall;
|
|---|
| 989 |
|
|---|
| 990 | # We need to run M4 if (i) the user wants it (--force), (ii) $REQ is
|
|---|
| 991 | # invalid.
|
|---|
| 992 | handle_m4 ($req, keys %{$req->macro})
|
|---|
| 993 | if $force || ! $req->valid;
|
|---|
| 994 |
|
|---|
| 995 | # Issue the warnings each time autom4te was run.
|
|---|
| 996 | my $separator = "\n" . ('-' x 25) . " END OF WARNING " . ('-' x 25) . "\n\n";
|
|---|
| 997 | handle_traces ($req, "$tmp/warnings",
|
|---|
| 998 | ('_m4_warn' => "\$1::\$f:\$l::\$2::\$3$separator"));
|
|---|
| 999 | # Swallow excessive newlines.
|
|---|
| 1000 | for (split (/\n*$separator\n*/o, contents ("$tmp/warnings")))
|
|---|
| 1001 | {
|
|---|
| 1002 | # The message looks like:
|
|---|
| 1003 | # | syntax::input.as:5::ouch
|
|---|
| 1004 | # | ::input.as:4: baz is expanded from...
|
|---|
| 1005 | # | input.as:2: bar is expanded from...
|
|---|
| 1006 | # | input.as:3: foo is expanded from...
|
|---|
| 1007 | # | input.as:5: the top level
|
|---|
| 1008 | my ($cat, $loc, $msg, $stacktrace) = split ('::', $_, 4);
|
|---|
| 1009 | msg $cat, $loc, "warning: $msg";
|
|---|
| 1010 | for (split /\n/, $stacktrace)
|
|---|
| 1011 | {
|
|---|
| 1012 | my ($loc, $trace) = split (': ', $_, 2);
|
|---|
| 1013 | msg $cat, $loc, $trace;
|
|---|
| 1014 | }
|
|---|
| 1015 | }
|
|---|
| 1016 |
|
|---|
| 1017 | # Now output...
|
|---|
| 1018 | if (%trace)
|
|---|
| 1019 | {
|
|---|
| 1020 | # Always produce traces, since even if the output is young enough,
|
|---|
| 1021 | # there is no guarantee that the traces use the same *format*
|
|---|
| 1022 | # (e.g., `-t FOO:foo' and `-t FOO:bar' are both using the same M4
|
|---|
| 1023 | # traces, hence the M4 traces cache is usable, but its formatting
|
|---|
| 1024 | # will yield different results).
|
|---|
| 1025 | handle_traces ($req, $output, %trace);
|
|---|
| 1026 | }
|
|---|
| 1027 | else
|
|---|
| 1028 | {
|
|---|
| 1029 | # Actual M4 expansion, if the user wants it, or if $output is old
|
|---|
| 1030 | # (STDOUT is pretty old).
|
|---|
| 1031 | handle_output ($req, $output)
|
|---|
| 1032 | if $force || mtime ($output) < mtime ($ocache . $req->id);
|
|---|
| 1033 | }
|
|---|
| 1034 |
|
|---|
| 1035 | # If we ran up to here, the cache is valid.
|
|---|
| 1036 | $req->valid (1);
|
|---|
| 1037 | Autom4te::C4che->save ($icache_file);
|
|---|
| 1038 |
|
|---|
| 1039 | exit $exit_code;
|
|---|
| 1040 |
|
|---|
| 1041 | ### Setup "GNU" style for perl-mode and cperl-mode.
|
|---|
| 1042 | ## Local Variables:
|
|---|
| 1043 | ## perl-indent-level: 2
|
|---|
| 1044 | ## perl-continued-statement-offset: 2
|
|---|
| 1045 | ## perl-continued-brace-offset: 0
|
|---|
| 1046 | ## perl-brace-offset: 0
|
|---|
| 1047 | ## perl-brace-imaginary-offset: 0
|
|---|
| 1048 | ## perl-label-offset: -2
|
|---|
| 1049 | ## cperl-indent-level: 2
|
|---|
| 1050 | ## cperl-brace-offset: 0
|
|---|
| 1051 | ## cperl-continued-brace-offset: 0
|
|---|
| 1052 | ## cperl-label-offset: -2
|
|---|
| 1053 | ## cperl-extra-newline-before-brace: t
|
|---|
| 1054 | ## cperl-merge-trailing-else: nil
|
|---|
| 1055 | ## cperl-continued-statement-offset: 2
|
|---|
| 1056 | ## End:
|
|---|