automake-patches
[Top][All Lists]
Advanced

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

FYI: 6/ Automake::Variable & Automake::VarDef


From: Alexandre Duret-Lutz
Subject: FYI: 6/ Automake::Variable & Automake::VarDef
Date: Sun, 25 May 2003 22:04:16 +0200
User-agent: Gnus/5.090016 (Oort Gnus v0.16) Emacs/21.3 (gnu/linux)

I'm installing this.  This moves approximately 1000 lines out of
automake.in.  There still remains a few variable-related
functions that should be moved to Automake::Variable (all the
recursive traversal things, I think).  I'll do this next week.

It removes most of the Tie::RefHash::Nestable uses.  The
remaining uses are related to target support.  I'll have to do
something similar with targets (Automake::Rule?).  Methods like
`def', `rdef', `conditions', `check_ambiguous_condition',
`not_always_defined_in_cond', etc.  should be sharable amongst
the implementations of Variable and Rule.

There is at least one drawback in the current implementation: I
did not manage to get the warning about "I'm expecting variable
FOO but you have defined FOO as a target" working.  I've
commented the code and disabled the test case for now.  It's not
really important, and I may be able to get it working again once
the targets are in their own package.

2003-05-25  Alexandre Duret-Lutz  <address@hidden>

        * lib/Automake/Variable.pm, lib/Automake/VarDef.pm: New files.
        * lib/Automake/Makefile.am (dist_perllib_DATA): Add Variable.pm
        and VarDef.pm.
        * automake.in: Use Automake::Variable and Automake::VarDef.
        (MACRO_PATTERN): Delete. Now Automake::Variable::_MACRO_PATTERN.
        (am_macro_for_var): Delete. Now Automake::Variable::_am_macro_for_var.
        (ac_macro_for_var): Delete. Now Automake::Variable::_ac_macro_for_var.
        (silent_variable_override): Delete.  Now
        Automake::Variable::_silent_variable_override.
        (var_value, var_location, var_comment, var_type, var_owner,
        var_pretty, content_seen): Delete.  This functionality is now
        offered by Automake::Variable and Automake::VarDef.
        (VAR_AUTOMAKE, VAR_CONFIGURE, VAR_MAKEFILE, VAR_ASIS, VAR_PRETTY):
        Delete.  Now defined in Automake::VarDef.
        (var_order): Delete.  Now Automake::Variable::_var_order.
        (appendvar): Delete.  Now Automake::Variable::_appendvar.
        (var_SUFFIX_trigger): Register using Automake::Variable::hook.
        (initialize_per_input): Call Automake::Variable::reset.
        (err_var, msg_cond_var, msg_var, reject_var): Delete.  Now
        defined in Automake::Variable.
        (generate_makefile, process_option_list, handle_languages)
        (traverse_variable_recursively_worker)
        (transform_variable_recursively, handle_compile)
        (handle_libraries, handle_ltlibraries)
        (check_typos, handle_dist, handle_subdirs, scan_autoconf_files):
        Adjust to use Automake::Variable functions.
        (check_ambiguous_condition): Delete.  Now
        Automake::Variable::_check_ambiguous_condition.
        (condition_ambiguous_p): Delete.  Now
        Automake::Variable::condition_ambiguous_p.
        (variable_not_always_defined_in_cond): Delete.  Now
        Automake::Variable::not_always_defined_in_cond.
        (macro_define): Delete.  Now Automake::Variable::define.
        (macro_delete): Delete.  Now Automake::Variable::variable_delete.
        (macro_dump): Delete.  Now Automake::Variable::variable_dump.
        (macros_dump): Delete.  Now Automake::Variable::variables_dump.
        (variable_defined): Delete.  Now
        Automake::Variable::variable_defined, with the target check
        temporarily disabled.
        (variable_assert): Delete.  Now Automake::Variable::variable_assert.
        (examine_variable): Delete.  Now
        Automake::Variable::examine_variable.
        (variable_conditions): Delete.  Now Automake::Variable::conditions.
        (scan_variable_expansions): Delete.  Now
        Automake::Variable::scan_variable_expansions.
        (check_variable_expansions): Delete.  Now
        Automake::Variable::check_variable_expansions.
        (check_variable_defined_unconditionally): Delete.  Now
        Automake::Variable::check_defined_unconditionally.
        (variable_value): Delete.  Now Automake::Variable::variable_value.
        (variable_value_as_list): Delete.  Now
        Automake::Variable::variable_value_as_list.
        (variable_value_as_list_recursive_worker): Adjust to use
        Automake::Variable functions.
        (variable_output): Delete.  Now Automake::Variable::output.
        (define_pretty_variable, define_configure_variable, read_am_file)
        (define_standard_variables, read_main_am_file): Adjust to use
        Automake::Variable functions.
        (handle_variables): Delete.  Now Automake::Variable::output_variables.
        (file_contents_internal, am_primary_prefixes, am_install_var)
        (require_file_with_macro, require_conf_file_with_macro)
        (push_dist_common): : Adjust to use
        Automake::Variable functions.
        (require_variables): Delete.  Now
        Automake::Variable::require_variables.
        (require_variables_for_macro): Delete.  Now
        Automake::Variable::require_variables_for_variable.
        * tests/Makefile.am (XFAIL_TESTS): Add target.test.

Index: automake.in
===================================================================
RCS file: /cvs/automake/automake/automake.in,v
retrieving revision 1.1459
diff -u -r1.1459 automake.in
--- automake.in 23 May 2003 21:10:38 -0000      1.1459
+++ automake.in 25 May 2003 19:47:03 -0000
@@ -129,6 +129,8 @@
 use Automake::Condition qw/TRUE FALSE/;
 use Automake::DisjConditions;
 use Automake::Version;
+use Automake::Variable;
+use Automake::VarDef;
 use Automake::Wrap 'makefile_wrap';
 use File::Basename;
 use Tie::RefHash;
@@ -170,7 +172,6 @@
 # Only recognize leading spaces, not leading tabs.  If we recognize
 # leading tabs here then we need to make the reader smarter, because
 # otherwise it will think rules like `foo=bar; \' are errors.
-my $MACRO_PATTERN = 'address@hidden' . "\$";
 my $ASSIGNMENT_PATTERN = '^ *([^ \t=:+]*)\s*([:+]?)=\s*(.*)' . "\$";
 # This pattern recognizes a Gnits version id and sets $1 if the
 # release is an alpha release.  We also allow a suffix which can be
@@ -242,48 +243,6 @@
                        pkgincludedir pkglibdir sbin sharedstate
                        sysconf));
 
-# Declare the macros that define known variables, so we can
-# hint the user if she try to use one of these variables.
-
-# Macros accessible via aclocal.
-my %am_macro_for_var =
-  (
-   ANSI2KNR => 'AM_C_PROTOTYPES',
-   CCAS => 'AM_PROG_AS',
-   CCASFLAGS => 'AM_PROG_AS',
-   EMACS => 'AM_PATH_LISPDIR',
-   GCJ => 'AM_PROG_GCJ',
-   LEX => 'AM_PROG_LEX',
-   LIBTOOL => 'AC_PROG_LIBTOOL',
-   lispdir => 'AM_PATH_LISPDIR',
-   pkgpyexecdir => 'AM_PATH_PYTHON',
-   pkgpythondir => 'AM_PATH_PYTHON',
-   pyexecdir => 'AM_PATH_PYTHON',
-   PYTHON => 'AM_PATH_PYTHON',
-   pythondir => 'AM_PATH_PYTHON',
-   U => 'AM_C_PROTOTYPES',
-   );
-
-# Macros shipped with Autoconf.
-my %ac_macro_for_var =
-  (
-   CC => 'AC_PROG_CC',
-   CFLAGS => 'AC_PROG_CC',
-   CXX => 'AC_PROG_CXX',
-   CXXFLAGS => 'AC_PROG_CXX',
-   F77 => 'AC_PROG_F77',
-   F77FLAGS => 'AC_PROG_F77',
-   RANLIB => 'AC_PROG_RANLIB',
-   YACC => 'AC_PROG_YACC',
-   );
-
-# Variables that can be overriden without complaint from -Woverride
-my %silent_variable_override =
-  (AR => 1,
-   ARFLAGS => 1,
-   DEJATOOL => 1,
-   JAVAC => 1);
-
 # Copyright on generated Makefile.ins.
 my $gen_copyright = "\
 # Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
@@ -517,39 +476,6 @@
 # Suffixes found during a run.
 my @suffixes;
 
-# Handling the variables.
-#
-# For a $VAR:
-# - $var_value{$VAR}{$COND} is its value associated to $COND,
-# - $var_location{$VAR}{$COND} is where it was defined,
-# - $var_comment{$VAR}{$COND} are the comments associated to it.
-# - $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).
-# - $var_pretty{$VAR}{$COND} records how one variable should be output
-#     (VAR_PRETTY or VAR_ASIS).
-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';
-my %var_pretty;   tie %var_pretty, '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).
-use constant VAR_AUTOMAKE => 0; # Variable defined by Automake.
-use constant VAR_CONFIGURE => 1;# Variable defined in configure.ac.
-use constant VAR_MAKEFILE => 2; # Variable defined in Makefile.am.
-# Possible values for var_output.
-use constant VAR_ASIS => 0;
-use constant VAR_PRETTY => 1;
-# The order in which variables should be output.  (May contain
-# duplicates -- only the first occurence matters.)
-my @var_order;
-
-# This holds a 1 if a particular variable was examined.
-my %content_seen;
-
 # This holds the names which are targets.  These also appear in
 # %contents.  $targets{TARGET}{COND} is the location of the definition
 # of TARGET for condition COND.  TARGETs should not include
@@ -715,11 +641,6 @@
 # are the values of the variable for condition COND1 and COND2.
 my %gen_varname = ();
 
-# This hash records helper variables used to implement conditional '+='.
-# Keys have the form "VAR:CONDITIONS".  The value associated to a key is
-# the named of the helper variable used to append to VAR in CONDITIONS.
-my %appendvar = ();
-
 ################################################################
 
 # Pattern that matches all know input extensions (i.e. extensions used
@@ -753,6 +674,7 @@
     my ($type, $value) = @_;
     accept_extensions (split (' ', $value));
 }
+Automake::Variable::hook ('SUFFIXES', &var_SUFFIXES_trigger);
 
 ################################################################
 
@@ -784,14 +706,7 @@
 
     @suffixes = ();
 
-    %var_value = ();
-    %var_location = ();
-    %var_comment = ();
-    %var_type = ();
-    %var_owner = ();
-    %var_pretty = ();
-
-    %content_seen = ();
+    Automake::Variable::reset ();
 
     %targets = ();
     %target_source = ();
@@ -901,8 +816,6 @@
 
     $need_link = 0;
 
-    @var_order = ();
-
     $get_object_extension_was_run = 0;
 
     %compile_clean_files = ();
@@ -911,8 +824,6 @@
     %libtool_clean_directories = ('.' => 1);
 
     %gen_varname = ();
-
-    %appendvar = ();
 }
 
 
@@ -1132,14 +1043,6 @@
 
 # Error reporting functions.
 
-# err_var ($VARNAME, $MESSAGE, [%OPTIONS])
-# ----------------------------------------
-# Uncategorized errors about variables.
-sub err_var ($$;%)
-{
-  msg_var ('error', @_);
-}
-
 # err_target ($TARGETNAME, $MESSAGE, [%OPTIONS])
 # ----------------------------------------------
 # Uncategorized errors about targets.
@@ -1172,26 +1075,6 @@
   msg_ac ('error', @_);
 }
 
-# msg_cond_var ($CHANNEL, $COND, $VARNAME, $MESSAGE, [%OPTIONS])
-# --------------------------------------------------------------
-# Messages about conditional variable.
-sub msg_cond_var ($$$$;%)
-{
-  my ($channel, $cond, $var, $msg, %opts) = @_;
-  msg $channel, $var_location{$var}{$cond}, $msg, %opts;
-}
-
-# msg_var ($CHANNEL, $VARNAME, $MESSAGE, [%OPTIONS])
-# --------------------------------------------------
-# Messages about variables.
-sub msg_var ($$$;%)
-{
-  my ($channel, $var, $msg, %opts) = @_;
-  # Don't know which condition is concerned.  Pick any.
-  my $cond = variable_conditions ($var)->one_cond;
-  msg_cond_var $channel, $cond, $var, $msg, %opts;
-}
-
 # msg_cond_target ($CHANNEL, $COND, $TARGETNAME, $MESSAGE, [%OPTIONS])
 # --------------------------------------------------------------------
 # Messages about conditional targets.
@@ -1231,20 +1114,6 @@
 }
 
 # $BOOL
-# reject_var ($VAR, $ERROR_MSG)
-# -----------------------------
-sub reject_var ($$)
-{
-  my ($var, $msg) = @_;
-  if (variable_defined ($var))
-    {
-      err_var $var, $msg;
-      return 1;
-    }
-  return 0;
-}
-
-# $BOOL
 # reject_target ($VAR, $ERROR_MSG)
 # --------------------------------
 sub reject_target ($$)
@@ -1348,12 +1217,14 @@
     # There are a few install-related variables that you should not define.
     foreach my $var ('PRE_INSTALL', 'POST_INSTALL', 'NORMAL_INSTALL')
       {
-       if (exists $var_owner{$var})
+       my $v = var $var;
+       if ($v)
          {
-           prog_error "\$var_owner{$var}{TRUE} doesn't exist"
-             unless exists $var_owner{$var}{&TRUE};
+           my $def = $v->def (TRUE);
+           prog_error "$var not defined in condition TRUE"
+             unless $def;
            reject_var $var, "`$var' should not be defined"
-             if $var_owner{$var}{&TRUE} != VAR_AUTOMAKE;
+             if $def->owner != VAR_AUTOMAKE;
          }
       }
 
