]> git.ipfire.org Git - thirdparty/autoconf.git/commitdiff
Improve handling of missing aux scripts (autoreconf)
authorZack Weinberg <zackw@panix.com>
Tue, 20 Oct 2020 17:36:58 +0000 (13:36 -0400)
committerZack Weinberg <zackw@panix.com>
Tue, 20 Oct 2020 20:57:01 +0000 (16:57 -0400)
Make ‘autoreconf --install’ add config.sub, config.guess, and
install-sh to the source tree when necessary.  This is only relevant
for packages that don’t use Automake, because ‘automake --add-missing’
already adds these scripts to the source tree, but apparently there
are plenty of packages out there that don’t use Automake, didn’t need
config.{sub,guess} with autoconf 2.69, and do need them with 2.70.
Such packages will need to have their equivalent of ‘make dist’
manually updated to ship the new files, of course.

This patch also has ‘autoreconf’ issue an error if aux files are
missing and ‘--install’ *wasn’t* used, or if --install *was* used but
could not install all the missing files.  This error is more likely to
be caught by maintainers than the configure-time error added in the
previous patch.  It is not currently practical to make autoconf itself
issue this error message, because of how the autoconf wrapper script
is different from all the other wrapper scripts.  Also, autoreconf
runs automake *after* autoconf, so we’d get spurious errors from
packages that do use automake.

* bin/autoreconf.in ($buildauxdir): New package global, initialized
  to $pkgdatadir/build-aux, or to $ENV{autom4te_buildauxdir} if that’s set.
  (find_missing_aux_files, can_install_aux_files, try_install_aux_files)
  (install_aux_file, make_executable): New subs.
  (autoreconf_current_directory): Trace AC_REQUIRE_AUX_FILE.
  After running all tools that might install aux files, try to
  install aux files ourself if --install was given.
  After that, report on any that are still missing.
* lib/autom4te.in (Autoreconf-preselections): Add AC_REQUIRE_AUX_FILE.
  Make list order consistent with list order in autoreconf.in.
* tests/wrapper.as: Set autom4te_buildauxdir to point to location of
  config.guess, config.sub, and install-sh within the source tree.

* lib/local.mk: Install config.guess, config.sub, and install-sh
  into $(pkgdatadir)/build-aux.

* doc/autoconf.texi: Document that autoreconf can now install
  config.guess, config.sub, and install-sh itself without help from
  automake, but packages not using automake will need to arrange for
  tarball distribution of these files by hand.

* tests/torture.at (Missing auxiliary files): Test autoreconf as well.

NEWS
bin/autoreconf.in
doc/autoconf.texi
lib/autom4te.in
lib/local.mk
tests/torture.at
tests/wrapper.as

diff --git a/NEWS b/NEWS
index 1883faab3cfe4cba5fcb72b4328a938ee50a5372..42095344128ae45023335ffe8b87890ef333f8c0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -55,11 +55,18 @@ GNU Autoconf NEWS - User visible changes.
   when your configure script is run, even if you have no intention of
   ever cross-compiling your program.
 
-  If you are using Automake, the auxiliary scripts your configure script
-  needs will be added to your source tree by ‘autoreconf --install’ or
-  ‘automake --add-missing’, and will be automatically included in your
-  distribution tarball.  If you are not using Automake, you will need
-  to add them yourself.  See the “Input” section of the manual for
+  autoreconf will issue an error if any auxiliary scripts are needed but
+  cannot be found.  (It is not currently possible to make autoconf
+  itself issue this error.)
+
+  ‘autoreconf --install’ will add ‘config.sub’, ‘config.guess’, and
+  ‘install-sh’ to your source tree if they are needed.  If you are
+  using Automake, scripts added to your tree by ‘autoreconf --install’
+  will automatically be included in the tarball produced by ‘make dist’;
+  otherwise, you will need to arrange for them to be distributed
+  yourself.
+
+  See the “Input” section of the manual for more detail, including
   where to get the auxiliary scripts that may be needed by autoconf macros.
 
 *** Older versions of automake and aclocal (< 1.8) are no longer supported.
index ba08c6acc686aa9d5c8391710c8663cba6cf8d99..2d4271556a08cee34105b0a6609a05e7b1a1fc20 100644 (file)
@@ -28,11 +28,14 @@ use 5.006;
 use strict;
 use warnings FATAL => 'all';
 
+my $buildauxdir;
 BEGIN
 {
   my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
   unshift @INC, $pkgdatadir;
 
+  $buildauxdir = $ENV{'autom4te_buildauxdir'} || $pkgdatadir . '/build-aux';
+
   # Override SHELL.  On DJGPP SHELL may not be set to a shell
   # that can handle redirection and quote arguments correctly,
   # e.g.: COMMAND.COM.  For DJGPP always use the shell that configure
@@ -42,6 +45,8 @@ BEGIN
 
 # Do not use Cwd::chdir, since it might hang.
 use Cwd qw (cwd);
+use File::Copy qw (copy);
+use File::Temp ();
 
 use Autom4te::ChannelDefs;
 use Autom4te::Channels;
@@ -244,6 +249,146 @@ sub parse_args ()
 }
 
 
+## ----------------------- ##
+## Handling of aux files.  ##
+## ----------------------- ##
+
+# find_missing_aux_files
+# ----------------------
+# Look in $aux_dir (or, if that is empty, ., .., and ../..) for all of the
+# files in @$aux_files; return a list of those that do not exist.
+sub find_missing_aux_files
+{
+  my ($aux_files, $aux_dir) = @_;
+  my @aux_dirs;
+  if ($aux_dir)
+    {
+      push @aux_dirs, $aux_dir;
+    }
+  else
+    {
+      @aux_dirs = qw(. .. ../..);
+    }
+
+  # If we find all the aux files in _some_ directory in @aux_dirs, we're
+  # good.  But if we don't find all of them in any directory in @aux_dirs,
+  # return the set of missing files from the _first_ directory in @aux_dirs;
+  # this will be less confusing in the common case where AC_CONFIG_AUX_DIR
+  # wasn't used and the parent directories don't provide any aux files.
+  my @missing_aux_files;
+  my @first_missing_aux_files;
+
+  for my $dir (@aux_dirs)
+    {
+      @missing_aux_files = ();
+      for my $file (@{$aux_files})
+        {
+          push @missing_aux_files, $file
+            unless -e "${dir}/${file}";
+        }
+
+      return () if !@missing_aux_files;
+
+      @first_missing_aux_files = @missing_aux_files
+        unless @first_missing_aux_files;
+    }
+
+  return @first_missing_aux_files;
+}
+
+# can_install_aux_files
+# ---------------------
+# Report whether all of the files listed in @_ exist in $buildauxdir,
+# which means we could install them.
+sub can_install_aux_files
+{
+  local $_;
+  for (@_)
+    {
+      return 0 unless -f "${buildauxdir}/$_";
+    }
+  return 1;
+}
+
+# try_install_aux_files
+# ---------------------
+# Install each of the aux files listed in @$auxfiles, that we are able
+# to install, into $destdir.
+# Remove the files we were able to install from @$auxfiles.
+sub try_install_aux_files
+{
+  my ($auxfiles, $destdir) = @_;
+  my @unable;
+  for my $f (@$auxfiles)
+    {
+      my $src = "${buildauxdir}/$f";
+      if (-f $src)
+        {
+          install_aux_file ($destdir, $f, $src);
+        }
+      else
+        {
+          push @unable, $f;
+        }
+    }
+  @$auxfiles = @unable;
+}
+
+# install_aux_file
+# ----------------
+# Install the file $src as $destdir/$f, honoring --symlink and --force.
+sub install_aux_file
+{
+  my ($destdir, $f, $src) = @_;
+  my $dest = "${destdir}/$f";
+  if ($symlink)
+    {
+      if ($force || ! -l $dest || readlink $dest != $src)
+        {
+          if (-e $dest)
+            {
+              unlink $dest
+                or fatal "rm -f $dest: $!\n";
+            }
+          verb "linking $dest to $src";
+          symlink $src, $dest
+            or fatal "ln -s $src $dest: $!\n";
+        }
+    }
+  else
+    {
+      if (-e $dest && ! -f $dest)
+        {
+          unlink $dest
+            or fatal "rm -f $dest: $!\n";
+        }
+      my $temp = new File::Temp (UNLINK => 0, DIR => $destdir);
+      copy ($src, $temp)
+        or fatal "copying $src to $temp: $!\n";
+      make_executable ($temp) if -x $src;
+      update_file ($temp, $dest, $force);
+    }
+}
+
+# make_executable
+# ---------------
+# Make the file $f be executable by all users it is currently readable by.
+sub make_executable
+{
+  my $f = shift;
+  my $perm = (stat $f)[2] & 07777;
+  $perm |= 0100 if ($perm & 0400);
+  $perm |= 0010 if ($perm & 0040);
+  $perm |= 0001 if ($perm & 0004);
+  chmod $perm, $f
+    or fatal "chmod $f: $!\n";
+}
+
+
+## -------------------------- ##
+## Per-directory operations.  ##
+## -------------------------- ##
+
 # &autoreconf_current_directory
 # -----------------------------
 sub autoreconf_current_directory ($)
@@ -386,11 +531,12 @@ sub autoreconf_current_directory ($)
 
   # Perform a single trace reading to avoid --force forcing a rerun
   # between two --trace, that's useless.  If there is no AC_INIT, then
-  # we are not interested: it looks like a Cygnus thingy.
+  # it's not an Autoconf script; ignore it.
   # Suppress all warnings from this invocation; they may be spurious
   # due to out-of-date files, and in any case they'll duplicate warnings
   # from the final autoconf invocation.
   my $aux_dir;
+  my @aux_files;
   my $uses_gettext_via_traces;
   my $uses_libtool;
   my $uses_intltool;
@@ -413,14 +559,15 @@ sub autoreconf_current_directory ($)
                'AC_CONFIG_HEADERS',
                'AC_CONFIG_SUBDIRS',
                'AC_INIT',
+               'AC_REQUIRE_AUX_FILE',
                'AC_PROG_LIBTOOL',
                'AM_PROG_LIBTOOL',
                'LT_INIT',
                'LT_CONFIG_LTDL_DIR',
                'AM_GNU_GETTEXT',
                'AM_INIT_AUTOMAKE',
-               'IT_PROG_INTLTOOL',
                'GTK_DOC_CHECK',
+               'IT_PROG_INTLTOOL',
        )
        . ' |');
   }
@@ -429,6 +576,7 @@ sub autoreconf_current_directory ($)
       chomp;
       my ($macro, @args) = split (/::/);
       $aux_dir = $args[0]           if $macro eq "AC_CONFIG_AUX_DIR";
+      push @aux_files, $args[0]     if $macro eq "AC_REQUIRE_AUX_FILE";
       $uses_autoconf = 1            if $macro eq "AC_INIT";
       $uses_gettext_via_traces = 1  if $macro eq "AM_GNU_GETTEXT";
       $uses_libtool = 1             if $macro eq "AC_PROG_LIBTOOL"
@@ -460,9 +608,9 @@ sub autoreconf_current_directory ($)
     }
 
   # Gettext consistency checks...
-  error "$configure_ac: AM_GNU_GETTEXT is used, but not AM_GNU_GETTEXT_VERSION"
+  error $configure_ac, "AM_GNU_GETTEXT is used, but not AM_GNU_GETTEXT_VERSION"
     if $uses_gettext_via_traces && ! $uses_gettext;
-  error "$configure_ac: AM_GNU_GETTEXT_VERSION is used, but not AM_GNU_GETTEXT"
+  error $configure_ac, "AM_GNU_GETTEXT_VERSION is used, but not AM_GNU_GETTEXT"
     if $uses_gettext && ! $uses_gettext_via_traces;
 
 
@@ -476,7 +624,7 @@ sub autoreconf_current_directory ($)
   # repository with hand written code only (there is not even a need
   # for a Makefile.am!).
 
-  if (defined $aux_dir && ! -d $aux_dir)
+  if ($install && defined $aux_dir && ! -d $aux_dir)
     {
       verb "$configure_ac: creating directory $aux_dir";
       mkdir $aux_dir, 0755
@@ -617,6 +765,38 @@ sub autoreconf_current_directory ($)
       xsystem ($automake);
     }
 
+  # ---------------------------------------------------- #
+  # Installing aux files and checking for missing ones.  #
+  # ---------------------------------------------------- #
+  my @missing_aux_files = find_missing_aux_files (\@aux_files, $aux_dir);
+  if (@missing_aux_files)
+    {
+      try_install_aux_files (\@missing_aux_files, $aux_dir || '.') if $install;
+
+      for (0 .. $#missing_aux_files)
+        {
+          my $f = $missing_aux_files[$_];
+          if ($_ == $#missing_aux_files)
+            {
+              # Offer some advice if --install wasn't given and has a
+              # chance of helping.
+              my $trailer = "";
+              $trailer = "\n  try running autoreconf --install"
+                if (!$install
+                    && ($uses_automake
+                        || $uses_libtool
+                        || $uses_intltool
+                        || $uses_gtkdoc
+                        || can_install_aux_files @missing_aux_files));
+
+              error $configure_ac, "required file '$f' not found$trailer";
+            }
+          else
+            {
+              error $configure_ac, "required file '$f' not found";
+            }
+        }
+    }
 
   # -------------- #
   # Running make.  #
@@ -688,6 +868,8 @@ for my $directory (@ARGV)
     autoreconf ($directory);
   }
 
+exit $exit_code;
+
 ### Setup "GNU" style for perl-mode and cperl-mode.
 ## Local Variables:
 ## perl-indent-level: 2
index 21bc1af9abbaf0f4a6c4b62315ff3df51dd66ee9..acc290b0ef9da99c71b672eaf247bbc9157c034a 100644 (file)
@@ -2152,17 +2152,30 @@ Macros that need auxiliary scripts must use this macro to register each
 script they need.
 @end defmac
 
-Some third-party tools can install and update auxiliary scripts in your
-source tree for you; for instance, Automake's @option{--add-missing}
-mode does this for many commonly-needed scripts, including
-@file{install-sh}, @file{config.sub}, and @file{config.guess}.
-If you are only using Autoconf, however, you will need to add auxiliary
-scripts to your source tree yourself, and arrange for them to be
-included in release tarballs.
-@command{configure} will report any missing scripts when run.
-
-The scripts needed by Autoconf core macros are included with the
-Autoconf source tree.  @file{install-sh} can be downloaded from
+@command{configure} checks for all the auxiliary scripts it needs on
+startup, and exits with an error if any are missing.
+
+@command{autoreconf} also detects missing auxiliary scripts.  When used
+with the @option{--install} option, @command{autoreconf} will try to add
+missing scripts to the directory specified by @code{AC_CONFIG_AUX_DIR},
+or to the top level of the source tree if @code{AC_CONFIG_AUX_DIR} was
+not used.  It can always do this for the scripts needed by Autoconf core
+macros: @file{install-sh}, @file{config.sub}, and @file{config.guess}.
+Many other commonly-needed scripts are installed by the third-party
+tools that @command{autoreconf} knows how to run, such as @file{missing}
+for Automake and @file{ltmain.sh} for Libtool.
+
+If you are using Automake, auxiliary scripts will automatically be
+included in the tarball created by @command{make dist}.  If you are
+not using Automake you will need to arrange for auxiliary scripts to
+be included in tarballs yourself.  Auxiliary scripts should normally
+@emph{not} be checked into a version control system, for the same
+reasons that @command{configure} shouldn't be.
+
+The scripts needed by Autoconf core macros can be found in
+@file{$(datadir)/autoconf/build-aux} of the Autoconf installation
+(@pxref{Installation Directory Variables}).
+@file{install-sh} can be downloaded from
 @url{https://git.savannah.gnu.org/cgit/automake.git/plain/lib/install-sh}.
 @file{config.sub} and @file{config.guess} can be downloaded from
 @url{https://git.savannah.gnu.org/cgit/config.git/tree/}.
@@ -4124,13 +4137,13 @@ macro requires @command{install} to be able to install multiple files into a
 target directory in a single invocation.
 
 Autoconf comes with a copy of @file{install-sh} that you can use.
-If you use @code{AC_PROG_INSTALL}, you must include @file{install-sh}
-in your distribution; otherwise @command{configure} produces an error
-message saying it can't find it---even if the system you're on has a
-good @command{install} program.  This check is a safety measure to
-prevent you from accidentally leaving that file out, which would prevent
-your package from installing on systems that don't have a BSD-compatible
-@command{install} program.
+If you use @code{AC_PROG_INSTALL}, you must include @file{install-sh} in
+your distribution; otherwise @command{autoreconf} and @command{configure}
+will produce an error message saying they can't find it---even if the
+system you're on has a good @command{install} program.  This check is a
+safety measure to prevent you from accidentally leaving that file out,
+which would prevent your package from installing on systems that don't
+have a BSD-compatible @command{install} program.
 
 If you need to use your own installation program because it has features
 not found in standard @command{install} programs, there is no reason to use
index 4f1f47994f732422814c82355ba71907aa8558c6..566c5dcaf6cb76e2aaf08082ee04fd496f7fface 100644 (file)
@@ -97,13 +97,14 @@ args: --preselect AC_CONFIG_HEADERS
 args: --preselect AC_CONFIG_MACRO_DIR_TRACE
 args: --preselect AC_CONFIG_SUBDIRS
 args: --preselect AC_INIT
+args: --preselect AC_REQUIRE_AUX_FILE
 args: --preselect AC_PROG_LIBTOOL
 args: --preselect AM_PROG_LIBTOOL
-args: --preselect GTK_DOC_CHECK
-args: --preselect IT_PROG_INTLTOOL
 args: --preselect LT_INIT
 args: --preselect LT_CONFIG_LTDL_DIR
 args: --preselect AM_GNU_GETTEXT
+args: --preselect GTK_DOC_CHECK
+args: --preselect IT_PROG_INTLTOOL
 end-language: "Autoreconf-preselections"
 
 
index 4e2e5b653adf69822b2f2e726760aa3b12069f45..d4ecf3cb3da902db046c003b7bb26972e1fa6681 100644 (file)
@@ -196,3 +196,13 @@ TAGS_FILES += $(dist_autotestlib_DATA)
 forbidden_patterns_files += $(dist_autotestlib_DATA)
 
 lib/autotest/autotest.m4f: $(autotest_m4f_dependencies)
+
+## --------------------------- ##
+## Install auxiliary scripts.  ##
+## --------------------------- ##
+
+buildauxdir = $(pkgdatadir)/build-aux
+dist_buildaux_SCRIPTS = \
+  build-aux/config.guess \
+  build-aux/config.sub \
+  build-aux/install-sh
index f9bcf5e5e12da75fb1578447a2401a4933dc1d2c..6ae6bfdfc679ff419ebf8fdd5d99c1e810258e72 100644 (file)
@@ -1932,6 +1932,7 @@ AT_CLEANUP
 ## ------------------------- ##
 
 AT_SETUP([Missing auxiliary files])
+AT_KEYWORDS([autoreconf])
 
 AT_DATA([configure.ac],
 [[AC_INIT([GNU foo], [1.0])
@@ -1941,16 +1942,55 @@ AC_OUTPUT
 ]])
 
 AT_CHECK_AUTOCONF
+
+# Both configure and autoreconf should detect the missing files.
 AT_CHECK_CONFIGURE([], [1], [ignore],
 [configure: error: cannot find required auxiliary files: config.guess config.sub
 ])
 
+AT_CHECK([autoreconf], 1, [],
+[configure.ac: error: required file 'config.sub' not found
+configure.ac: error: required file 'config.guess' not found
+configure.ac:   try running autoreconf --install
+])
+
+# If only one file is missing, the error messages should only report
+# that one.  Also, the above invocation of autoreconf should _not_
+# have created build-aux, because it wasn't called with --install.
+AT_CHECK([test ! -e build-aux])
+mkdir build-aux
 : > build-aux/config.guess
 
 AT_CHECK_CONFIGURE([], [1], [ignore],
 [configure: error: cannot find required auxiliary files: config.sub
 ])
 
+AT_CHECK([autoreconf], 1, [],
+[configure.ac: error: required file 'config.sub' not found
+configure.ac:   try running autoreconf --install
+])
+
+# Missing aux files should not interfere with --help and --version.
+AT_CHECK_CONFIGURE([--help], [0], [ignore], [ignore])
+AT_CHECK_CONFIGURE([--version], [0], [ignore], [ignore])
+
+# autoreconf --install should be able to install config.sub and config.guess.
+rm build-aux/config.guess
+AT_CHECK([autoreconf --install])
+
+AT_CHECK([test -x build-aux/config.guess])
+AT_CHECK([test -x build-aux/config.sub])
+AT_CHECK([test ! -e build-aux/install-sh])
+
+AT_CHECK_CONFIGURE
+
+# Repeat all the above tests with a configure script that _doesn't_
+# need config.{sub,guess} but does need install-sh.
+
+rm build-aux/config.guess
+rm build-aux/config.sub
+rmdir build-aux
+
 AT_DATA([configure.ac],
 [[AC_INIT([GNU foo], [1.0])
 AC_CONFIG_AUX_DIR([build-aux])
@@ -1958,9 +1998,27 @@ AC_PROG_INSTALL
 AC_OUTPUT
 ]])
 
+
 AT_CHECK_AUTOCONF
 AT_CHECK_CONFIGURE([], [1], [ignore],
 [configure: error: cannot find required auxiliary files: install-sh
 ])
 
+AT_CHECK([autoreconf], 1, [],
+[configure.ac: error: required file 'install-sh' not found
+configure.ac:   try running autoreconf --install
+])
+AT_CHECK([test ! -e build-aux])
+
+AT_CHECK_CONFIGURE([--help], [0], [ignore], [ignore])
+AT_CHECK_CONFIGURE([--version], [0], [ignore], [ignore])
+
+AT_CHECK([autoreconf --install])
+
+AT_CHECK([test ! -e build-aux/config.guess])
+AT_CHECK([test ! -e build-aux/config.sub])
+AT_CHECK([test -x build-aux/install-sh])
+
+AT_CHECK_CONFIGURE
+
 AT_CLEANUP
index f0a5c037f62db744a8c4867256fb9c23e9d4cf92..f310166c99fd63640b790f78b4bef0889c32a89e 100644 (file)
@@ -23,9 +23,11 @@ AUTOCONF=autoconf
 AUTOHEADER=autoheader
 AUTOM4TE=autom4te
 AUTOM4TE_CFG='@abs_top_builddir@/lib/autom4te.cfg'
+autom4te_buildauxdir='@abs_top_srcdir@/build-aux'
 autom4te_perllibdir='@abs_top_srcdir@/lib'
 trailer_m4='@abs_top_srcdir@/lib/autoconf/trailer.m4'
-export AUTOCONF AUTOHEADER AUTOM4TE AUTOM4TE_CFG autom4te_perllibdir trailer_m4
+export AUTOCONF AUTOHEADER AUTOM4TE AUTOM4TE_CFG
+export autom4te_buildauxdir autom4te_perllibdir trailer_m4
 
 case '@wrap_program@' in
   ifnames)