automake-patches
[Top][All Lists]
Advanced

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

FYI: Automake::Conditional


From: Alexandre Duret-Lutz
Subject: FYI: Automake::Conditional
Date: 07 Oct 2002 11:22:37 +0200
User-agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/20.7

I'm checking this in.

This is one more step towards the goal of defining targets and
variables as objects.

Automake::Conditional represents a conjunction of conditions.
What was formerly carried around as "COND1_TRUE COND2_FALSE" is
now passed as an Automake::Conditional object, and supporting
functions has been rewritten as methods.  
(Run `perldoc lib/Automake/Conditional.pm' for the documentation.)

My next step will be to define Automake::ConditionalSet to
represent disjunctions of conditions we currently represent as a
list of Automake::Conditional (e.g., the list of conditionals in
which a variable is defined.)

The rationnal for doing this is
  - this degreases automake.in
  - this documents conditionals in a single place
  - with ConditionalSet we'll be able to *cache* the result
    of complex algorithms like invert_conditions 

Now there is the following implementation drawback.  We used to
use conditional strings like "COND1_TRUE COND2_FALSE" as keys in
hashes.  Now we have to use Automake::Conditional objects
instead (we could have continued to use strings, but I didn't
want to change all the code to use `$cond->string' instead of
`$cond' in hash keys).  An object is a (blessed) reference,
which is a scalar, so one might think it can be used as a key...
Well, that's wrong.

   my $cond = new Automake::Conditional "COND1_TRUE", "COND2_FALSE";
   $targets{'rule'}{$cond} = "here:1";

When used as key, $cond will be converted as a string
(something like "Automake::Conditional=0x12345678").  So when you
later fetch the keys, 

   my @conds = keys %{$targets{'rule'}}

you will be returned a list of *strings*, not a list of 
blessed references.  Silly language...

One way to allow references to be used as keys is

   tie %targets, 'Tie::RefHash::Netsable';

See `man Tie::RefHash'.  I expect to get rid of this horror
when targets and variables are objects.

2002-10-07  Alexandre Duret-Lutz  <address@hidden>

        * lib/Automake/Conditional.pm: New file.
        * lib/Automake/Makefile.am (dist_perllib_DATA): Add Conditional.pm.
        * automake.in: Use Automake::Conditional.
        (TRUE, FALSE): New constants.
        (%var_value, %var_location, %var_comment, %var_type, %var_owner,
        %targets, %target_source, %target_name, %target_owner): Tie to
        Tie::RefHash::Nestable.
        (generate_makefile, process_option_list, handle_options,
        handle_languages, handle_source_transform, handle_compile,
        handle_libtool, handle_texinfo_helper, handle_dist, handle_subdirs,
        scan_aclocal_m4, handle_emacs_lisp, handle_python,
        scan_autoconf_files, variable_assert, define_variable,
        define_pretty_variable, define_configure_variable, am_install_var,
        push_dist_common): Use TRUE.
        (define_objects_from_sources): Fix return value on
        "recursively-defined" errors.
        (conditional_string, conditional_true_when, conditional_is_redundant,
        conditional_implies_any, make_conditions): Remove these functions,
        obsoleted by Conditional.pm.
        (cond_stack_if, cond_stack_else, cond_stack_endif): Return
        an Automake::Conditional instance.
        (by_condition, conditional_ambiguous_p,
        variable_not_always_defined_in_cond, macro_define,
        variable_conditions_recursive, variable_conditions_recursive_sub,
        variable_conditions_reduce, invert_conditions,
        variable_conditions_permutations,
        check_variable_defined_unconditionally, variable_value_as_list,
        variable_output, variable_pretty_output, rule_define,
        read_am_file, file_contents_internal, require_variables): Adjust
        to use Automake::Conditional objects.
        (handle_footer): Get $(SUFFIXES) in 'all' conditions.
        * tests/cond12.test: Adjust to use Automake::Conditional objects.

Index: automake.in
===================================================================
RCS file: /cvs/automake/automake/automake.in,v
retrieving revision 1.1374
diff -u -b -r1.1374 automake.in
--- automake.in 1 Oct 2002 19:59:32 -0000       1.1374
+++ automake.in 7 Oct 2002 09:16:15 -0000
@@ -116,7 +116,9 @@
 use Automake::XFile;
 use Automake::Channels;
 use Automake::Location;
+use Automake::Conditional;
 use File::Basename;
+use Tie::RefHash;
 use Carp;
 
 ## ----------- ##
@@ -293,6 +295,10 @@
 # when its defined by Automake.  We use INTERNAL in this case.
 use constant INTERNAL => new Automake::Location;
 
+# The TRUE and FALSE conditionals.
+use constant TRUE => new Automake::Conditional;
+use constant FALSE => new Automake::Conditional "FALSE";
+
 
 ## ---------------------------------- ##
 ## Variables related to the options.  ##
@@ -503,11 +509,11 @@
 # - $var_type{$VAR}{$COND} is how it has been defined (`', `+', or `:'),
 # - $var_owner{$VAR}{$COND} tells who owns the variable (VAR_AUTOMAKE,
 #     VAR_CONFIGURE, or VAR_MAKEFILE).
-my %var_value;
-my %var_location;
-my %var_comment;
-my %var_type;
-my %var_owner;
+my %var_value;   tie %var_value, 'Tie::RefHash::Nestable';
+my %var_location; tie %var_location, 'Tie::RefHash::Nestable';
+my %var_comment;  tie %var_comment, 'Tie::RefHash::Nestable';
+my %var_type;     tie %var_type, 'Tie::RefHash::Nestable';
+my %var_owner;    tie %var_owner, 'Tie::RefHash::Nestable';
 # Possible values for var_owner.  Defined so that the owner of
 # a variable can only be increased (e.g Automake should not
 # override a configure or Makefile variable).
@@ -522,20 +528,20 @@
 # %contents.  $targets{TARGET}{COND} is the location of the definition
 # of TARGET for condition COND.  TARGETs should not include
 # a trailing $(EXEEXT), we record this in %target_name.
-my %targets;
+my %targets;       tie %targets, 'Tie::RefHash::Nestable';
 
 # $target_source{TARGET}{COND} is the filename where TARGET
 # were defined for condition COND.  Note this must be a
 # filename, *without* any line number.
-my %target_source;
+my %target_source; tie %target_source, 'Tie::RefHash::Nestable';
 
 # $target_name{TARGET}{COND} is the real name of TARGET (in condition COND).
 # The real name is often TARGET or TARGET$(EXEEXT), and TARGET never
 # contain $(EXEEXT)
-my %target_name;
+my %target_name;   tie %target_name, 'Tie::RefHash::Nestable';
 
 # $target_owner{TARGET}{COND} the owner of TARGET in condition COND.
-my %target_owner;
+my %target_owner;  tie %target_owner, 'Tie::RefHash::Nestable';
 use constant TARGET_AUTOMAKE => 0; # Target defined by Automake.
 use constant TARGET_USER => 1; # Target defined in the user's Makefile.am.
 
@@ -1615,9 +1621,9 @@
        if (exists $var_owner{$var})
          {
            prog_error "\$var_owner{$var}{TRUE} doesn't exist"
-             unless exists $var_owner{$var}{'TRUE'};
+             unless exists $var_owner{$var}{&TRUE};
            reject_var $var, "`$var' should not be defined"
-             if $var_owner{$var}{'TRUE'} != VAR_AUTOMAKE;
+             if $var_owner{$var}{&TRUE} != VAR_AUTOMAKE;
          }
       }
 
@@ -1678,8 +1684,8 @@
 
     # Re-init SOURCES.  FIXME: other code shouldn't depend on this
     # (but currently does).
-    macro_define ('SOURCES', VAR_AUTOMAKE, '', 'TRUE', "@sources", INTERNAL);
-    define_pretty_variable ('DIST_SOURCES', '', INTERNAL, @dist_sources);
+    macro_define ('SOURCES', VAR_AUTOMAKE, '', TRUE, "@sources", INTERNAL);
+    define_pretty_variable ('DIST_SOURCES', TRUE, INTERNAL, @dist_sources);
 
     &handle_multilib;
     &handle_texinfo;
@@ -1859,7 +1865,7 @@
   # FIXME: We should disallow conditional deffinitions of AUTOMAKE_OPTIONS.
   my $where = ($config ?
               $seen_init_automake :
-              $var_location{'AUTOMAKE_OPTIONS'}{'TRUE'});
+              $var_location{'AUTOMAKE_OPTIONS'}{&TRUE});
 
   foreach (@list)
     {
@@ -1933,7 +1939,7 @@
 
     if (variable_defined ('AUTOMAKE_OPTIONS'))
     {
-       if (&process_option_list (0, &variable_value_as_list_recursive 
('AUTOMAKE_OPTIONS', '')))
+       if (&process_option_list (0, &variable_value_as_list_recursive 
('AUTOMAKE_OPTIONS', TRUE)))
        {
            return 1;
        }
@@ -1993,8 +1999,9 @@
            # We define this as a conditional variable because BSD
            # make can't handle backslashes for continuing comments on
            # the following line.
-           define_pretty_variable ('DEP_FILES', 'AMDEP_TRUE', INTERNAL,
-                                   @deplist);
+           define_pretty_variable ('DEP_FILES',
+                                   new Automake::Conditional ('AMDEP_TRUE'),
+                                   INTERNAL, @deplist);
 
            # Generate each `include' individually.  Irix 6 make will
            # not properly include several files resulting from a
@@ -2192,7 +2199,7 @@
          if ($lang->link);
 
        require_variables ("$am_file.am", $lang->Name . " source seen",
-                          'TRUE', @{$lang->config_vars});
+                          TRUE, @{$lang->config_vars});
 
        # Call the finisher.
        $lang->finish;
@@ -2631,7 +2638,7 @@
     if (defined $vars_scanned{$var})
     {
        err_var $var, "variable `$var' recursively defined";
-       return "";
+       return ("", $objvar || "ERROR");
     }
     $vars_scanned{$var} = 1;
 
@@ -2810,12 +2817,12 @@
            # and add this variable to DIST_SOURCES.
            my $distvar = "$var";
            my @conds = variable_conditions_recursive ($var);
-           if (@conds && $conds[0] ne 'TRUE')
+           if (@conds && $conds[0] != TRUE)
              {
                $distvar = "am__${var}_DIST";
                my @files =
                  uniq (variable_value_as_list_recursive ($var, 'all'));
-               define_pretty_variable ($distvar, '', $where, @files);
+               define_pretty_variable ($distvar, TRUE, $where, @files);
              }
            push @dist_sources, "\$($distvar)"
          }
@@ -2849,12 +2856,12 @@
                                         $one_file, $obj,
                                         "$unxformed.c");
        $linker ||= &resolve_linker (%linkers_used);
-       define_pretty_variable ($one_file . '_OBJECTS', '', $where, @result)
+       define_pretty_variable ($one_file . '_OBJECTS', TRUE, $where, @result);
     }
     else
     {
        grep ($_ = '$(' . $_ . $one_file . '_OBJECTS)', @keys);
-       define_pretty_variable ($one_file . '_OBJECTS', '', $where, @keys);
+       define_pretty_variable ($one_file . '_OBJECTS', TRUE, $where, @keys);
     }
 
     # If we want to use `LINK' we must make sure it is defined.
@@ -3105,7 +3112,7 @@
          {
            # Only require ansi2knr files if they should appear in
            # this directory.
-           require_file_with_macro ('TRUE', 'AUTOMAKE_OPTIONS', FOREIGN,
+           require_file_with_macro (TRUE, 'AUTOMAKE_OPTIONS', FOREIGN,
                                     'ansi2knr.c', 'ansi2knr.1');
 
            # ansi2knr needs to be built before subdirs, so unshift it.
@@ -3131,7 +3138,7 @@
   return unless variable_defined ('LIBTOOL');
 
   # Libtool requires some files, but only at top level.
-  require_conf_file_with_macro ('TRUE', 'LIBTOOL', FOREIGN, @libtool_files)
+  require_conf_file_with_macro (TRUE, 'LIBTOOL', FOREIGN, @libtool_files)
     if $relative_dir eq '.';
 
   my @libtool_rms;
@@ -3786,12 +3793,12 @@
            # This is ugly, but it is our historical practice.
            if ($config_aux_dir_set_in_configure_in)
            {
-               require_conf_file_with_macro ('TRUE', 'info_TEXINFOS', FOREIGN,
+               require_conf_file_with_macro (TRUE, 'info_TEXINFOS', FOREIGN,
                                              'mdate-sh');
            }
            else
            {
-               require_file_with_macro ('TRUE', 'info_TEXINFOS',
+               require_file_with_macro (TRUE, 'info_TEXINFOS',
                                         FOREIGN, 'mdate-sh');
            }
 
@@ -3873,12 +3880,12 @@
     {
        if ($need_texi_file > 1)
        {
-           require_conf_file_with_macro ('TRUE', 'info_TEXINFOS', FOREIGN,
+           require_conf_file_with_macro (TRUE, 'info_TEXINFOS', FOREIGN,
                                          'texinfo.tex');
        }
        else
        {
-           require_file_with_macro ('TRUE', 'info_TEXINFOS', FOREIGN,
+           require_file_with_macro (TRUE, 'info_TEXINFOS', FOREIGN,
                                     'texinfo.tex');
        }
     }
@@ -4130,7 +4137,7 @@
     # Files to distributed.  Don't use &variable_value_as_list_recursive
     # as it recursively expands `$(dist_pkgdata_DATA)' etc.
     check_variable_defined_unconditionally ('DIST_COMMON');
-    my @dist_common = split (' ', variable_value ('DIST_COMMON', 'TRUE'));
+    my @dist_common = split (' ', variable_value ('DIST_COMMON', TRUE));
     @dist_common = uniq (sort for_dist_common (@dist_common));
     pretty_print ('DIST_COMMON = ', "\t", @dist_common);
 
@@ -4149,7 +4156,7 @@
        # appropriate condition.  This is meaningful if the nature of
        # the distribution should depend upon the configure options
        # used.
-       foreach (&variable_value_as_list_recursive ('EXTRA_DIST', ''))
+       foreach (&variable_value_as_list_recursive ('EXTRA_DIST', 'all'))
        {
            next if /address@hidden@$/;
            next unless s,/+[^/]+$,,;
@@ -4198,7 +4205,7 @@
            if (! variable_defined ('DIST_SUBDIRS'))
            {
                define_pretty_variable
-                 ('DIST_SUBDIRS', '', INTERNAL,
+                 ('DIST_SUBDIRS', TRUE, INTERNAL,
                   uniq (&variable_value_as_list_recursive ('SUBDIRS', 'all')));
            }
        }
@@ -4207,7 +4214,7 @@
            $dist_subdir_name = 'SUBDIRS';
            # We always define this because that is what `distclean'
            # wants.
-           define_pretty_variable ('DIST_SUBDIRS', '', INTERNAL,
+           define_pretty_variable ('DIST_SUBDIRS', TRUE, INTERNAL,
                                    '$(SUBDIRS)');
        }
 
@@ -4283,7 +4290,7 @@
     }
 
     $output_rules .= &file_contents ('subdirs', new Automake::Location);
-    variable_pretty_output ('RECURSIVE_TARGETS', 'TRUE');
+    variable_pretty_output ('RECURSIVE_TARGETS', TRUE);
 }
 
 
@@ -4328,7 +4335,7 @@
        # Scan all -I directories for m4 files.  These are our
        # dependencies.
        my $examine_next = 0;
-       foreach my $amdir (&variable_value_as_list_recursive 
('ACLOCAL_AMFLAGS', ''))
+       foreach my $amdir (&variable_value_as_list_recursive 
('ACLOCAL_AMFLAGS', TRUE))
        {
            if ($examine_next)
            {
@@ -4631,7 +4638,7 @@
     }
 
     # These files get removed by "make clean".
-    define_pretty_variable ('CONFIG_CLEAN_FILES', '', INTERNAL,
+    define_pretty_variable ('CONFIG_CLEAN_FILES', TRUE, INTERNAL,
                            @actual_other_files);
 }
 
@@ -4695,7 +4702,8 @@
        # actual suffixes, and not $(SUFFIXES).  Some versions of make
        # do not like variable substitutions on the .SUFFIXES line.
        my @user_suffixes = (variable_defined ('SUFFIXES')
-                            ? &variable_value_as_list_recursive ('SUFFIXES', 
'')
+                            ? &variable_value_as_list_recursive ('SUFFIXES',
+                                                                 'all')
                             : ());
 
        my %suffixes = map { $_ => 1 } @suffixes;
@@ -5008,11 +5016,11 @@
 
   # Generate .elc files.
   my @elcfiles = map { $_->[1] . 'c' } @elfiles;
-  define_pretty_variable ('ELCFILES', '', INTERNAL, @elcfiles);
+  define_pretty_variable ('ELCFILES', TRUE, INTERNAL, @elcfiles);
 
   push (@all, '$(ELCFILES)');
 
-  require_variables ($elfiles[0][0], "Emacs Lisp sources seen", 'TRUE',
+  require_variables ($elfiles[0][0], "Emacs Lisp sources seen", TRUE,
                     'EMACS', 'lispdir');
   require_conf_file ($elfiles[0][0], FOREIGN, 'elisp-comp');
   &define_variable ('elisp_comp', $config_aux_dir . '/elisp-comp', INTERNAL);
@@ -5025,7 +5033,7 @@
                                 'noinst');
   return if ! @pyfiles;
 
-  require_variables ($pyfiles[0][0], "Python sources seen", 'TRUE', 'PYTHON');
+  require_variables ($pyfiles[0][0], "Python sources seen", TRUE, 'PYTHON');
   require_conf_file ($pyfiles[0][0], FOREIGN, 'py-compile');
   &define_variable ('py_compile', $config_aux_dir . '/py-compile', INTERNAL);
 }
@@ -5074,7 +5082,7 @@
            {
              # This means we have an alpha release.  See
              # GNITS_VERSION_PATTERN for details.
-             require_file_with_macro ('TRUE', 'AUTOMAKE_OPTIONS',
+             require_file_with_macro (TRUE, 'AUTOMAKE_OPTIONS',
                                       FOREIGN, 'README-alpha');
            }
        }
@@ -5339,7 +5347,7 @@
       if -f $config_aux_path[0] . '/install.sh';
 
     # Preserve dist_common for later.
-    $configure_dist_common = variable_value ('DIST_COMMON', 'TRUE') || '';
+    $configure_dist_common = variable_value ('DIST_COMMON', TRUE) || '';
 }
 
 ################################################################
@@ -5891,99 +5899,6 @@
 ################################################################
 
 
-# $STRING
-# &conditional_string(@COND-STACK)
-# --------------------------------
-# Build a string which denotes the conditional in @COND-STACK.  Some
-# simplifications are done: `TRUE' entries are elided, and any `FALSE'
-# entry results in a return of `FALSE'.
-sub conditional_string
-{
-  my (@stack) = @_;
-
-  if (grep (/^FALSE$/, @stack))
-    {
-      return 'FALSE';
-    }
-  else
-    {
-      return join (' ', uniq sort grep (!/^TRUE$/, @stack));
-    }
-}
-
-
-# $BOOLEAN
-# &conditional_true_when ($COND, $WHEN)
-# -------------------------------------
-# See if a conditional is true.  Both arguments are conditional
-# strings.  This returns true if the first conditional is true when
-# the second conditional is true.
-# For instance with $COND = `BAR FOO', and $WHEN = `BAR BAZ FOO',
-# obviously return 1, and 0 when, for instance, $WHEN = `FOO'.
-sub conditional_true_when ($$)
-{
-    my ($cond, $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))
-    {
-       # TRUE is always true.
-       next if $comp eq 'TRUE';
-       return 0 if ! defined $cond_vals{$comp};
-    }
-
-    return 1;
-}
-
-
-# $BOOLEAN
-# &conditional_is_redundant ($COND, @WHENS)
-# ----------------------------------------
-# Determine whether $COND is redundant with respect to @WHENS.
-#
-# Returns true if $COND is true for any of the conditions in @WHENS.
-#
-# If there are no @WHENS, then behave as if @WHENS contained a single empty
-# condition.
-sub conditional_is_redundant ($@)
-{
-    my ($cond, @whens) = @_;
-
-    @whens = ("") if @whens == 0;
-
-    foreach my $when (@whens)
-    {
-       return 1 if conditional_true_when ($cond, $when);
-    }
-    return 0;
-}
-
-
-# $BOOLEAN
-# &conditional_implies_any ($COND, @CONDS)
-# ----------------------------------------
-# Returns true iff $COND implies any of the conditions in @CONDS.
-sub conditional_implies_any ($@)
-{
-    my ($cond, @conds) = @_;
-
-    @conds = ("") if @conds == 0;
-
-    foreach my $c (@conds)
-    {
-       return 1 if conditional_true_when ($c, $cond);
-    }
-    return 0;
-}
-
-
 # $NEGATION
 # condition_negate ($COND)
 # ------------------------
@@ -6004,9 +5919,9 @@
 sub by_condition
 {
     # Be careful we might be comparing `' or `#'.
-    $a =~ /^(.*)_(TRUE|FALSE)$/;
+    $a->string =~ /^(.*)_(TRUE|FALSE)$/;
     my ($aname, $abool) = ($1 || '', $2 || '');
-    $b =~ /^(.*)_(TRUE|FALSE)$/;
+    $b->string =~ /^(.*)_(TRUE|FALSE)$/;
     my ($bname, $bbool) = ($1 || '', $2 || '');
     return ($aname cmp $bname
            # Don't bother with IFs, given that TRUE is after FALSE
@@ -6017,44 +5932,12 @@
 }
 
 
-# &make_condition (@CONDITIONS)
-# -----------------------------
-# Transform a list of conditions (themselves can be an internal list
-# of conditions, e.g., @CONDITIONS = ('cond1 cond2', 'cond3')) into a
-# Make conditional (a pattern for AC_SUBST).
-# Correctly returns the empty string when there are no conditions.
-sub make_condition
-{
-    my $res = conditional_string (@_);
-
-    # There are no conditions.
-    if ($res eq '')
-      {
-       # Nothing to do.
-      }
-    # It's impossible.
-    elsif ($res eq 'FALSE')
-      {
-       $res = '#';
-      }
-    # Build it.
-    else
-      {
-       $res = '@' . $res . '@';
-       $res =~ s/ /@@/g;
-      }
-
-    return $res;
-}
-
-
-
 ## ------------------------------ ##
 ## Handling the condition stack.  ##
 ## ------------------------------ ##
 
 
-# $COND_STRING
+# $COND
 # cond_stack_if ($NEGATE, $COND, $WHERE)
 # --------------------------------------
 sub cond_stack_if ($$$)
@@ -6071,11 +5954,11 @@
 
   push (@cond_stack, $cond);
 
-  return conditional_string (@cond_stack);
+  return new Automake::Conditional (@cond_stack);
 }
 
 
-# $COND_STRING
+# $COND
 # cond_stack_else ($NEGATE, $COND, $WHERE)
 # ----------------------------------------
 sub cond_stack_else ($$$)
@@ -6103,11 +5986,11 @@
        if $cond_stack[$#cond_stack] ne $cond;
     }
 
-  return conditional_string (@cond_stack);
+  return new Automake::Conditional (@cond_stack);
 }
 
 
-# $COND_STRING
+# $COND
 # cond_stack_endif ($NEGATE, $COND, $WHERE)
 # -----------------------------------------
 sub cond_stack_endif ($$$)
@@ -6137,7 +6020,7 @@
 
   pop @cond_stack;
 
-  return conditional_string (@cond_stack);
+  return new Automake::Conditional (@cond_stack);
 }
 
 
@@ -6198,12 +6081,12 @@
        {
          return ("$var multiply defined in condition $cond", $vcond);
        }
-      elsif (&conditional_true_when ($vcond, $cond))
+      elsif ($vcond->true_when ($cond))
        {
          return ("$var was already defined in condition $vcond, "
                  . "which implies condition $cond", $vcond);
        }
-      elsif (&conditional_true_when ($cond, $vcond))
+      elsif ($cond->true_when ($vcond))
        {
          return ("$var was already defined in condition $vcond, "
                   . "which is implied by condition $cond", $vcond);
@@ -6237,7 +6120,8 @@
 #   endif
 #   C = mumble
 #
-# we should have:
+# we should have (we display result as conditional strings in this
+# illustration, but we really return Conditional objects):
 #   variable_not_always_defined_in_cond ('A', 'COND1_TRUE COND2_TRUE')
 #     => ()
 #   variable_not_always_defined_in_cond ('A', 'COND1_TRUE')
@@ -6255,13 +6139,12 @@
 #     => ()
 #   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};
+  return (TRUE,) unless exists $var_value{$var};
 
   # How does it work?  Let's take the second example:
   #
@@ -6287,7 +6170,7 @@
        if exists $var_value{$var}{$icond};
 
       push @res, $icond
-       if (conditional_true_when ($cond, $icond)); # (3)
+       if ($cond->true_when ($icond)); # (3)
     }
   return @res;
 }