@@ -1385,8 +1256,7 @@
     push (@sources, '$(SOURCES)')
        if variable_defined ('SOURCES');
 
-    # Must do this after reading .am file.  See read_main_am_file to
-    # understand weird tricks we play there with variables.
+    # Must do this after reading .am file.
     &define_variable ('subdir', $relative_dir, INTERNAL);
 
     # Check first, because we might modify some state.
@@ -1414,8 +1284,8 @@
 
     # Re-init SOURCES.  FIXME: other code shouldn't depend on this
     # (but currently does).
-    macro_define ('SOURCES', VAR_AUTOMAKE, '', TRUE, "@sources", '',
-                 INTERNAL, VAR_PRETTY);
+    Automake::Variable::define ('SOURCES', VAR_AUTOMAKE, '', TRUE,
+                               "@sources", '', INTERNAL, VAR_PRETTY);
     define_pretty_variable ('DIST_SOURCES', TRUE, INTERNAL, @dist_sources);
 
     &handle_multilib;
@@ -1451,7 +1321,7 @@
 
     # Comes last, because all the above procedures may have
     # defined or overridden variables.
-    &handle_variables;
+    $output_vars .= output_variables;
 
     check_typos ();
 
@@ -1514,7 +1384,7 @@
   # FIXME: We should disallow conditional deffinitions of AUTOMAKE_OPTIONS.
   my $where = ($config ?
               $seen_init_automake :
-              $var_location{'AUTOMAKE_OPTIONS'}{&TRUE});
+              rvar ('AUTOMAKE_OPTIONS')->rdef (TRUE)->location);
 
   foreach (@list)
     {
@@ -1944,11 +1814,12 @@
 
        foreach my $flag (@dont_override)
          {
-           if (exists $var_owner{$flag})
+           my $var = var $flag;
+           if ($var)
              {
-               for my $cond (keys %{$var_owner{$flag}})
+               for my $cond ($var->conditions->conds)
                  {
-                   if ($var_owner{$flag}{$cond} == VAR_MAKEFILE)
+                   if ($var->rdef ($cond)->owner == VAR_MAKEFILE)
                      {
                        msg_cond_var ('gnu', $cond, $flag,
                                      "`$flag' is a user variable, "
@@ -2409,7 +2280,8 @@
 
   my @allresults = ();
   my $cond_once = 0;
-  foreach my $cond (variable_conditions ($var)->conds)
+  my $v = var $var;
+  foreach my $cond ($v->conditions->conds)
     {
       if (ref $cond_filter)
        {
@@ -2583,7 +2455,7 @@
           # If the new variable is the source variable, we assume
           # we are trying to override a user variable.  Delete
           # the old variable first.
-          macro_delete ($varname) if $varname eq $var;
+          variable_delete ($varname) if $varname eq $var;
           # Define for all conditions.
           foreach my $pair (@allresults)
             {
@@ -2950,9 +2822,9 @@
     # Check for automatic de-ANSI-fication.
     if (defined $options{'ansi2knr'})
       {
-       require_variables_for_macro ('AUTOMAKE_OPTIONS',
-                                    "option `ansi2knr' is used",
-                                    "ANSI2KNR", "U");
+       require_variables_for_variable ('AUTOMAKE_OPTIONS',
+                                       "option `ansi2knr' is used",
+                                       "ANSI2KNR", "U");
 
        # topdir is where ansi2knr should be.
        if ($options{'ansi2knr'} eq 'ansi2knr')
@@ -3120,8 +2992,8 @@
   my @prefix = am_primary_prefixes ('LIBRARIES', 0, 'lib', 'pkglib',
                                    'noinst', 'check');
 
-  require_variables_for_macro ($prefix[0] . '_LIBRARIES',
-                              'library used', 'RANLIB')
+  require_variables_for_variable ($prefix[0] . '_LIBRARIES',
+                                 'library used', 'RANLIB')
     if (@prefix);
 
   foreach my $pair (@liblist)
@@ -3206,8 +3078,8 @@
   my @prefix = am_primary_prefixes ('LTLIBRARIES', 0, 'lib', 'pkglib',
                                    'noinst', 'check');
 
-  require_variables_for_macro ($prefix[0] . '_LTLIBRARIES',
-                              'Libtool library used', 'LIBTOOL')
+  require_variables_for_variable ($prefix[0] . '_LTLIBRARIES',
+                                 'Libtool library used', 'LIBTOOL')
     if (@prefix);
 
   my %liblocations = ();       # Location (in Makefile.am) of each library.
@@ -3373,15 +3245,29 @@
   # It is ok if the user sets this particular variable.
   &examine_variable ('AM_LDFLAGS');
 
-  foreach my $varname (keys %var_value)
+  foreach my $varname (variables)
     {
+      # A configure variable is always legitimate.
+      next if exists $configure_vars{$varname};
+
+      my $check = 0;
       foreach my $primary ('_SOURCES', '_LIBADD', '_LDADD', '_LDFLAGS',
                           '_DEPENDENCIES')
        {
-         msg_var 'syntax', $varname, "unused variable: `$varname'"
-           # Note that a configure variable is always legitimate.
-           if ($varname =~ /$primary$/ && ! $content_seen{$varname}
-               && ! exists $configure_vars{$varname});
+         if ($varname =~ /$primary$/)
+           {
+             $check = 1;
+             last;
+           }
+       }
+      next unless $check;
+
+      my $var = rvar $varname;
+
+      for my $cond ($var->conditions->conds)
+       {
+         msg_var 'syntax', $var, "unused variable: `$varname'"
+           unless $var->rdef ($cond)->seen;
        }
     }
 }
@@ -3985,12 +3871,9 @@
        }
     }
 
-
-
     # 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 (' ', rvar ('DIST_COMMON')->variable_value);
     @dist_common = uniq (sort for_dist_common (@dist_common));
     define_pretty_variable ('DIST_COMMON', TRUE, INTERNAL, @dist_common);
 
@@ -4141,7 +4024,7 @@
     }
 
     $output_rules .= &file_contents ('subdirs', new Automake::Location);
-    $var_pretty{'RECURSIVE_TARGETS'}{&TRUE} = VAR_PRETTY; # Gross!
+    rvar ('RECURSIVE_TARGETS')->rdef (TRUE)->{'pretty'} = VAR_PRETTY; # Gross!
 }
 
 
@@ -5256,7 +5139,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') || '';
 }
 
 ################################################################
@@ -5870,584 +5753,6 @@
 ## ------------------------ ##
 
 
-# check_ambiguous_condition ($VAR, $COND, $WHERE)
-# -------------------------------------------------
-# Check for an ambiguous conditional.  This is called when a variable
-# is being defined conditionally.  If we already know about a
-# definition that is true under the same conditions, then we have an
-# ambiguity.
-sub check_ambiguous_condition ($$$)
-{
-  my ($var, $cond, $where) = @_;
-  my ($message, $ambig_cond) =
-    condition_ambiguous_p ($var, $cond, variable_conditions ($var));
-  if ($message)
-    {
-      msg 'syntax', $where, "$message ...", partial => 1;
-      msg_var ('syntax', $var, "... `$var' previously defined here");
-      verb (macro_dump ($var));
-    }
-}
-
-# $STRING, $AMBIG_COND
-# condition_ambiguous_p ($WHAT, $COND, $CONDSET)
-# ----------------------------------------------
-# Check for an ambiguous condition.  Return an error message and
-# the other condition involved if we have one, two empty strings otherwise.
-#   WHAT:    the thing being defined
-#   COND:    the Condition under which it is being defined
-#   CONDSET: the DisjConditions under which it had already been defined
-sub condition_ambiguous_p ($$$)
-{
-  my ($var, $cond, $condset) = @_;
-
-  foreach my $vcond ($condset->conds)
-    {
-      # Note that these rules doesn't consider the following
-      # example as ambiguous.
-      #
-      #   if COND1
-      #     FOO = foo
-      #   endif
-      #   if COND2
-      #     FOO = bar
-      #   endif
-      #
-      # It's up to the user to not define COND1 and COND2
-      # simultaneously.
-      my $message;
-      if ($vcond eq $cond)
-       {
-         return ("$var multiply defined in condition " . $cond->human,
-                 $vcond);
-       }
-      elsif ($vcond->true_when ($cond))
-       {
-         return ("$var was already defined in condition " . $vcond->human
-                 . ", which implies condition ". $cond->human, $vcond);
-       }
-      elsif ($cond->true_when ($vcond))
-       {
-         return ("$var was already defined in condition "
-                 . $vcond->human . ", which is implied by condition "
-                 . $cond->human, $vcond);
-       }
-    }
-  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 (we display result as conditional strings in this
-# illustration, but we really return DisjConditions objects):
-#   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 COND3_FALSE")
-#   variable_not_always_defined_in_cond ('B', 'COND1_TRUE')
-#     => ("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};
-
-  # Otherwise compute the subconditions where $var isn't defined.
-  return
-    variable_conditions ($var)
-      ->sub_conditions ($cond)
-       ->invert
-         ->simplify
-           ->multiply ($cond);
-}
-
-# &macro_define($VAR, $OWNER, $TYPE, $COND, $VALUE, $COMMENT, $WHERE, $PRETTY)
-# ----------------------------------------------------------------------------
-#  $VAR      the name of the variable
-#  $OWNER    owner of the variable (one of VAR_MAKEFILE,
-#              VAR_CONFIGURE, or VAR_AUTOMAKE)
-#  $TYPE     the type of the assignment (`' for `FOO = bar',
-#              `:' for `FOO := bar', and `+' for `FOO += bar')
-#  $COND     the DisjConditions in which $VAR is being defined
-#  $VALUE    the value assigned to $VAR in condition $COND
-#  $COMMENT  any comment (`# bla.') associated with the assignment.
-#  $WHERE    the Location of the assignment
-#  $PRETTY   whether $VALUE should be pretty printed (one of
-#              VAR_ASIS or VAR_PRETTY)
-#
-# Notes:
-#  - Variables can be overriden, provided the new owner is not weaker
-#    (VAR_AUTOMAKE < VAR_CONFIGURE < VAR_MAKEFILE)
-#  - $PRETTY applies only to real assignment.  I.e., it doesn't
-#    apply to a `+=' assignment (except when part of it is being
-#    done as a conditional `=' assignment).
-#  - Comments from `+=' assignments stack with comments from the last `='
-#    assignment.
-sub macro_define ($$$$$$$$)
-{
-  my ($var, $owner, $type, $cond, $value, $comment, $where, $pretty) = @_;
-
-  prog_error "$cond is not a reference"
-    unless ref $where;
-
-  prog_error "$where is not a reference"
-    unless ref $where;
-
-  prog_error "pretty argument missing"
-    unless defined $pretty && ($pretty == VAR_PRETTY || $pretty == VAR_ASIS);
-
-  # We will adjust the owner of this variable unless told otherwise.
-  my $adjust_owner = 1;
-
-  error $where, "bad characters in variable name `$var'"
-    if $var !~ /$MACRO_PATTERN/o;
-
-  # NEWS-OS 4.2R complains if a Makefile variable begins with `_'.
-  msg ('portability', $where,
-       "$var: variable names starting with `_' are not portable")
-    if $var =~ /^_/;
-
-  # `:='-style assignments are not acknowledged by POSIX.  Moreover it
-  # has multiple meanings.  In GNU make or BSD make it means "assign
-  # with immediate expansion", while in OSF make it is used for
-  # conditional assignments.
-  msg ('portability', $where, "`:='-style assignments are not portable")
-    if $type eq ':';
-
-  check_variable_expansions ($value, $where);
-
-  # 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 `+='.
-  if ($owner == VAR_AUTOMAKE)
-    {
-      if (exists $var_type{$var}
-         && exists $var_type{$var}{$cond}
-         && $var_type{$var}{$cond} ne $type)
-       {
-         error ($where, "$var was set with `$var_type{$var}=' "
-                . "and is now set with `$type='");
-       }
-    }
-  else
-    {
-      if (!exists $var_type{$var} && $type eq '+')
-       {
-         error $where, "$var must be set with `=' before using `+='";
-       }
-    }
-  $var_type{$var}{$cond} = $type;
-
-  # If there's a comment, make sure it is \n-terminated.
-  if ($comment)
-    {
-      chomp $comment;
-      $comment .= "\n";
-    }
-  else
-    {
-      $comment = '';
-    }
-
-  # Differentiate assignment types.
-
-  # 1. append (+=) to a variable defined for current condition
-  if ($type eq '+' && exists $var_value{$var}{$cond})
-    {
-      $var_comment{$var}{$cond} .= $comment;
-
-      if (chomp $var_value{$var}{$cond})
-       {
-         # Insert a backslash before a trailing newline.
-         $var_value{$var}{$cond} .= "\\\n";
-       }
-      elsif ($var_value{$var}{$cond})
-       {
-         # Insert a separator.
-         $var_value{$var}{$cond} .= ' ';
-       }
-       $var_value{$var}{$cond} .= $value;
-    }
-  # 2. append (+=) to a variable defined for *another* condition
-  elsif ($type eq '+' && ! variable_conditions ($var)->false)
-    {
-      # * Generally, $cond is not TRUE.  For instance:
-      #     FOO = foo
-      #     if COND
-      #       FOO += bar
-      #     endif
-      #   In this case, we declare an helper variable conditionally,
-      #   and append it to FOO:
-      #     FOO = foo $(am__append_1)
-      #     @address@hidden = bar
-      #   Of course if FOO is defined under several conditions, we add
-      #   $(am__append_1) to each definitions.
-      #
-      # * If $cond is TRUE, we don't need the helper variable.  E.g., in
-      #     if COND1
-      #       FOO = foo1
-      #     else
-      #       FOO = foo2
-      #     endif
-      #     FOO += bar
-      #   we can add bar directly to all definition of FOO, and output
-      #     @address@hidden = foo1 bar
-      #     @address@hidden = foo2 bar
-
-      # Do we need an helper variable?
-      if ($cond != TRUE)
-        {
-           # Does the helper variable already exists?
-           my $key = "$var:" . $cond->string;
-           if (exists $appendvar{$key})
-             {
-               # Yes, let's simply append to it.
-               $var = $appendvar{$key};
-               $owner = VAR_AUTOMAKE;
-             }
-           else
-             {
-               # No, create it.
-               my $num = 1 + keys (%appendvar);
-               my $hvar = "am__append_$num";
-               $appendvar{$key} = $hvar;
-               &macro_define ($hvar, VAR_AUTOMAKE, '+',
-                              $cond, $value, $comment, $where, $pretty);
-               # Now HVAR is to be added to VAR.
-               $comment = '';
-               $value = "\$($hvar)";
-             }
-       }
-
-      # Add VALUE to all definitions of VAR.
-      foreach my $vcond (variable_conditions ($var)->conds)
-        {
-         # 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->false)
-           {
-             error ($where,
-                    "Cannot apply `+=' because `$var' is not defined "
-                    . "in\nthe following conditions:\n  "
-                    . join ("\n  ", map { $_->human } $undef_cond->conds)
-                    . "\nEither define `$var' in these conditions,"
-                    . " or use\n`+=' in the same conditions as"
-                    . " the definitions.");
-           }
-         else
-           {
-             &macro_define ($var, $owner, '+', $vcond, $value, $comment,
-                            $where, $pretty);
-           }
-       }
-      # Don't adjust the owner.  The above &macro_define did it in the
-      # right conditions.
-      $adjust_owner = 0;
-    }
-  # 3. first assignment (=, :=, or +=)
-  else
-    {
-      # If Automake tries to override a value specified by the user,
-      # just don't let it do.
-      if (exists $var_value{$var}{$cond}
-         && $var_owner{$var}{$cond} != VAR_AUTOMAKE
-         && $owner == VAR_AUTOMAKE)
-       {
-         if (! exists $silent_variable_override{$var})
-           {
-             my $condmsg = ($cond == TRUE
-                            ? '' : (" in condition `" . $cond->human . "'"));
-             msg_cond_var ('override', $cond, $var,
-                           "user variable `$var' defined here$condmsg...",
-                           partial => 1);
-             msg ('override', $where,
-                  "... overrides Automake variable `$var' defined here");
-           }
-         verb ("refusing to override the user definition of:\n"
-               . macro_dump ($var)
-               ."with `" . $cond->human . "' => `$value'");
-       }
-      else
-       {
-         # There must be no previous value unless the user is redefining
-         # an Automake variable or an AC_SUBST variable for an existing
-         # condition.
-         check_ambiguous_condition ($var, $cond, $where)
-           unless (exists $var_owner{$var}{$cond}
-                   && (($var_owner{$var}{$cond} == VAR_AUTOMAKE
-                        && $owner != VAR_AUTOMAKE)
-                       || $var_owner{$var}{$cond} == VAR_CONFIGURE));
-
-         $var_value{$var}{$cond} = $value;
-         # Assignments to a macro set its location.  We don't adjust
-         # locations for `+='.  Ideally I suppose we would associate
-         # line numbers with random bits of text.
-         $var_location{$var}{$cond} = $where->clone;
-         $var_comment{$var}{$cond} = $comment;
-         $var_pretty{$var}{$cond} = $pretty;
-         push (@var_order, $var);
-       }
-    }
-
-  # The owner of a variable can only increase, because an Automake
-  # variable can be given to the user, but not the converse.
-  if ($adjust_owner &&
-      (! exists $var_owner{$var}{$cond}
-       || $owner > $var_owner{$var}{$cond}))
-    {
-      $var_owner{$var}{$cond} = $owner;
-      # Always adjust the location when the owner changes (even for
-      # `+=' statements).  The risk otherwise is to warn about
-      # a VAR_MAKEFILE variable and locate it in configure.ac...
-      $var_location{$var}{$cond} = $where->clone;
-    }
-
-  # Call var_VAR_trigger if it's defined.
-  # This hook helps to update some internal state *while*
-  # parsing the file.  For instance the handling of SUFFIXES
-  # requires this (see var_SUFFIXES_trigger).
-  my $var_trigger = \&{"var_${var}_trigger"};
-  &$var_trigger($type, $value) if defined &$var_trigger;
-}
-
-
-# &macro_delete ($VAR, address@hidden)
-# ------------------------------
-# Forget about $VAR under the conditions @CONDS, or completely if
-# @CONDS is empty.
-sub macro_delete ($@)
-{
-  my ($var, @conds) = @_;
-
-  if (address@hidden)
-    {
-      delete $var_value{$var};
-      delete $var_location{$var};
-      delete $var_owner{$var};
-      delete $var_comment{$var};
-      delete $var_type{$var};
-    }
-  else
-    {
-      foreach my $cond (@conds)
-       {
-         delete $var_value{$var}{$cond};
-         delete $var_location{$var}{$cond};
-         delete $var_owner{$var}{$cond};
-         delete $var_comment{$var}{$cond};
-         delete $var_type{$var}{$cond};
-       }
-    }
-}
-
-
-# &macro_dump ($VAR)
-# ------------------
-sub macro_dump ($)
-{
-  my ($var) = @_;
-  my $text = '';
-
-  if (!exists $var_value{$var})
-    {
-      $text = "  $var does not exist\n";
-    }
-  else
-    {
-      $text .= "  $var $var_type{$var}=\n  {\n";
-      foreach my $vcond (variable_conditions ($var)->conds)
-       {
-         prog_error ("`$var' is a key in \$var_value, "
-                     . "but not in \$var_owner\n")
-           unless exists $var_owner{$var}{$vcond};
-
-         my $var_owner;
-         if ($var_owner{$var}{$vcond} == VAR_AUTOMAKE)
-           {
-             $var_owner = 'Automake';
-           }
-         elsif ($var_owner{$var}{$vcond} == VAR_CONFIGURE)
-           {
-             $var_owner = 'Configure';
-           }
-         elsif ($var_owner{$var}{$vcond} == VAR_MAKEFILE)
-           {
-             $var_owner = 'Makefile';
-           }
-         else
-           {
-             prog_error ("unexpected value for `\$var_owner{$var}{$vcond}': "
-                         . $var_owner{$var}{$vcond})
-               unless defined $var_owner;
-           }
-
-         my $where = (defined $var_location{$var}{$vcond}
-                      ? $var_location{$var}{$vcond} : "undefined");
-         $text .= "$var_comment{$var}{$vcond}"
-           if exists $var_comment{$var}{$vcond};
-         $text .= "    $vcond => $var_value{$var}{$vcond}\n";
-       }
-      $text .= "  }\n";
-    }
-  return $text;
-}
-
-
-# &macros_dump ()
-# ---------------
-sub macros_dump ()
-{
-  my ($var) = @_;
-
-  my $text = "%var_value =\n{\n";
-  foreach my $var (sort (keys %var_value))
-    {
-      $text .= macro_dump ($var);
-    }
-  $text .= "}\n";
-  return $text;
-}
-
-
-# $BOOLEAN
-# variable_defined ($VAR, [$COND])
-# ---------------------------------
-# See if a variable exists.  $VAR is the variable name, and $COND is
-# the condition which we should check.  If no condition is given, we
-# currently return true if the variable is defined under any
-# condition.
-sub variable_defined ($;$)
-{
-    my ($var, $cond) = @_;
-
-    if (! exists $var_value{$var}
-       || (defined $cond && ! exists $var_value{$var}{$cond}))
-      {
-       # VAR is not defined.
-
-       # Check there is no target defined with the name of the
-       # variable we check.
-
-       # adl> I'm wondering if this error still makes any sense today. I
-       # adl> guess it was because targets and variables used to share
-       # adl> the same namespace in older versions of Automake?
-       # tom> While what you say is definitely part of it, I think it
-       # tom> might also have been due to someone making a "spelling error"
-       # tom> -- writing "foo:..." instead of "foo = ...".
-       # tom> I'm not sure whether it is really worth diagnosing
-       # tom> this sort of problem.  In the old days I used to add warnings
-       # tom> and errors like this pretty randomly, based on bug reports I
-       # tom> got.  But there's a plausible argument that I was trying
-       # tom> too hard to prevent people from making mistakes.
-       if (exists $targets{$var}
-           && (! defined $cond || exists $targets{$var}{$cond}))
-         {
-           for my $tcond ($cond || target_conditions ($var)->conds)
-             {
-               prog_error ("\$targets{$var}{$tcond} exists but "
-                           . "\$target_owner doesn't")
-                 unless exists $target_owner{$var}{$tcond};
-               # Diagnose the first user target encountered, if any.
-               # Restricting this test to user targets allows Automake
-               # to create rules for things like `bin_PROGRAMS = LDADD'.
-               if ($target_owner{$var}{$tcond} == TARGET_USER)
-                 {
-                   msg_cond_target ('syntax', $tcond, $var,
-                                    "`$var' is a target; "
-                                    . "expected a variable");
-                   return 0;
-                 }
-             }
-         }
-       return 0;
-      }
-
-    # Even a var_value examination is good enough for us.  FIXME:
-    # really should maintain examined status on a per-condition basis.
-    $content_seen{$var} = 1;
-    return 1;
-}
-
-
-# $BOOLEAN
-# variable_assert ($VAR, $WHERE)
-# ------------------------------
-# Make sure a variable exists.  $VAR is the variable name, and $WHERE
-# is the name of a macro which refers to $VAR.
-sub variable_assert ($$)
-{
-  my ($var, $where) = @_;
-
-  return 1
-    if variable_defined $var;
-
-  require_variables ($where, "variable `$var' is used", TRUE, $var);
-
-  return 0;
-}
-
-# Mark a variable as examined.
-sub examine_variable
-{
-  my ($var) = @_;
-  variable_defined ($var);
-}
-
-
-# @CONDS
-# variable_conditions ($VAR)
-# --------------------------
-# Get the list of conditions that a variable is defined with, without
-# recursing through the conditions of any subvariables.
-# Argument is $VAR: the variable to get the conditions of.
-# Returns the list of conditions.
-sub variable_conditions ($)
-{
-    my ($var) = @_;
-    my @conds = keys %{$var_value{$var}};
-    return new Automake::DisjConditions @conds;
-}
-
-
 # @CONDS
 # target_conditions ($TARGET)
 # ---------------------------
@@ -6491,149 +5796,6 @@
     return 0;
 }
 
-# @LIST
-# &scan_variable_expansions ($TEXT)
-# ---------------------------------
-# Return the list of variable names expanded in $TEXT.
-# Note that unlike some other functions, $TEXT is not split
-# on spaces before we check for subvariables.
-sub scan_variable_expansions ($)
-{
-  my ($text) = @_;
-  my @result = ();
-
-  # Strip comments.
-  $text =~ s/#.*$//;
-
-  # Record each use of ${stuff} or $(stuff) that do not follow a $.
-  while ($text =~ /(?<!\$)\$(?:\{([^\}]*)\}|\(([^\)]*)\))/g)
-    {
-      my $var = $1 || $2;
-      # The occurent may look like $(string1[:subst1=[subst2]]) but
-      # we want only `string1'.
-      $var =~ s/:[^:=]*=[^=]*$//;
-      push @result, $var;
-    }
-
-  return @result;
-}
-
-# &check_variable_expansions ($TEXT, $WHERE)
-# ------------------------------------------
-# Check variable expansions in $TEXT and warn about any name that
-# does not conform to POSIX.  $WHERE is the location of $TEXT for
-# the error message.
-sub check_variable_expansions ($$)
-{
-  my ($text, $where) = @_;
-  # Catch expansion of variables whose name does not conform to POSIX.
-  foreach my $var (scan_variable_expansions ($text))
-    {
-      if ($var !~ /$MACRO_PATTERN/)
-       {
-         # If the variable name contains a space, it's likely
-         # to be a GNU make extension (such as $(addsuffix ...)).
-         # Mention this in the diagnostic.
-         my $gnuext = "";
-         $gnuext = "\n(probably a GNU make extension)" if $var =~ / /;
-         msg ('portability', $where,
-              "$var: non-POSIX variable name$gnuext");
-       }
-    }
-}
-
-
-# $BOOL
-# &check_variable_defined_unconditionally($VAR, $PARENT)
-# ------------------------------------------------------
-# Warn if a variable is conditionally defined.  This is called if we
-# are using the value of a variable.
-sub check_variable_defined_unconditionally ($$)
-{
-  my ($var, $parent) = @_;
-  foreach my $cond (variable_conditions ($var)->conds)
-    {
-      next
-       if $cond->true || $cond->false;
-
-      if ($parent)
-       {
-         msg_var ('unsupported', $parent,
-                  "automake does not support conditional definition of "
-                  . "$var in $parent");
-       }
-      else
-       {
-         msg_var ('unsupported', $var,
-                  "automake does not support $var being defined "
-                  . "conditionally");
-       }
-    }
-}
-
-
-# Get the TRUE value of a variable, warn if the variable is
-# conditionally defined.
-sub variable_value
-{
-    my ($var) = @_;
-    &check_variable_defined_unconditionally ($var);
-    return $var_value{$var}{&TRUE};
-}
-
-
-# @VALUES
-# variable_value_as_list ($VAR, $COND, $PARENT)
-# ---------------------------------------------
-# Get the value of a variable given a specified condition. without
-# recursing through any subvariables.
-# Arguments are:
-#   $VAR    is the variable
-#   $COND   is the condition.  If this is not given, the value for the
-#           "TRUE" condition will be returned.
-#   $PARENT is the variable in which the variable is used: this is used
-#           only for error messages.
-# For example, if A is defined as "foo $(B) bar", and B is defined as
-# "baz", this will return ("foo", "$(B)", "bar")
-sub variable_value_as_list
-{
-    my ($var, $cond, $parent) = @_;
-    my @result;
-
-    # Check defined
-    return
-      unless variable_assert $var, $parent;
-
-    # Get value for given condition
-    my $onceflag;
-    foreach my $vcond (variable_conditions ($var)->conds)
-    {
-       my $val = $var_value{$var}{$vcond};
-
-       if ($vcond->true_when ($cond))
-       {
-           # Unless variable is not defined conditionally, there should only
-           # be one value of $vcond true when $cond.
-           &check_variable_defined_unconditionally ($var, $parent)
-                   if $onceflag;
-           $onceflag = 1;
-
-           # Strip backslashes
-           $val =~ s/\\(\n|$)/ /g;
-
-           foreach (split (' ', $val))
-           {
-               # If a comment seen, just leave.
-               last if /^#/;
-
-               push (@result, $_);
-           }
-       }
-    }
-
-    return @result;
-}
-
 
 # @VALUE
 # &variable_value_as_list_recursive_worker ($VAR, $COND, $LOC_WANTED)
@@ -6654,7 +5816,7 @@
        # Construct [$location, $value] pairs if requested.
        sub {
         my ($var, $val, $cond, $full_cond) = @_;
-        return [$var_location{$var}{$cond}, $val] if $loc_wanted;
+        return [rvar ($var)->rdef ($cond)->location, $val] if $loc_wanted;
         return $val;
        },
        # Collect results.
@@ -6684,49 +5846,6 @@
 }
 
 
-# &variable_output ($VAR, address@hidden)
-# ---------------------------------
-# Output all the values of $VAR if @COND is not specified, else only
-# that corresponding to @COND.
-sub variable_output ($@)
-{
-  my ($var, @conds) = @_;
-
-  @conds = variable_conditions ($var)->conds
-    unless @conds;
-
-  foreach my $cond (@conds)
-    {
-      prog_error ("unknown condition `$cond' for `$var'")
-       unless exists $var_value{$var}{$cond};
-
-      if (exists $var_comment{$var} && exists $var_comment{$var}{$cond})
-       {
-         $output_vars .= $var_comment{$var}{$cond};
-       }
-
-      my $val = $var_value{$var}{$cond};
-      my $equals = $var_type{$var}{$cond} eq ':' ? ':=' : '=';
-      my $output_var = "$var $equals $val";
-      my $str = $cond->subst_string;
-
-      if ($var_pretty{$var}{$cond} == VAR_PRETTY)
-       {
-         # Suppress escaped new lines.  &makefile_wrap will
-         # add them back, maybe at other places.
-         $val =~ s/\\$//mg;
-         $output_vars .= makefile_wrap ("$str$var $equals",
-                                        "$str\t", split (' ' , $val));
-       }
-      else                     # VAR_ASIS
-       {
-         $output_var =~ s/^/$str/meg;
-         $output_vars .= $output_var . "\n";
-       }
-    }
-}
-
-
 # &define_pretty_variable ($VAR, $COND, $WHERE, @VALUE)
 # -----------------------------------------------------
 # Like define_variable, but the value is a list, and the variable may
@@ -6741,9 +5860,9 @@
 
     if (! variable_defined ($var, $cond))
     {
-        macro_define ($var, VAR_AUTOMAKE, '', $cond, "@value", '', $where,
-                     VAR_PRETTY);
-       $content_seen{$var} = 1;
+        Automake::Variable::define ($var, VAR_AUTOMAKE, '', $cond, "@value",
+                                   '', $where, VAR_PRETTY);
+       rvar ($var)->rdef ($cond)->set_seen;
     }
 }
 
@@ -6763,16 +5882,24 @@
 sub define_configure_variable ($)
 {
   my ($var) = @_;
-  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:
-      # it might be subst'd by `\', which certainly would not be
-      # appreciated by Make.
-      && ! grep { $_ eq $var } (qw(ANSI2KNR AMDEPBACKSLASH)))
+  if (! variable_defined ($var, TRUE))
     {
-      macro_define ($var, VAR_CONFIGURE, '', TRUE,
-                   subst $var, '', $configure_vars{$var}, VAR_ASIS);
+      my $pretty = VAR_ASIS;
+      my $owner = VAR_CONFIGURE;
+
+      # Do not output the ANSI2KNR configure variable -- we AC_SUBST
+      # it in protos.m4, but later redefine it elsewhere.  This is
+      # pretty hacky.  We also don't output AMDEPBACKSLASH: it might
+      # be subst'd by `\', which certainly would not be appreciated by
+      # Make.
+      if ($var eq 'ANSI2KNR' || $var eq 'AMDEPBACKSLASH')
+       {
+         $pretty = VAR_SILENT;
+         $owner = VAR_AUTOMAKE;
+       }
+
+      Automake::Variable::define ($var, $owner, '', TRUE, subst $var,
+                                 '', $configure_vars{$var}, $pretty);
     }
 }
 
@@ -7178,7 +6305,7 @@
 # &read_am_file ($AMFILE, $WHERE)
 # -------------------------------
 # Read Makefile.am and set up %contents.  Simultaneously copy lines
-# from Makefile.am into $output_trailer or $output_vars as
+# from Makefile.am into $output_trailer, or define variables as
 # appropriate.  NOTE we put rules in the trailer section.  We want
 # user rules to come after our generated stuff.
 sub read_am_file ($$)
@@ -7310,10 +6437,10 @@
 
              if (!/\\$/)
                {
-                 macro_define ($last_var_name, VAR_MAKEFILE,
-                               $last_var_type, $cond,
-                               $last_var_value, $comment,
-                               $last_where, VAR_ASIS)
+                 Automake::Variable::define ($last_var_name, VAR_MAKEFILE,
+                                             $last_var_type, $cond,
+                                             $last_var_value, $comment,
+                                             $last_where, VAR_ASIS)
                    if $cond != FALSE;
                  $comment = $spacing = '';
                }
@@ -7369,9 +6496,10 @@
 
            if (!/\\$/)
              {
-               macro_define ($last_var_name, VAR_MAKEFILE,
-                             $last_var_type, $cond,
-                             $last_var_value, $comment, $last_where, VAR_ASIS)
+               Automake::Variable::define ($last_var_name, VAR_MAKEFILE,
+                                           $last_var_type, $cond,
+                                           $last_var_value, $comment,
+                                           $last_where, VAR_ASIS)
                  if $cond != FALSE;
                $comment = $spacing = '';
              }
@@ -7444,20 +6572,17 @@
 # and variables from header-vars.am.
 sub define_standard_variables
 {
-    my $saved_output_vars = $output_vars;
-    my ($comments, undef, $rules) =
-      file_contents_internal (1, "$libdir/am/header-vars.am",
-                             new Automake::Location);
+  my $saved_output_vars = $output_vars;
+  my ($comments, undef, $rules) =
+    file_contents_internal (1, "$libdir/am/header-vars.am",
+                           new Automake::Location);
 
-    # This will output the definitions in $output_vars, which we don't
-    # want...
-    foreach my $var (sort keys %configure_vars)
+  foreach my $var (sort keys %configure_vars)
     {
-        &define_configure_variable ($var);
+      &define_configure_variable ($var);
     }
 
-    # ... hence, we restore $output_vars.
-    $output_vars = $saved_output_vars . $comments . $rules;
+  $output_vars .= $comments . $rules;
 }
 
 # Read main am file.
@@ -7467,7 +6592,7 @@
 
     # This supports the strange variable tricks we are about to play.
     prog_error (macros_dump () . "variable defined before read_main_am_file")
-      if (scalar keys %var_value > 0);
+      if (scalar (variables) > 0);
 
     # Generate copyright header for generated Makefile.in.
     # We do discard the output of predefined variables, handled below.
@@ -7477,9 +6602,7 @@
     $output_vars .= $gen_copyright;
 
     # We want to predefine as many variables as possible.  This lets
-    # the user set them with `+=' in Makefile.am.  However, we don't
-    # want these initial definitions to end up in the output quite
-    # yet.  So we just load them, but output them later.
+    # the user set them with `+=' in Makefile.am.
     &define_standard_variables;
 
     # Read user file, which might override some of our values.
@@ -7487,38 +6610,6 @@
 }
 
 
-# handle_variables ()
-# -------------------
-# Ouput definitions for all variables.
-sub handle_variables ()
-{
-  my @vars = uniq @var_order;
-
-  # Output all the Automake variables.  If the user changed one,
-  # then it is now marked as VAR_CONFIGURE or VAR_MAKEFILE.
-  foreach my $var (@vars)
-    {
-      # Some variables, like AMDEPBACKSLASH are in @var_order
-      # but don't have an owner.  This is good, because we don't want
-      # to output them.
-      foreach my $cond (keys %{$var_owner{$var}})
-       {
-         variable_output ($var, $cond)
-           if $var_owner{$var}{$cond} == VAR_AUTOMAKE;
-       }
-    }
-
-  # Now dump the user variables that were defined.  We do it in the same
-  # order in which they were defined (skipping duplicates).
-  foreach my $var (@vars)
-    {
-      foreach my $cond (keys %{$var_owner{$var}})
-       {
-         variable_output ($var, $cond)
-           if $var_owner{$var}{$cond} != VAR_AUTOMAKE;
-       }
-    }
-}
 
 ################################################################
 
@@ -7791,18 +6882,12 @@
 
            $is_rule = 0;
 
-           macro_define ($var, $is_am ? VAR_AUTOMAKE : VAR_MAKEFILE,
-                         $type, $cond, $val, $comment, $where, VAR_ASIS)
+           Automake::Variable::define ($var,
+                                       $is_am ? VAR_AUTOMAKE : VAR_MAKEFILE,
+                                       $type, $cond, $val, $comment, $where,
+                                       VAR_ASIS)
              if $cond != FALSE;
 
-           # 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 != FALSE && $type ne '+'
-                 && exists $var_owner{$var}{$cond}
-                 && $var_owner{$var}{$cond} == VAR_AUTOMAKE);
-
            $comment = $spacing = '';
        }
        else
@@ -7920,8 +7005,9 @@
   local $_;
   my %valid = map { $_ => 0 } @prefixes;
   $valid{'EXTRA'} = 0;
-  foreach my $varname (keys %var_value)
+  foreach my $varname (variables)
     {
+      my $var = var $varname;
       # Automake is allowed to define variables that look like primaries
       # but which aren't.  E.g. INSTALL_sh_DATA.
       # Autoconf can also define variables like INSTALL_DATA, so
@@ -7929,33 +7015,35 @@
       # redefined in Makefile.am).
       # FIXME: We should make sure that these variables are not
       # 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);
+      if ($var)
+       {
+         my $def = $var->def (TRUE);
+         next if $def && $def->owner != VAR_MAKEFILE;
+       }
 
       if ($varname =~ /^(nobase_)?(dist_|nodist_)?(.*)_$primary$/)
        {
          my ($base, $dist, $X) = ($1 || '', $2 || '', $3 || '');
          if ($dist ne '' && ! $can_dist)
             {
-             err_var ($varname,
+             err_var ($var,
                       "invalid variable `$varname': `dist' is forbidden");
            }
          # Standard directories must be explicitely allowed.
          elsif (! defined $valid{$X} && exists $standard_prefix{$X})
            {
-             err_var ($varname,
+             err_var ($var,
                       "`${X}dir' is not a legitimate directory " .
                       "for `$primary'");
            }
          # A not explicitely valid directory is allowed if Xdir is defined.
          elsif (! defined $valid{$X} &&
-                require_variables_for_macro ($varname, "`$varname' is used",
-                                             "${X}dir"))
+                require_variables_for_variable ($varname,
+                                                "`$varname' is used",
+                                                "${X}dir"))
            {
              # Nothing to do.  Any error message has been output
-             # by require_variables_for_macro.
+             # by require_variables_for_variable.
            }
          else
            {
@@ -8041,6 +7129,7 @@
     {
       my $nodir_name = $X;
       my $one_name = $X . '_' . $primary;
+      my $one_var = var $one_name;
 
       my $strip_subdir = 1;
       # If subdir prefix should be preserved, do so.
@@ -8063,8 +7152,8 @@
       # Use the location of the currently processed variable.
       # We are not processing a particular condition, so pick the first
       # available.
-      my $tmpcond = variable_conditions ($one_name)->one_cond;
-      my $where = $var_location{$one_name}{$tmpcond}->clone;
+      my $tmpcond = $one_var->conditions->one_cond;
+      my $where = $one_var->def ($tmpcond)->location->clone;
 
       # Append actual contents of where_PRIMARY variable to
       # @result, skipping @address@hidden
@@ -8399,7 +7488,7 @@
 sub require_file_with_macro ($$$@)
 {
     my ($cond, $macro, $mystrict, @files) = @_;
-    require_file ($var_location{$macro}{$cond}, $mystrict, @files);
+    require_file (rvar ($macro)->rdef ($cond)->location, $mystrict, @files);
 }
 
 
@@ -8423,7 +7512,8 @@
 sub require_conf_file_with_macro ($$$@)
 {
     my ($cond, $macro, $mystrict, @files) = @_;
-    require_conf_file ($var_location{$macro}{$cond}, $mystrict, @files);
+    require_conf_file (rvar ($macro)->rdef ($cond)->location,
+                      $mystrict, @files);
 }
 
 ################################################################
@@ -8486,8 +7576,8 @@
 {
   prog_error "push_dist_common run after handle_dist"
     if $handle_dist_run;
-  macro_define ('DIST_COMMON', VAR_AUTOMAKE, '+', TRUE, "@_", '',
-               INTERNAL, VAR_PRETTY);
+  Automake::Variable::define ('DIST_COMMON', VAR_AUTOMAKE, '+', TRUE, "@_",
+                             '', INTERNAL, VAR_PRETTY);
 }
 
 
@@ -8518,74 +7608,6 @@
 
 
 ################################################################
-
-# INTEGER
-# require_variables ($WHERE, $REASON, $COND, @VARIABLES)
-# ------------------------------------------------------
-# Make sure that each supplied variable is defined in $COND.
-# Otherwise, issue a warning.  If we know which macro can
-# define this variable, hint the user.
-# Return the number of undefined variables.
-sub require_variables ($$$@)
-{
-  my ($where, $reason, $cond, @vars) = @_;
-  my $res = 0;
-  $reason .= ' but ' unless $reason eq '';
-
- VARIABLE:
-  foreach my $var (@vars)
-    {
-      # Nothing to do if the variable exists.  The $configure_vars test
-      # needed for strange variables like AMDEPBACKSLASH or ANSI2KNR
-      # that are AC_SUBST'ed but never macro_define'd.
-      next VARIABLE
-       if ((exists $var_value{$var} && exists $var_value{$var}{$cond})
-           || exists $configure_vars{$var});
-
-      my $undef_cond = variable_not_always_defined_in_cond $var, $cond;
-      next VARIABLE
-       if $undef_cond->false;
-
-      my $text = "$reason`$var' is undefined\n";
-      if (! $undef_cond->true)
-       {
-         $text .= ("in the following conditions:\n  "
-                   . join ("\n  ", map { $_->human } $undef_cond->conds));
-       }
-
-      ++$res;
-
-      if (exists $am_macro_for_var{$var})
-       {
-         $text .= "\nThe usual way to define `$var' is to add "
-           . "`$am_macro_for_var{$var}'\nto `$configure_ac' and run "
-           . "`aclocal' and `autoconf' again.";
-       }
-      elsif (exists $ac_macro_for_var{$var})
-       {
-         $text .= "\nThe usual way to define `$var' is to add "
-           . "`$ac_macro_for_var{$var}'\nto `$configure_ac' and run "
-           . "`autoconf' again.";
-       }
-
-      error $where, $text, uniq_scope => US_GLOBAL;
-    }
-  return $res;
-}
-
-# INTEGER
-# require_variables_for_macro ($MACRO, $REASON, @VARIABLES)
-# ---------------------------------------------------------
-# Same as require_variables, but take a macro name as first argument.
-sub require_variables_for_macro ($$@)
-{
-  my ($macro, $reason, @args) = @_;
-  for my $cond (variable_conditions ($macro)->conds)
-    {
-      return require_variables ($var_location{$macro}{$cond}, $reason,
-                               $cond, @args);
-    }
-}
 
 # Print usage information.
 sub usage ()
Index: lib/Automake/Makefile.am
===================================================================
RCS file: /cvs/automake/automake/lib/Automake/Makefile.am,v
retrieving revision 1.12
diff -u -r1.12 Makefile.am
--- lib/Automake/Makefile.am    21 May 2003 20:30:07 -0000      1.12
+++ lib/Automake/Makefile.am    25 May 2003 19:47:03 -0000
@@ -28,6 +28,8 @@
   General.pm \
   Location.pm \
   Struct.pm \
+  Variable.pm \
+  VarDef.pm \
   Version.pm \
   XFile.pm \
   Wrap.pm
Index: lib/Automake/Makefile.in
===================================================================
RCS file: /cvs/automake/automake/lib/Automake/Makefile.in,v
retrieving revision 1.69
diff -u -r1.69 Makefile.in
--- lib/Automake/Makefile.in    21 May 2003 20:30:07 -0000      1.69
+++ lib/Automake/Makefile.in    25 May 2003 19:47:04 -0000
@@ -136,6 +136,8 @@
   General.pm \
   Location.pm \
   Struct.pm \
+  Variable.pm \
+  VarDef.pm \
   Version.pm \
   XFile.pm \
   Wrap.pm
@@ -172,7 +174,6 @@
 $(ACLOCAL_M4):  $(top_srcdir)/configure.in  $(am__configure_deps)
        cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 uninstall-info-am:
-dist_perllibDATA_INSTALL = $(INSTALL_DATA)
 install-dist_perllibDATA: $(dist_perllib_DATA)
        @$(NORMAL_INSTALL)
        $(mkinstalldirs) $(DESTDIR)$(perllibdir)
@@ -250,12 +251,6 @@
          test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) 
ctags); \
        done
 
-ETAGS = etags
-ETAGSFLAGS =
-
-CTAGS = ctags
-CTAGSFLAGS =
-
 tags: TAGS
 
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
@@ -314,7 +309,6 @@
 
 distclean-tags:
        -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 
 distdir: $(DISTFILES)
        @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
Index: lib/Automake/VarDef.pm
===================================================================
RCS file: lib/Automake/VarDef.pm
diff -N lib/Automake/VarDef.pm
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/Automake/VarDef.pm      25 May 2003 19:47:04 -0000
@@ -0,0 +1,351 @@
+# Copyright (C) 2003  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::VarDef;
+use strict;
+use Carp;
+use Automake::ChannelDefs;
+
+require Exporter;
+use vars '@ISA', '@EXPORT';
address@hidden = qw/Exporter/;
address@hidden = qw (&VAR_AUTOMAKE &VAR_CONFIGURE &VAR_MAKEFILE
+             &VAR_ASIS &VAR_PRETTY &VAR_SILENT);
+
+=head1 NAME
+
+Automake::VarDef - a class for variable definitions
+
+=head1 SYNOPSIS
+
+  use Automake::VarDef;
+  use Automake::Location;
+
+  # Create a VarDef for a definition such as
+  # | # any comment
+  # | foo = bar
+  # in Makefile.am
+  my $loc = new Automake::Location 'Makefile.am:2';
+  my $def = new Automake::VarDef ('foo', 'bar', '# any comment',
+                                  $loc, '', VAR_MAKEFILE, VAR_ASIS);
+
+  # Appending to a definition.
+  $def->append ('value to append', 'comment to append');
+
+  # Accessors.
+  my $value    = $def->value;
+  my $comment  = $def->comment;
+  my $location = $def->location;
+  my $type     = $def->type;
+  my $owner    = $def->owner;
+  my $pretty   = $def->pretty;
+
+  # Changing owner.
+  $def->set_owner (VAR_CONFIGURE,
+                   new Automake::Location 'configure.ac:15');
+
+  # Marking examined definitions.
+  $def->set_seen;
+  my $seen_p = $def->seen;
+
+  # Printing a variable for debugging.
+  print STDERR $def->dump;
+
+=head1 DESCRIPTION
+
+This class gather data related to one Makefile-variable definition.
+
+=head2 Constants
+
+=over 4
+
+=item C<VAR_AUTOMAKE>, C<VAR_CONFIGURE>, C<VAR_MAKEFILE>
+
+Possible owners for variables.  A variable can be defined
+by Automake, in F<configure.ac> (using C<AC_SUBST>), or in
+the user's F<Makefile.am>.
+
+=cut
+
+# Defined so that the owner of a variable can only be increased (e.g
+# Automake should not override a configure or Makefile variable).
+use constant VAR_AUTOMAKE => 0; # Variable defined by Automake.
+use constant VAR_CONFIGURE => 1;# Variable defined in configure.ac.
+use constant VAR_MAKEFILE => 2; # Variable defined in Makefile.am.
+
+=item C<VAR_ASIS>, C<VAR_PRETTY>, C<VAR_SILENT>
+
+Possible print styles.  C<VAR_ASIS> variable should be output as-is.
+C<VAR_PRETTY> variable are wrapped on multiple lines if they cannot
+fit on one.  Finally, C<VAR_SILENT> variable are not output at all.
+
+C<VAR_SILENT> variables can also be overridden silently (unlike the
+other kinds of variables whose overridding may sometimes produce
+warnings).
+
+=cut
+
+# Possible values for pretty.
+use constant VAR_ASIS => 0;    # Output as-is.
+use constant VAR_PRETTY => 1;  # Pretty printed on output.
+use constant VAR_SILENT => 2;  # Not output.  (Can also be
+                               # overridden silently.)
+
+=back
+
+=head2 Methods
+
+=over 4
+
+=item C<my $def = Automake::new ($varname, $value, $comment, $location, $type, 
$owner, $pretty)>
+
+Create a new Makefile-variable definition.  C<$varname> is the name of
+the variable being defined and C<$value> its value.
+
+C<$comment> is any comment preceding the definition.  (Because
+Automake reorders variable definitions in the output, it also tries to
+carry comments around.)
+
+C<$location> is the place where the definition occured, it should be
+an instance of L<Automake::Location>.
+
+C<$type> should be C<''> for definitions made with C<=>, and C<':'>
+for those made with C<:=>.
+
+C<$owner> specifies who owns the variables, it can be one of
+C<VAR_AUTOMAKE>, C<VAR_CONFIGURE>, or C<VAR_MAKEFILE> (see these
+definitions).
+
+Finally, C<$pretty> tells how the variable should be output, and can
+be one of C<VAR_ASIS>, C<VAR_PRETTY>, or C<VAR_SILENT> (see these
+definitions).
+
+=cut
+
+sub new ($$$$$$$$)
+{
+  my ($class, $var, $value, $comment, $location, $type, $owner, $pretty) = @_;
+
+  # A user variable must be set by either `=' or `:=', and later
+  # promoted to `+='.
+  if ($owner != VAR_AUTOMAKE && $type eq '+')
+    {
+      error $location, "$var must be set with `=' before using `+='";
+    }
+
+  my $self = {
+    value => $value,
+    comment => $comment,
+    location => $location,
+    type => $type,
+    owner => $owner,
+    pretty => $pretty,
+    seen => 0,
+  };
+  bless $self, $class;
+
+  return $self;
+}
+
+=item C<$def-E<gt>append ($value, $comment)>
+
+Append C<$value> and <$comment> to the exisiting value and comment of
+C<$def>.  This is normally called on C<+=> definitions.
+
+=cut
+
+sub append ($$$)
+{
+  my ($self, $value, $comment) = @_;
+  $self->{'comment'} .= $comment;
+
+  my $val = $self->{'value'};
+  if (chomp $val)
+    {
+      # Insert a backslash before a trailing newline.
+      $val .= "\\\n";
+    }
+  elsif ($val)
+    {
+      # Insert a separator.
+      $val .= ' ';
+    }
+  $self->{'value'} = $val . $value;
+}
+
+=item C<$def-E<gt>value>
+
+=item C<$def-E<gt>comment>
+
+=item C<$def-E<gt>location>
+
+=item C<$def-E<gt>type>
+
+=item C<$def-E<gt>owner>
+
+=item C<$def-E<gt>pretty>
+
+Accessors to the various constituents of a C<VarDef>.  See the
+documentation of C<new>'s arguments for a description of these.
+
+=cut
+
+sub value ($)
+{
+  my ($self) = @_;
+  return $self->{'value'};
+}
+
+sub comment ($)
+{
+  my ($self) = @_;
+  return $self->{'comment'};
+}
+
+sub location ($)
+{
+  my ($self) = @_;
+  return $self->{'location'};
+}
+
+sub type ($)
+{
+  my ($self) = @_;
+  return $self->{'type'};
+}
+
+sub owner ($)
+{
+  my ($self) = @_;
+  return $self->{'owner'};
+}
+
+sub pretty ($)
+{
+  my ($self) = @_;
+  return $self->{'pretty'};
+}
+
+=item C<$def-E<gt>set_owner ($owner, $location)>
+
+Change the owner of a definition.  This usually happens because
+the user used C<+=> on an Automake variable, so (s)he now owns
+the content.  C<$location> should be an instance of L<Automake::Location>
+indicating where the change took place.
+
+=cut
+
+sub set_owner ($$$)
+{
+  my ($self, $owner, $location) = @_;
+  # We always adjust the location when the owner changes (even for
+  # `+=' statements).  The risk otherwise is to warn about
+  # a VAR_MAKEFILE variable and locate it in configure.ac...
+  $self->{'owner'} = $owner;
+  $self->{'location'} = $location;
+}
+
+=item C<$def-E<gt>set_seen>
+
+=item C<$bool = $def-E<gt>seen>
+
+These function allows Automake to mark (C<set_seen>) variable that
+it has examined in some way, and latter check (using C<seen>) for
+unused variables.  Unused variables usually indicate typos.
+
+=cut
+
+sub set_seen ($)
+{
+  my ($self) = @_;
+  $self->{'seen'} = 1;
+}
+
+sub seen ($)
+{
+  my ($self) = @_;
+  return $self->{'seen'};
+}
+
+=item C<$str = $def-E<gt>dump>
+
+Format the contents of C<$def> as a human-readable string,
+for debugging.
+
+=cut
+
+sub dump ($)
+{
+  my ($self) = @_;
+  my $owner = $self->owner;
+
+  if ($owner == VAR_AUTOMAKE)
+    {
+      $owner = 'Automake';
+    }
+  elsif ($owner == VAR_CONFIGURE)
+    {
+      $owner = 'Configure';
+    }
+  elsif ($owner == VAR_MAKEFILE)
+    {
+      $owner = 'Makefile';
+    }
+  else
+    {
+      prog_error ("unexpected owner");
+    }
+
+  my $where = $self->location->dump;
+  my $comment = $self->comment;
+  my $value = $self->value;
+  my $type = $self->type;
+
+  return "{
+      type: $type=
+      where: $where      comment: $comment
+      value: $value
+      owner: $owner
+    }\n";
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<Automake::Variable>.
+
+=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/Variable.pm
===================================================================
RCS file: lib/Automake/Variable.pm
diff -N lib/Automake/Variable.pm
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/Automake/Variable.pm    25 May 2003 19:47:04 -0000
@@ -0,0 +1,1369 @@
+# Copyright (C) 2003  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::Variable;
+use strict;
+use Carp;
+use Automake::Channels;
+use Automake::ChannelDefs;
+use Automake::VarDef;
+use Automake::Condition qw (TRUE FALSE);
+use Automake::DisjConditions;
+use Automake::General 'uniq';
+use Automake::Wrap 'makefile_wrap';
+
+require Exporter;
+use vars '@ISA', '@EXPORT', '@EXPORT_OK';
address@hidden = qw/Exporter/;
address@hidden = qw (err_var msg_var msg_cond_var reject_var
+             var rvar
+             variables
+             scan_variable_expansions check_variable_expansions
+             condition_ambiguous_p
+             variable_delete
+             variable_dump variables_dump
+             variable_defined
+             variable_assert
+             examine_variable
+             require_variables require_variables_for_variable
+             variable_value variable_value_as_list
+             output_variables);
+
+=head1 NAME
+
+Automake::Variable - support for variable definitions
+
+=head1 SYNOPSIS
+
+  use Automake::Variable;
+  use Automake::VarDef;
+
+  # Defining a variable.
+  Automake::Variable::define($varname, $owner, $type,
+                             $cond, $value, $comment,
+                             $where, $pretty)
+
+  # Looking up a variable.
+  my $var = var $varname;
+  if ($var)
+    {
+      ...
+    }
+
+  # Looking up a variable that is assumed to exist.
+  my $var = rvar $varname;
+
+  # The list of conditions where $var has been defined.
+  # ($var->conditions is an Automake::DisjConditions,
+  # $var->conditions->conds is a list of Automake::Condition.)
+  my @conds = $var->conditions->conds
+
+  # Accessing to the definition in Condition $cond.
+  # $def is an Automake::VarDef.
+  my $def = $var->def ($cond);
+  if ($def)
+    {
+      ...
+    }
+
+  # When the conditional definition is assumed to exist, use
+  my $def = $var->rdef ($cond);
+
+
+=head1 DESCRIPTION
+
+This package provides support for Makefile variable definitions.
+
+An C<Automake::Variable> is a variable name associated to possibly
+many conditional definitions.  These definitions are instances
+of C<Automake::VarDef>.
+
+Therefore obtaining the value of a variable under a given
+condition involves two lookups.  One to look up the variable,
+and one to look up the conditional definition:
+
+  my $var = var $name;
+  if ($var)
+    {
+      my $def = $var->def ($cond);
+      if ($def)
+        {
+          return $def->value;
+        }
+      ...
+    }
+  ...
+
+When it is known that the variable and the definition
+being looked up exist, the above can be simplified to
+
+  return var ($name)->def ($cond)->value; # Do not write this.
+
+but is better written
+
+  return rvar ($name)->rdef ($cond)->value;
+
+The I<r> variants of the C<var> and C<def> methods add an extra test
+to ensure that the lookup succeeded, and will diagnose failure as
+internal errors (which a message which is much more informative than
+Perl's warning about calling a method on a non-object).
+
+=cut
+
+my $_VARIABLE_PATTERN = 'address@hidden' . "\$";
+
+# The order in which variables should be output.  (May contain
+# duplicates -- only the first occurence matters.)
+my @_var_order;
+
+# Declare the macros that define known variables, so we can
+# hint the user if she try to use one of these variables.
+
+# Macros accessible via aclocal.
+my %_am_macro_for_var =
+  (
+   ANSI2KNR => 'AM_C_PROTOTYPES',
+   CCAS => 'AM_PROG_AS',
+   CCASFLAGS => 'AM_PROG_AS',
+   EMACS => 'AM_PATH_LISPDIR',
+   GCJ => 'AM_PROG_GCJ',
+   LEX => 'AM_PROG_LEX',
+   LIBTOOL => 'AC_PROG_LIBTOOL',
+   lispdir => 'AM_PATH_LISPDIR',
+   pkgpyexecdir => 'AM_PATH_PYTHON',
+   pkgpythondir => 'AM_PATH_PYTHON',
+   pyexecdir => 'AM_PATH_PYTHON',
+   PYTHON => 'AM_PATH_PYTHON',
+   pythondir => 'AM_PATH_PYTHON',
+   U => 'AM_C_PROTOTYPES',
+   );
+
+# Macros shipped with Autoconf.
+my %_ac_macro_for_var =
+  (
+   CC => 'AC_PROG_CC',
+   CFLAGS => 'AC_PROG_CC',
+   CXX => 'AC_PROG_CXX',
+   CXXFLAGS => 'AC_PROG_CXX',
+   F77 => 'AC_PROG_F77',
+   F77FLAGS => 'AC_PROG_F77',
+   RANLIB => 'AC_PROG_RANLIB',
+   YACC => 'AC_PROG_YACC',
+   );
+
+# Variables that can be overriden without complaint from -Woverride
+my %_silent_variable_override =
+  (AR => 1,
+   ARFLAGS => 1,
+   DEJATOOL => 1,
+   JAVAC => 1);
+
+# This hash records helper variables used to implement conditional '+='.
+# Keys have the form "VAR:CONDITIONS".  The value associated to a key is
+# the named of the helper variable used to append to VAR in CONDITIONS.
+my %_appendvar = ();
+
+
+=head2 Error reporting functions
+
+In these functions, C<$var> can be either a variable name, or
+an instance of C<Automake::Variable>.
+
+=over 4
+
+=item C<err_var ($var, $message, [%options])>
+
+Uncategorized errors about variables.
+
+=cut
+
+sub err_var ($$;%)
+{
+  msg_var ('error', @_);
+}
+
+=item C<msg_cond_var ($channel, $cond, $var, $message, [%options])>
+
+Messages about conditional variable.
+
+=cut
+
+sub msg_cond_var ($$$$;%)
+{
+  my ($channel, $cond, $var, $msg, %opts) = @_;
+  my $v = ref ($var) ? $var : rvar ($var);
+  msg $channel, $v->rdef ($cond)->location, $msg, %opts;
+}
+
+=item C<msg_var ($channel, $var, $message, [%options])>
+
+messages about variables.
+
+=cut
+
+sub msg_var ($$$;%)
+{
+  my ($channel, $var, $msg, %opts) = @_;
+  my $v = ref ($var) ? $var : rvar ($var);
+  # Don't know which condition is concerned.  Pick any.
+  my $cond = $v->conditions->one_cond;
+  msg_cond_var $channel, $cond, $v, $msg, %opts;
+}
+
+=item C<reject_var ($varname, $error_msg)>
+
+Bail out with C<$ERROR_MSG> if a variable with name C<$VARNAME> has
+been defined.
+
+=cut
+
+# $BOOL
+# reject_var ($VARNAME, $ERROR_MSG)
+# -----------------------------
+sub reject_var ($$)
+{
+  my ($var, $msg) = @_;
+  my $v = var ($var);
+  if ($v)
+    {
+      err_var $v, $msg;
+      return 1;
+    }
+  return 0;
+}
+
+=back
+
+=head2 Administrative functions
+
+=over 4
+
+=item C<Automake::Variable::hook ($varname, $fun)>
+
+Declare a function to be called whenever a variable
+named C<$varname> is defined or redefined.
+
+C<$fun> should take two arguments: C<$type> and C<$value>.
+When type is C<''> or <':'>, C<$value> is the value being
+assigned to C<$varname>.  When C<$type> is C<'+'>, C<$value>
+is the value being appended to  C<$varname>.
+
+=cut
+
+use vars '%_hooks';
+sub hook ($\&)
+{
+  my ($var, $fun) = @_;
+  $_hooks{$var} = $fun;
+}
+
+=item C<variables>
+
+Returns the list of all L<Automake::Variable> instances.  (I.e., all
+variables defined so far.)
+
+=cut
+
+use vars '%_variable_dict';
+sub variables ()
+{
+  return keys %_variable_dict;
+}
+
+=item C<Automake::Variable::reset>
+
+The I<forget all> function.  Clears all know variables and reset some
+other internal data.
+
+=cut
+
+sub reset ()
+{
+  %_variable_dict = ();
+  %_appendvar = ();
+  @_var_order = ();
+}
+
+=item C<var ($varname)>
+
+Return the C<Automake::Variable> object for the variable
+named C<$varname> if defined.   Return the empty list
+otherwise.
+
+=cut
+
+sub var ($)
+{
+  my ($name) = @_;
+  return $_variable_dict{$name} if exists $_variable_dict{$name};
+  return ();
+}
+
+# Create the variable if it does not exist.
+# This is used only by other functions in this package.
+sub _cvar ($)
+{
+  my ($name) = @_;
+  my $v = var $name;
+  return $v if $v;
+  return _new Automake::Variable $name;
+}
+
+=item C<rvar ($varname)>
+
+Return the C<Automake::Variable> object for the variable named
+C<$varname>.  Abort with an internal error if the variable was not
+defined.
+
+The I<r> in front of C<var> stands for I<required>.  One
+should call C<rvar> to assert the variable's existence.
+
+=cut
+
+sub rvar ($)
+{
+  my ($name) = @_;
+  my $v = var $name;
+  prog_error ("undefined variable $name\n" . &variables_dump)
+    unless $v;
+  return $v;
+}
+
+=back
+
+=head2 Methods
+
+Here are the methods of the C<Automake::Variable> instances.
+Use the C<define> function, described latter, to create such objects.
+
+=over 4
+
+=cut
+
+# Create Automake::Variable objects.  This is used
+# only in this file.  Other users should use
+# the "define" function.
+sub _new ($$)
+{
+  my ($class, $name) = @_;
+  my $self = {
+    name => $name,
+    defs => {},
+    conds => {},
+  };
+  bless $self, $class;
+  $_variable_dict{$name} = $self;
+  return $self;
+}
+
+=item C<$var-E<gt>name>
+
+Return the name of C<$var>.
+
+=cut
+
+sub name ($)
+{
+  my ($self) = @_;
+  return $self->{'name'};
+}
+
+=item C<$var-E<gt>def ($cond)>
+
+Return the C<Automake::VarDef> definition for this variable in
+condition C<$cond>, if it exists.  Return the empty list otherwise.
+
+=cut
+
+sub def ($$)
+{
+  my ($self, $cond) = @_;
+  return $self->{'defs'}{$cond} if exists $self->{'defs'}{$cond};
+  return ();
+}
+
+=item C<$var-E<gt>rdef ($cond)>
+
+Return the C<Automake::VarDef> definition for this variable in
+condition C<$cond>.  Abort with an internal error if the variable was
+not defined under this condition.
+
+The I<r> in front of C<def> stands for I<required>.  One
+should call C<rdef> to assert the conditional definition's existence.
+
+=cut
+
+sub rdef ($$)
+{
+  my ($self, $cond) = @_;
+  my $d = $self->def ($cond);
+  prog_error ("undefined condition `" . $cond->human . "' for `"
+             . $self->name . "'\n" . variable_dump ($self->name))
+    unless $d;
+  return $d;
+}
+
+# Add a new VarDef to an existing Variable.  This is a private
+# function.  Our public interface is the `define' function.
+sub _set ($$$)
+{
+  my ($self, $cond, $def) = @_;
+  $self->{'defs'}{$cond} = $def;
+  $self->{'conds'}{$cond} = $cond;
+}
+
+=item C<$var-E<gt>conditions>
+
+Return an L<Automake::DisjConditions> describing the conditions that
+that a variable is defined with, without recursing through the
+conditions of any subvariables.
+
+These are all the conditions for which is would be safe to call
+C<rdef>.
+
+=cut
+
+sub conditions ($)
+{
+  my ($self) = @_;
+  prog_error ("self is not a reference")
+    unless ref $self;
+  return new Automake::DisjConditions (values %{$self->{'conds'}});
+}
+
+# _check_ambiguous_condition ($SELF, $COND, $WHERE)
+# -------------------------------------------------
+# Check for an ambiguous conditional.  This is called when a variable
+# is being defined conditionally.  If we already know about a
+# definition that is true under the same conditions, then we have an
+# ambiguity.
+sub _check_ambiguous_condition ($$$)
+{
+  my ($self, $cond, $where) = @_;
+  my $var = $self->name;
+  my ($message, $ambig_cond) =
+    condition_ambiguous_p ($var, $cond, $self->conditions);
+
+  # We allow silent variables to be overridden silently.
+  my $def = $self->def ($cond);
+  if ($message && !($def && $def->pretty == VAR_SILENT))
+    {
+      msg 'syntax', $where, "$message ...", partial => 1;
+      msg_var ('syntax', $var, "... `$var' previously defined here");
+      verb (variable_dump ($var));
+    }
+}
+
+=item C<@missing_conds = $var-E<gt>not_always_defined_in_cond ($cond)>
+
+Check whether C<$var> is always defined for condition C<$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 (we display result as conditional strings in this
+illustration, but we really return DisjConditions objects):
+
+  var ('A')->not_always_defined_in_cond ('COND1_TRUE COND2_TRUE')
+    => ()
+  var ('A')->not_always_defined_in_cond ('COND1_TRUE')
+    => ()
+  var ('A')->not_always_defined_in_cond ('TRUE')
+    => ("COND1_FALSE COND3_FALSE")
+  var ('B')->not_always_defined_in_cond ('COND1_TRUE')
+    => ("COND1_TRUE COND3_FALSE")
+  var ('C')->not_always_defined_in_cond ('COND1_TRUE')
+    => ()
+  var ('D')->not_always_defined_in_cond ('TRUE')
+    => ()
+  var ('Z')->not_always_defined_in_cond ('TRUE')
+    => ("TRUE")
+
+=cut
+
+sub not_always_defined_in_cond ($$)
+{
+  my ($self, $cond) = @_;
+
+  # Compute the subconditions where $var isn't defined.
+  return
+    $self->conditions
+      ->sub_conditions ($cond)
+       ->invert
+         ->simplify
+           ->multiply ($cond);
+}
+
+=item C<$bool = $var-E<gt>check_defined_unconditionally ($parent)>
+
+Warn if the variable is conditionally defined.  C<$parent>
+is the name of the parent variable, to display in error message.
+
+=cut
+
+sub check_defined_unconditionally ($;$)
+{
+  my ($self, $parent) = @_;
+  if (!$self->conditions->true)
+    {
+      if ($parent)
+       {
+         msg_var ('unsupported', $parent,
+                  "automake does not support conditional definition of "
+                  . $self->name . " in $parent");
+       }
+      else
+       {
+         msg_var ('unsupported', $self,
+                  "automake does not support " . $self->name
+                  . " being defined conditionally");
+       }
+    }
+}
+
+=back
+
+=head2 Utility functions
+
+=over 4
+
+=item C<@list = scan_variable_expansions ($text)>
+
+Return the list of variable names expanded in C<$text>.  Note that
+unlike some other functions, C<$text> is not split on spaces before we
+check for subvariables.
+
+=cut
+
+sub scan_variable_expansions ($)
+{
+  my ($text) = @_;
+  my @result = ();
+
+  # Strip comments.
+  $text =~ s/#.*$//;
+
+  # Record each use of ${stuff} or $(stuff) that do not follow a $.
+  while ($text =~ /(?<!\$)\$(?:\{([^\}]*)\}|\(([^\)]*)\))/g)
+    {
+      my $var = $1 || $2;
+      # The occurent may look like $(string1[:subst1=[subst2]]) but
+      # we want only `string1'.
+      $var =~ s/:[^:=]*=[^=]*$//;
+      push @result, $var;
+    }
+
+  return @result;
+}
+
+=item C<check_variable_expansions ($text, $where)>
+
+Check variable expansions in C<$text> and warn about any name that
+does not conform to POSIX.  C<$where> is the location of C<$text>
+for the error message.
+
+=cut
+
+sub check_variable_expansions ($$)
+{
+  my ($text, $where) = @_;
+  # Catch expansion of variables whose name does not conform to POSIX.
+  foreach my $var (scan_variable_expansions ($text))
+    {
+      if ($var !~ /$_VARIABLE_PATTERN/o)
+       {
+         # If the variable name contains a space, it's likely
+         # to be a GNU make extension (such as $(addsuffix ...)).
+         # Mention this in the diagnostic.
+         my $gnuext = "";
+         $gnuext = "\n(probably a GNU make extension)" if $var =~ / /;
+         msg ('portability', $where,
+              "$var: non-POSIX variable name$gnuext");
+       }
+    }
+}
+
+
+=item C<($string, $ambig_cond) = condition_ambiguous_p ($what, $cond, 
$condset)>
+
+Check for an ambiguous condition.  Return an error message and
+the other condition involved if we have one, two empty strings otherwise.
+
+C<$what> is the name of the thing being defined, to use in the error
+message.  C<$cond> is the C<Condition> under which it is being
+defined.  C<$condset> is the C<DisjConditions> under which it had
+already been defined.
+
+=cut
+
+sub condition_ambiguous_p ($$$)
+{
+  my ($var, $cond, $condset) = @_;
+
+  foreach my $vcond ($condset->conds)
+    {
+      # Note that these rules doesn't consider the following
+      # example as ambiguous.
+      #
+      #   if COND1
+      #     FOO = foo
+      #   endif
+      #   if COND2
+      #     FOO = bar
+      #   endif
+      #
+      # It's up to the user to not define COND1 and COND2
+      # simultaneously.
+      my $message;
+      if ($vcond eq $cond)
+       {
+         return ("$var multiply defined in condition " . $cond->human,
+                 $vcond);
+       }
+      elsif ($vcond->true_when ($cond))
+       {
+         return ("$var was already defined in condition " . $vcond->human
+                 . ", which implies condition ". $cond->human, $vcond);
+       }
+      elsif ($cond->true_when ($vcond))
+       {
+         return ("$var was already defined in condition "
+                 . $vcond->human . ", which is implied by condition "
+                 . $cond->human, $vcond);
+       }
+    }
+  return ('', '');
+}
+
+=item C<Automake::Variable::define($varname, $owner, $type, $cond, $value, 
$comment, $where, $pretty)>
+
+Define or append to a new variable.
+
+C<$varname>: the name of the variable being defined.
+
+C<$owner>: owner of the variable (one of C<VAR_MAKEFILE>,
+C<VAR_CONFIGURE>, or C<VAR_AUTOMAKE>, defined by L<Automake::VarDef>).
+Variables can be overriden, provided the new owner is not weaker
+(C<VAR_AUTOMAKE> < C<VAR_CONFIGURE> < C<VAR_MAKEFILE>).
+
+C<$type>: the type of the assignment (C<''> for C<FOO = bar>,
+C<':'> for C<FOO := bar>, and C<'+'> for C<'FOO += bar'>).
+
+C<$cond>: the DisjConditions in which C<$var> is being defined.
+
+C<$value>: the value assigned to C<$var> in condition C<$cond>.
+
+C<$comment>: any comment (C<'# bla.'>) associated with the assignment.
+Comments from C<+=> assignments stack with comments from the last C<=>
+assignment.
+
+C<$where>: the C<Location> of the assignment.
+
+C<$pretty>: whether C<$value> should be pretty printed (one of
+C<VAR_ASIS>, C<VAR_PRETTY>, or C<VAR_SILENT>, defined by by
+L<Automake::VarDef>).  C<$pretty> applies only to real assignments.
+I.e., it doesn't apply to a C<+=> assignment (except when part of it
+is being done as a conditional C<=> assignment).
+
+This function will all run any hook registered with the C<hook>
+function.
+
+=cut
+
+sub define ($$$$$$$$)
+{
+  my ($var, $owner, $type, $cond, $value, $comment, $where, $pretty) = @_;
+
+  prog_error "$cond is not a reference"
+    unless ref $where;
+
+  prog_error "$where is not a reference"
+    unless ref $where;
+
+  prog_error "pretty argument missing"
+    unless defined $pretty && ($pretty == VAR_PRETTY
+                              || $pretty == VAR_ASIS
+                              || $pretty == VAR_SILENT);
+
+  # We will adjust the owner of this variable unless told otherwise.
+  my $adjust_owner = 1;
+
+  error $where, "bad characters in variable name `$var'"
+    if $var !~ /$_VARIABLE_PATTERN/o;
+
+  # NEWS-OS 4.2R complains if a Makefile variable begins with `_'.
+  msg ('portability', $where,
+       "$var: variable names starting with `_' are not portable")
+    if $var =~ /^_/;
+
+  # `:='-style assignments are not acknowledged by POSIX.  Moreover it
+  # has multiple meanings.  In GNU make or BSD make it means "assign
+  # with immediate expansion", while in OSF make it is used for
+  # conditional assignments.
+  msg ('portability', $where, "`:='-style assignments are not portable")
+    if $type eq ':';
+
+  check_variable_expansions ($value, $where);
+
+  # If there's a comment, make sure it is \n-terminated.
+  if ($comment)
+    {
+      chomp $comment;
+      $comment .= "\n";
+    }
+  else
+    {
+      $comment = '';
+    }
+
+  my $self = _cvar $var;
+
+  my $def = $self->def ($cond);
+  my $new_var = $def ? 0 : 1;
+
+  # An Automake variable must be consistently defined with the same
+  # sign by Automake.
+  error ($where, "$var was set with `". $def->type .
+        "=' and is now set with `$type='")
+    if $owner == VAR_AUTOMAKE && ! $new_var && $def->type ne $type;
+
+
+  # Differentiate assignment types.
+
+  # 1. append (+=) to a variable defined for current condition
+  if ($type eq '+' && ! $new_var)
+    {
+      $def->append ($value, $comment);
+    }
+  # 2. append (+=) to a variable defined for *another* condition
+  elsif ($type eq '+' && ! $self->conditions->false)
+    {
+      # * Generally, $cond is not TRUE.  For instance:
+      #     FOO = foo
+      #     if COND
+      #       FOO += bar
+      #     endif
+      #   In this case, we declare an helper variable conditionally,
+      #   and append it to FOO:
+      #     FOO = foo $(am__append_1)
+      #     @address@hidden = bar
+      #   Of course if FOO is defined under several conditions, we add
+      #   $(am__append_1) to each definitions.
+      #
+      # * If $cond is TRUE, we don't need the helper variable.  E.g., in
+      #     if COND1
+      #       FOO = foo1
+      #     else
+      #       FOO = foo2
+      #     endif
+      #     FOO += bar
+      #   we can add bar directly to all definition of FOO, and output
+      #     @address@hidden = foo1 bar
+      #     @address@hidden = foo2 bar
+
+      # Do we need an helper variable?
+      if ($cond != TRUE)
+        {
+           # Does the helper variable already exists?
+           my $key = "$var:" . $cond->string;
+           if (exists $_appendvar{$key})
+             {
+               # Yes, let's simply append to it.
+               $var = $_appendvar{$key};
+               $owner = VAR_AUTOMAKE;
+               $self = var ($var);
+               $def = $self->rdef ($cond);
+               $new_var = 0;
+             }
+           else
+             {
+               # No, create it.
+               my $num = 1 + keys (%_appendvar);
+               my $hvar = "am__append_$num";
+               $_appendvar{$key} = $hvar;
+               &define ($hvar, VAR_AUTOMAKE, '+',
+                        $cond, $value, $comment, $where, $pretty);
+               # Now HVAR is to be added to VAR.
+               $comment = '';
+               $value = "\$($hvar)";
+             }
+       }
+
+      # Add VALUE to all definitions of SELF.
+      foreach my $vcond ($self->conditions->conds)
+        {
+         # 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 = $self->not_always_defined_in_cond ($cond);
+         if (! $undef_cond->false)
+           {
+             error ($where,
+                    "Cannot apply `+=' because `$var' is not defined "
+                    . "in\nthe following conditions:\n  "
+                    . join ("\n  ", map { $_->human } $undef_cond->conds)
+                    . "\nEither define `$var' in these conditions,"
+                    . " or use\n`+=' in the same conditions as"
+                    . " the definitions.");
+           }
+         else
+           {
+             &define ($var, $owner, '+', $vcond, $value, $comment,
+                      $where, $pretty);
+           }
+       }
+      # Don't adjust the owner.  The above &define did it in the
+      # right conditions.
+      $adjust_owner = 0;
+    }
+  # 3. first assignment (=, :=, or +=)
+  else
+    {
+      # If Automake tries to override a value specified by the user,
+      # just don't let it do.
+      if (! $new_var && $def->owner != VAR_AUTOMAKE
+         && $owner == VAR_AUTOMAKE)
+       {
+         if (! exists $_silent_variable_override{$var})
+           {
+             my $condmsg = ($cond == TRUE
+                            ? '' : (" in condition `" . $cond->human . "'"));
+             msg_cond_var ('override', $cond, $var,
+                           "user variable `$var' defined here$condmsg...",
+                           partial => 1);
+             msg ('override', $where,
+                  "... overrides Automake variable `$var' defined here");
+           }
+         verb ("refusing to override the user definition of:\n"
+               . variable_dump ($var)
+               ."with `" . $cond->human . "' => `$value'");
+       }
+      else
+       {
+         # There must be no previous value unless the user is redefining
+         # an Automake variable or an AC_SUBST variable for an existing
+         # condition.
+         _check_ambiguous_condition ($self, $cond, $where)
+           unless (!$new_var
+                   && (($def->owner == VAR_AUTOMAKE && $owner != VAR_AUTOMAKE)
+                       || $def->owner == VAR_CONFIGURE));
+
+         # Never decrease an owner.
+         $owner = $def->owner
+           if ! $new_var && $owner < $def->owner;
+
+         # Assignments to a macro set its location.  We don't adjust
+         # locations for `+='.  Ideally I suppose we would associate
+         # line numbers with random bits of text.
+         $def = new Automake::VarDef ($var, $value, $comment, $where->clone,
+                                      $type, $owner, $pretty);
+         $self->_set ($cond, $def);
+         push @_var_order, $var;
+
+         # No need to adjust the owner later as we have overridden
+         # the definition.
+         $adjust_owner = 0;
+       }
+    }
+
+  # The owner of a variable can only increase, because an Automake
+  # variable can be given to the user, but not the converse.
+  $def->set_owner ($owner, $where->clone)
+    if $adjust_owner && $owner > $def->owner;
+
+  # Call any defined hook.  This helps to update some internal state
+  # *while* parsing the file.  For instance the handling of SUFFIXES
+  # requires this (see var_SUFFIXES_trigger).
+  &{$_hooks{$var}}($type, $value) if exists $_hooks{$var};
+}
+
+=item C<variable_delete ($varname, address@hidden)>
+
+Forget about C<$varname> under the conditions C<@conds>, or completely
+if C<@conds> is empty.
+
+=cut
+
+sub variable_delete ($@)
+{
+  my ($var, @conds) = @_;
+
+  if (address@hidden)
+    {
+      delete $_variable_dict{$var};
+    }
+  else
+    {
+      for my $cond (@conds)
+       {
+         delete $_variable_dict{$var}{'defs'}{$cond};
+       }
+    }
+}
+
+=item C<$str = variable_dump ($varname)>
+
+Return a string describing all we know about C<$varname>.
+For debugging.
+
+=cut
+
+# &variable_dump ($VAR)
+# ---------------------
+sub variable_dump ($)
+{
+  my ($var) = @_;
+  my $text = '';
+
+  my $v = var $var;
+
+  if (!$v)
+    {
+      $text = "  $var does not exist\n";
+    }
+  else
+    {
+      $text .= "$var: \n  {\n";
+      foreach my $vcond ($v->conditions->conds)
+       {
+         my $def = $v->def ($vcond);
+         $text .= "    " . $vcond->human . " => " . $v->def ($vcond)->dump ()
+       }
+      $text .= "  }\n";
+    }
+  return $text;
+}
+
+
+=item C<$str = variables_dump ($varname)>
+
+Return a string describing all we know about all variables.
+For debugging.
+
+=cut
+
+sub variables_dump ()
+{
+  my ($var) = @_;
+
+  my $text = "All variables:\n{\n";
+  foreach my $var (sort (variables()))
+    {
+      $text .= variable_dump ($var);
+    }
+  $text .= "}\n";
+  return $text;
+}
+
+=item C<$bool = variable_defined ($varname, [$cond])>
+
+See if a variable exists.  C<$varname> is the variable name, and
+C<$cond> is the condition which we should check.  If no condition is
+given, we currently return true if the variable is defined under any
+condition.
+
+=cut
+
+sub variable_defined ($;$)
+{
+  my ($var, $cond) = @_;
+
+  my $v = var $var;
+  my $def = ($v && $cond) ? ($v->def ($cond)) : 0;
+
+  if (!$v || ($cond && !$def))
+    {
+      # VAR is not defined.
+
+      # Check there is no target defined with the name of the
+      # variable we check.
+
+      # adl> I'm wondering if this error still makes any sense today. I
+      # adl> guess it was because targets and variables used to share
+      # adl> the same namespace in older versions of Automake?
+      # tom> While what you say is definitely part of it, I think it
+      # tom> might also have been due to someone making a "spelling error"
+      # tom> -- writing "foo:..." instead of "foo = ...".
+      # tom> I'm not sure whether it is really worth diagnosing
+      # tom> this sort of problem.  In the old days I used to add warnings
+      # tom> and errors like this pretty randomly, based on bug reports I
+      # tom> got.  But there's a plausible argument that I was trying
+      # tom> too hard to prevent people from making mistakes.
+
+      ### FIXME: Presently we can't do this.  Wait until targets are handled
+      ### in there own module.
+      # if (exists $Automake::targets{$var}
+      #          && (!$cond || exists $Automake::targets{$var}{$cond}))
+      #        {
+      #          for my $tcond ($cond || keys %{$Automake::targets{$var}})
+      #            {
+      #              prog_error ("\$Automake::targets{$var}{" . $tcond->human
+      #                          . "} exists but \$target_owner doesn't")
+      #                unless exists $Automake::target_owner{$var}{$tcond};
+      #              # Diagnose the first user target encountered, if any.
+      #              # Restricting this test to user targets allows Automake
+      #              # to create rules for things like `bin_PROGRAMS = LDADD'.
+      #              if ($Automake::target_owner{$var}{$tcond}
+      #                  == &Automake::TARGET_USER)
+      #                {
+      #                  Automake::msg_cond_target ('syntax', $tcond, $var,
+      #                                             "`$var' is a target; "
+      #                                             . "expected a variable");
+      #                  return 0;
+      #                }
+      #            }
+      #        }
+      return 0;
+    }
+
+  # VAR is defined.  Record we have examined this variable.
+  if (!$cond)
+    {
+      for my $c ($v->conditions->conds)
+       {
+         $v->rdef ($c)->set_seen;
+       }
+    }
+  else
+    {
+      $def->set_seen;
+    }
+  return 1;
+}
+
+=item C<$bool = variable_assert ($varname, $where)>
+
+Make sure a variable exists in any condition, issue an error message
+otherwise.  C<$varname> is the variable name, and C<$where> is the
+name of a macro which refers to C<$varname>.
+
+=cut
+
+sub variable_assert ($$)
+{
+  my ($var, $where) = @_;
+
+  return 1
+    if variable_defined $var;
+
+  require_variables ($where, "variable `$var' is used", TRUE, $var);
+
+  return 0;
+}
+
+=item C<examine_variable ($varname)>
+
+Mark a variable as examined.
+
+=cut
+
+sub examine_variable ($)
+{
+  my ($var) = @_;
+  variable_defined ($var);
+}
+
+=item C<$count = require_variables ($where, $reason, $cond, @variables)>
+
+Make sure that each supplied variable is defined in C<$cond>.
+Otherwise, issue a warning showing C<$reason> (C<$reason> should be
+the reason why these variable are required, for instance C<'option foo
+used'>).  If we know which macro can define this variable, hint the
+user.  Return the number of undefined variables.
+
+=cut
+
+sub require_variables ($$$@)
+{
+  my ($where, $reason, $cond, @vars) = @_;
+  my $res = 0;
+  $reason .= ' but ' unless $reason eq '';
+
+ VARIABLE:
+  foreach my $var (@vars)
+    {
+      # Nothing to do if the variable exists.
+      next VARIABLE
+       if variable_defined ($var, $cond);
+
+      my $v = _cvar $var;
+      my $undef_cond = $v->not_always_defined_in_cond ($cond);
+      next VARIABLE
+       if $undef_cond->false;
+
+      my $text = "$reason`$var' is undefined\n";
+      if (! $undef_cond->true)
+       {
+         $text .= ("in the following conditions:\n  "
+                   . join ("\n  ", map { $_->human } $undef_cond->conds));
+       }
+
+      ++$res;
+
+      if (exists $_am_macro_for_var{$var})
+       {
+         $text .= "\nThe usual way to define `$var' is to add "
+           . "`$_am_macro_for_var{$var}'\nto `$Automake::configure_ac' and "
+           . "run `aclocal' and `autoconf' again.";
+       }
+      elsif (exists $_ac_macro_for_var{$var})
+       {
+         $text .= "\nThe usual way to define `$var' is to add "
+           . "`$_ac_macro_for_var{$var}'\nto `$Automake::configure_ac' and "
+           . "run `autoconf' again.";
+       }
+
+      error $where, $text, uniq_scope => US_GLOBAL;
+    }
+  return $res;
+}
+
+=item C<$count = require_variables_for_variable ($varname, $reason, 
@variables)>
+
+Same as C<require_variables>, but take a variable name as first argument.
+C<@variables> should be defined in the same conditions as C<$varname> is
+defined.
+
+=cut
+
+sub require_variables_for_variable ($$@)
+{
+  my ($varname, $reason, @args) = @_;
+  my $v = rvar ($varname);
+  for my $cond ($v->conditions->conds)
+    {
+      return require_variables ($v->def ($cond)->location, $reason,
+                               $cond, @args);
+    }
+}
+
+
+=item C<variable_value ($var)>
+
+Get the C<TRUE> value of a variable, warn if the variable is
+conditionally defined.  C<$var> can be either a variable name
+or a C<Automake::Variable> instance (this allows to calls sucha
+as C<$var-E<gt>variable_value>).
+
+=cut
+
+sub variable_value ($)
+{
+    my ($var) = @_;
+    my $v = ref ($var) ? $var : var ($var);
+    return () unless $v;
+    $v->check_defined_unconditionally;
+    return $v->rdef (TRUE)->value;
+}
+
+=item C<@values = variable_value_as_list ($varname, $cond, [$parent])>
+
+Get the value of a variable given a specified condition. without
+recursing through any subvariables.
+
+C<$varname> is the variable name.  C<$cond> is the condition of interest.
+C<$parent> is the variable in which the variable is used: this is used
+only for error messages.
+
+For example, if C<A> is defined as "C<foo $(B) bar>" in condition
+C<TRUE>, calling C<variable_value_as_list ('A', TRUE)> will return
+C<("foo", "$(B)", "bar")>.
+
+=cut
+
+sub variable_value_as_list($$;$)
+{
+  my ($var, $cond, $parent) = @_;
+  my @result;
+
+  # Check defined
+  return
+    unless variable_assert $var, $parent;
+
+  my $v = rvar ($var);
+
+  # Get value for given condition
+  my $onceflag;
+  foreach my $vcond ($v->conditions->conds)
+    {
+      my $val = $v->def ($vcond)->value;
+
+      if ($vcond->true_when ($cond))
+       {
+         # Unless variable is not defined conditionally, there should only
+         # be one value of $vcond true when $cond.
+
+         &check_variable_defined_unconditionally ($var, $parent)
+           if $onceflag;
+         $onceflag = 1;
+
+         # Strip backslashes
+         $val =~ s/\\(\n|$)/ /g;
+
+         foreach (split (' ', $val))
+           {
+             # If a comment seen, just leave.
+             last if /^#/;
+
+             push (@result, $_);
+           }
+       }
+    }
+  return @result;
+}
+
+=item C<$str = output ($var, address@hidden)>
+
+Format all the definitions of C<$var> if C<@cond> is not specified,
+else only that corresponding to C<@cond>.
+
+=cut
+
+sub output ($@)
+{
+  my ($var, @conds) = @_;
+
+  $var = ref ($var) ? $var : rvar ($var);
+
+  @conds = $var->conditions->conds
+    unless @conds;
+
+  my $res = '';
+  my $name = $var->name;
+
+  foreach my $cond (@conds)
+    {
+      my $def = $var->def ($cond);
+      prog_error ("unknown condition `" . $cond->human . "' for `$var'")
+       unless $def;
+
+      next
+       if $def->pretty == VAR_SILENT;
+
+      $res .= $def->comment;
+
+      my $val = $def->value;
+      my $equals = $def->type eq ':' ? ':=' : '=';
+      my $str = $cond->subst_string;
+
+      if ($def->pretty == VAR_PRETTY)
+       {
+         # Suppress escaped new lines.  &makefile_wrap will
+         # add them back, maybe at other places.
+         $val =~ s/\\$//mg;
+         $res .= makefile_wrap ("$str$name $equals", "$str\t",
+                                split (' ' , $val));
+       }
+      else                     # VAR_ASIS
+       {
+         my $output_var = "$name $equals $val";
+         $output_var =~ s/^/$str/meg;
+         $res .= "$output_var\n";
+       }
+    }
+  return $res;
+}
+
+
+=item C<$str = output_variables>
+
+Format definitions for all variables.
+
+=cut
+
+sub output_variables ()
+{
+  my $res = '';
+  # We output variables it in the same order in which they were
+  # defined (skipping duplicates).
+  my @vars = uniq @_var_order;
+
+  # Output all the Automake variables.  If the user changed one,
+  # then it is now marked as VAR_CONFIGURE or VAR_MAKEFILE.
+  foreach my $var (@vars)
+    {
+      my $v = rvar $var;
+      foreach my $cond ($v->conditions->conds)
+       {
+         $res .= $v->output ($cond)
+           if $v->rdef ($cond)->owner == VAR_AUTOMAKE;
+       }
+    }
+
+  # Now dump the user variables that were defined.
+  foreach my $var (@vars)
+    {
+      my $v = rvar $var;
+      foreach my $cond ($v->conditions->conds)
+       {
+         $res .= $v->output ($cond)
+           if $v->rdef ($cond)->owner != VAR_AUTOMAKE;
+       }
+    }
+  return $res;
+}
+
+
+=back
+
+=head1 SEE ALSO
+
+L<Automake::VarDef>, L<Automake::Condition>,
+L<Automake::DisjConditions>, L<Automake::Location>.
+
+=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: tests/Makefile.am
===================================================================
RCS file: /cvs/automake/automake/tests/Makefile.am,v
retrieving revision 1.493
diff -u -r1.493 Makefile.am
--- tests/Makefile.am   17 May 2003 11:31:57 -0000      1.493
+++ tests/Makefile.am   25 May 2003 19:47:04 -0000
@@ -1,6 +1,6 @@
 ## Process this file with automake to create Makefile.in
 
-XFAIL_TESTS = auxdir2.test cond17.test txinfo5.test
+XFAIL_TESTS = auxdir2.test cond17.test txinfo5.test target.test
 
 TESTS =        \
 aclibobj.test \
Index: tests/Makefile.in
===================================================================
RCS file: /cvs/automake/automake/tests/Makefile.in,v
retrieving revision 1.633
diff -u -r1.633 Makefile.in
--- tests/Makefile.in   17 May 2003 11:31:57 -0000      1.633
+++ tests/Makefile.in   25 May 2003 19:47:04 -0000
@@ -112,7 +112,7 @@
 sharedstatedir = @sharedstatedir@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
-XFAIL_TESTS = auxdir2.test cond17.test txinfo5.test
+XFAIL_TESTS = auxdir2.test cond17.test txinfo5.test target.test
 TESTS = \
 aclibobj.test \
 aclocal.test \
@@ -698,7 +698,6 @@
          echo "$$dashes"; \
          test "$$failed" -eq 0; \
        else :; fi
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 
 distdir: $(DISTFILES)
        @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
-- 
Alexandre Duret-Lutz





reply via email to

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