** New features
+*** autoheader and autoreconf preserve hand-written template files
+ If ‘config.h.in’ (or whatever your primary configuration header
+ template’s name is) already exists, and does not begin with a
+ comment line indicating it was generated by autoheader, autoheader
+ and autoreconf will now leave it alone instead of replacing it.
+ You can force them to replace the template anyway with the new
+ command line option, --replace-handwritten. (This is separate
+ from --force because --force is specifically about updating files
+ even if they don’t appear to be _out of date_.)
+
+ We invite feedback on whether the new option should also apply to
+ other existing files that might or might not be machine-generated,
+ most importantly aclocal.m4 and Makefile.in.
+
*** Programs now recognize #elifdef and #elifndef.
The autom4te, autoscan and ifnames programs now recognize the two
preprocessor directives, which were introduced in C23 and C++23.
my @prepend_include;
my @include;
my @warnings;
+my $replace_handwritten = 0;
# $HELP
# -----
-v, --verbose verbosely report processing
-d, --debug don\'t remove temporary files
-f, --force consider all files obsolete
+ -R, --replace-handwritten
+ overwrite an existing template file that appears
+ not to have been generated by autoheader
-W, --warnings=CATEGORY report the warnings falling in CATEGORY
(comma-separated list accepted)
{
my $srcdir;
- getopt ('I|include=s' => \@include,
- 'B|prepend-include=s' => \@prepend_include,
- 'W|warnings=s' => \@warnings);
+ getopt ('I|include=s' => \@include,
+ 'B|prepend-include=s' => \@prepend_include,
+ 'W|warnings=s' => \@warnings,
+ 'R|replace-handwritten' => \$replace_handwritten);
parse_WARNINGS;
parse_warnings @warnings;
$config_h_in = shift(@config_templates);
$config_h =~ s/[ :].*//;
+# If $config_h_in already exists and doesn't appear to have been generated
+# by autoheader, stop, unless --replace-handwritten was given on the command
+# line. This is not considered an error condition.
+if (open (my $fh, "<", $config_h_in))
+ {
+ my $firstline = readline($fh);
+ # If the file is empty, $firstline will be undef. We _do_ want to
+ # go ahead and update it in that case.
+ if (defined $firstline
+ && $firstline !~ /^\/\* .*\. Generated from .* by autoheader\. \*\//
+ && !$replace_handwritten)
+ {
+ msg 'override', "${config_h_in} was not generated by autoheader";
+ msg 'override',
+ "leaving it alone (force update with --replace-handwritten)";
+ exit 0;
+ }
+ }
+else
+ {
+ # If we can't read $config_h_in for any reason besides it not existing
+ # yet, we probably can't update it either.
+ fatal "$config_h_in: $!" unless $!{ENOENT};
+ }
+
# %SYMBOL might contain things like 'F77_FUNC(name,NAME)', but we keep
# only the name of the macro.
%symbol = map { s/\(.*//; $_ => 1 } keys %symbol;
-v, --verbose verbosely report processing
-d, --debug don't remove temporary files
-f, --force consider all generated and standard files obsolete
+ -R, --replace-handwritten
+ replace files that *could* be generated but appear
+ to have been written by hand (only config.h.in at
+ present)
-i, --install copy missing standard auxiliary files
--no-recursive don't rebuild sub-packages
-s, --symlink with -i, install symbolic links instead of copies
# Recurse into subpackages
my $recursive = 1;
+# Replace handwritten files (only config.h.in right now)
+my $replace_handwritten = 0;
+
## ---------- ##
## Routines. ##
## ---------- ##
# List of command line warning requests.
my @warning;
- getopt ("W|warnings=s" => \@warning,
- 'I|include=s' => \@include,
- 'B|prepend-include=s' => \@prepend_include,
- 'i|install' => \$install,
- 's|symlink' => \$symlink,
- 'm|make' => \$run_make,
- 'recursive!' => \$recursive);
+ getopt ("W|warnings=s" => \@warning,
+ 'I|include=s' => \@include,
+ 'B|prepend-include=s' => \@prepend_include,
+ 'i|install' => \$install,
+ 'R|replace-handwritten' => \$replace_handwritten,
+ 's|symlink' => \$symlink,
+ 'm|make' => \$run_make,
+ 'recursive!' => \$recursive);
# Split the warnings as a list of elements instead of a list of
# lists.
{
$automake .= ' --no-force';
}
+ # --replace-handwritten (could also be applied to aclocal but that
+ # requires changes in automake as well)
+ if ($replace_handwritten)
+ {
+ $autoheader .= ' --replace-handwritten';
+ }
# --verbose --verbose or --debug;
if ($verbose > 1 || $debug)
{
my $uses_intltool;
my $uses_gtkdoc;
my $uses_libltdl;
- my $uses_autoheader;
my $uses_automake;
my @subdir;
+ my @header_templates;
my $traces;
verb "$configure_ac: tracing";
{
|| $macro eq "AM_PROG_LIBTOOL"
|| $macro eq "LT_INIT";
$uses_libltdl = 1 if $macro eq "LT_CONFIG_LTDL_DIR";
- $uses_autoheader = 1 if $macro eq "AC_CONFIG_HEADERS";
$uses_automake = 1 if $macro eq "AM_INIT_AUTOMAKE";
$uses_intltool = 1 if $macro eq "IT_PROG_INTLTOOL";
$uses_gtkdoc = 1 if $macro eq "GTK_DOC_CHECK";
+ push @header_templates, split(' ', $args[0] || '')
+ if $macro eq "AC_CONFIG_HEADERS";
push @subdir, split (' ', $args[0] || '')
if $macro eq "AC_CONFIG_SUBDIRS"
&& $recursive;
#
# Run it before automake, since the latter checks the presence of
# config.h.in when it sees an AC_CONFIG_HEADERS.
- if (!$uses_autoheader)
+ #
+ # If config.h.in exists and was not created by autoheader, don't run
+ # autoheader, unless --replace-handwritten was given. Autoheader will
+ # only update the first template file mentioned in AC_CONFIG_HEADERS.
+ if (!@header_templates)
{
- verb "$configure_ac: not using Autoheader";
+ verb "$configure_ac: not running autoheader, no config headers"
}
else
{
- xsystem ($autoheader);
- }
+ my $need_autoheader = 1;
+ my ($header, @templates) = split(':', $header_templates[0]);
+ my $tmpl1 = (scalar @templates) ? $templates[0] : "${header}.in";
+
+ if (open (my $fh, "<", $tmpl1))
+ {
+ my $line = readline($fh);
+ if (defined $line
+ && $line !~ /^\/\* .*\. Generated from .* by autoheader\. \*\//)
+ {
+ if ($replace_handwritten)
+ {
+ verb "$configure_ac: replacing handwritten $tmpl1";
+ }
+ else
+ {
+ verb "$configure_ac: $tmpl1 was not generated by autoheader";
+ verb "force update of $tmpl1 with --replace-handwritten";
+ $need_autoheader = 0;
+ }
+ }
+ }
+ else
+ {
+ # If we can't read $tmpl1 for any reason besides it
+ # not existing yet, we probably can't update it either.
+ fatal "$tmpl1: $!" unless $!{ENOENT};
+ }
+
+ if ($need_autoheader)
+ {
+ xsystem ($autoheader);
+ }
+ }
# ------------------ #
# Running automake. #
files. Note that the macro @code{AM_INIT_AUTOMAKE} has some options
which change the set of files considered to be standard.
+@item --replace-handwritten
+@itemx -R
+Replace files that @emph{could} be generated but appear to have been
+written by hand. Currently this only affects the treatment of the
+primary configuration header template (usually @file{config.h.in};
+@pxref{Header Templates}). In the future it may also affect
+@file{aclocal.m4} and others.
+
@item --install
@itemx -i
Install any missing standard auxiliary files in the package. By
@itemx -f
Remake the template file even if newer than its input files.
+@item --replace-handwritten
+@itemx -R
+Remake the template file even if it appears not to have been generated
+by @command{autoheader}.
+
@item --include=@var{dir}
@itemx -I @var{dir}
Append @var{dir} to the include path. Multiple invocations accumulate.
AT_CLEANUP
+# autoheader should not clobber a hand-written config header template,
+# even if it is the only one.
+AT_SETUP([autoheader preserves a hand-written template])
+
+AT_DATA([config.h.in],
+[[/* Define this to whatever you want. */
+#undef HANNA
+]])
+
+AT_DATA([configure.ac],
+[[AC_INIT
+AC_CONFIG_HEADERS([config.h])
+AC_DEFINE([HANNA], ["Hanna"], [Define this however you want])
+AC_DEFINE([SEAN], ["Sean"], [Sean's name])
+AC_OUTPUT
+]])
+
+AT_CHECK_AUTOCONF
+AT_CHECK([grep HANNA configure], [0], [ignore], [ignore])
+AT_CHECK([grep SEAN configure], [0], [ignore], [ignore])
+
+AT_CHECK_AUTOHEADER([-Wall], [ignore], [0], [],
+[autoheader: warning: config.h.in was not generated by autoheader
+autoheader: warning: leaving it alone (force update with --replace-handwritten)
+])
+
+# autoreconf should not run autoheader either
+AT_CHECK([autoreconf])
+
+AT_CHECK([grep Generated config.h.in], [1], [ignore], [ignore])
+AT_CHECK([grep however config.h.in], [1], [ignore], [ignore])
+AT_CHECK([grep whatever config.h.in], [0], [ignore], [ignore])
+
+AT_CHECK([grep HANNA config.h.in], [0], [ignore], [ignore])
+AT_CHECK([grep SEAN config.h.in], [1], [ignore], [ignore])
+
+AT_CHECK_AUTOHEADER([-Wall --replace-handwritten],
+ [HANNA SEAN], [0], [], [])
+
+AT_CHECK([grep Generated config.h.in], [0], [ignore], [ignore])
+AT_CHECK([grep however config.h.in], [0], [ignore], [ignore])
+AT_CHECK([grep whatever config.h.in], [1], [ignore], [ignore])
+
+AT_CLEANUP
+
+
+# autoheader _should_ update an empty template file.
+AT_SETUP([autoheader updates an empty template])
+
+AT_DATA([config.h.in], [[]])
+
+AT_DATA([configure.ac],
+[[AC_INIT
+AC_CONFIG_HEADERS([config.h])
+AC_DEFINE([HANNA], ["Hanna"], [Define this however you want])
+AC_DEFINE([SEAN], ["Sean"], [Sean's name])
+AC_OUTPUT
+]])
+
+AT_CHECK_AUTOCONF
+AT_CHECK([grep HANNA configure], [0], [ignore], [ignore])
+AT_CHECK([grep SEAN configure], [0], [ignore], [ignore])
+
+AT_CHECK_AUTOHEADER([-Wall], [HANNA SEAN], [0], [], [])
+
+AT_CHECK([grep Generated config.h.in], [0], [ignore], [ignore])
+AT_CHECK([grep however config.h.in], [0], [ignore], [ignore])
+
+AT_CLEANUP
## ------------ ##