X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=aclocal.in;h=cc525283f4c1508f6dfd3af2aeac46c54a4e4725;hb=3a12ed5e97dc193a38dd14e031658cbd329b50ca;hp=fe35aaa3f9808b5c42b2c1946dc9a53733333fbb;hpb=1156f6be9ab29493b1b1ccaba65f8eae0b9976f5;p=platform%2Fupstream%2Fautomake.git diff --git a/aclocal.in b/aclocal.in index fe35aaa..cc52528 100644 --- a/aclocal.in +++ b/aclocal.in @@ -1,4 +1,4 @@ -#!@PERL@ +#!@PERL@ -w # -*- perl -*- # @configure_input@ @@ -7,12 +7,12 @@ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac' # aclocal - create aclocal.m4 by scanning configure.ac -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 -# Free Software Foundation, Inc. +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 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) +# the Free Software Foundation; either version 3, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, @@ -21,455 +21,1058 @@ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac' # 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. +# along with this program. If not, see . -# Written by Tom Tromey . +# Written by Tom Tromey , and +# Alexandre Duret-Lutz . BEGIN { - my $prefix = "@prefix@"; - my $perllibdir = $ENV{'perllibdir'} || "@datadir@/@PACKAGE@-@APIVERSION@"; - unshift @INC, "$perllibdir"; + my $perllibdir = $ENV{'perllibdir'} || '@datadir@/@PACKAGE@-@APIVERSION@'; + unshift @INC, (split '@PATH_SEPARATOR@', $perllibdir); } +use strict; + +use Automake::Config; use Automake::General; +use Automake::Configure_ac; +use Automake::Channels; +use Automake::ChannelDefs; use Automake::XFile; - -# Some constants. -$VERSION = "@VERSION@"; -$APIVERSION = "@APIVERSION@"; -$PACKAGE = "@PACKAGE@"; -$prefix = "@prefix@"; -# Note that this isn't pkgdatadir, but a separate directory. -# Note also that the versioned directory is handled later. -$acdir = "@datadir@/aclocal"; -$default_acdir = $acdir; +use Automake::FileUtils; +use File::Basename; +use File::stat; +use Cwd; # Some globals. -# Exit status. -$exit_status = 0; +# We do not operate in threaded mode. +$perl_threads = 0; + +# Include paths for searching macros. We search macros in this order: +# user-supplied directories first, then the directory containing the +# automake macros, and finally the system-wide directories for +# third-party macro. @user_includes can be augmented with -I. +# @system_includes can be augmented with the `dirlist' file. Also +# --acdir will reset both @automake_includes and @system_includes. +my @user_includes = (); +my @automake_includes = ("@datadir@/aclocal-$APIVERSION"); +my @system_includes = ('@datadir@/aclocal'); + +# Whether we should copy M4 file in $user_includes[0]. +my $install = 0; -# Name of the top autoconf input: `configure.ac' or `configure.in'. -$configure_ac = find_configure_ac; +# --diff +my @diff_command; -# Text to output. -$output = ''; +# --dry-run +my $dry_run = 0; + +# configure.ac or configure.in. +my $configure_ac; # Output file name. -$output_file = 'aclocal.m4'; +my $output_file = 'aclocal.m4'; + +# Option --force. +my $force_output = 0; + +# Modification time of the youngest dependency. +my $greatest_mtime = 0; # Which macros have been seen. -%macro_seen = (); +my %macro_seen = (); -# Which files have been seen. -%file_seen = (); +# Remember the order into which we scanned the files. +# It's important to output the contents of aclocal.m4 in the opposite order. +# (Definitions in first files we have scanned should override those from +# later files. So they must appear last in the output.) +my @file_order = (); # Map macro names to file names. -%map = (); +my %map = (); + +# 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. -%file_contents = (); +my %file_contents = (); -# How much to say. -$verbose = 0; +# Map file names to file types. +my %file_type = (); +use constant FT_USER => 1; +use constant FT_AUTOMAKE => 2; +use constant FT_SYSTEM => 3; -# Map from obsolete macros to hints for new macros. -my %obsolete_macros = - ( - 'AC_FEATURE_CTYPE' => "use `AC_HEADER_STDC'", - 'AC_FEATURE_ERRNO' => "add `strerror' to `AC_REPLACE_FUNCS(...)'", - 'AC_FEATURE_EXIT' => '', - 'AC_SYSTEM_HEADER' => '', - - # Note that we do not handle this one, because it is still run - # from AM_CONFIG_HEADER. - # 'AC_CONFIG_HEADER' => "use `AM_CONFIG_HEADER'", - - 'fp_C_PROTOTYPES' => "use `AM_C_PROTOTYPES'", - 'fp_PROG_CC_STDC' => "use `AM_PROG_CC_STDC'", - 'fp_PROG_INSTALL' => "use `AC_PROG_INSTALL'", - 'fp_WITH_DMALLOC' => "use `AM_WITH_DMALLOC'", - 'fp_WITH_REGEX' => "use `AM_WITH_REGEX'", - 'gm_PROG_LIBTOOL' => "use `AM_PROG_LIBTOOL'", - 'jm_MAINTAINER_MODE' => "use `AM_MAINTAINER_MODE'", - 'md_TYPE_PTRDIFF_T' => "add `ptrdiff_t' to `AC_CHECK_TYPES(...)'", - 'ud_PATH_LISPDIR' => "use `AM_PATH_LISPDIR'", - 'ud_GNU_GETTEXT' => "use `AM_GNU_GETTEXT'", - - # Now part of autoconf proper, under a different name. - 'fp_FUNC_FNMATCH' => "use `AC_FUNC_FNMATCH'", - 'AM_SANITY_CHECK_CC' => "automatically done by `AC_PROG_CC'", - 'AM_PROG_INSTALL' => "use `AC_PROG_INSTALL'", - 'AM_EXEEXT' => "automatically done by `AC_PROG_(CC|CXX|F77)'", - 'AM_CYGWIN32' => "use `AC_CYGWIN'", - 'AM_MINGW32' => "use `AC_MINGW32'", - 'AM_FUNC_MKTIME' => "use `AC_FUNC_MKTIME'", - ); +# Map file names to included files (transitively closed). +my %file_includes = (); -# Regexp to match the above macros. -$obsolete_rx = '\b(' . join ('|', keys %obsolete_macros) . ')\b'; +# Files which have already been added. +my %file_added = (); + +# 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_rx = "AC_DEFUN\\(\\[?([^],)\n]+)\\]?"; +# AC_DEFUN([macroname], ...) +# or +# AC_DEFUN(macroname, ...) +# When macroname is `['-quoted , we accept any character in the name, +# except `]'. Otherwise macroname stops on the first `]', `,', `)', +# or `\n' encountered. +my $ac_defun_rx = + "(?:AU_ALIAS|A[CU]_DEFUN|AC_DEFUN_ONCE)\\((?:\\[([^]]+)\\]|([^],)\n]+))"; # Matches an AC_REQUIRE line. -$ac_require_rx = "AC_REQUIRE\\(\\[?([^])]*)\\]?\\)"; +my $ac_require_rx = "AC_REQUIRE\\((?:\\[([^]]+)\\]|([^],)\n]+))\\)"; - +# Matches an m4_include line. +my $m4_include_rx = "(m4_|m4_s|s)include\\((?:\\[([^]]+)\\]|([^],)\n]+))\\)"; -local (@dirlist) = &parse_arguments (@ARGV); -&scan_m4_files (@dirlist); -&scan_configure; -if (! $exit_status) -{ - &write_aclocal; -} -&check_acinclude; +# Match a serial number. +my $serial_line_rx = '^#\s*serial\s+(\S*)'; +my $serial_number_rx = '^\d+(?:\.\d+)*$'; -exit $exit_status; +# Autoconf version +# Set by trace_used_macros. +my $ac_version; +# If set, names a temporary file that must be erased on abnormal exit. +my $erase_me; + ################################################################ -# Print usage and exit. -sub usage +# Erase temporary file ERASE_ME. Handle signals. +sub unlink_tmp { - local ($status) = @_; + my ($sig) = @_; - print "Usage: aclocal [OPTIONS] ...\n\n"; - print "\ -Generate `aclocal.m4' by scanning `configure.ac' or `configure.in' + if ($sig) + { + verb "caught SIG$sig, bailing out"; + } + if (defined $erase_me && -e $erase_me && !unlink ($erase_me)) + { + fatal "could not remove `$erase_me': $!"; + } + undef $erase_me; - --acdir=DIR directory holding config files - --help print this help, then exit - -I DIR add directory to search list for .m4 files - --output=FILE put output in FILE (default aclocal.m4) - --print-ac-dir print name of directory holding m4 files - --verbose don't be silent - --version print version number, then exit + # reraise default handler. + if ($sig) + { + $SIG{$sig} = 'DEFAULT'; + kill $sig => $$; + } +} -Report bugs to .\n"; +$SIG{'INT'} = $SIG{'TERM'} = $SIG{'QUIT'} = $SIG{'HUP'} = 'unlink_tmp'; +END { unlink_tmp } - exit $status; +# Check macros in acinclude.m4. If one is not used, warn. +sub check_acinclude () +{ + foreach my $key (keys %map) + { + # FIXME: should print line number of acinclude.m4. + msg ('syntax', "warning: macro `$key' defined in " + . "acinclude.m4 but never used") + if $map{$key} eq 'acinclude.m4' && ! exists $macro_seen{$key}; + } } -# Parse command line. -sub parse_arguments +sub reset_maps () +{ + $greatest_mtime = 0; + %macro_seen = (); + @file_order = (); + %map = (); + %map_traced_defs = (); + %file_contents = (); + %file_type = (); + %file_includes = (); + %file_added = (); + %scanned_configure_dep = (); + %invmap = (); + %serial = (); + undef &search; +} + +# install_file ($SRC, $DEST) +sub install_file ($$) { - local (@arglist) = @_; - local (@dirlist); - local ($print_and_exit) = 0; + my ($src, $dest) = @_; + my $diff_dest; - while (@arglist) + if ($force_output + || !exists $file_contents{$dest} + || $file_contents{$src} ne $file_contents{$dest}) { - if ($arglist[0] =~ /^--acdir=(.+)$/) + if (-e $dest) { - $acdir = $1; + msg 'note', "overwriting `$dest' with `$src'"; + $diff_dest = $dest; } - elsif ($arglist[0] =~/^--output=(.+)$/) + else { - $output_file = $1; + msg 'note', "installing `$dest' from `$src'"; } - elsif ($arglist[0] eq '-I') + + if (@diff_command) { - shift (@arglist); - push (@dirlist, $arglist[0]); + if (! defined $diff_dest) + { + # $dest does not exist. We create an empty one just to + # run diff, and we erase it afterward. Using the real + # the destination file (rather than a temporary file) is + # good when diff is run with options that display the + # file name. + # + # If creating $dest fails, fall back to /dev/null. At + # least one diff implementation (Tru64's) cannot deal + # with /dev/null. However working around this is not + # worth the trouble since nobody run aclocal on a + # read-only tree anyway. + $erase_me = $dest; + my $f = new IO::File "> $dest"; + if (! defined $f) + { + undef $erase_me; + $diff_dest = '/dev/null'; + } + else + { + $diff_dest = $dest; + $f->close; + } + } + my @cmd = (@diff_command, $diff_dest, $src); + $! = 0; + verb "running: @cmd"; + my $res = system (@cmd); + Automake::FileUtils::handle_exec_errors "@cmd", 1 + if $res; + unlink_tmp; } - elsif ($arglist[0] eq '--print-ac-dir') + elsif (!$dry_run) { - $print_and_exit = 1; + xsystem ('cp', $src, $dest); } - elsif ($arglist[0] eq '--verbose') + } +} + +# Compare two lists of numbers. +sub list_compare (\@\@) +{ + my @l = @{$_[0]}; + my @r = @{$_[1]}; + while (1) + { + if (0 == @l) { - ++$verbose; + return (0 == @r) ? 0 : -1; } - elsif ($arglist[0] eq '--version') + elsif (0 == @r) { - print "aclocal (GNU $PACKAGE) $VERSION\n\n"; - print "Copyright 2002 Free Software Foundation, Inc.\n"; - print "This is free software; see the source for copying conditions. There is NO\n"; - print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"; - print "Written by Tom Tromey \n"; - exit 0; + return 1; } - elsif ($arglist[0] eq '--help') + elsif ($l[0] < $r[0]) { - &usage (0); + return -1; } - else + elsif ($l[0] > $r[0]) { - die "aclocal: unrecognized option -- `$arglist[0]'\nTry `aclocal --help' for more information.\n"; + return 1; } - - shift (@arglist); + shift @l; + shift @r; } +} + +################################################################ + +# scan_m4_dirs($TYPE, @DIRS) +# -------------------------- +# Scan all M4 files installed in @DIRS for new macro definitions. +# Register each file as of type $TYPE (one of the FT_* constants). +sub scan_m4_dirs ($@) +{ + my ($type, @dirlist) = @_; - if ($print_and_exit) + foreach my $m4dir (@dirlist) { - print $acdir, "\n"; - exit 0; + if (! opendir (DIR, $m4dir)) + { + fatal "couldn't open directory `$m4dir': $!"; + } + + # We reverse the directory contents so that foo2.m4 gets + # used in preference to foo1.m4. + foreach my $file (reverse sort grep (! /^\./, readdir (DIR))) + { + # Only examine .m4 files. + next unless $file =~ /\.m4$/; + + # Skip some files when running out of srcdir. + next if $file eq 'aclocal.m4'; + + my $fullfile = File::Spec->canonpath ("$m4dir/$file"); + &scan_file ($type, $fullfile, 'aclocal'); + } + closedir (DIR); } +} - # Search the versioned directory near the end, and then the - # unversioned directory last. Only do this if the user didn't - # override acdir. - push (@dirlist, "$acdir-$APIVERSION") - if $acdir eq $default_acdir; +# Scan all the installed m4 files and construct a map. +sub scan_m4_files () +{ + # First, scan configure.ac. It may contain macro definitions, + # or may include other files that define macros. + &scan_file (FT_USER, $configure_ac, 'aclocal'); + + # Then, scan acinclude.m4 if it exists. + if (-f 'acinclude.m4') + { + &scan_file (FT_USER, 'acinclude.m4', 'aclocal'); + } - # By default $(datadir)/aclocal doesn't exist. We don't want to - # get an error in the case where we are searching the default - # directory and it hasn't been created. - push (@dirlist, $acdir) - unless $acdir eq $default_acdir && ! -d $acdir; + # Finally, scan all files in our search paths. + scan_m4_dirs (FT_USER, @user_includes); + scan_m4_dirs (FT_AUTOMAKE, @automake_includes); + scan_m4_dirs (FT_SYSTEM, @system_includes); - return @dirlist; + # Construct a new function that does the searching. We use a + # function (instead of just evaluating $search in the loop) so that + # "die" is correctly and easily propagated if run. + my $search = "sub search {\nmy \$found = 0;\n"; + foreach my $key (reverse sort keys %map) + { + $search .= ('if (/\b\Q' . $key . '\E(?!\w)/) { & add_macro ("' . $key + . '"); $found = 1; }' . "\n"); + } + $search .= "return \$found;\n};\n"; + eval $search; + prog_error "$@\n search is $search" if $@; } ################################################################ -sub scan_configure +# Add a macro to the output. +sub add_macro ($) { - die "aclocal: `configure.ac' or `configure.in' is required\n" - if !$configure_ac; + my ($macro) = @_; - open (CONFIGURE, $configure_ac) - || die "aclocal: couldn't open `$configure_ac': $!\n"; + # Ignore unknown required macros. Either they are not really + # needed (e.g., a conditional AC_REQUIRE), in which case aclocal + # should be quiet, or they are needed and Autoconf itself will + # complain when we trace for macro usage later. + return unless defined $map{$macro}; - # Make sure we include acinclude.m4 if it exists. - if (-f 'acinclude.m4') + verb "saw macro $macro"; + $macro_seen{$macro} = 1; + &add_file ($map{$macro}); +} + +# scan_configure_dep ($file) +# -------------------------- +# Scan a configure dependency (configure.ac, or separate m4 files) +# for uses of known macros and AC_REQUIREs of possibly unknown macros. +# Recursively scan m4_included files. +sub scan_configure_dep ($) +{ + my ($file) = @_; + # Do not scan a file twice. + return () + if exists $scanned_configure_dep{$file}; + $scanned_configure_dep{$file} = 1; + + my $mtime = mtime $file; + $greatest_mtime = $mtime if $greatest_mtime < $mtime; + + my $contents = exists $file_contents{$file} ? + $file_contents{$file} : contents $file; + + my $line = 0; + my @rlist = (); + my @ilist = (); + foreach (split ("\n", $contents)) { - &add_file ('acinclude.m4'); + ++$line; + # Remove comments from current line. + s/\bdnl\b.*$//; + s/\#.*$//; + # Avoid running all the following regexes on white lines. + next if /^\s*$/; + + while (/$m4_include_rx/go) + { + my $ifile = $2 || $3; + # Skip missing `sinclude'd files. + next if $1 ne 'm4_' && ! -f $ifile; + push @ilist, $ifile; + } + + while (/$ac_require_rx/go) + { + push (@rlist, $1 || $2); + } + + # The search function is constructed dynamically by + # scan_m4_files. The last parenthetical match makes sure we + # don't match things that look like macro assignments or + # AC_SUBSTs. + if (! &search && /(^|\s+)(AM_[A-Z0-9_]+)($|[^\]\)=A-Z0-9_])/) + { + # Macro not found, but AM_ prefix found. + # Make this just a warning, because we do not know whether + # the macro is actually used (it could be called conditionally). + msg ('unsupported', "$file:$line", + "warning: macro `$2' not found in library"); + } } - while () + add_macro ($_) foreach (@rlist); + &scan_configure_dep ($_) foreach @ilist; +} + +# add_file ($FILE) +# ---------------- +# Add $FILE to output. +sub add_file ($) +{ + my ($file) = @_; + + # Only add a file once. + return if ($file_added{$file}); + $file_added{$file} = 1; + + scan_configure_dep $file; +} + +# Point to the documentation for underquoted AC_DEFUN only once. +my $underquoted_manual_once = 0; + +# scan_file ($TYPE, $FILE, $WHERE) +# -------------------------------- +# Scan a single M4 file ($FILE), and all files it includes. +# Return the list of included files. +# $TYPE is one of FT_USER, FT_AUTOMAKE, or FT_SYSTEM, depending +# on where the file comes from. +# $WHERE is the location to use in the diagnostic if the file +# does not exist. +sub scan_file ($$$) +{ + my ($type, $file, $where) = @_; + my $basename = basename $file; + + # Do not scan the same file twice. + return @{$file_includes{$file}} if exists $file_includes{$file}; + # Prevent potential infinite recursion (if two files include each other). + return () if exists $file_contents{$file}; + + unshift @file_order, $file; + + $file_type{$file} = $type; + + fatal "$where: file `$file' does not exist" if ! -e $file; + + my $fh = new Automake::XFile $file; + my $contents = ''; + my @inc_files = (); + my %inc_lines = (); + + my $defun_seen = 0; + my $serial_seen = 0; + my $serial_older = 0; + + while ($_ = $fh->getline) { - # Remove comments from current line. - s/\bdnl\b.*$//; - s/\#.*$//; + # Ignore `##' lines. + next if /^##/; - if (/$obsolete_rx/o) + $contents .= $_; + my $line = $_; + + if ($line =~ /$serial_line_rx/go) { - local ($hint) = ''; - if ($obsolete_macros{$1} ne '') + my $number = $1; + if ($number !~ /$serial_number_rx/go) + { + msg ('syntax', "$file:$.", + "warning: ill-formed serial number `$number', " + . "expecting a version string with 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) { - $hint = '; ' . $obsolete_macros{$1}; + $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; + } } - warn "aclocal: $configure_ac: $.: `$1' is obsolete$hint\n"; - $exit_status = 1; - next; } - # Search for things we know about. The "search" sub is - # constructed dynamically by scan_m4_files. The last - # parenthethical match makes sure we don't match things that - # look like macro assignments or AC_SUBSTs. - if (! &search && /(^|\s+)(AM_[A-Z0-9_]+)($|[^\]\)=A-Z0-9_])/) + # Remove comments from current line. + # Do not do it earlier, because the serial line is a comment. + $line =~ s/\bdnl\b.*$//; + $line =~ s/\#.*$//; + + while ($line =~ /$ac_defun_rx/go) { - # Macro not found, but AM_ prefix found. - warn "aclocal: $configure_ac: $.: macro `$2' not found in library\n"; - $exit_status = 1; + $defun_seen = 1; + if (! defined $1) + { + msg ('syntax', "$file:$.", "warning: underquoted definition of $2" + . "\n run info '(automake)Extending aclocal'\n" + . " or see http://sources.redhat.com/automake/" + . "automake.html#Extending-aclocal") + 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 (!$serial_older && !defined $map{$macro}) + { + verb "found macro $macro in $file: $."; + $map{$macro} = $file; + push @{$invmap{$basename}}, $macro; + } + else + { + # Note: we used to give an error here if we saw a + # duplicated macro. However, this turns out to be + # extremely unpopular. It causes actual problems which + # are hard to work around, especially when you must + # mix-and-match tool versions. + verb "ignoring macro $macro in $file: $."; + } + } + + while ($line =~ /$m4_include_rx/go) + { + my $ifile = $2 || $3; + # Skip missing `sinclude'd files. + next if $1 ne 'm4_' && ! -f $ifile; + push (@inc_files, $ifile); + $inc_lines{$ifile} = $.; } } - close (CONFIGURE); + # 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 + # to do `map { scan_file ($_, ...) } @inc_files' below. + # With Perl 5.8.2 it undefines @inc_files. + my @copy = @inc_files; + my @all_inc_files = (@inc_files, + map { scan_file ($type, $_, + "$file:$inc_lines{$_}") } @copy); + $file_includes{$file} = \@all_inc_files; + return @all_inc_files; } -################################################################ - -# Check macros in acinclude.m4. If one is not used, warn. -sub check_acinclude +# strip_redundant_includes (%FILES) +# --------------------------------- +# Each key in %FILES is a file that must be present in the output. +# However some of these files might already include other files in %FILES, +# so there is no point in including them another time. +# This removes items of %FILES which are already included by another file. +sub strip_redundant_includes (%) { - local ($key); - - foreach $key (keys %map) + my %files = @_; + + # Always include acinclude.m4, even if it does not appear to be used. + $files{'acinclude.m4'} = 1 if -f 'acinclude.m4'; + # File included by $configure_ac are redundant. + $files{$configure_ac} = 1; + + # Files at the end of @file_order should override those at the beginning, + # so it is important to preserve these trailing files. We can remove + # a file A if it is going to be output before a file B that includes + # file A, not the converse. + foreach my $file (reverse @file_order) { - next unless $map{$key} eq 'acinclude.m4'; - if (! $macro_seen{$key}) + next unless exists $files{$file}; + foreach my $ifile (@{$file_includes{$file}}) { - # FIXME: should print line number of acinclude.m4. - warn "aclocal: macro `$key' defined in acinclude.m4 but never used\n"; + next unless exists $files{$ifile}; + delete $files{$ifile}; + verb "$ifile is already included by $file"; } } + + # configure.ac is implicitly included. + delete $files{$configure_ac}; + + return %files; } -################################################################ +sub trace_used_macros () +{ + my %files = map { $map{$_} => 1 } keys %macro_seen; + %files = strip_redundant_includes %files; + + my $traces = ($ENV{AUTOM4TE} || 'autom4te'); + $traces .= " --language Autoconf-without-aclocal-m4 "; + # All candidate files. + $traces .= join (' ', + (map { "'$_'" } + (grep { exists $files{$_} } @file_order))) . " "; + # All candidate macros. + $traces .= join (' ', + (map { "--trace='$_:\$f::\$n::\$1'" } + ('AC_DEFUN', + 'AC_DEFUN_ONCE', + 'AU_DEFUN', + '_AM_AUTOCONF_VERSION')), + # Do not trace $1 for all other macros as we do + # not need it and it might contains harmful + # characters (like newlines). + (map { "--trace='$_:\$f::\$n'" } (keys %macro_seen))); + + verb "running $traces $configure_ac"; + + my $tracefh = new Automake::XFile ("$traces $configure_ac |"); + + my %traced = (); + + while ($_ = $tracefh->getline) + { + chomp; + my ($file, $macro, $arg1) = split (/::/); -# Scan all the installed m4 files and construct a map. -sub scan_m4_files + $traced{$macro} = 1 if exists $macro_seen{$macro}; + + $map_traced_defs{$arg1} = $file + if ($macro eq 'AC_DEFUN' + || $macro eq 'AC_DEFUN_ONCE' + || $macro eq 'AU_DEFUN'); + + $ac_version = $arg1 if $macro eq '_AM_AUTOCONF_VERSION'; + } + + $tracefh->close; + + return %traced; +} + +sub scan_configure () { - local (@dirlist) = @_; + # Make sure we include acinclude.m4 if it exists. + if (-f 'acinclude.m4') + { + add_file ('acinclude.m4'); + } + scan_configure_dep ($configure_ac); +} + +################################################################ - # First, scan acinclude.m4 if it exists. - if (-f 'acinclude.m4') +# Write output. +# Return 0 iff some files were installed locally. +sub write_aclocal ($@) +{ + my ($output_file, @macros) = @_; + my $output = ''; + + my %files = (); + # Get the list of files containing definitions for the macros used. + # (Filter out unused macro definitions with $map_traced_defs. This + # can happen when an Autoconf macro is conditionally defined: + # aclocal sees the potential definition, but this definition is + # actually never processed and the Autoconf implementation is used + # instead.) + for my $m (@macros) { - $file_contents{'acinclude.m4'} = &scan_file ('acinclude.m4'); + $files{$map{$m}} = 1 + if (exists $map_traced_defs{$m} + && $map{$m} eq $map_traced_defs{$m}); } + # Do not explicitly include a file that is already indirectly included. + %files = strip_redundant_includes %files; + + my $installed = 0; - local ($m4dir); - foreach $m4dir (@dirlist) + for my $file (grep { exists $files{$_} } @file_order) { - opendir (DIR, $m4dir) - || die "aclocal: couldn't open directory `$m4dir': $!\n"; - local ($file, $fullfile); - foreach $file (sort grep (! /^\./, readdir (DIR))) + # Check the time stamp of this file, and of all files it includes. + for my $ifile ($file, @{$file_includes{$file}}) { - # Only examine .m4 files. - next unless $file =~ /\.m4$/; - - # Skip some files when running out of srcdir. - next if $file eq 'aclocal.m4'; + my $mtime = mtime $ifile; + $greatest_mtime = $mtime if $greatest_mtime < $mtime; + } - $fullfile = $m4dir . '/' . $file; - $file_contents{$fullfile} = &scan_file ($fullfile); + # If the file to add looks like outside the project, copy it + # to the output. The regex catches filenames starting with + # things like `/', `\', or `c:\'. + if ($file_type{$file} != FT_USER + || $file =~ m,^(?:\w:)?[\\/],) + { + if (!$install || $file_type{$file} != FT_SYSTEM) + { + # Copy the file into aclocal.m4. + $output .= $file_contents{$file} . "\n"; + } + else + { + # Install the file (and any file it includes). + my $dest; + for my $ifile (@{$file_includes{$file}}, $file) + { + $dest = "$user_includes[0]/" . basename $ifile; + verb "installing $ifile to $dest"; + install_file ($ifile, $dest); + } + $installed = 1; + } } - closedir (DIR); + else + { + # Otherwise, simply include the file. + $output .= "m4_include([$file])\n"; + } + } + + if ($installed) + { + verb "running aclocal anew, because some files were installed locally"; + return 0; + } + + # Nothing to output?! + # FIXME: Shouldn't we diagnose this? + return 1 if ! length ($output); + + if ($ac_version) + { + # Do not use "$output_file" here for the same reason we do not + # use it in the header below. autom4te will output the name of + # the file in the diagnostic anyway. + $output = "m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [$ac_version],, +[m4_warning([this file was generated for autoconf $ac_version. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +$output"; + } + + # We used to print `# $output_file generated automatically etc.' But + # this creates spurious differences when using autoreconf. Autoreconf + # creates aclocal.m4t and then rename it to aclocal.m4, but the + # rebuild rules generated by Automake create aclocal.m4 directly -- + # this would gives two ways to get the same file, with a different + # name in the header. + $output = "# generated automatically by aclocal $VERSION -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +$output"; + + # We try not to update $output_file unless necessary, because + # doing so invalidate Autom4te's cache and therefore slows down + # tools called after aclocal. + # + # We need to overwrite $output_file in the following situations. + # * The --force option is in use. + # * One of the dependencies is younger. + # (Not updating $output_file in this situation would cause + # make to call aclocal in loop.) + # * The contents of the current file are different from what + # we have computed. + if (!$force_output + && $greatest_mtime < mtime ($output_file) + && $output eq contents ($output_file)) + { + verb "$output_file unchanged"; + return 1; } - # Construct a new function that does the searching. We use a - # function (instead of just evalling $search in the loop) so that - # "die" is correctly and easily propagated if run. - my $search = "sub search {\nmy \$found = 0;\n"; - foreach my $key (reverse sort keys %map) + verb "writing $output_file"; + + if (!$dry_run) { - # EXPR is a regexp matching the name of the macro. - (my $expr = $key) =~ s/(\W)/\\$1/g; - $search .= ('if (/\b' . $key . '\b/) { & add_macro (' . $key - . '); $found = 1; }' . "\n"); + if (-e $output_file && !unlink $output_file) + { + fatal "could not remove `$output_file': $!"; + } + my $out = new Automake::XFile "> $output_file"; + print $out $output; } - $search .= "return \$found;\n};\n"; - eval $search; - die "internal error: $@\n search is $search" if $@; + return 1; } ################################################################ -# Add a macro to the output. -sub add_macro +# Print usage and exit. +sub usage ($) { - local ($macro) = @_; + my ($status) = @_; - # We want to ignore AC_ macros. However, if an AC_ macro is - # defined in (eg) acinclude.m4, then we want to make sure we mark - # it as seen. - return if $macro =~ /^AC_/ && ! defined $map{$macro}; + print "Usage: aclocal [OPTIONS] ... - if (! defined $map{$macro}) - { - warn "aclocal: macro `$macro' required but not defined\n"; - $exit_status = 1; - return; - } +Generate `aclocal.m4' by scanning `configure.ac' or `configure.in' + +Options: + --acdir=DIR directory holding config files (for debugging) + --diff[=COMMAND] run COMMAND [diff -u] on M4 files that would be + changed (implies --install and --dry-run) + --dry-run pretend to, but do not actually update any file + --force always update output file + --help print this help, then exit + -I DIR add directory to search list for .m4 files + --install copy third-party files to the first -I directory + --output=FILE put output in FILE (default aclocal.m4) + --print-ac-dir print name of directory holding m4 files, then exit + --verbose don't be silent + --version print version number, then exit + -W, --warnings=CATEGORY report the warnings falling in CATEGORY + +Warning categories include: + `syntax' dubious syntactic constructs (default) + `unsupported' unknown macros (default) + `all' all the warnings (default) + `no-CATEGORY' turn off warnings in CATEGORY + `none' turn off all the warnings + `error' treat warnings as errors - print STDERR "aclocal: saw macro $macro\n" if $verbose; - $macro_seen{$macro} = 1; - &add_file ($map{$macro}); +Report bugs to .\n"; + + exit $status; } -# Add a file to output. -sub add_file +# Print version and exit. +sub version() { - local ($file) = @_; + print < +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +Written by Tom Tromey + and Alexandre Duret-Lutz . +EOF + exit 0; +} - # Only add a file once. - return if ($file_seen{$file}); - $file_seen{$file} = 1; +# Parse command line. +sub parse_arguments () +{ + my $print_and_exit = 0; + my $diff_command; - $output .= $file_contents{$file} . "\n"; - local ($a, @rlist); - foreach (split ("\n", $file_contents{$file})) + my %cli_options = + ( + 'acdir=s' => sub # Setting --acdir overrides both the + { # automake (versioned) directory and the + # public (unversioned) system directory. + @automake_includes = (); + @system_includes = ($_[1]) + }, + 'diff:s' => \$diff_command, + 'dry-run' => \$dry_run, + 'force' => \$force_output, + 'I=s' => \@user_includes, + 'install' => \$install, + 'output=s' => \$output_file, + 'print-ac-dir' => \$print_and_exit, + 'verbose' => sub { setup_channel 'verb', silent => 0; }, + 'W|warnings=s' => \&parse_warnings, + ); + use Getopt::Long; + Getopt::Long::config ("bundling", "pass_through"); + + # See if --version or --help is used. We want to process these before + # anything else because the GNU Coding Standards require us to + # `exit 0' after processing these options, and we can't guarantee this + # if we treat other options first. (Handling other options first + # could produce error diagnostics, and in this condition it is + # confusing if aclocal does `exit 0'.) + my %cli_options_1st_pass = + ( + 'version' => \&version, + 'help' => sub { usage(0); }, + # Recognize all other options (and their arguments) but do nothing. + map { $_ => sub {} } (keys %cli_options) + ); + my @ARGV_backup = @ARGV; + Getopt::Long::GetOptions %cli_options_1st_pass + or exit 1; + @ARGV = @ARGV_backup; + + # Now *really* process the options. This time we know that --help + # and --version are not present, but we specify them nonetheless so + # that ambiguous abbreviation are diagnosed. + Getopt::Long::GetOptions %cli_options, 'version' => sub {}, 'help' => sub {} + or exit 1; + + if (@ARGV) { - # This is a hack for Perl 4. - $a = $_; - if ($a =~ /$ac_require_rx/g) + my %argopts; + for my $k (keys %cli_options) { - push (@rlist, $1); + if ($k =~ /(.*)=s$/) + { + map { $argopts{(length ($_) == 1) + ? "-$_" : "--$_" } = 1; } (split (/\|/, $1)); + } } - - # Remove comments from current line. - s/\bdnl\b.*$//; - s/\#.*$//; - - # The search function is constructed dynamically by - # scan_m4_files. The last parenthethical match makes sure we - # don't match things that look like macro assignments or - # AC_SUBSTs. - if (! &search && /(^|\s+)(AM_[A-Z0-9_]+)($|[^\]\)=A-Z0-9_])/) + if (exists $argopts{$ARGV[0]}) { - # Macro not found, but AM_ prefix found. - warn "aclocal: $configure_ac: $.: macro `$2' not found in library\n"; - $exit_status = 1; + fatal ("option `$ARGV[0]' requires an argument\n" + . "Try `$0 --help' for more information."); + } + else + { + fatal ("unrecognized option `$ARGV[0]'\n" + . "Try `$0 --help' for more information."); } } - local ($macro); - foreach $macro (@rlist) + if ($print_and_exit) { - &add_macro ($macro); + print "@system_includes\n"; + exit 0; } -} -# Scan a single M4 file. Return contents. -sub scan_file -{ - local ($file) = @_; - - my $fh = new Automake::XFile $file; - my $contents = ''; - while ($_ = $fh->getline) + if (defined $diff_command) { - # Ignore `##' lines. - next if /^##/; + $diff_command = 'diff -u' if $diff_command eq ''; + @diff_command = split (' ', $diff_command); + $install = 1; + $dry_run = 1; + } - $contents .= $_; + if ($install && !@user_includes) + { + fatal ("--install should copy macros in the directory indicated by the" + . "\nfirst -I option, but no -I was supplied."); + } - if (/$ac_defun_rx/) + if (! -d $system_includes[0]) + { + # By default $(datadir)/aclocal doesn't exist. We don't want to + # get an error in the case where we are searching the default + # directory and it hasn't been created. (We know + # @system_includes has its default value if @automake_includes + # is not empty, because --acdir is the only way to change this.) + @system_includes = () if @automake_includes; + } + else + { + # Finally, adds any directory listed in the `dirlist' file. + if (open (DIRLIST, "$system_includes[0]/dirlist")) { - if (! defined $map{$1}) + while () { - $map{$1} = $file; + # Ignore '#' lines. + next if /^#/; + # strip off newlines and end-of-line comments + s/\s*\#.*$//; + chomp; + foreach my $dir (glob) + { + push (@system_includes, $dir) if -d $dir; + } } - - # Note: we used to give an error here if we saw a - # duplicated macro. However, this turns out to be - # extremely unpopular. It causes actual problems which - # are hard to work around, especially when you must - # mix-and-match tool versions. - - print STDERR "aclocal: found macro $1 in $file: $.\n" if $verbose; + close (DIRLIST); } } - - return $contents; } ################################################################ -# Write output. -sub write_aclocal -{ - return if ! length ($output); - - print STDERR "aclocal: writing $output_file\n" if $verbose; - - my $out = new Automake::XFile "> $output_file"; - print $out -"# $output_file generated automatically by aclocal $VERSION -*- Autoconf -*- - -# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 -# Free Software Foundation, Inc. -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -$output"; -} +parse_WARNINGS; # Parse the WARNINGS environment variable. +parse_arguments; +$configure_ac = require_configure_ac; + +# We may have to rerun aclocal if some file have been installed, but +# it should not happen more than once. The reason we must run again +# is that once the file has been moved from /usr/share/aclocal/ to the +# local m4/ directory it appears at a new place in the search path, +# hence it should be output at a different position in aclocal.m4. If +# we did not rerun aclocal, the next run of aclocal would produce a +# different aclocal.m4. +my $loop = 0; +while (1) + { + ++$loop; + prog_error "Too many loops." if $loop > 2; + + reset_maps; + scan_m4_files; + scan_configure; + last if $exit_code; + my %macro_traced = trace_used_macros; + last if write_aclocal ($output_file, keys %macro_traced); + last if $dry_run; + } +check_acinclude; + +exit $exit_code; ### Setup "GNU" style for perl-mode and cperl-mode. ## Local Variables: