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;
# 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 = '^[.A-Za-z0-9_@]+' . "\$";
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
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
# 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
# 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
my ($type, $value) = @_;
accept_extensions (split (' ', $value));
}
+Automake::Variable::hook ('SUFFIXES', &var_SUFFIXES_trigger);
################################################################
@suffixes = ();
- %var_value = ();
- %var_location = ();
- %var_comment = ();
- %var_type = ();
- %var_owner = ();
- %var_pretty = ();
-
- %content_seen = ();
+ Automake::Variable::reset ();
%targets = ();
%target_source = ();
$need_link = 0;
- @var_order = ();
-
$get_object_extension_was_run = 0;
%compile_clean_files = ();
%libtool_clean_directories = ('.' => 1);
%gen_varname = ();
-
- %appendvar = ();
}
# 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.
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.
msg $channel, $configure_ac, $msg, %opts;
}
-# $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)
# --------------------------------
# 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;
}
}
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.
# 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;
# Comes last, because all the above procedures may have
# defined or overridden variables.
- &handle_variables;
+ $output_vars .= output_variables;
check_typos ();
# 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)
{
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, "
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)
{
# 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)
{
# 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')
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)
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.
# 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;
}
}
}
}
}
-
-
# 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);
}
$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!
}
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') || '';
}
################################################################
## ------------------------ ##
-# 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);
-}
-
-# ¯o_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)
- # @COND_TRUE@am__append_1 = 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
- # @COND_TRUE@FOO = foo1 bar
- # @COND_FALSE@FOO = 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;
- ¯o_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
- {
- ¯o_define ($var, $owner, '+', $vcond, $value, $comment,
- $where, $pretty);
- }
- }
- # Don't adjust the owner. The above ¯o_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;
-}
-
-
-# ¯o_delete ($VAR, [@CONDS])
-# ------------------------------
-# Forget about $VAR under the conditions @CONDS, or completely if
-# @CONDS is empty.
-sub macro_delete ($@)
-{
- my ($var, @conds) = @_;
-
- if (!@conds)
- {
- 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};
- }
- }
-}
-
-
-# ¯o_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;
-}
-
-
-# ¯os_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)
# ---------------------------
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)
# 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.
}
-# &variable_output ($VAR, [@CONDS])
-# ---------------------------------
-# 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
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;
}
}
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);
}
}
# &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 ($$)
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 = '';
}
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 = '';
}
# 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.
# 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.
$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.
}
-# 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;
- }
- }
-}
################################################################
$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
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
# 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
{
{
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.
# 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->rdef ($tmpcond)->location->clone;
# Append actual contents of where_PRIMARY variable to
# @result, skipping @substitutions@.
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);
}
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);
}
################################################################
{
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);
}
################################################################
-# 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 ()
{
--- /dev/null
+# 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';
+@ISA = qw/Exporter/;
+@EXPORT = 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 = '^[.A-Za-z0-9_@]+' . "\$";
+
+# 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)
+ # @COND_TRUE@am__append_1 = 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
+ # @COND_TRUE@FOO = foo1 bar
+ # @COND_FALSE@FOO = 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, [@conds])>
+
+Forget about C<$varname> under the conditions C<@conds>, or completely
+if C<@conds> is empty.
+
+=cut
+
+sub variable_delete ($@)
+{
+ my ($var, @conds) = @_;
+
+ if (!@conds)
+ {
+ 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)
+ {
+ $text .= " " . $vcond->human . " => " . $v->rdef ($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->rdef ($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->rdef ($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, [@conds])>
+
+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: