autoconf-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/2] Improve handling of missing aux scripts (autoreconf)


From: Zack Weinberg
Subject: [PATCH 2/2] Improve handling of missing aux scripts (autoreconf)
Date: Tue, 20 Oct 2020 17:04:35 -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.

I will commit these patches tomorrow afternoon if I don't hear any
comments by then.

zw

* 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              |  17 ++--
 bin/autoreconf.in | 192 ++++++++++++++++++++++++++++++++++++++++++++--
 doc/autoconf.texi |  47 ++++++++----
 lib/autom4te.in   |   5 +-
 lib/local.mk      |  10 +++
 tests/torture.at  |  58 ++++++++++++++
 tests/wrapper.as  |   4 +-
 7 files changed, 303 insertions(+), 30 deletions(-)

diff --git a/NEWS b/NEWS
index 1883faab..42095344 100644
--- 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.
diff --git a/bin/autoreconf.in b/bin/autoreconf.in
index ba08c6ac..2d427155 100644
--- a/bin/autoreconf.in
+++ b/bin/autoreconf.in
@@ -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
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index 21bc1af9..acc290b0 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -2152,17 +2152,30 @@ Input
 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.
+@command{configure} checks for all the auxiliary scripts it needs on
+startup, and exits with an error if any are missing.
 
-The scripts needed by Autoconf core macros are included with the
-Autoconf source tree.  @file{install-sh} can be downloaded from
+@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 @@ Particular Programs
 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
diff --git a/lib/autom4te.in b/lib/autom4te.in
index 4f1f4799..566c5dca 100644
--- a/lib/autom4te.in
+++ b/lib/autom4te.in
@@ -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"
 
 
diff --git a/lib/local.mk b/lib/local.mk
index 4e2e5b65..d4ecf3cb 100644
--- a/lib/local.mk
+++ b/lib/local.mk
@@ -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
diff --git a/tests/torture.at b/tests/torture.at
index f9bcf5e5..6ae6bfdf 100644
--- a/tests/torture.at
+++ b/tests/torture.at
@@ -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
diff --git a/tests/wrapper.as b/tests/wrapper.as
index f0a5c037..f310166c 100644
--- a/tests/wrapper.as
+++ b/tests/wrapper.as
@@ -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)
-- 
2.28.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]