# Ditto, but records the last definition of each macro as returned by --trace.
my %map_traced_defs = ();
+# Map basenames to macro names.
+my %invmap = ();
+
# Map file names to file contents.
my %file_contents = ();
# Files that have already been scanned.
my %scanned_configure_dep = ();
+# Serial numbers, for files that have one.
+# The key is the basename of the file,
+# the value is the serial number represented as a list.
+my %serial = ();
+
# Matches a macro definition.
# AC_DEFUN([macroname], ...)
# or
# Matches an m4_include line
my $m4_include_rx = "(?:m4_)?s?include\\((?:\\[([^]]+)\\]|([^],)\n]+))\\)";
+# Match a serial number
+my $serial_line_rx = '^#\s*serial\s*(.*?)\s*$';
+my $serial_number_rx = '^\d+(?:\.\d+)*$';
\f
################################################################
%file_includes = ();
%file_added = ();
%scanned_configure_dep = ();
+ %invmap = ();
+ %serial = ();
undef &search;
}
}
}
+# Compare two lists of numbers.
+sub list_compare (\@\@)
+{
+ my @l = @{$_[0]};
+ my @r = @{$_[1]};
+ while (1)
+ {
+ if (0 == @l)
+ {
+ return (0 == @r) ? 0 : -1;
+ }
+ elsif (0 == @r)
+ {
+ return 1;
+ }
+ elsif ($l[0] < $r[0])
+ {
+ return -1;
+ }
+ elsif ($l[0] > $r[0])
+ {
+ return 1;
+ }
+ shift @l;
+ shift @r;
+ }
+}
+
################################################################
# scan_m4_dirs($TYPE, @DIRS)
sub scan_file ($$$)
{
my ($type, $file, $where) = @_;
- my $base = dirname $file;
+ my $dirname = dirname $file;
+ my $basename = basename $file;
# Do not scan the same file twice.
return @{$file_includes{$file}} if exists $file_includes{$file};
my $contents = '';
my @inc_files = ();
my %inc_lines = ();
+
+ my $defun_seen = 0;
+ my $serial_seen = 0;
+ my $serial_older = 0;
+
while ($_ = $fh->getline)
{
# Ignore `##' lines.
$contents .= $_;
my $line = $_;
+ if ($line =~ /$serial_line_rx/go)
+ {
+ my $number = $1;
+ if ($number !~ /$serial_number_rx/go)
+ {
+ msg ('syntax', "$file:$.",
+ "malformed serial number `$number', "
+ . "expecting only digits and dots");
+ }
+ elsif ($defun_seen)
+ {
+ # aclocal removes all definitions from M4 file with the
+ # same basename if a greater serial number is found.
+ # Encountering a serial after some macros will undefine
+ # these macros...
+ msg ('syntax', "$file:$.",
+ 'the serial number must appear before any macro definition');
+ }
+ # We really care about serials only for non-automake macros
+ # and when --install is used. But the above diagnostics are
+ # made regardless of this, because not using --install is
+ # not a reason not the fix macro files.
+ elsif ($install && $type != FT_AUTOMAKE)
+ {
+ $serial_seen = 1;
+ my @new = split (/\./, $number);
+
+ verb "$file:$.: serial $number";
+
+ if (!exists $serial{$basename}
+ || list_compare (@new, @{$serial{$basename}}) > 0)
+ {
+ # Delete any definition we knew from the old macro.
+ foreach my $def (@{$invmap{$basename}})
+ {
+ verb "$file:$.: ignoring previous definition of $def";
+ delete $map{$def};
+ }
+ $invmap{$basename} = [];
+ $serial{$basename} = \@new;
+ }
+ else
+ {
+ $serial_older = 1;
+ }
+ }
+ }
+
while ($line =~ /$ac_defun_rx/go)
{
+ $defun_seen = 1;
if (! defined $1)
{
msg ('syntax', "$file:$.", "warning: underquoted definition of $2"
unless $underquoted_manual_once;
$underquoted_manual_once = 1;
}
+
+ # If this macro does not have a serial and we have already
+ # seen a macro with the same basename earlier, we should
+ # ignore the macro (don't exit immediately so we can still
+ # diagnose later #serial numbers and underquoted macros).
+ $serial_older ||= ($type != FT_AUTOMAKE
+ && !$serial_seen && exists $serial{$basename});
+
my $macro = $1 || $2;
- if (! defined $map{$macro})
+ if (!$serial_older && !defined $map{$macro})
{
verb "found macro $macro in $file: $.";
$map{$macro} = $file;
+ push @{$invmap{$basename}}, $macro;
}
else
{
# paths (they might be used later of aclocal outputs an
# m4_include for this file, or if the user itself includes
# this file).
- $ifile = "$base/$ifile"
- unless $base eq '.' || File::Spec->file_name_is_absolute ($ifile);
+ $ifile = "$dirname/$ifile"
+ unless $dirname eq '.' || File::Spec->file_name_is_absolute ($ifile);
push (@inc_files, $ifile);
$inc_lines{$ifile} = $.;
}
}
+
+ # Ignore any file that has an old serial (or no serial if we know
+ # another one with a serial).
+ return ()
+ if ($serial_older ||
+ ($type != FT_AUTOMAKE && !$serial_seen && exists $serial{$basename}));
+
$file_contents{$file} = $contents;
# For some reason I don't understand, it does not work
specified with @code{-I @var{dir}} instead of copying them in the
output files.
+When this option is used, @command{aclocal} will also honor
+@code{#serial @var{NUMBER}} lines that appear in macros: an M4 file is
+ignored if there exists another M4 file with the same basename and a
+greater serial number in the search path.
+
@item --force
@opindex --force
Always overwrite the output file. The default is to overwrite the output
system-wide third-party macros in your local macro directory, solving
the above problem. Simply use:
-@example
+@smallexample
ACLOCAL_AMFLAGS = -I m4 --install
-@end example
+@end smallexample
@noindent
With this setup, system-wide macros will be copied to @file{m4/}
the first time you run @command{autoreconf}. Then the locally
installed macros will have precedence over the system-wide installed
-macros each time @command{aclocal} is run again. (So the only reason
-to keep @code{--install} in the flags after the first run is that when
-you later edit @file{configure.ac} and depend on a new macro, this
-macro will be installed in your @file{m4/} automatically.)
+macros each time @command{aclocal} is run again.
+
+One reason why you should keep @code{--install} in the flags even
+after the first run is that when you later edit @file{configure.ac}
+and depend on a new macro, this macro will be installed in your
+@file{m4/} automatically. Another one is that serial numbers can be
+used to update the macros in your source tree automatically when new
+system-wide versions are installed. A serial number should be a
+single line of the form
+
+@smallexample
+#serial @var{NNN}
+@end smallexample
+
+@noindent
+where @var{NNN} contains only digits and dots. It should appear in
+the M4 file before any macro definition. It is a good practice to
+maintain a serial number for each macro you distribute, even if you do
+not use the @code{--install} option of @command{aclocal}: this allows
+other people to use it.
@node Future of aclocal
--- /dev/null
+#! /bin/sh
+# Copyright (C) 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Automake.
+#
+# GNU Automake 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.
+#
+# GNU Automake 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 Automake; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# Test for --install with #serial numbers.
+
+. ./defs || exit 1
+
+set -e
+
+cat >> configure.in << 'END'
+AM_MACRO1
+AM_MACRO2
+END
+
+mkdir 1 2 3 4
+
+cat >1/m1.m4 <<EOF
+#serial 1.8.1230.9
+AC_DEFUN([AM_MACRO1], [echo macro11 >> foo])
+AC_DEFUN([AM_MACRO2], [echo macro21 >> foo])
+EOF
+
+cat >2/m1.m4 <<EOF
+#serial 1.8.1231.9
+AC_DEFUN([AM_MACRO1], [echo macro12 >> foo])
+EOF
+
+cat >3/m2.m4 <<EOF
+#serial 13
+AC_DEFUN([AM_MACRO2], [echo macro23 >> foo])
+EOF
+
+cat >3/m1.m4 <<EOF
+#serial 1.8.1230.1
+AC_DEFUN([AM_MACRO1], [echo macro13 >> foo])
+EOF
+
+cat >4/mumble.m4 <<EOF
+#serial 0
+AC_DEFUN([AM_MACRO1], [echo macro14 >> foo])
+EOF
+
+
+ACLOCAL_TESTSUITE_FLAGS='-I 1 -I 2 -I 3 -I 4'
+
+$ACLOCAL
+$AUTOCONF
+./configure
+grep macro11 foo
+grep macro21 foo
+
+rm -f foo
+$ACLOCAL --install
+$AUTOCONF
+./configure
+grep macro12 foo
+grep macro23 foo
+
+ACLOCAL_TESTSUITE_FLAGS='-I 4 -I 1 -I 2 -I 3'
+rm -f foo
+$ACLOCAL --install
+$AUTOCONF
+./configure
+grep macro14 foo
+grep macro23 foo
+
+ACLOCAL_TESTSUITE_FLAGS='-I 4 -I 1 -I 2'
+rm -f foo
+$ACLOCAL --install 2>stderr && exit 1
+grep AM_MACRO2 stderr
+
+ACLOCAL_TESTSUITE_FLAGS='-I 4 -I 1'
+rm -f foo
+$ACLOCAL --install
+$AUTOCONF
+./configure
+grep macro14 foo
+grep macro21 foo