@@ -6299,6 +6182,9 @@
 {
   my ($var, $owner, $type, $cond, $value, $where) = @_;
 
+  prog_error "$cond is not a reference"
+    unless ref $where;
+
   prog_error "$where is not a reference"
     unless ref $where;
 
@@ -6322,8 +6208,6 @@
 
   check_variable_expansions ($value, $where);
 
-  $cond ||= 'TRUE';
-
   # An Automake variable must be consistently defined with the same
   # sign by Automake.  A user variable must be set by either `=' or
   # `:=', and later promoted to `+='.
@@ -6395,10 +6279,10 @@
       #     @address@hidden = foo2 bar
 
       # Do we need an helper variable?
-      if ($cond ne 'TRUE')
+      if ($cond != TRUE)
         {
            # Does the helper variable already exists?
-           my $key = "$var:$cond";
+           my $key = "$var:" . $cond->string;
            if (exists $appendvar{$key})
              {
                # Yes, let's simply append to it.
@@ -6436,7 +6320,7 @@
              err ($where,
                   "Cannot apply `+=' because `$var' is not defined "
                   . "in\nthe following conditions:\n  "
-                  . join ("\n  ", @undef_cond)
+                  . join ("\n  ", map { $_->string } @undef_cond)
                   . "\nEither define `$var' in these conditions,"
                   . " or use\n`+=' in the same conditions as"
                   . " the definitions.");
@@ -6461,7 +6345,7 @@
        {
          verb ("refusing to override the user definition of:\n"
                . macro_dump ($var)
-               ."with `$cond' => `$value'");
+               ."with `$cond->string' => `$value'");
        }
       else
        {
@@ -6674,7 +6558,7 @@
   return 1
     if variable_defined $var;
 
-  require_variables ($where, "variable `$var' is used", 'TRUE', $var);
+  require_variables ($where, "variable `$var' is used", TRUE, $var);
 
   return 0;
 }
@@ -6711,14 +6595,14 @@
 
     %vars_scanned = ();
 
-    my @new_conds = variable_conditions_recursive_sub ($var, '');
+    my @new_conds = variable_conditions_recursive_sub ($var, TRUE);
 
     # Now we want to return all permutations of the subvariable
     # conditions.
     my %allconds = ();
     foreach my $item (@new_conds)
     {
-       foreach (split (' ', $item))
+       foreach ($item->conds)
        {
            s/^(.*)_(TRUE|FALSE)$/$1_TRUE/;
            $allconds{$_} = 1;
@@ -6726,18 +6610,9 @@
     }
     @new_conds = variable_conditions_permutations (sort keys %allconds);
 
-    my %uniqify;
-    foreach my $cond (@new_conds)
-    {
-       my $reduce = variable_conditions_reduce (split (' ', $cond));
-        next
-           if $reduce eq 'FALSE';
-       $uniqify{$cond} = 1;
-    }
-
-    # Note we cannot just do `return sort keys %uniqify', because this
+    # Note we cannot just do `return sort @new_conds', because this
     # function is sometimes used in a scalar context.
-    my @uniq_list = sort by_condition keys %uniqify;
+    my @uniq_list = sort by_condition @new_conds;
     return @uniq_list;
 }
 
@@ -6860,9 +6735,7 @@
          my @svc = variable_conditions_recursive_sub ($varname, $var);
          foreach my $item (@svc)
            {
-             my $val = conditional_string ($vcond, split (' ', $item));
-             $val ||= 'TRUE';
-             push (@subvar_conds, $val);
+             push (@subvar_conds, $vcond->merge ($item));
            }
        }
 
@@ -6892,14 +6765,13 @@
     foreach my $this_cond (@this_conds)
     {
        my @perms =
-           variable_conditions_permutations (split (' ', $this_cond));
+           variable_conditions_permutations ($this_cond->conds);
        foreach my $perm (@perms)
        {
            my $ok = 1;
            foreach my $scan (@this_conds)
            {
-               if (&conditional_true_when ($perm, $scan)
-                   || &conditional_true_when ($scan, $perm))
+               if ($perm->true_when ($scan) || $scan->true_when ($perm))
                {
                    $ok = 0;
                    last;
@@ -6926,21 +6798,21 @@
     my (@conds) = @_;
     my @ret = ();
     my $cond;
-    while(@conds > 0)
+    while (@conds > 0)
     {
-       $cond = shift(@conds);
+       $cond = shift @conds;
 
         # FALSE is absorbent.
-       return 'FALSE'
-         if $cond eq 'FALSE';
+       return FALSE
+         if $cond == FALSE;
 
-       if (!conditional_is_redundant ($cond, @ret, @conds))
+       if (! $cond->redundant_wrt (@ret, @conds))
          {
            push (@ret, $cond);
          }
     }
 
-    return "TRUE" if @ret == 0;
+  return TRUE if @ret == 0;
     return @ret;
 }
 
@@ -6964,8 +6836,7 @@
     my @notconds = ();
 
     # Generate all permutation for all inputs.
-    my @perm =
-       map { variable_conditions_permutations (split(' ', $_)); } @conds;
+    my @perm = map { variable_conditions_permutations ($_->conds); } @conds;
     # Remove redundant conditions.
     @perm = variable_conditions_reduce @perm;
 
@@ -6973,7 +6844,7 @@
     foreach my $perm (@perm)
     {
        push @notconds, $perm
-           if ! conditional_implies_any ($perm, @conds);
+           if ! $perm->implies_any (@conds);
     }
     return @notconds;
 }
@@ -7007,13 +6878,13 @@
     my @ret;
     foreach my $sub (variable_conditions_permutations (@comps))
     {
-       push (@ret, "$comp $sub") if $comp ne 'FALSE';
-       push (@ret, "$neg $sub") if $neg ne 'FALSE';
+      push (@ret, $sub->merge_conds ($comp)) if $comp ne 'FALSE';
+      push (@ret, $sub->merge_conds ($neg)) if $neg ne 'FALSE';
     }
     if (! @ret)
     {
-       push (@ret, $comp) if $comp ne 'FALSE';
-       push (@ret, $neg) if $neg ne 'FALSE';
+      push (@ret, new Automake::Conditional $comp) if $comp ne 'FALSE';
+      push (@ret, new Automake::Conditional $neg) if $neg ne 'FALSE';
     }
     return @ret;
 }
@@ -7030,7 +6901,7 @@
   foreach my $cond (keys %{$var_value{$var}})
     {
       next
-       if $cond =~ /^TRUE|FALSE$/;
+       if $cond->true || $cond->false;
 
       if ($parent)
        {
@@ -7054,7 +6925,7 @@
 {
     my ($var) = @_;
     &check_variable_defined_unconditionally ($var);
-    return $var_value{$var}{'TRUE'};
+    return $var_value{$var}{&TRUE};
 }
 
 
@@ -7162,13 +7033,12 @@
       unless variable_assert $var, $parent;
 
     # Get value for given condition
-    $cond ||= 'TRUE';
     my $onceflag;
     foreach my $vcond (keys %{$var_value{$var}})
     {
        my $val = $var_value{$var}{$vcond};
 
-       if (&conditional_true_when ($vcond, $cond))
+       if ($vcond->true_when ($cond))
        {
            # Unless variable is not defined conditionally, there should only
            # be one value of $vcond true when $cond.
@@ -7234,14 +7104,13 @@
     }
     else
     {
-        $cond ||= 'TRUE';
        $vars_scanned{$var} = 1;
        my $onceflag;
        foreach my $vcond (keys %{$var_value{$var}})
        {
            my $val = $var_value{$var}{$vcond};
            my $where = $var_location{$var}{$vcond};
-           if (&conditional_true_when ($vcond, $cond))
+           if ($vcond->true_when ($cond))
            {
                # Warn if we have an ambiguity.  It's hard to know how
                # to handle this case correctly.
@@ -7286,7 +7155,8 @@
       my $val = $var_value{$var}{$cond};
       my $equals = $var_type{$var}{$cond} eq ':' ? ':=' : '=';
       my $output_var = "$var $equals $val";
-      $output_var =~ s/^/make_condition ($cond)/meg;
+      my $str = $cond->subst_string;
+      $output_var =~ s/^/$str/meg;
       $output_vars .= $output_var . "\n";
     }
 }
@@ -7315,7 +7185,7 @@
 
       my $val = $var_value{$var}{$cond};
       my $equals = $var_type{$var}{$cond} eq ':' ? ':=' : '=';
-      my $make_condition = make_condition ($cond);
+      my $make_condition = $cond->subst_string;
       $output_vars .= pretty_print_internal ("$make_condition$var $equals",
                                             "$make_condition\t",
                                             split (' ' , $val));
@@ -7363,14 +7233,10 @@
 {
     my ($var, $cond, $where, @value) = @_;
 
-    # Beware that an empty $cond has a different semantics for
-    # macro_define and variable_pretty_output.
-    $cond ||= 'TRUE';
-
     if (! variable_defined ($var, $cond))
     {
         macro_define ($var, VAR_AUTOMAKE, '', $cond, "@value", $where);
-       variable_pretty_output ($var, $cond || 'TRUE');
+       variable_pretty_output ($var, $cond);
        $content_seen{$var} = 1;
     }
 }
@@ -7382,7 +7248,7 @@
 sub define_variable ($$$)
 {
     my ($var, $value, $where) = @_;
-    define_pretty_variable ($var, 'TRUE', $where, $value);
+    define_pretty_variable ($var, TRUE, $where, $value);
 }
 
 
@@ -7391,7 +7257,7 @@
 sub define_configure_variable ($)
 {
   my ($var) = @_;
-  if (! variable_defined ($var, 'TRUE')
+  if (! variable_defined ($var, TRUE)
       # Explicitly avoid ANSI2KNR -- we AC_SUBST that in
       # protos.m4, but later define it elsewhere.  This is
       # pretty hacky.  We also explicitly avoid AMDEPBACKSLASH:
@@ -7399,9 +7265,9 @@
       # appreciated by Make.
       && ! grep { $_ eq $var } (qw(ANSI2KNR AMDEPBACKSLASH)))
     {
-      macro_define ($var, VAR_CONFIGURE, '', 'TRUE',
+      macro_define ($var, VAR_CONFIGURE, '', TRUE,
                    subst $var, $configure_vars{$var});
-      variable_pretty_output ($var, 'TRUE');
+      variable_pretty_output ($var, TRUE);
     }
 }
 
@@ -7532,9 +7398,11 @@
 
   prog_error "$where is not a reference"
     unless ref $where;
+  prog_error "$cond is not a reference"
+    unless ref $cond;
 
   # Don't even think about defining a rule in condition FALSE.
-  return () if $cond eq 'FALSE';
+  return () if $cond == FALSE;
 
   # For now `foo:' will override `foo$(EXEEXT):'.  This is temporary,
   # though, so we emit a warning.
@@ -7584,7 +7452,7 @@
       my $oldowner  = $target_owner{$target}{$cond};
 
       # Don't mention true conditions in diagnostics.
-      my $condmsg = $cond ne 'TRUE' ? " in condition `$cond'" : '';
+      my $condmsg = $cond == TRUE ? " in condition `$cond'" : '';
 
       if ($owner == TARGET_USER)
        {
@@ -7694,7 +7562,7 @@
          @conds = ();
          for my $undefined_cond (invert_conditions(@defined_conds))
            {
-             push @conds, make_condition ($cond, $undefined_cond);
+             push @conds, $cond->merge ($undefined_cond);
            }
          # No conditions left to define the rule.
          # Warn, because our workaround is meaningless in this case.
@@ -7730,9 +7598,6 @@
       register_suffix_rule ($where, $1, $2);
     }
 
-  # Return "" instead of TRUE so it can be used with make_paragraphs
-  # directly.
-  return "" if 1 == @conds && $conds[0] eq 'TRUE';
   return @conds;
 }
 
@@ -7826,7 +7691,7 @@
     # sure it is the same on exit.  This lets us conditonally include
     # other files.
     my @saved_cond_stack = @cond_stack;
-    my $cond = conditional_string (@cond_stack);
+    my $cond = new Automake::Conditional (@cond_stack);
 
     my $last_var_name = '';
     my $last_var_type = '';
@@ -7871,7 +7736,8 @@
        {
            if ($prev_state == IN_RULE_DEF)
            {
-               $output_trailer .= &make_condition (@cond_stack);
+             my $cond = new Automake::Conditional @cond_stack;
+             $output_trailer .= $cond->subst_string;
                $output_trailer .= $_;
            }
            elsif ($prev_state == IN_COMMENT)
@@ -7894,13 +7760,12 @@
 
              if (!/\\$/)
                {
-                 append_comments ($cond || 'TRUE',
-                                  $last_var_name, $spacing, $comment);
+                 append_comments ($cond, $last_var_name, $spacing, $comment);
                  $comment = $spacing = '';
                  macro_define ($last_var_name, VAR_MAKEFILE,
                                $last_var_type, $cond,
                                $last_var_value, $where)
-                   if $cond ne 'FALSE';
+                   if $cond != FALSE;
                  push (@var_list, $last_var_name);
                }
            }
@@ -7927,12 +7792,13 @@
            # For now we have to output all definitions of user rules
            # and can't diagnose duplicates (see the comment in
            # rule_define). So we go on and ignore the return value.
-           rule_define ($1, $amfile, TARGET_USER, $cond || 'TRUE', $where);
+           rule_define ($1, $amfile, TARGET_USER, $cond, $where);
 
            check_variable_expansions ($_, $where);
 
            $output_trailer .= $comment . $spacing;
-            $output_trailer .= &make_condition (@cond_stack);
+           my $cond = new Automake::Conditional @cond_stack;
+           $output_trailer .= $cond->subst_string;
             $output_trailer .= $_;
            $comment = $spacing = '';
        }
@@ -7954,14 +7820,13 @@
            if (!/\\$/)
              {
                # Accumulating variables must not be output.
-               append_comments ($cond || 'TRUE',
-                                $last_var_name, $spacing, $comment);
+               append_comments ($cond, $last_var_name, $spacing, $comment);
                $comment = $spacing = '';
 
                macro_define ($last_var_name, VAR_MAKEFILE,
                              $last_var_type, $cond,
                              $last_var_value, $where)
-                 if $cond ne 'FALSE';
+                 if $cond != FALSE;
                push (@var_list, $last_var_name);
              }
        }
@@ -8004,7 +7869,8 @@
            $prev_state = IN_RULE_DEF;
            check_variable_expansions ($_, $where);
            $output_trailer .= $comment . $spacing;
-           $output_trailer .= &make_condition  (@cond_stack);
+           my $cond = new Automake::Conditional @cond_stack;
+           $output_trailer .= $cond->subst_string;
            $output_trailer .= $_;
            $comment = $spacing = '';
            err $where, "`#' comment at start of rule is unportable"
@@ -8232,7 +8098,7 @@
     # sure it is the same on exit.  This lets us conditonally include
     # other files.
     my @saved_cond_stack = @cond_stack;
-    my $cond = conditional_string (@cond_stack);
+    my $cond = new Automake::Conditional (@cond_stack);
 
     foreach (make_paragraphs ($file, %transform))
     {
@@ -8261,7 +8127,7 @@
        # Handle inclusion of other files.
         elsif (/$INCLUDE_PATTERN/o)
         {
-           if ($cond ne 'FALSE')
+           if ($cond != FALSE)
              {
                my $file = ($is_am ? "$libdir/am/" : '') . $1;
                $where->push_context ("`$file' included from here");
@@ -8330,7 +8196,7 @@
              # `foo:' after `foo bar:'.
 
              # Output only if not in FALSE.
-             if (defined $dependencies{$_} && $cond ne 'FALSE')
+             if (defined $dependencies{$_} && $cond != FALSE)
                {
                  &depend ($_, @deps);
                  $actions{$_} .= $actions;
@@ -8342,11 +8208,11 @@
                  my @undefined_conds =
                    rule_define ($targets, $file,
                                 $is_am ? TARGET_AUTOMAKE : TARGET_USER,
-                                $cond || 'TRUE', $where);
+                                $cond, $where);
                  for my $undefined_cond (@undefined_conds)
                    {
                      my $condparagraph = $paragraph;
-                     $condparagraph =~ s/^/$undefined_cond/gm;
+                     $condparagraph =~ s/^/$undefined_cond->subst_string/gme;
                      $result_rules .= "$spacing$comment$condparagraph\n";
                    }
                  if (scalar @undefined_conds == 0)
@@ -8371,19 +8237,19 @@
            $is_rule = 0;
 
            # Accumulating variables must not be output.
-           append_comments ($cond || 'TRUE', $var, $spacing, $comment);
+           append_comments ($cond, $var, $spacing, $comment);
            macro_define ($var, $is_am ? VAR_AUTOMAKE : VAR_MAKEFILE,
                          $type, $cond, $val, $where)
-             if $cond ne 'FALSE';
+             if $cond != FALSE;
            push (@var_list, $var);
 
            # If the user has set some variables we were in charge
            # of (which is detected by the first reading of
            # `header-vars.am'), we must not output them.
            $result_vars .= "$spacing$comment$_\n"
-             if ($cond ne 'FALSE' && $type ne '+'
-                 && exists $var_owner{$var}{$cond || 'TRUE'}
-                 && $var_owner{$var}{$cond || 'TRUE'} == VAR_AUTOMAKE);
+             if ($cond != FALSE && $type ne '+'
+                 && exists $var_owner{$var}{$cond}
+                 && $var_owner{$var}{$cond} == VAR_AUTOMAKE);
 
            $comment = $spacing = '';
        }
@@ -8392,9 +8258,9 @@
            # This isn't an error; it is probably some tokens which
            # configure is supposed to replace, such as address@hidden@',
            # or some part of a rule cut by an if/endif.
-           if ($cond ne 'FALSE' && ! ($is_rule && $discard_rule))
+           if (! $cond->false && ! ($is_rule && $discard_rule))
              {
-               s/^/make_condition (@cond_stack)/gme;
+               s/^/$cond->subst_string/gme;
                $result_rules .= "$spacing$comment$_\n";
              }
            $comment = $spacing = '';
@@ -8543,8 +8409,8 @@
       # conditionally defined (or else adjust the condition below).
       next
        if (exists $var_owner{$varname}
-           && exists $var_owner{$varname}{'TRUE'}
-           && $var_owner{$varname}{'TRUE'} != VAR_MAKEFILE);
+           && exists $var_owner{$varname}{&TRUE}
+           && $var_owner{$varname}{&TRUE} != VAR_MAKEFILE);
 
       if ($varname =~ /^(nobase_)?(dist_|nodist_)?(.*)_$primary$/)
        {
@@ -8765,7 +8631,7 @@
   if (@used && $primary ne 'JAVA' && $primary ne 'PYTHON')
     {
       # Define it.
-      define_pretty_variable ($primary, '', INTERNAL, @used);
+      define_pretty_variable ($primary, TRUE, INTERNAL, @used);
       $output_vars .= "\n";
     }
 
@@ -9093,7 +8959,7 @@
 {
   prog_error "push_dist_common run after handle_dist"
     if $handle_dist_run;
-  macro_define ('DIST_COMMON', VAR_AUTOMAKE, '+', '', "@_", INTERNAL);
+  macro_define ('DIST_COMMON', VAR_AUTOMAKE, '+', TRUE, "@_", INTERNAL);
 }
 
 
@@ -9192,10 +9058,10 @@
        unless @undef_cond;
 
       my $text = "$reason`$var' is undefined\n";
-      if (@undef_cond && $undef_cond[0] ne 'TRUE')
+      if (@undef_cond && $undef_cond[0] != TRUE)
        {
          $text .= ("in the following conditions:\n  "
-                   . join ("\n  ", @undef_cond));
+                   . join ("\n  ", map { $_->string } @undef_cond));
        }
 
       ++$res;
Index: lib/Automake/Conditional.pm
===================================================================
RCS file: lib/Automake/Conditional.pm
diff -N lib/Automake/Conditional.pm
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/Automake/Conditional.pm 7 Oct 2002 09:16:16 -0000
@@ -0,0 +1,420 @@
+# Copyright (C) 1997, 2001, 2002  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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+package Automake::Conditional;
+use strict;
+use Carp;
+
+=head1 NAME
+
+Automake::Conditional - record a conjunction of conditions
+
+=head1 SYNOPSIS
+
+  use Automake::Conditional;
+
+  # Create a conditional to represent "COND1 and not COND2".
+  my $cond = new Automake::Conditional "COND1_TRUE", "COND2_FALSE";
+  # Create a conditional to represent "not COND3".
+  my $other = new Automake::Conditional "COND3_FALSE";
+
+  # Create a conditional to represent
+  #   "COND1 and not COND2 and not COND3".
+  my $both = $cond->merge ($other);
+
+  # Likewise, but using a list of atomica conditional strings
+  my $both2 = $cond->merge_conds ("COND3_FALSE");
+
+  # Return the list of conditions ("COND1_TRUE", "COND2_FALSE"):
+  my @conds = $cond->conds;
+
+  # Is $cond always true?  (Not in this example)
+  if ($cond->true) { ... }
+
+  # Is $cond always false? (Not in this example)
+  if ($cond->false) { ... }
+
+  # Return the list of conditions as a string:
+  #  "COND1_TRUE COND2_FALSE"
+  my $str = $cond->string;
+
+  # Return the list of conditions as a AC_SUBST-style string:
+  #  "@COND1_TRUE@@COND2_FALSE@"
+  my $subst = $cond->subst_string;
+
+  # Is $cond true when $both is true?  (Yes in this example)
+  if ($cond->true_when ($both)) { ... }
+
+  # Is $cond redundant w.r.t. {$other, $both}?
+  # (Yes in this example)
+  if ($cond->redundant_wrt ($other, $both)) { ... }
+
+  # Does $cond imply any of {$other, $both}?
+  # (Not in this example)
+  if ($cond->implies_any ($other, $both)) { ... }
+
+=head1 DESCRIPTION
+
+A C<Conditional> is a conjunction of atomic conditions.  In Automake they
+are used to represent the conditions into which Makefile variables and
+Makefile rules are defined.
+
+If the variable C<VAR> is defined as
+
+  if COND1
+    if COND2
+      VAR = value
+    endif
+  endif
+
+then it will be associated a C<Conditional> created with
+the following statement.
+
+  new Automake::Conditional "COND1_TRUE", "COND2_TRUE";
+
+Remember that a C<Conditional> is a I<conjunction> of conditions, so
+the above C<Conditional> means C<VAR> is defined when C<COND1> is true
+B<and> C<COND2> are true. There is no way to express disjunctions
+(i.e., I<or>s) with this class.
+
+Another point worth to mention is that each C<Conditional> object is
+unique with respect to its conditions.  Two C<Conditional> objects
+created for the same set of conditions will have the same adress.
+This makes it easy to compare C<Conditional>s, just compare the
+references.
+
+  my $c1 = new Automake::Conditional "COND1_TRUE", "COND2_TRUE";
+  my $c2 = new Automake::Conditional "COND1_TRUE", "COND2_TRUE";
+  $c1 == $c2;  # True!
+
+=head2 Methods
+
+=over 4
+
+=item C<$cond = new Automake::Conditional address@hidden>
+
+Return a C<Conditional> objects for the conjunctions of conditions
+listed in C<@conds> as strings.
+
+An item in C<@conds> should be either C<"FALSE">, C<"TRUE">, or have
+the form C<"NAME_FALSE"> or C<"NAME_TRUE"> where C<NAME> can be
+anything (in practice C<NAME> should be the name of a conditional
+declared in F<configure.ac> with C<AM_CONDITIONAL>, but it's not
+C<Automake::Conditional>'s responsability to ensure this).
+
+An empty C<@conds> means C<"TRUE">.
+
+As explained previously, the reference (object) returned is unique
+with respect to C<@conds>.  For this purpose, duplicate elements are
+ignored, and C<@conds> is rewriten as C<("FALSE")> if it contains
+C<"FALSE"> or two contradictory conditions (such as C<"NAME_FALSE">
+and C<"NAME_TRUE">.)
+
+Therefore the following two statements create the same object (they
+both create the C<"FALSE"> conditional).
+
+  my $c3 = new Automake::Conditional "COND1_TRUE", "COND1_FALSE";
+  my $c4 = new Automake::Conditional "COND2_TRUE", "FALSE";
+  $c3 == $c4;   # True!
+  $c3 == FALSE; # True!
+
+=cut
+
+# Keys in this hash are conditionnal strings. Values are the
+# associated object conditions.  This is used by `new' to reuse
+# Conditional objects with identical conditions.
+use vars '%_conditional_singletons';
+%_conditional_singletons = ();
+
+sub new ($;@)
+{
+  my ($class, @conds) = @_;
+  my $self = {
+    hash => {},
+  };
+  bless $self, $class;
+
+  # Accept strings like "FOO BAR" as shorthand for ("FOO", "BAR").
+  @conds = map { split (' ', $_) } @conds;
+
+  for my $cond (@conds)
+    {
+      next if $cond eq 'TRUE';
+
+      # Catch some common programming errors:
+      # - A conditional passed to new
+      confess "`$cond' is a reference, expected a string" if ref $cond;
+      # - A conditional passed as a string to new
+      confess "`$cond' doesn't look like a condition" if $cond =~ /::/;
+
+      # Detect cases when @conds can be simplified to FALSE.
+      if (($cond eq 'FALSE' && $#conds > 0)
+         || ($cond =~ /^(.*)_TRUE$/ && exists $self->{'hash'}{"${1}_FALSE"})
+         || ($cond =~ /^(.*)_FALSE$/ && exists $self->{'hash'}{"${1}_TRUE"}))
+       {
+         return new Automake::Conditional 'FALSE';
+       }
+
+      $self->{'hash'}{$cond} = 1;
+    }
+
+  my $key = $self->string;
+  if (exists $_conditional_singletons{$key})
+    {
+      return $_conditional_singletons{$key};
+    }
+  $_conditional_singletons{$key} = $self;
+  return $self;
+}
+
+=item C<$newcond = $cond-E<gt>merge ($othercond)>
+
+Return a new condition which is the conjunction of
+C<$cond> and C<$othercond>.
+
+=cut
+
+sub merge ($$)
+{
+  my ($self, $other) = @_;
+  new Automake::Conditional $self->conds, $other->conds;
+}
+
+=item C<$newcond = $cond-E<gt>merge_conds (@conds)>
+
+Return a new condition which is the conjunction of C<$cond> and
+C<@conds>, where C<@conds> is a list of atomic condition strings, as
+passed to C<new>.
+
+=cut
+
+sub merge_conds ($@)
+{
+  my ($self, @conds) = @_;
+  new Automake::Conditional $self->conds, @conds;
+}
+
+=item C<@list = $cond-E<gt>conds>
+
+Return the set of conditions defining C<$cond>, as strings.  Note that
+this might not be exactly the list passed to C<new> (or a
+concatenation of such lists if C<merge> was used), because of the
+cleanup mentioned in C<new>'s description.
+
+For instance C<$c3-E<gt>conds> will simply return C<("FALSE")>.
+
+=cut
+
+sub conds ($ )
+{
+  my ($self) = @_;
+  my @conds = keys %{$self->{'hash'}};
+  return ("TRUE") unless @conds;
+  return sort @conds;
+}
+
+# Undocumented, shouldn't be needed out of this class.
+sub has ($$)
+{
+  my ($self, $cond) = @_;
+  if (exists $self->{'hash'}{$cond})
+    {
+      return $self->{'hash'}{$cond};
+    }
+  return 0;
+}
+
+=item C<$cond-E<gt>false>
+
+Return 1 iff this condition is always false.
+
+=cut
+
+sub false ($ )
+{
+  my ($self) = @_;
+  return $self->has ('FALSE');
+}
+
+=item C<$cond-E<gt>true>
+
+Return 1 iff this condition is always true.
+
+=cut
+
+sub true ($ )
+{
+  my ($self) = @_;
+  return 0 == keys %{$self->{'hash'}};
+}
+
+=item C<$cond-E<gt>string>
+
+Build a string which denotes the conditional.
+
+For instance using the C<$cond> definition from L<SYNOPSYS>,
+C<$cond-E<gt>string> will return C<"COND1_TRUE COND2_FALSE">.
+
+=cut
+
+sub string ($ )
+{
+  my ($self) = @_;
+
+  return $self->{'string'} if defined $self->{'string'};
+
+  my $res = '';
+  if ($self->false)
+    {
+      $res = 'FALSE';
+    }
+  else
+    {
+      $res = join (' ', sort $self->conds);
+    }
+  $self->{'string'} = $res;
+  return $res;
+}
+
+=item C<$cond-E<gt>subst_string>
+
+Build a C<AC_SUBST>-style string for output in F<Makefile.in>.
+
+For instance using the C<$cond> definition from L<SYNOPSYS>,
+C<$cond-E<gt>subst_string> will return C<"@COND1_TRUE@@COND2_FALSE@">.
+
+=cut
+
+sub subst_string ($ )
+{
+  my ($self) = @_;
+
+  return $self->{'subst_string'} if defined $self->{'subst_string'};
+
+  my $res = '';
+  if ($self->false)
+    {
+      $res = '#';
+    }
+  elsif (! $self->true)
+    {
+      $res = '@' . join ('@@', sort $self->conds) . '@';
+    }
+  $self->{'subst_string'} = $res;
+  return $res;
+}
+
+=item C<$cond-E<gt>true_when ($when)>
+
+Return 1 iff C<$cond> is true when C<$when> is true.
+Return 0 otherwise.
+
+Using the definitions from L<SYNOPSYS>, C<$cond> is true
+when C<$both> is true, but the converse is wrong.
+
+=cut
+
+sub true_when ($$)
+{
+  my ($self, $when) = @_;
+
+  # Nothing is true when FALSE (not even FALSE itself, but it
+  # shouldn't hurt if you decide to change that).
+  return 0 if $self->false || $when->false;
+
+  # If we are true, we stay true when $when is true :)
+  return 1 if $self->true;
+
+  # $SELF is true under $WHEN if each conditional component of $SELF
+  # exists in $WHEN.
+  foreach my $cond ($self->conds)
+    {
+      return 0 unless $when->has ($cond);
+    }
+  return 1;
+}
+
+=item C<$cond-E<gt>redundant_wrt (@conds)>
+
+Return 1 iff C<$cond> is true for any condition in C<@conds>.
+If @conds is empty, return 1 iff C<$cond> is C<FALSE>.
+Return 0 otherwise.
+
+=cut
+
+sub redundant_wrt ($@)
+{
+  my ($self, @conds) = @_;
+
+  foreach my $cond (@conds)
+    {
+      return 1 if $self->true_when ($cond);
+    }
+  return $self->false;
+}
+
+=item C<$cond-E<gt>implies_any (@conds)>
+
+Return 1 iff C<$cond> implies any of the conditions in C<@conds>.
+Return 0 otherwise.
+
+=cut
+
+# $BOOLEAN
+# &conditional_implies_any ($COND, @CONDS)
+# ----------------------------------------
+# Returns true iff $COND implies any of the conditions in @CONDS.
+sub implies_any ($@)
+{
+  my ($self, @conds) = @_;
+
+  foreach my $cond (@conds)
+    {
+      return 1 if $cond->true_when ($self);
+    }
+  return 0;
+}
+
+=head1 HISTORY
+
+C<AM_CONDITIONAL>s and supporting code were added to Automake 1.1o by
+Ian Lance Taylor <address@hidden> in 1997.  Since then it has been
+improved by Tom Tromey <address@hidden>, Richard Boulton
+<address@hidden>, Raja R Harinath <address@hidden>, and
+Akim Demaile <address@hidden>.  Alexandre Duret-Lutz <address@hidden>
+extracted the code out of Automake to create this package in 2002.
+
+=cut
+
+1;
+
+### 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:
Index: lib/Automake/Makefile.am
===================================================================
RCS file: /cvs/automake/automake/lib/Automake/Makefile.am,v
retrieving revision 1.5
diff -u -b -r1.5 Makefile.am
--- lib/Automake/Makefile.am    28 Sep 2002 12:41:05 -0000      1.5
+++ lib/Automake/Makefile.am    7 Oct 2002 09:16:16 -0000
@@ -1,4 +1,10 @@
 ## Process this file with automake to create Makefile.in
 
 perllibdir = $(pkgvdatadir)/Automake
-dist_perllib_DATA = Channels.pm General.pm Location.pm Struct.pm XFile.pm
+dist_perllib_DATA = \
+  Channels.pm \
+  Conditional.pm \
+  General.pm \
+  Location.pm \
+  Struct.pm \
+  XFile.pm
Index: lib/Automake/Makefile.in
===================================================================
RCS file: /cvs/automake/automake/lib/Automake/Makefile.in,v
retrieving revision 1.52
diff -u -b -r1.52 Makefile.in
--- lib/Automake/Makefile.in    30 Sep 2002 13:05:03 -0000      1.52
+++ lib/Automake/Makefile.in    7 Oct 2002 09:16:16 -0000
@@ -93,7 +93,14 @@
 target_alias = @target_alias@
 
 perllibdir = $(pkgvdatadir)/Automake
-dist_perllib_DATA = Channels.pm General.pm Location.pm Struct.pm XFile.pm
+dist_perllib_DATA = \
+  Channels.pm \
+  Conditional.pm \
+  General.pm \
+  Location.pm \
+  Struct.pm \
+  XFile.pm
+
 subdir = lib/Automake
 mkinstalldirs = $(SHELL) $(top_srcdir)/lib/mkinstalldirs
 CONFIG_CLEAN_FILES =
Index: tests/cond12.test
===================================================================
RCS file: /cvs/automake/automake/tests/cond12.test,v
retrieving revision 1.3
diff -u -b -r1.3 cond12.test
--- tests/cond12.test   8 Sep 2002 13:07:55 -0000       1.3
+++ tests/cond12.test   7 Oct 2002 09:16:18 -0000
@@ -32,14 +32,18 @@
 my $failed = 0;
 sub check_reduce($$) {
  my ($inref, $outref) = @_;
- my @result = sort &Automake::variable_conditions_reduce(@$inref);
- my $correct = 1;
- $correct = 0 if (join(",", @result) ne join(",", @$outref));
+ my @inconds = map { new Automake::Conditional $_ } @$inref;
+ my @outconds = map { (new Automake::Conditional $_)->string } @$outref;
+ my @res =
+    map { $_->string } (&Automake::variable_conditions_reduce (@inconds));
+ my $result = join (",", sort @res);
+ my $exresult = join (",", @outconds);
 
- if (! $correct) {
+ if ($result ne $exresult)
+ {
    print '"'.join(",", @$inref) . '" => "' .
-        join(",", @result) . '" expected "' .
-        join(",", @$outref) . '"' . "\n";
+        $result . '" expected "' .
+        $exresult . '"' . "\n";
    $failed = 1;
  }
 }

-- 
Alexandre Duret-Lutz





reply via email to

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