From: Alexandre Duret-Lutz Date: Thu, 16 May 2002 20:36:29 +0000 (+0000) Subject: * automake.in (conditional_true_when): Return false if $WHEN == FALSE. X-Git-Tag: Release-1-6b~102 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=f17d8fe15477dd6a77fb1b4ff07bc3342245b966;p=automake.git * automake.in (conditional_true_when): Return false if $WHEN == FALSE. (conditional_is_redundant): Simplify. (conditional_implies_one_of, variable_not_always_defined_in_cond): New functions (macro_define): Reject appends if the variable is not defined in all conditions where `+=' applies. (invert_conditions): Rewrite. Before this patch, invert_conditions("A_TRUE B_TRUE", "A_TRUE B_FALSE", "A_FALSE") would return ("A_FALSE B_TRUE", "A_FALSE B_TRUE"), which seems wrong (these conditions implies "A_FALSE"). Now it outputs (), which just means the input conditions cover all cases. (variable_conditions_permutations): Never output FALSE conditions. * tests/pluseq2.test, tests/pluseq3.test: Define data_DATA in the CHECK_FALSE condition to fix the test. * tests/pluseq5.test: Actually check the diagnostic. * tests/pluseq9.test: New file. * tests/Makefile.am (TESTS): Add pluseq9.test. --- diff --git a/ChangeLog b/ChangeLog index 15ac16d3..3fb59028 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2002-05-16 Alexandre Duret-Lutz + + * automake.in (conditional_true_when): Return false if $WHEN == FALSE. + (conditional_is_redundant): Simplify. + (conditional_implies_one_of, + variable_not_always_defined_in_cond): New functions + (macro_define): Reject appends if the variable is not defined in + all conditions where `+=' applies. + (invert_conditions): Rewrite. Before this patch, + invert_conditions("A_TRUE B_TRUE", "A_TRUE B_FALSE", "A_FALSE") + would return ("A_FALSE B_TRUE", "A_FALSE B_TRUE"), which seems + wrong (these conditions implies "A_FALSE"). Now it outputs (), + which just means the input conditions cover all cases. + (variable_conditions_permutations): Never output FALSE conditions. + * tests/pluseq2.test, tests/pluseq3.test: Define data_DATA + in the CHECK_FALSE condition to fix the test. + * tests/pluseq5.test: Actually check the diagnostic. + * tests/pluseq9.test: New file. + * tests/Makefile.am (TESTS): Add pluseq9.test. + 2002-05-14 Alexandre Duret-Lutz Fix for PR automake/322: diff --git a/automake.in b/automake.in index bf252a15..f6cb0074 100755 --- a/automake.in +++ b/automake.in @@ -5351,6 +5351,10 @@ sub conditional_true_when ($$) # Make a hash holding all the values from $WHEN. my %cond_vals = map { $_ => 1 } split (' ', $when); + # Nothing is true when FALSE (not even FALSE itself, but it + # shouldn't hurt if you decide to change that). + return 0 if exists $cond_vals{'FALSE'}; + # Check each component of $cond, which looks `COND1 COND2'. foreach my $comp (split (' ', $cond)) { @@ -5376,18 +5380,30 @@ sub conditional_is_redundant ($@) { my ($cond, @whens) = @_; - if (@whens == 0) + @whens = ("") if @whens == 0; + + foreach my $when (@whens) { - return 1 if conditional_true_when ($cond, ""); + return 1 if conditional_true_when ($cond, $when); } - else + return 0; +} + + +# $BOOLEAN +# &conditional_implies_one_of ($COND, @CONDS) +# ------------------------------------------- +# Returns true iff $COND implies one of the conditions in @CONDS. +sub conditional_implies_one_of ($@) +{ + my ($cond, @conds) = @_; + + @conds = ("") if @conds == 0; + + foreach my $c (@conds) { - foreach my $when (@whens) - { - return 1 if conditional_true_when ($cond, $when); - } + return 1 if conditional_true_when ($c, $cond); } - return 0; } @@ -5618,6 +5634,85 @@ sub conditional_ambiguous_p ($$) return ''; } +# @MISSING_CONDS +# variable_not_always_defined_in_cond ($VAR, $COND) +# --------------------------------------------- +# Check whether $VAR is always defined for condition $COND. +# Return a list of conditions where the definition is missing. +# +# For instance, given +# +# if COND1 +# if COND2 +# A = foo +# D = d1 +# else +# A = bar +# D = d2 +# endif +# else +# D = d3 +# endif +# if COND3 +# A = baz +# B = mumble +# endif +# C = mumble +# +# we should have: +# variable_not_always_defined_in_cond ('A', 'COND1_TRUE COND2_TRUE') +# => () +# variable_not_always_defined_in_cond ('A', 'COND1_TRUE') +# => () +# variable_not_always_defined_in_cond ('A', 'TRUE') +# => ("COND1_FALSE COND2_FALSE COND3_FALSE", +# "COND1_FALSE COND2_TRUE COND3_FALSE", +# "COND1_TRUE COND2_FALSE COND3_FALSE", +# "COND1_TRUE COND2_TRUE COND3_FALSE") +# variable_not_always_defined_in_cond ('B', 'COND1_TRUE') +# => ("COND3_FALSE") +# variable_not_always_defined_in_cond ('C', 'COND1_TRUE') +# => () +# variable_not_always_defined_in_cond ('D', 'TRUE') +# => () +# variable_not_always_defined_in_cond ('Z', 'TRUE') +# => ("TRUE") +# +sub variable_not_always_defined_in_cond ($$) +{ + my ($var, $cond) = @_; + + # It's easy to answer if the variable is not defined. + return ("TRUE",) unless exists $var_value{$var}; + + # How does it work? Let's take the second example: + # + # variable_not_always_defined_in_cond ('A', 'COND1_TRUE') + # + # (1) First, we get the list of conditions where A is defined: + # + # ("COND1_TRUE COND2_TRUE", "COND1_TRUE COND2_FALSE", "COND3_TRUE") + # + # (2) Then we generate the set of inverted conditions: + # + # ("COND1_FALSE COND2_TRUE COND3_FALSE", + # "COND1_FALSE COND2_FALSE COND3_FALSE") + # + # (3) Finally we remove these conditions which are not implied by + # COND1_TRUE. This yields an empty list and we are done. + + my @res = (); + my @cond_defs = keys %{$var_value{$var}}; # (1) + foreach my $icond (invert_conditions (@cond_defs)) # (2) + { + prog_error ("invert_conditions returned an input condition") + if exists $var_value{$var}{$icond}; + + push @res, $icond + if (conditional_true_when ($cond, $icond)); # (3) + } + return @res; +} # ¯o_define($VAR, $VAR_IS_AM, $TYPE, $COND, $VALUE, $WHERE) # ------------------------------------------------------------- @@ -5727,7 +5822,29 @@ sub macro_define ($$$$$$) # Add VALUE to all definitions of VAR. foreach my $vcond (keys %{$var_value{$var}}) { - ¯o_define ($var, $var_is_am, '+', $vcond, $value, $where); + # We have a bit of error detection to do here. + # This: + # if COND1 + # X = Y + # endif + # X += Z + # should be rejected because X is not defined for all conditions + # where `+=' applies. + my @undef_cond = variable_not_always_defined_in_cond $var, $cond; + if (@undef_cond != 0) + { + file_error ($where, + "Cannot apply `+=' because `$var' is not defined " + . "in\nthe following conditions:\n " + . join ("\n ", @undef_cond) + . "\nEither define `$var' in these conditions," + . " or use\n`+=' in the same conditions as" + . " the definitions."); + } + else + { + ¯o_define ($var, $var_is_am, '+', $vcond, $value, $where); + } } } # 3. first assignment (=, :=, or +=) @@ -5933,6 +6050,7 @@ sub variable_conditions_recursive ($) %vars_scanned = (); my @new_conds = variable_conditions_recursive_sub ($var, ''); + # Now we want to return all permutations of the subvariable # conditions. my %allconds = (); @@ -6131,25 +6249,49 @@ sub variable_conditions_reduce # are never true for any of the input conditionals, and when taken # together with the input conditionals cover all possible cases. # -# For example: invert_conditions("A_TRUE B_TRUE", "A_FALSE B_FALSE") will -# return ("A_FALSE B_TRUE", "A_TRUE B_FALSE") +# For example: +# invert_conditions("A_TRUE B_TRUE", "A_FALSE B_FALSE") +# => ("A_FALSE B_TRUE", "A_TRUE B_FALSE") +# +# invert_conditions("A_TRUE B_TRUE", "A_TRUE B_FALSE", "A_FALSE") +# => () sub invert_conditions { my (@conds) = @_; my @notconds = (); - foreach my $cond (@conds) + + # Generate all permutation for all inputs. + my @perm = + map { variable_conditions_permutations (split(' ', $_)); } @conds; + # Remove redundant conditions. + @perm = variable_conditions_reduce @perm; + + # Now remove all conditions which imply one of the input conditions. + foreach my $perm (@perm) { - foreach my $perm (variable_conditions_permutations (split(' ', $cond))) - { - push @notconds, $perm - if ! conditional_is_redundant ($perm, @conds); - } + push @notconds, $perm + if ! conditional_implies_one_of ($perm, @conds); } - return variable_conditions_reduce (@notconds); + return @notconds; } # Return a list of permutations of a conditional string. +# (But never output FALSE conditions, they are useless.) +# +# Examples: +# variable_conditions_permutations ("FOO_FALSE", "BAR_TRUE") +# => ("FOO_FALSE BAR_FALSE", +# "FOO_FALSE BAR_TRUE", +# "FOO_TRUE BAR_FALSE", +# "FOO_TRUE BAR_TRUE") +# variable_conditions_permutations ("FOO_FALSE", "TRUE") +# => ("FOO_FALSE TRUE", +# "FOO_TRUE TRUE") +# variable_conditions_permutations ("TRUE") +# => ("TRUE") +# variable_conditions_permutations ("FALSE") +# => ("TRUE") sub variable_conditions_permutations { my (@comps) = @_; @@ -6163,13 +6305,13 @@ sub variable_conditions_permutations my @ret; foreach my $sub (variable_conditions_permutations (@comps)) { - push (@ret, "$comp $sub"); - push (@ret, "$neg $sub"); + push (@ret, "$comp $sub") if $comp ne 'FALSE'; + push (@ret, "$neg $sub") if $neg ne 'FALSE'; } if (! @ret) { - push (@ret, $comp); - push (@ret, $neg); + push (@ret, $comp) if $comp ne 'FALSE'; + push (@ret, $neg) if $neg ne 'FALSE'; } return @ret; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 837a13fd..33e5ed4e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -254,6 +254,7 @@ pluseq5.test \ pluseq6.test \ pluseq7.test \ pluseq8.test \ +pluseq9.test \ postproc.test \ ppf77.test \ pr2.test \ diff --git a/tests/Makefile.in b/tests/Makefile.in index 12618e1b..45b4f2a0 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -338,6 +338,7 @@ pluseq5.test \ pluseq6.test \ pluseq7.test \ pluseq8.test \ +pluseq9.test \ postproc.test \ ppf77.test \ pr2.test \ diff --git a/tests/pluseq2.test b/tests/pluseq2.test index be1e0705..90626f8d 100755 --- a/tests/pluseq2.test +++ b/tests/pluseq2.test @@ -10,6 +10,8 @@ cat > Makefile.am << 'END' if CHECK data_DATA = zar +else +data_DATA = endif if CHECK diff --git a/tests/pluseq3.test b/tests/pluseq3.test index 58555a6e..71778011 100755 --- a/tests/pluseq3.test +++ b/tests/pluseq3.test @@ -10,6 +10,8 @@ cat > Makefile.am << 'END' if CHECK data_DATA = zar +else +data_DATA = endif if CHECK diff --git a/tests/pluseq5.test b/tests/pluseq5.test index e1d4903d..6009e5ec 100755 --- a/tests/pluseq5.test +++ b/tests/pluseq5.test @@ -14,5 +14,21 @@ INCLUDES += def END $ACLOCAL || exit 1 -$AUTOMAKE || exit 0 -exit 1 +$AUTOMAKE 2>stderr && exit 1 + +cat stderr # for debugging + +# We expect the following diagnostic: +# +# Makefile.am:4: Cannot apply `+=' because `INCLUDES' is not defined in +# Makefile.am:4: the following conditions: +# Makefile.am:4: CHECK_FALSE +# Makefile.am:4: Either define `INCLUDES' in these conditions, or use +# Makefile.am:4: `+=' in the same conditions as the definitions. + +# Is CHECK_FALSE mentioned? +grep ':.*CHECK_FALSE$' stderr || exit 1 +# Is there only one missing condition? +test `grep ': ' stderr | wc -l` = 1 || exit 1 + +: diff --git a/tests/pluseq9.test b/tests/pluseq9.test new file mode 100755 index 00000000..2aed68f2 --- /dev/null +++ b/tests/pluseq9.test @@ -0,0 +1,60 @@ +#! /bin/sh + +# Test the += diagnostics. + +. $srcdir/defs || exit 1 + +cat >>configure.in < Makefile.am << 'END' +if COND1 +if COND2 + A = a + B = aa +else + A = b + B = bb +endif + A += c +else + A = d +endif +A += e + +if COND3 + A += f + B = cc +endif +B += dd +END + +$ACLOCAL || exit 1 +$AUTOMAKE 2>stderr && exit 1 + +cat stderr # for debugging + +# We expect the following diagnostic: +# +# Makefile.am:19: Cannot apply `+=' because `B' is not defined in +# Makefile.am:19: the following conditions: +# Makefile.am:19: COND3_FALSE +# Makefile.am:19: COND1_FALSE COND2_FALSE +# Makefile.am:19: COND1_FALSE COND2_TRUE +# Makefile.am:19: Either define `B' in these conditions, or use +# Makefile.am:19: `+=' in the same conditions as the definitions. +# +# It would be nice if Automake could print only COND3_FALSE and +# COND1_FALSE (merging the last two conditions), so we'll support +# this case in the check too. + +# Are COND3_FALSE and COND1_FALSE mentioned? +grep ':.*COND3_FALSE$' stderr || exit 1 +grep ':.*COND1_FALSE' stderr || exit 1 +# Make sure there are no more than three missing conditions. +test `grep ': ' stderr | wc -l` -le 3 || exit 1 + +: