autoconf-patches
[Top][All Lists]
Advanced

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

[PATCH] Generate manpages directly from source code.


From: Zack Weinberg
Subject: [PATCH] Generate manpages directly from source code.
Date: Fri, 21 Aug 2020 18:04:37 -0400

We generate manpages for autoconf’s installed programs (autoconf,
autoheader, etc.) using help2man, which runs each program in order to
learn its --help output.  Each manpage therefore has a dependency on
the existence of the corresponding program, but this dependency is
intentionally left out of the Makefile so that one can build from a
tarball release (which will include prebuilt manpages) without having
help2man installed.

But when building from a git checkout with high levels of
parallelism (-j20 or so), the missing dependency can lead to build
failures, because help2man will try to run the program before it
exists.  In an earlier patch I tried to work around this with a
recursive make invocation in the ‘.x.1’ rule, to ensure the existence
of the program.  That only traded one concurrency bug for another, now
we could have two jobs trying to build the same program simultaneously
and they would clobber each other’s work and the build would still
fail.

Instead, this patch introduces a utility script ‘help-extract.pl’ that
reads --help and --version information directly from the source code
for each program.  This utility, wrapped appropriately for each
program, is what help2man now runs.  Usage is a little weird because
help2man doesn’t let you specify any arguments to the “executable”
that it runs, but it works, and lets us write all of the true
dependencies of each manpage into the Makefile without naming any file
that would be created during a build from a tarball.  help-extract.pl
is a Perl script, so it introduces no new build-time requirements.

A downside is that we have to make sure each of the script sources in
bin/, and also part of lib/Autom4te/ChannelDefs.pm, are parseable by
help-extract.  The most important constraints are that the text output
by --help must be defined in a global variable named ‘help’, and its
definition has to be formatted just the way these definitions are
currently formatted.  Similarly for --version.  Furthermore, only some
non-literal substitutions are possible in these texts; each has to be
explicitly supported in help-extract.pl.  The current list of supported
substitutions is $0, @PACKAGE_NAME@, @VERSION@, @RELEASE_YEAR@, and
Autom4te::ChannelDefs::usage.

The generated manpages themselves are character-for-character
identical before and after this patch.

I've gone ahead and pushed this change because I need to fix the
concurrency problems for some CI experiments I'm doing, but if anyone
has a more elegant solution I'm all ears.  (One strong candidate is
that we switch to Perl's built-in manpage-generation-from-scripts
system, pod2man, but that would be rather more work than I think is
feasible before 2.70 -- for one thing, we'd have to convert bin/autoconf
to a perl script.)

zw

 * build-aux/help-extract.pl: New build script that extracts --help
  and --version output from manpages.

 * man/autoconf.w, man/autoheader.w, man/autom4te.w, man/autoreconf.w
 * man/autoscan.w, man/autoupdate.w, man/ifnames.w: New shell scripts
   which wrap build-aux/help-extract.pl.

 * man/local.mk: Generate each manpage by running help2man on the
   corresponding .w script, not on the built utility itself.
   Revise all dependencies to match.

 * bin/autoconf.as: Rename ‘usage’ variable to ‘help’ and
   ‘help’ variable to ‘usage_err’.
 * bin/autoheader.in: Call Autom4te::ChannelDefs::usage with no
   function-call parentheses, matching all the other scripts.
 * bin/autom4te.in: Initialize $version with a regular double-quoted
   string, not a heredoc, matching all the other scripts.
 * bin/autoscan.in: Remove global variable $configure_scan.
---
 Makefile.am               |   1 +
 bin/autoconf.as           |  12 +-
 bin/autoheader.in         |   2 +-
 bin/autom4te.in           |   5 +-
 bin/autoscan.in           |   5 +-
 build-aux/help-extract.pl | 275 ++++++++++++++++++++++++++++++++++++++
 man/autoconf.w            |   4 +
 man/autoheader.w          |   4 +
 man/autom4te.w            |   4 +
 man/autoreconf.w          |   4 +
 man/autoscan.w            |   4 +
 man/autoupdate.w          |   4 +
 man/common.w              |   4 +
 man/ifnames.w             |   4 +
 man/local.mk              | 115 ++++++++++------
 15 files changed, 390 insertions(+), 57 deletions(-)
 create mode 100644 build-aux/help-extract.pl
 create mode 100755 man/autoconf.w
 create mode 100755 man/autoheader.w
 create mode 100755 man/autom4te.w
 create mode 100755 man/autoreconf.w
 create mode 100755 man/autoscan.w
 create mode 100755 man/autoupdate.w
 create mode 100755 man/common.w
 create mode 100755 man/ifnames.w

diff --git a/Makefile.am b/Makefile.am
index 8c7ce7b6..ecc9cb35 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,6 +34,7 @@ EXTRA_DIST = ChangeLog.0 ChangeLog.1 ChangeLog.2 ChangeLog.3 \
             build-aux/git-version-gen \
             build-aux/announce-gen build-aux/gnupload \
             build-aux/gitlog-to-changelog \
+            build-aux/help-extract.pl \
             .prev-version .version
 
 edit = sed \
diff --git a/bin/autoconf.as b/bin/autoconf.as
index ab6e3c52..ddf8cced 100644
--- a/bin/autoconf.as
+++ b/bin/autoconf.as
@@ -22,7 +22,7 @@ m4_divert_push([HEADER-COPYRIGHT])dnl
 m4_divert_pop([HEADER-COPYRIGHT])dnl back to BODY
 AS_ME_PREPARE[]dnl
 
-usage=["\
+help=["\
 Usage: $0 [OPTION]... [TEMPLATE-FILE]
 
 Generate a configuration script from a TEMPLATE-FILE if given, or
@@ -75,11 +75,11 @@ There is NO WARRANTY, to the extent permitted by law.
 
 Written by David J. MacKenzie and Akim Demaille."]
 
-help="\
+usage_err="\
 Try '$as_me --help' for more information."
 
 exit_missing_arg='
-  m4_bpatsubst([AS_ERROR([option '$[1]' requires an argument$as_nl$help])],
+  m4_bpatsubst([AS_ERROR([option '$[1]' requires an 
argument$as_nl$usage_err])],
     ['], ['\\''])'
 # restore font-lock: '
 
@@ -100,7 +100,7 @@ while test $# -gt 0 ; do
     --version | -V )
        echo "$version" ; exit ;;
     --help | -h )
-       AS_ECHO(["$usage"]); exit ;;
+       AS_ECHO(["$usage_err"]); exit ;;
 
     --verbose | -v )
        verbose=:
@@ -154,7 +154,7 @@ while test $# -gt 0 ; do
        break ;;
     -* )
        exec >&2
-       AS_ERROR([invalid option '$[1]'$as_nl$help]) ;;
+       AS_ERROR([invalid option '$[1]'$as_nl$usage_err]) ;;
     * )
        break ;;
   esac
@@ -178,7 +178,7 @@ case $# in
   1)
     infile=$1 ;;
   *) exec >&2
-     AS_ERROR([invalid number of arguments$as_nl$help]) ;;
+     AS_ERROR([invalid number of arguments$as_nl$usage_err]) ;;
 esac
 
 # Unless specified, the output is stdout.
diff --git a/bin/autoheader.in b/bin/autoheader.in
index b8ed9d3f..2a9a2e07 100644
--- a/bin/autoheader.in
+++ b/bin/autoheader.in
@@ -72,7 +72,7 @@ or else 'configure.in'.
   -f, --force              consider all files obsolete
   -W, --warnings=CATEGORY  report the warnings falling in CATEGORY
 
-" . Autom4te::ChannelDefs::usage () . "
+" . Autom4te::ChannelDefs::usage . "
 
 Library directories:
   -B, --prepend-include=DIR  prepend directory DIR to search path
diff --git a/bin/autom4te.in b/bin/autom4te.in
index 3a80d4b7..d98998de 100644
--- a/bin/autom4te.in
+++ b/bin/autom4te.in
@@ -204,8 +204,7 @@ General help using GNU software: 
<https://www.gnu.org/gethelp/>.
 
 # $VERSION
 # --------
-$version =  <<"EOF";
-autom4te (@PACKAGE_NAME@) @VERSION@
+$version = "autom4te (@PACKAGE_NAME@) @VERSION@
 Copyright (C) @RELEASE_YEAR@ Free Software Foundation, Inc.
 License GPLv3+/Autoconf: GNU GPL version 3 or later
 <https://gnu.org/licenses/gpl.html>, <https://gnu.org/licenses/exceptions.html>
@@ -213,7 +212,7 @@ This is free software: you are free to change and 
redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
 
 Written by Akim Demaille.
-EOF
+";
 
 
 ## ---------- ##
diff --git a/bin/autoscan.in b/bin/autoscan.in
index 0eb35040..9780f7db 100644
--- a/bin/autoscan.in
+++ b/bin/autoscan.in
@@ -87,7 +87,6 @@ my %needed_macros =
    'AC_PREREQ' => [$me],
   );
 
-my $configure_scan = 'configure.scan';
 my $log;
 
 # Autoconf and lib files.
@@ -103,7 +102,7 @@ $help = "Usage: $0 [OPTION]... [SRCDIR]
 Examine source files in the directory tree rooted at SRCDIR, or the
 current directory if none is given.  Search the source files for
 common portability problems, check for incompleteness of
-'configure.ac', and create a file '$configure_scan' which is a
+'configure.ac', and create a file 'configure.scan' which is a
 preliminary 'configure.ac' for that package.
 
   -h, --help          print this help, then exit
@@ -462,7 +461,7 @@ sub output_kind ($$)
     if exists $kind_comment{$kind};
   foreach my $word (sort keys %{$used{$kind}})
     {
-      # Output the needed macro invocations in $configure_scan if not
+      # Output the needed macro invocations in configure.scan if not
       # already printed, and remember these macros are needed.
       foreach my $macro (@{$macro{$kind}{$word}})
        {
diff --git a/build-aux/help-extract.pl b/build-aux/help-extract.pl
new file mode 100644
index 00000000..0edc793a
--- /dev/null
+++ b/build-aux/help-extract.pl
@@ -0,0 +1,275 @@
+# help-extract -- extract --help and --version output from a script.
+# Copyright (C) 2020 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 3 of the License, or
+# (at your option) any later version.
+
+# This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+# Written by Zack Weinberg.
+
+use strict;
+use warnings;
+
+# File::Spec itself was added in 5.005.
+# File::Spec::Functions was added in 5.6.1 which is just barely too new.
+use File::Spec;
+
+# This script is not intended to be used directly.  It's run by
+# help2man via wrappers in man/, e.g.  man/autoconf.w, as if it were
+# one of autoconf's executable scripts.  It extracts the --help and
+# --version output of that script from its source form, without
+# actually running it.  The script to work from is set by the wrapper,
+# and several other parameters are passed down from the Makefile as
+# environment variables; see parse_args below.
+
+# The point of this script is, the preprocessed forms of the
+# executable scripts, and their wrappers for uninstalled use
+# (e.g. <build-dir>/{bin,tests}/autoconf) do not need to exist to
+# generate the corresponding manpages.  This is desirable because we
+# can't put those dependencies in the makefiles without breaking
+# people's ability to build autoconf from a release tarball without
+# help2man installed.  It also ensures that we will generate manpages
+# from the current source code and not from an older version of the
+# script that has already been installed.
+
+## ----------------------------- ##
+## Extraction from Perl scripts. ##
+## ----------------------------- ##
+
+sub eval_qq_no_interpolation ($)
+{
+  # The argument is expected to be a "double quoted string" including the
+  # leading and trailing delimiters.  Returns the text of this string after
+  # processing backslash escapes but NOT interpolation.
+  # / (?<!\\) (?>\\\\)* blah /x means match blah preceded by an
+  # *even* number of backslashes.  It would be nice if we could use \K
+  # to exclude the backslashes from the matched text, but that was only
+  # added in Perl 5.10 and we still support back to 5.006.
+  return eval $_[0] =~ s/ (?<!\\) (?>\\\\)* [\$\@] /\\$&/xrg;
+}
+
+sub extract_channeldefs_usage ($)
+{
+  my ($channeldefs_pm) = @_;
+  my $usage = "";
+  my $parse_state = 0;
+  local $_;
+
+  open (my $fh, "<", $channeldefs_pm) or die "$channeldefs_pm: $!\n";
+  while (<$fh>)
+    {
+      if ($parse_state == 0)
+       {
+         $parse_state = 1 if /^sub usage\b/;
+       }
+      elsif ($parse_state == 1)
+       {
+         if (s/^  return "//)
+           {
+             $parse_state = 2;
+             $usage .= $_;
+           }
+       }
+      elsif ($parse_state == 2)
+       {
+         if (s/(?<!\\) ((?>\\\\)*) "; $/$1/x)
+           {
+             $usage .= $_;
+             return $usage;
+           }
+         else
+           {
+             $usage .= $_;
+           }
+       }
+    }
+
+  die "$channeldefs_pm: unexpected EOF in state $parse_state\n";
+}
+
+sub extract_perl_assignment (*$$$)
+{
+  my ($fh, $source, $channeldefs_pm, $what) = @_;
+  my $value = "";
+  my $parse_state = 0;
+  local $_;
+
+  while (<$fh>)
+    {
+      if ($parse_state == 0)
+       {
+         if (s/^\$\Q${what}\E = (?=")//o)
+           {
+             $value .= $_;
+             $parse_state = 1;
+           }
+       }
+      elsif ($parse_state == 1)
+       {
+         if (/^"\s*\.\s*Autom4te::ChannelDefs::usage\s*(?:\(\))?\s*\.\s*"$/)
+           {
+             $value .= extract_channeldefs_usage ($channeldefs_pm);
+           }
+         elsif (/^";$/)
+           {
+             $value .= '"';
+             return eval_qq_no_interpolation ($value);
+           }
+         else
+           {
+             $value .= $_;
+           }
+       }
+    }
+
+  die "$source: unexpected EOF in state $parse_state\n";
+}
+
+
+## ------------------------------ ##
+## Extraction from shell scripts. ##
+## ------------------------------ ##
+
+sub extract_shell_assignment (*$$)
+{
+  my ($fh, $source, $what) = @_;
+  my $value = "";
+  my $parse_state = 0;
+  local $_;
+
+  while (<$fh>)
+    {
+      if ($parse_state == 0)
+       {
+         if (/^\Q${what}\E=\[\"\\$/)
+           {
+             $parse_state = 1;
+           }
+       }
+      elsif ($parse_state == 1)
+       {
+         my $done = s/"\]$//;
+         $value .= $_;
+         if ($done)
+           {
+             # This is not strictly correct but it works acceptably
+             # for the escapes that actually occur in the strings
+             # we're extracting.
+             return eval_qq_no_interpolation ('"'.$value.'"');
+           }
+       }
+    }
+
+  die "$source: unexpected EOF in state $parse_state\n";
+}
+
+
+## -------------- ##
+## Main program.  ##
+## -------------- ##
+
+
+sub extract_assignment ($$$)
+{
+  my ($source, $channeldefs_pm, $what) = @_;
+
+  open (my $fh, "<", $source) or die "$source: $!\n";
+
+  my $firstline = <$fh>;
+  if ($firstline =~ /\@PERL\@/ || $firstline =~ /-\*-\s*perl\s*-\*-/i)
+    {
+      return extract_perl_assignment ($fh, $source, $channeldefs_pm, $what);
+    }
+  elsif ($firstline =~ /\bAS_INIT\b/
+        || $firstline =~ /bin\/[a-z0-9]*sh\b/
+        || $firstline =~ /-\*-\s*shell-script\s*-\*-/i)
+    {
+      return extract_shell_assignment ($fh, $source, $what);
+    }
+  else
+    {
+      die "$source: language not recognized\n";
+    }
+}
+
+sub main ()
+{
+  # Most of our arguments come from environment variables, because
+  # help2man doesn't allow for passing additional command line
+  # arguments to the wrappers, and it's easier to write the wrappers
+  # to not mess with the command line.
+  my $usage = "Usage: $0 script-source (--help | --version)
+
+Extract help and version information from a perl or shell script.
+Required environment variables:
+
+  top_srcdir       relative path from cwd to the top of the source tree
+  channeldefs_pm   relative path from top_srcdir to ChannelDefs.pm
+  PACKAGE_NAME     the autoconf PACKAGE_NAME substitution variable
+  VERSION          the autoconf VERSION substitution variable
+  RELEASE_YEAR     the autoconf RELEASE_YEAR substitution variable
+
+The script-source argument should also be relative to top_srcdir.
+";
+
+  my $source         = shift(@ARGV)         || die $usage;
+  my $what           = shift(@ARGV)         || die $usage;
+  my $top_srcdir     = $ENV{top_srcdir}     || die $usage;
+  my $channeldefs_pm = $ENV{channeldefs_pm} || die $usage;
+  my $package_name   = $ENV{PACKAGE_NAME}   || die $usage;
+  my $version        = $ENV{VERSION}        || die $usage;
+  my $release_year   = $ENV{RELEASE_YEAR}   || die $usage;
+
+  if ($what eq "-h" || $what eq "--help")
+    {
+      $what = "help";
+    }
+  elsif ($what eq "-V" || $what eq "--version")
+    {
+      $what = "version";
+    }
+  else
+    {
+      die $usage;
+    }
+
+  my $cmd_name    = $source =~ s{^.*/([^./]+)\.(?:as|in)$}{$1}r;
+  $source         = File::Spec->catfile($top_srcdir, $source);
+  $channeldefs_pm = File::Spec->catfile($top_srcdir, $channeldefs_pm);
+
+  my $text = extract_assignment ($source, $channeldefs_pm, $what);
+  $text =~ s/\$0\b/$cmd_name/g;
+  $text =~ s/[@]PACKAGE_NAME@/$package_name/g;
+  $text =~ s/[@]VERSION@/$version/g;
+  $text =~ s/[@]RELEASE_YEAR@/$release_year/g;
+  print $text;
+}
+
+main;
+
+
+### Setup "GNU" style for perl-mode and cperl-mode.
+## Local Variables:
+## perl-indent-level: 2
+## perl-continued-statement-offset: 2
+## perl-continued-brace-offset: 0
+## perl-brace-offset: 0
+## perl-brace-imaginary-offset: 0
+## perl-label-offset: -2
+## cperl-indent-level: 2
+## cperl-brace-offset: 0
+## cperl-continued-brace-offset: 0
+## cperl-label-offset: -2
+## cperl-extra-newline-before-brace: t
+## cperl-merge-trailing-else: nil
+## cperl-continued-statement-offset: 2
+## End:
diff --git a/man/autoconf.w b/man/autoconf.w
new file mode 100755
index 00000000..4bb2eb63
--- /dev/null
+++ b/man/autoconf.w
@@ -0,0 +1,4 @@
+#! /bin/sh
+# help-extract wrapper, see build-aux/help-extract.pl and man/local.mk
+exec "${PERL-perl}" "${top_srcdir}/build-aux/help-extract.pl" \
+   bin/autoconf.as "$@"
diff --git a/man/autoheader.w b/man/autoheader.w
new file mode 100755
index 00000000..821d30ba
--- /dev/null
+++ b/man/autoheader.w
@@ -0,0 +1,4 @@
+#! /bin/sh
+# help-extract wrapper, see build-aux/help-extract.pl and man/local.mk
+exec "${PERL-perl}" "${top_srcdir}/build-aux/help-extract.pl" \
+   bin/autoheader.in "$@"
diff --git a/man/autom4te.w b/man/autom4te.w
new file mode 100755
index 00000000..03375042
--- /dev/null
+++ b/man/autom4te.w
@@ -0,0 +1,4 @@
+#! /bin/sh
+# help-extract wrapper, see build-aux/help-extract.pl and man/local.mk
+exec "${PERL-perl}" "${top_srcdir}/build-aux/help-extract.pl" \
+   bin/autom4te.in "$@"
diff --git a/man/autoreconf.w b/man/autoreconf.w
new file mode 100755
index 00000000..ab98a4f2
--- /dev/null
+++ b/man/autoreconf.w
@@ -0,0 +1,4 @@
+#! /bin/sh
+# help-extract wrapper, see build-aux/help-extract.pl and man/local.mk
+exec "${PERL-perl}" "${top_srcdir}/build-aux/help-extract.pl" \
+   bin/autoreconf.in "$@"
diff --git a/man/autoscan.w b/man/autoscan.w
new file mode 100755
index 00000000..214fc794
--- /dev/null
+++ b/man/autoscan.w
@@ -0,0 +1,4 @@
+#! /bin/sh
+# help-extract wrapper, see build-aux/help-extract.pl and man/local.mk
+exec "${PERL-perl}" "${top_srcdir}/build-aux/help-extract.pl" \
+   bin/autoscan.in "$@"
diff --git a/man/autoupdate.w b/man/autoupdate.w
new file mode 100755
index 00000000..0b75208d
--- /dev/null
+++ b/man/autoupdate.w
@@ -0,0 +1,4 @@
+#! /bin/sh
+# help-extract wrapper, see build-aux/help-extract.pl and man/local.mk
+exec "${PERL-perl}" "${top_srcdir}/build-aux/help-extract.pl" \
+   bin/autoupdate.in "$@"
diff --git a/man/common.w b/man/common.w
new file mode 100755
index 00000000..ed981db4
--- /dev/null
+++ b/man/common.w
@@ -0,0 +1,4 @@
+#! /bin/sh
+# help-extract wrapper, see build-aux/help-extract.pl and man/local.mk
+exec "${PERL-perl}" "${top_srcdir}/build-aux/help-extract.pl" \
+   bin/common.in "$@"
diff --git a/man/ifnames.w b/man/ifnames.w
new file mode 100755
index 00000000..7812018a
--- /dev/null
+++ b/man/ifnames.w
@@ -0,0 +1,4 @@
+#! /bin/sh
+# help-extract wrapper, see build-aux/help-extract.pl and man/local.mk
+exec "${PERL-perl}" "${top_srcdir}/build-aux/help-extract.pl" \
+   bin/ifnames.in "$@"
diff --git a/man/local.mk b/man/local.mk
index 68cf5a8d..d594448d 100644
--- a/man/local.mk
+++ b/man/local.mk
@@ -15,8 +15,6 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-binsrcdir = $(srcdir)/bin
-
 dist_man_MANS = \
   man/autoconf.1 \
   man/autoheader.1 \
@@ -26,28 +24,81 @@ dist_man_MANS = \
   man/autoupdate.1 \
   man/ifnames.1
 
-EXTRA_DIST += $(dist_man_MANS:.1=.x) man/common.x
+EXTRA_DIST += $(dist_man_MANS:.1=.w) $(dist_man_MANS:.1=.x) man/common.x
 
-# Depend on .version to get version number changes.
-# Don't depend on the generated scripts, because then we would try to
-# regenerate the manpages after building the scripts, which would
-# defeat the purpose of shipping the manpages in the tarball.
-# (Instead we have recursive makes in the .x.1 rule below, which is
-# not ideal, but at least it prevents us from generating a manpage
-# from the *installed* utility.)
-common_dep = $(srcdir)/.version $(srcdir)/man/common.x
-man/autoconf.1:   $(common_dep) $(binsrcdir)/autoconf.as
-man/autoheader.1: $(common_dep) $(binsrcdir)/autoheader.in
-man/autom4te.1:   $(common_dep) $(binsrcdir)/autom4te.in
-man/autoreconf.1: $(common_dep) $(binsrcdir)/autoreconf.in
-man/autoscan.1:   $(common_dep) $(binsrcdir)/autoscan.in
-man/autoupdate.1: $(common_dep) $(binsrcdir)/autoupdate.in
-man/ifnames.1:    $(common_dep) $(binsrcdir)/ifnames.in
+# Each manpage depends on:
+# - its .w and .x files and its source script in bin/
+# - common.x for the SEE ALSO list
+# - lib/Autom4te/ChannelDefs.pm which contains additional --help text
+#   (not included in _all_ the manpages, but it's easier to have them
+#   all depend on it)
+# - .version and configure.ac for version information
+#
+# We ship the manpages in tarball releases so people can build from
+# them without having help2man installed.  For this to work correctly,
+# the manpages cannot have declared dependencies on any file that is
+# not also shipped in the tarball.  To avoid concurrency bugs, those
+# files plus the Makefile must in fact be sufficient to generate the
+# manpages.  See the automake manual, section 'Errors with distclean',
+# for further discussion.
+
+binsrcdir      = $(top_srcdir)/bin
+channeldefs_pm = lib/Autom4te/ChannelDefs.pm
+man_common_dep = $(top_srcdir)/man/common.x \
+                $(top_srcdir)/$(channeldefs_pm) \
+                $(top_srcdir)/.version \
+                $(top_srcdir)/configure.ac
+
+man/autoconf.1:   $(common_dep) man/autoconf.w   man/autoconf.x   
$(binsrcdir)/autoconf.as
+man/autoheader.1: $(common_dep) man/autoheader.w man/autoheader.x 
$(binsrcdir)/autoheader.in
+man/autom4te.1:   $(common_dep) man/autom4te.w   man/autom4te.x   
$(binsrcdir)/autom4te.in
+man/autoreconf.1: $(common_dep) man/autoreconf.w man/autoreconf.x 
$(binsrcdir)/autoreconf.in
+man/autoscan.1:   $(common_dep) man/autoscan.w   man/autoscan.x   
$(binsrcdir)/autoscan.in
+man/autoupdate.1: $(common_dep) man/autoupdate.w man/autoupdate.x 
$(binsrcdir)/autoupdate.in
+man/ifnames.1:    $(common_dep) man/ifnames.w    man/ifnames.x    
$(binsrcdir)/ifnames.in
+
+# To generate the manpages, we use help2man, but we don't have it run
+# the built script that corresponds to the manpage.  Instead it runs
+# the .w file listed above, which is a wrapper around
+# build-aux/help-extract.pl, which parses the *source* of the script
+# and extracts the help and version text.  This means that the built
+# script doesn't need to exist to create the manpage.  If it did,
+# we would have a concurrency bug, since we can't declare a dependency
+# on the built script, as discussed above.
+# We use a suffix rule describing the manpage as built from its .w file
+# so that we can use $(<F) to name the executable to be run, which avoids
+# an extra subshell and sed invocation.
 
 remove_time_stamp = 's/^\(\.TH[^"]*"[^"]*"[^"]*\)"[^"]*"/\1/'
+SUFFIXES += .w .1
 
-MOSTLYCLEANFILES     += $(dist_man_MANS:=.t) $(dist_man_MANS:=a.t) \
-                       $(dist_man_MANS:=.tmp)
+.w.1:
+       @echo "Updating man page $@"
+       $(MKDIR_P) $(@D)
+       PATH="$(top_srcdir)/man$(PATH_SEPARATOR)$$PATH"; \
+       PERL="$(PERL)"; \
+       PACKAGE_NAME="$(PACKAGE_NAME)"; \
+       VERSION="$(VERSION)"; \
+       RELEASE_YEAR="$(RELEASE_YEAR)"; \
+       top_srcdir="$(top_srcdir)"; \
+       channeldefs_pm="$(channeldefs_pm)"; \
+       export PATH PERL PACKAGE_NAME VERSION RELEASE_YEAR; \
+       export top_srcdir channeldefs_pm; \
+       $(HELP2MAN) \
+           --include=$(srcdir)/$*.x \
+           --include=$(srcdir)/man/common.x \
+           --source='$(PACKAGE_STRING)' \
+           --output=$@.t $(<F)
+       if $(SED) $(remove_time_stamp) $@ >$@a.t 2>/dev/null && \
+          $(SED) $(remove_time_stamp) $@.t | cmp $@a.t - >/dev/null 2>&1; then 
\
+               touch $@; \
+       else \
+               mv $@.t $@; \
+       fi
+       rm -f $@.t $@a.t
+
+
+MOSTLYCLEANFILES     += $(dist_man_MANS:=.t) $(dist_man_MANS:=a.t)
 MAINTAINERCLEANFILES += $(dist_man_MANS)
 
 # To satisfy 'distcleancheck', we need to delete built manpages in
@@ -56,27 +107,3 @@ MAINTAINERCLEANFILES += $(dist_man_MANS)
 distclean-local: distclean-local-man
 distclean-local-man:
        test -f man/common.x || rm -f $(dist_man_MANS)
-
-
-SUFFIXES += .x .1
-
-.x.1:
-       @set -e; cmd=`basename $*`; \
-       test -x bin/$$cmd || $(MAKE) bin/$$cmd; \
-       test -x tests/$$cmd || $(MAKE) tests/$$cmd;
-       @echo "Updating man page $@"
-       @test -d $(@D) || mkdir $(@D)
-       
PATH="./tests$(PATH_SEPARATOR)$(top_srcdir)/build-aux$(PATH_SEPARATOR)$$PATH"; \
-       export PATH; \
-       $(HELP2MAN) \
-           --include=$(srcdir)/$*.x \
-           --include=$(srcdir)/man/common.x \
-           --source='$(PACKAGE_STRING)' \
-           --output=$@.t `echo '$*' | sed 's,.*/,,'`
-       if sed $(remove_time_stamp) $@ >$@a.t 2>/dev/null && \
-          sed $(remove_time_stamp) $@.t | cmp $@a.t - >/dev/null 2>&1; then \
-               touch $@; \
-       else \
-               mv $@.t $@; \
-       fi
-       rm -f $@.t $@a.t
-- 
2.28.0




reply via email to

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