Dear Recipient,The issue that you reported, bug#13940, has been resolved. For your convenience, the patch has been forwarded. Thank you for reporting.
-------- Forwarded Message --------Subject: [automake-commit] branch master updated: rules: accept overlapping conditional target declarations (bug#13940)
Date: Mon, 19 Oct 2026 15:04:28 -0400 From: Kamila Szewczyk <[email protected]> Reply-To: [email protected], Kamila Szewczyk <[email protected]> To: [email protected] This is an automated email from the git hooks/post-receive script. iczelia pushed a commit to branch master in repository automake. View the commit online: https://git.savannah.gnu.org/gitweb/?p=automake.git;a=commitdiff;h=d163f0d56b11f294510c356443d1d993bf35608b The following commit(s) were added to refs/heads/master by this push:new d163f0d56 rules: accept overlapping conditional target declarations (bug#13940)
d163f0d56 is described below commit d163f0d56b11f294510c356443d1d993bf35608b Author: Kamila Szewczyk <[email protected]> AuthorDate: Mon Oct 19 21:04:13 2026 +0200 rules: accept overlapping conditional target declarations (bug#13940) --- NEWS | 4 + bin/automake.in | 69 ++++++++++++++- lib/Automake/Rule.pm | 35 ++++++-- t/list-of-tests.mk | 2 +- t/override-conditional-pr13940-link.sh | 78 +++++++++++++++++t/override-conditional-pr13940.sh | 155 ++++++++++++++++++++++++++++++---
6 files changed, 318 insertions(+), 25 deletions(-) diff --git a/NEWS b/NEWS index 094b08e79..d837c5daa 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,10 @@ New in 1.20 (????-??-??): * Bugs fixed + - Repeated target declarations in overlapping Automake conditionals no+ longer produce spurious redefinition warnings when adding prerequisites.
+ (bug#13940)
+
- Non-recursive Vala builds now pass distcheck when generated Vala
sources trigger recompilation in the build directory. Generated C
files are moved into their subdirectories together, and build-tree
diff --git a/bin/automake.in b/bin/automake.in
index 0d4b24525..6fb9cba36 100644
--- a/bin/automake.in
+++ b/bin/automake.in
@@ -116,6 +116,7 @@ sub handle_tests ();
sub handle_tests_dejagnu ();
sub handle_texinfo ();
sub handle_user_recursion ();
+sub has_inline_recipe ($);
sub initialize_per_input ();
sub lang_lex_finish ();
sub lang_sub_obj ();
@@ -6588,6 +6589,38 @@ sub check_trailing_slash ($\$)
}
+sub has_inline_recipe ($)
+{
+ my ($text) = @_;
+ my @closing;
+ while (length $text)
+ {
+ if ($text =~ s/^\\.//s || $text =~ s/^\$\$//)
+ { next; }
+ if ($text =~ s/^\$([({])//)
+ {
+ push @closing, $1 eq '(' ? ')' : '}';
+ next;
+ }
+ next if $text =~ s/^\$.//s;
+ my $char = substr ($text, 0, 1, '');
+ if (@closing)
+ {
+ if ($char eq $closing[-1])
+ { pop @closing; }
+ elsif (($char eq '(' && $closing[-1] eq ')')
+ || ($char eq '{' && $closing[-1] eq '}'))
+ { push @closing, $closing[-1]; }
+ }
+ else
+ {
+ return 0 if $char eq '#';
+ return 1 if $char eq ';';
+ }
+ }
+ return 0;
+}
+
# read_am_file ($AMFILE, $WHERE, $RELDIR)
# ---------------------------------------
# Read $AMFILE file name which is located in $RELDIR, and set up
@@ -6599,7 +6632,8 @@ sub check_trailing_slash ($\$)
# come after our generated stuff.
sub read_am_file
{
- my ($amfile, $where, $reldir) = @_;
+ my ($amfile, $where, $reldir, $recipe) = @_;
+ $recipe ||= {};
my $canon_reldir = &canonicalize ($reldir);
my $am_file = new Automake::XFile ("< $amfile");
@@ -6724,6 +6758,17 @@ sub read_am_file
{
if ($prev_state == IN_RULE_DEF)
{
+ if (exists $recipe->{'targets'} && !$recipe->{'commands'})
+ {
+ $recipe->{'prerequisites'} .= $_;
+ if (has_inline_recipe ($recipe->{'prerequisites'}))
+ {
+ Automake::Rule::register_recipe
+ ($recipe->{'targets'}, $cond, $recipe->{'where'},
+ $recipe->{'where'});
+ $recipe->{'commands'} = 1;
+ }
+ }
my $cond = new Automake::Condition @cond_stack;
$output_trailer .= $cond->subst_string;
$output_trailer .= $_;
@@ -6779,7 +6824,17 @@ sub read_am_file
# For now we have to output all definitions of user rules
# and can't diagnose duplicates (see the comment in
# Automake::Rule::define). So we go on and ignore the return value.
- Automake::Rule::define ($1, $amfile, RULE_USER, $cond, $where);
+ my ($targets, $prerequisites) = ($1, $2);
+ %$recipe = (targets => $targets,
+ prerequisites => $prerequisites . "\n",
+ where => $where->clone);
+ Automake::Rule::define ($targets, $amfile, RULE_USER,
$cond, $where);
+ if (has_inline_recipe ($prerequisites))
+ {
+ Automake::Rule::register_recipe
+ ($targets, $cond, $where, $recipe->{'where'});
+ $recipe->{'commands'} = 1;
+ }
check_variable_expansions ($_, $where);
@@ -6792,6 +6847,7 @@ sub read_am_file
elsif (/$ASSIGNMENT_PATTERN/o)
{
# Found a macro definition.
+ %$recipe = ();
$prev_state = IN_VAR_DEF;
$last_var_name = $1;
$last_var_type = $2;
@@ -6860,11 +6916,18 @@ sub read_am_file
my $new_reldir = File::Spec->abs2rel ($path, $relative_dir);
$new_reldir = '.' if $new_reldir !~ s,/[^/]*$,,;
$where->push_context ("'$path' included from here");
- read_am_file ($path, $where, $new_reldir);
+ read_am_file ($path, $where, $new_reldir, $recipe);
$where->pop_context;
}
else
{
+ if (/^\t/ && exists $recipe->{'targets'})
+ {
+ Automake::Rule::register_recipe
+ ($recipe->{'targets'}, $cond, $recipe->{'where'},
+ $recipe->{'where'});
+ $recipe->{'commands'} = 1;
+ }
# This isn't an error; it is probably a continued rule.
# In fact, this is what we assume.
$prev_state = IN_RULE_DEF;
diff --git a/lib/Automake/Rule.pm b/lib/Automake/Rule.pm
index 90de27b42..00d5e77bb 100644
--- a/lib/Automake/Rule.pm
+++ b/lib/Automake/Rule.pm
@@ -681,6 +681,32 @@ sub _maybe_warn_about_duplicated_target ($$$$$$)
}
}
+sub register_recipe ($$$$)
+{
+ my ($target, $cond, $where, $declaration) = @_;
+ return if $cond == FALSE;
+
+ my $rule = _crule $target;
+ my $recipes = $rule->{'recipes'} ||= [];
+ return if grep { $_->[0] == $cond && $_->[2] == $declaration } @$recipes;
+ for my $old (@$recipes)
+ {
+ my ($oldcond, $oldwhere, $olddeclaration) = @$old;
+ next if $olddeclaration == $declaration;
+
+ next if $oldcond == $cond || $target =~ /^[^%]*%[^%]*$/;
+ my ($message) =
+ (new Automake::DisjConditions ($oldcond))->ambiguous_p
($target, $cond);
+ if ($message)
+ {
+ msg 'syntax', $where, "$message ...", partial => 1;
+ msg 'syntax', $oldwhere, "... '$target' previously defined here";
+ last;
+ }
+ }
+ push @$recipes, [$cond, $where->clone, $declaration];
+}
+
# Return the list of conditionals in which the rule was defined. In case
# an ambiguous conditional definition is detected, return the empty list.
sub _conditionals_for_rule ($$$$)
@@ -695,14 +721,7 @@ sub _conditionals_for_rule ($$$$)
# Don't coalesce the several pattern rules from footer.am into a
single one.
return $cond if $target eq "%:" && $where->get =~ /\/am\/footer\.am$/;
- if ($owner == RULE_USER)
- {
- # For user rules, just diagnose the ambiguity.
- msg 'syntax', $where, "$message ...", partial => 1;
- msg_cond_rule ('syntax', $ambig_cond, $target,
- "... '$target' previously defined here");
- return ();
- }
+ return () if $owner == RULE_USER;
# FIXME: for Automake rules, we can't diagnose ambiguities yet.
# The point is that Automake doesn't propagate conditions
diff --git a/t/list-of-tests.mk b/t/list-of-tests.mk
index c6cacdc55..d369ddb91 100644
--- a/t/list-of-tests.mk
+++ b/t/list-of-tests.mk
@@ -36,7 +36,6 @@ t/all.sh \
t/cond17.sh \
t/gcj6.sh \
t/override-conditional-2.sh \
-t/override-conditional-pr13940.sh \
t/dist-pr109765.sh \
t/instdir-cond2.sh \
t/instdir-ltlib.sh \
@@ -800,6 +799,7 @@ t/output9.sh \
t/override-conditional-1.sh \
t/override-conditional-2.sh \
t/override-conditional-pr13940.sh \
+t/override-conditional-pr13940-link.sh \
t/override-html.sh \
t/override-suggest-local.sh \
t/parallel-am.sh \
diff --git a/t/override-conditional-pr13940-link.sh
b/t/override-conditional-pr13940-link.sh
new file mode 100644 index 000000000..3712f137c --- /dev/null +++ b/t/override-conditional-pr13940-link.sh @@ -0,0 +1,78 @@ +#! /bin/sh +# Copyright (C) 2013-2026 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) +# 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/>. + +# Prerequisite-only redeclarations must not change the selection of +# Automake's generated link rules (bug#13940). + +required=cc +. test-init.sh + +cat >> configure.ac << 'END' +AC_PROG_CC +AM_CONDITIONAL([FOO], [test "$foo" = yes]) +AC_OUTPUT +END + +cat > Makefile.am << 'END' +bin_PROGRAMS = prog +prog_SOURCES = main.c +if FOO +prog$(EXEEXT): conditional +endif +prog$(EXEEXT): always +always conditional: + : +END + +cat > main.c << 'END' +int main (void) { return 0; } +END + +$ACLOCAL +$AUTOMAKE -a -Werror +$AUTOCONF +./configure foo=no +$MAKE +./prog +$MAKE clean +$MAKE prog +./prog + +# A conditional custom recipe must still override the generated one only+# in that condition; adding unconditional prerequisites must not broaden it.
+cat > Makefile.am << 'END' +bin_PROGRAMS = prog +prog_SOURCES = main.c +if FOO +prog$(EXEEXT): + @echo custom > custom-seen +endif +prog$(EXEEXT): always +always: + : +END +$AUTOMAKE -Werror +./configure foo=no +$MAKE clean +$MAKE prog +./prog +test ! -e custom-seen +./configure foo=yes +$MAKE clean +$MAKE prog +test -f custom-seen + +:diff --git a/t/override-conditional-pr13940.sh b/t/override-conditional-pr13940.sh
index 0ec41577c..45e5c9719 100644 --- a/t/override-conditional-pr13940.sh +++ b/t/override-conditional-pr13940.sh @@ -14,31 +14,160 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -# Expose automake bug#1394: automake erroneously think that a .PHONY -# target's rule is overridden only because we declare dependencies -# to such targets twice: one in an Automake conditional, and once -# unconditionally. +# Repeated target declarations may add prerequisites in overlapping +# conditions, in either order (bug#13940). . test-init.sh cat >> configure.ac << 'END' -AM_CONDITIONAL([FOO], [true]) +AM_CONDITIONAL([FOO], [test "$foo" = yes]) +AM_CONDITIONAL([BAR], [test "$bar" = yes]) AC_OUTPUT END cat > Makefile.am << 'END' -# The conditional here is important: Automake only appears to warn -# when one of the all-local rules is inside a conditional and the -# other is not. if FOO -all-local: bar -bar: ; @echo bar +all-local: conditional +forward: conditional +.PHONY: conditional +if BAR +nested: both endif -all-local: baz -baz: ; @echo baz +endif +all-local: always forward reverse nested overlap +forward: always +reverse: always +nested: always +overlap: always +.PHONY: always forward reverse nested overlap both +if FOO +reverse: conditional +overlap: conditional +endif +if BAR +overlap: other +endif +always conditional both other: + @echo $@ >> seen END $ACLOCAL -$AUTOMAKE -a +$AUTOMAKE -a -Werror +$AUTOCONF + +for foo in yes no; do + for bar in yes no; do + ./configure foo=$foo bar=$bar + rm -f seen + $MAKE all + echo always > expected + if test "$foo" = yes; then + echo conditional >> expected + if test "$bar" = yes; then + echo both >> expected + fi + fi + if test "$bar" = yes; then + echo other >> expected + fi + sort seen > seen.sorted + sort expected > expected.sorted + diff expected.sorted seen.sorted + done +done + +# Adding prerequisites before or after a recipe is also legitimate. +cat > Makefile.am << 'END' +if FOO +first: conditional +last: + @echo last >> seen +endif +first: + @echo first >> seen +last: always +all-local: first last +always conditional: + @echo $@ >> seen +.PHONY: first last always conditional +END + +$AUTOMAKE -Werror +for foo in yes no; do + ./configure foo=$foo bar=no + rm -f seen + $MAKE all + echo always > expected + echo first >> expected + if test "$foo" = yes; then + echo conditional >> expected + echo last >> expected + fi + sort seen > seen.sorted + sort expected > expected.sorted + diff expected.sorted seen.sorted +done + +# Only actual recipes conflict. A semicolon in a comment, an escaped +# filename, or a variable reference must not turn prerequisites into one. +cat > Makefile.am << 'END' +if FOO +comment: dep # ; not a recipe +escaped: dep\;name +reference: $(subst ;,x,dep) +short: $; +continued: \ + dep +endif +comment: ; : +escaped: ; : +reference: ; : +short: ; : +continued: ; : +END +$AUTOMAKE -Werror -Wno-portability + +# Diagnose real conditional recipe overrides in either declaration order. +# Include empty inline recipes and recipes on continued dependency lines. +for style in tab inline empty continued included; do + case $style in + tab) printf 'clash:\n\t:\n\t:\n' > recipe ;; + inline) echo 'clash: ; :' > recipe ;; + empty) echo 'clash: ;' > recipe ;; + continued) printf 'clash: \\\n; :\n' > recipe ;; + included) + printf 'clash:\ninclude commands.am\n' > recipe + printf '\t:\n' > commands.am + ;; + esac + for order in before after; do + echo 'clash: ; :' > unconditional + { + if test "$order" = before; then + cat unconditional + fi + echo 'if FOO' + cat recipe + echo endif + if test "$order" = after; then + cat unconditional + fi + } > Makefile.am + AUTOMAKE_fails + test $(grep -c 'clash was already defined in condition' stderr) -eq 1 + grep "'clash' previously defined here" stderr + done +done + +# Separate conditional pieces of the same recipe are not overrides. +cat > Makefile.am << 'END' +whole: + : +if FOO + : +endif + : +END +$AUTOMAKE -Werror :
OpenPGP_0xC868F0B6DE38409D.asc
Description: OpenPGP public key
OpenPGP_signature.asc
Description: OpenPGP digital signature
