* lib/Automake/Rule.pm, lib/Automake/RuleDef.pm: New files.
* lib/Automake/Makefile.am (dist_perllib_DATA): Add them.
* lib/Automake/VarDef.pm: Make this a subclass of Automake::ItemDef.
(new): Adjust to call Automake::ItemDef::new.
(comment, location, owner): Delete. Now inherited from ItemDef.
* lib/Automake/Variable.pm: Make this a subclass of Automake::Item.
(_new): Adjust to call Automake::Item::new.
(name, def, rdef, _set, conditions, not_always_defined_in_cond):
Delete. How inherited from Item, where `_set' is called `set'.
* automake.in (SUFFIX_RULE_PATTERN): Delete. Now in Automake::Rule.
(suffix_rules_default): Delete. Now
Automake::Rule::_suffix_rules_default
(suffixes): Delete. Now Automake::Rule::suffixes.
(TARGET_AUTOMAKE, TARGET_USER): Delete. Now
Automake::RuleDef::RULE_AUTOMAKE and Automake::RuleDef::RULE_USER.
(%targets, %target_source, %target_name, %target_owner): Delete,
replaced by the Rule and RuleDef classes.
(dependencies, depend, actions): Delete. Now in Automake::Rule.
(suffix_rules, register_suffix_rule): Likewise.
(KNOWN_EXTENSIONS_PATTERN, accept_extensions): Likewise.
(known_extensions_list): Delete. Now
Automake::Rule::_known_extensions_list.
(target_conditions): Delete. Now inherited by Automake::Rule
from Automake::Item::conditions.
(rule_define): Delete. Now Automake::Rule::define. Adjust all
callers.
(target_defined): Delete. Now Automake::Rule::rule. Adjust all
callers.
(initialize_per_input): Adjust to call Automake::Rule::reset.
(err_target, err_cond_target, msg_cond_target, msg_target,
reject_target): Delete. Now defined in Automake::Rule as
err_rule, err_cond_rule, msg_cond_rule, msg_rule and reject_target.
Adjust all callers.
(handle_languages): Call suffix_rules_count.
* tests/location.test: Adjust expected diagnostics. We now display
$(EXEEXT) accurately.
+2003-08-12 Alexandre Duret-Lutz <adl@gnu.org>
+
+ * lib/Automake/Item.pm, lib/Automake/ItemDef.pm: New files.
+ * lib/Automake/Rule.pm, lib/Automake/RuleDef.pm: New files.
+ * lib/Automake/Makefile.am (dist_perllib_DATA): Add them.
+ * lib/Automake/VarDef.pm: Make this a subclass of Automake::ItemDef.
+ (new): Adjust to call Automake::ItemDef::new.
+ (comment, location, owner): Delete. Now inherited from ItemDef.
+ * lib/Automake/Variable.pm: Make this a subclass of Automake::Item.
+ (_new): Adjust to call Automake::Item::new.
+ (name, def, rdef, _set, conditions, not_always_defined_in_cond):
+ Delete. How inherited from Item, where `_set' is called `set'.
+ * automake.in (SUFFIX_RULE_PATTERN): Delete. Now in Automake::Rule.
+ (suffix_rules_default): Delete. Now
+ Automake::Rule::_suffix_rules_default
+ (suffixes): Delete. Now Automake::Rule::suffixes.
+ (TARGET_AUTOMAKE, TARGET_USER): Delete. Now
+ Automake::RuleDef::RULE_AUTOMAKE and Automake::RuleDef::RULE_USER.
+ (%targets, %target_source, %target_name, %target_owner): Delete,
+ replaced by the Rule and RuleDef classes.
+ (dependencies, depend, actions): Delete. Now in Automake::Rule.
+ (suffix_rules, register_suffix_rule): Likewise.
+ (KNOWN_EXTENSIONS_PATTERN, accept_extensions): Likewise.
+ (known_extensions_list): Delete. Now
+ Automake::Rule::_known_extensions_list.
+ (target_conditions): Delete. Now inherited by Automake::Rule
+ from Automake::Item::conditions.
+ (rule_define): Delete. Now Automake::Rule::define. Adjust all
+ callers.
+ (target_defined): Delete. Now Automake::Rule::rule. Adjust all
+ callers.
+ (initialize_per_input): Adjust to call Automake::Rule::reset.
+ (err_target, err_cond_target, msg_cond_target, msg_target,
+ reject_target): Delete. Now defined in Automake::Rule as
+ err_rule, err_cond_rule, msg_cond_rule, msg_rule and reject_target.
+ Adjust all callers.
+ (handle_languages): Call suffix_rules_count.
+ * tests/location.test: Adjust expected diagnostics. We now display
+ $(EXEEXT) accurately.
+
2003-08-10 Alexandre Duret-Lutz <adl@gnu.org>
Revert the fix for PR automake/291:
use Automake::Version;
use Automake::Variable;
use Automake::VarDef;
+use Automake::Rule;
+use Automake::RuleDef;
use Automake::Wrap 'makefile_wrap';
use File::Basename;
-use Tie::RefHash;
use Carp;
## ----------- ##
my $RULE_PATTERN =
"^($TARGET_PATTERN(?:(?:\\\\\n|\\s)+$TARGET_PATTERN)*) *:([^=].*|)\$";
-my $SUFFIX_RULE_PATTERN =
- '^(\.[a-zA-Z0-9_(){}$+@]+)(\.[a-zA-Z0-9_(){}$+@]+)' . "\$";
# 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.
# should distribute depcomp -- has been generated.)
my $automake_needs_to_reprocess_all_files = 0;
-# Same as $suffix_rules (declared below), but records only the
-# default rules supplied by the languages Automake supports.
-my $suffix_rules_default;
-
# If a file name appears as a key in this hash, then it has already
# been checked for. This variable is local to the "require file"
# functions.
my $output_all;
my $output_header;
-# Suffixes found during a run.
-my @suffixes;
-
-# 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
-# a trailing $(EXEEXT), we record this in %target_name.
-my %targets; tie %targets, 'Tie::RefHash::Nestable';
-
-# $target_source{TARGET}{COND} is the filename where TARGET
-# were defined for condition COND. Note this must be a
-# filename, *without* any line number.
-my %target_source; tie %target_source, 'Tie::RefHash::Nestable';
-
-# $target_name{TARGET}{COND} is the real name of TARGET (in condition COND).
-# The real name is often TARGET or TARGET$(EXEEXT), and TARGET never
-# contain $(EXEEXT)
-my %target_name; tie %target_name, 'Tie::RefHash::Nestable';
-
-# $target_owner{TARGET}{COND} the owner of TARGET in condition COND.
-my %target_owner; tie %target_owner, 'Tie::RefHash::Nestable';
-use constant TARGET_AUTOMAKE => 0; # Target defined by Automake.
-use constant TARGET_USER => 1; # Target defined in the user's Makefile.am.
-
# This is the conditional stack, updated on if/else/endif, and
# used to build Condition objects.
my @cond_stack;
my @check;
my @check_tests;
-# Holds the dependencies of targets which dependencies are factored.
-# Typically, `.PHONY' will appear in plenty of *.am files, but must
-# be output once. Arguably all pure dependencies could be subject
-# to this factorization, but it is not unpleasant to have paragraphs
-# in Makefile: keeping related stuff altogether.
-my %dependencies;
-
-# &depend ($CATEGORY, @DEPENDENDEES)
-# ----------------------------------
-# The target $CATEGORY depends on @DEPENDENDEES.
-sub depend ($@)
-{
- my ($category, @dependendees) = @_;
- push (@{$dependencies{$category}}, @dependendees);
-}
-
-
-# Holds the factored actions. Tied to %DEPENDENCIES, i.e., filled
-# only when keys exists in %DEPENDENCIES.
-my %actions;
-
# Keys in this hash table are files to delete. The associated
# value tells when this should happen (MOSTLY_CLEAN, DIST_CLEAN, etc.)
my %clean_files;
# trailing `/'.
my %de_ansi_files;
-# This maps the source extension for all suffix rule seen to
-# a \hash whose keys are the possible output extensions.
-#
-# Note that this is transitively closed by construction:
-# if we have
-# exists $suffix_rules{$ext1}{$ext2}
-# && exists $suffix_rules{$ext2}{$ext3}
-# then we also have
-# exists $suffix_rules{$ext1}{$ext3}
-#
-# So it's easy to check whether '.foo' can be transformed to '.$(OBJEXT)'
-# by checking whether $suffix_rules{'.foo'}{'.$(OBJEXT)'} exist. This
-# will work even if transforming '.foo' to '.$(OBJEXT)' involves a chain
-# of several suffix rules.
-#
-# The value of `$suffix_rules{$ext1}{$ext2}' is the a pair
-# `[ $next_sfx, $dist ]' where `$next_sfx' is target suffix
-# for the next rule to use to reach '$ext2', and `$dist' the
-# distance to `$ext2'.
-my $suffix_rules;
-
# This is the name of the redirect `all' target to use.
my $all_target;
################################################################
-# Pattern that matches all know input extensions (i.e. extensions used
-# by the languages supported by Automake). Using this pattern
-# (instead of `\..*$') to match extensions allows Automake to support
-# dot-less extensions.
-my $KNOWN_EXTENSIONS_PATTERN = "";
-my @known_extensions_list = ();
-
-# accept_extensions (@EXTS)
-# -------------------------
-# Update $KNOWN_EXTENSIONS_PATTERN to recognize the extensions
-# listed @EXTS. Extensions should contain a dot if needed.
-sub accept_extensions (@)
-{
- push @known_extensions_list, @_;
- $KNOWN_EXTENSIONS_PATTERN =
- '(?:' . join ('|', map (quotemeta, @known_extensions_list)) . ')';
-}
-
# var_SUFFIXES_trigger ($TYPE, $VALUE)
# ------------------------------------
-# This is called automagically by macro_define() when SUFFIXES
+# This is called by Automake::Variable::define() when SUFFIXES
# is defined ($TYPE eq '') or appended ($TYPE eq '+').
# The work here needs to be performed as a side-effect of the
# macro_define() call because SUFFIXES definitions impact
-# on $KNOWN_EXTENSIONS_PATTERN, and $KNOWN_EXTENSIONS_PATTERN
-# are used when parsing the input am file.
+# on $KNOWN_EXTENSIONS_PATTERN which is used used when parsing
+# the input am file.
sub var_SUFFIXES_trigger ($$)
{
my ($type, $value) = @_;
$output_all = '';
$output_header = '';
- @suffixes = ();
-
Automake::Options::reset;
Automake::Variable::reset;
-
- %targets = ();
- %target_source = ();
- %target_name = ();
- %target_owner = ();
+ Automake::Rule::reset;
@cond_stack = ();
@check = ();
@check_tests = ();
- %dependencies =
- (
- # Texinfoing.
- 'dvi' => [],
- 'dvi-am' => [],
- 'pdf' => [],
- 'pdf-am' => [],
- 'ps' => [],
- 'ps-am' => [],
- 'info' => [],
- 'info-am' => [],
- 'html' => [],
- 'html-am' => [],
-
- # Installing/uninstalling.
- 'install-data-am' => [],
- 'install-exec-am' => [],
- 'uninstall-am' => [],
-
- 'install-man' => [],
- 'uninstall-man' => [],
-
- 'install-info' => [],
- 'install-info-am' => [],
- 'uninstall-info' => [],
-
- 'installcheck-am' => [],
-
- # Cleaning.
- 'clean-am' => [],
- 'mostlyclean-am' => [],
- 'maintainer-clean-am' => [],
- 'distclean-am' => [],
- 'clean' => [],
- 'mostlyclean' => [],
- 'maintainer-clean' => [],
- 'distclean' => [],
-
- # Tarballing.
- 'dist-all' => [],
-
- # Phoning.
- '.PHONY' => []
- );
- %actions = ();
-
%clean_files = ();
@sources = ();
%de_ansi_files = ();
-
- # The first time we initialize the variables,
- # we save the value of $suffix_rules.
- if (defined $suffix_rules_default)
- {
- $suffix_rules = $suffix_rules_default;
- }
- else
- {
- $suffix_rules_default = $suffix_rules;
- }
-
$all_target = '';
%extension_seen = ();
# Error reporting functions.
-# err_target ($TARGETNAME, $MESSAGE, [%OPTIONS])
-# ----------------------------------------------
-# Uncategorized errors about targets.
-sub err_target ($$;%)
-{
- msg_target ('error', @_);
-}
-
-# err_cond_target ($COND, $TARGETNAME, $MESSAGE, [%OPTIONS])
-# ----------------------------------------------------------
-# Uncategorized errors about conditional targets.
-sub err_cond_target ($$$;%)
-{
- msg_cond_target ('error', @_);
-}
-
# err_am ($MESSAGE, [%OPTIONS])
# -----------------------------
# Uncategorized errors about the current Makefile.am.
msg_ac ('error', @_);
}
-# msg_cond_target ($CHANNEL, $COND, $TARGETNAME, $MESSAGE, [%OPTIONS])
-# --------------------------------------------------------------------
-# Messages about conditional targets.
-sub msg_cond_target ($$$$;%)
-{
- my ($channel, $cond, $target, $msg, %opts) = @_;
- msg $channel, $targets{$target}{$cond}, $msg, %opts;
-}
-
-# msg_target ($CHANNEL, $TARGETNAME, $MESSAGE, [%OPTIONS])
-# --------------------------------------------------------
-# Messages about targets.
-sub msg_target ($$$;%)
-{
- my ($channel, $target, $msg, %opts) = @_;
- # Don't know which condition is concerned. Pick any.
- my $cond = target_conditions ($target)->one_cond;
- msg_cond_target ($channel, $cond, $target, $msg, %opts);
-}
-
# msg_am ($CHANNEL, $MESSAGE, [%OPTIONS])
# ---------------------------------------
# Messages about about the current Makefile.am.
msg $channel, $configure_ac, $msg, %opts;
}
-# $BOOL
-# reject_target ($VAR, $ERROR_MSG)
-# --------------------------------
-sub reject_target ($$)
-{
- my ($target, $msg) = @_;
- if (target_defined ($target))
- {
- err_target $target, $msg;
- return 1;
- }
- return 0;
-}
-
################################################################
# subst ($TEXT)
# suffix rule was learned), don't bother with the C stuff. But if
# anything else creeps in, then use it.
$needs_c = 1
- if $need_link || ((scalar keys %$suffix_rules)
- - (scalar keys %$suffix_rules_default)) > 1;
+ if $need_link || suffix_rules_count > 1;
if ($needs_c)
{
{
if (-f ($relative_dir . "/" . $cfile)
# The file might be absent, but if it can be built it's ok.
- || exists $targets{$cfile})
+ || rule $cfile)
{
&push_dist_common ($cfile);
}
}
# Rule to check whether a distribution is viable.
- my %transform = ('DISTCHECK-HOOK' => &target_defined ('distcheck-hook'),
+ my %transform = ('DISTCHECK-HOOK' => !! rule 'distcheck-hook',
'GETTEXT' => $seen_gettext && !$seen_gettext_external);
# Prepend $(distdir) to each directory given.
# allows users to do random weird things to the distribution
# before it is packaged up.
push (@dist_targets, 'dist-hook')
- if &target_defined ('dist-hook');
+ if rule 'dist-hook';
$transform{'DIST-TARGETS'} = join(' ', @dist_targets);
$output_rules .= &file_contents ('distdir',
$output_vars .= 'SOURCES = ' . variable_value ('SOURCES') . "\n\n"
if variable_value ('SOURCES');
- reject_target ('.SUFFIXES',
- "use variable `SUFFIXES', not target `.SUFFIXES'");
+ reject_rule ('.SUFFIXES',
+ "use variable `SUFFIXES', not target `.SUFFIXES'");
# Note: AIX 4.1 /bin/make will fail if any suffix rule appears
# before .SUFFIXES. So we make sure that .SUFFIXES appears before
# anything else, by sticking it right after the default: target.
$output_header .= ".SUFFIXES:\n";
my $suffixes = var 'SUFFIXES';
+ my @suffixes = Automake::Rule::suffixes;
if (@suffixes || $suffixes)
{
- # Make sure suffixes has unique elements. Sort them to ensure
+ # Make sure SUFFIXES has unique elements. Sort them to ensure
# the output remains consistent. However, $(SUFFIXES) is
# always at the start of the list, unsorted. This is done
# because make will choose rules depending on the ordering of
? (" \$(BUILT_SOURCES)\n"
. "\t\$(MAKE) \$(AM_MAKEFLAGS)")
: ''),
- 'installdirs-local' => (target_defined ('installdirs-local')
+ 'installdirs-local' => (rule 'installdirs-local'
? ' installdirs-local' : ''),
am__installdirs => variable_value ('am__installdirs') || '');
}
}
# Install `all' hooks.
- if (&target_defined ("all-local"))
+ if (rule "all-local")
{
push (@all, "all-local");
&depend ('.PHONY', "all-local");
# Handle check merge target specially.
sub do_check_merge_target ()
{
- if (target_defined ('check-local'))
+ if (rule 'check-local')
{
# User defined local form of target. So include it.
push @check_tests, 'check-local';
{
my $x = $utarg;
$x =~ s/(data|exec)-//;
- reject_target ($utarg, "use `$x', not `$utarg'");
+ reject_rule ($utarg, "use `$x', not `$utarg'");
}
- reject_target ('install-local',
- "use `install-data-local' or `install-exec-local', "
- . "not `install-local'");
+ reject_rule ('install-local',
+ "use `install-data-local' or `install-exec-local', "
+ . "not `install-local'");
- reject_target ('install-info-local',
- "`install-info-local' target defined but "
- . "`no-installinfo' option not in use")
+ reject_rule ('install-info-local',
+ "`install-info-local' target defined but "
+ . "`no-installinfo' option not in use")
unless option 'no-installinfo';
# Install the -local hooks.
{
# Hooks are installed on the -am targets.
s/-am$// or next;
- if (&target_defined ("$_-local"))
+ if (rule "$_-local")
{
depend ("$_-am", "$_-local");
- &depend ('.PHONY', "$_-local");
+ depend ('.PHONY', "$_-local");
}
}
# FIXME: Why not be as liberal as we are with -local hooks?
foreach ('install-exec', 'install-data', 'uninstall')
{
- if (&target_defined ("$_-hook"))
+ if (rule ("$_-hook"))
{
$actions{"$_-am"} .=
("\t\@\$(NORMAL_INSTALL)\n"
if ($_ ne '.PHONY')
{
@undefined_conds =
- rule_define ($_, 'internal', TARGET_AUTOMAKE, TRUE, INTERNAL);
+ Automake::Rule::define ($_, 'internal',
+ RULE_AUTOMAKE, TRUE, INTERNAL);
}
my @uniq_deps = uniq (sort @{$dependencies{$_}});
foreach my $cond (@undefined_conds)
{
foreach my $dest (&{$lang->output_extensions} ($suffix))
{
- ®ister_suffix_rule ('internal', $suffix, $dest);
+ register_suffix_rule (INTERNAL, $suffix, $dest);
}
}
}
## ------------------------ ##
-# @CONDS
-# target_conditions ($TARGET)
-# ---------------------------
-# Get the list of conditions that a target is defined with.
-sub target_conditions ($)
-{
- my ($target) = @_;
- my @conds = keys %{$targets{$target}};
- return new Automake::DisjConditions @conds;
-}
-
-
# &define_pretty_variable ($VAR, $COND, $WHERE, @VALUE)
# -----------------------------------------------------
# Like define_variable, but the value is a list, and the variable may
################################################################
-## ---------------- ##
-## Handling rules. ##
-## ---------------- ##
-
-sub register_suffix_rule ($$$)
-{
- my ($where, $src, $dest) = @_;
-
- verb "Sources ending in $src become $dest";
- push @suffixes, $src, $dest;
-
- # When tranforming sources to objects, Automake uses the
- # %suffix_rules to move from each source extension to
- # `.$(OBJEXT)', not to `.o' or `.obj'. However some people
- # define suffix rules for `.o' or `.obj', so internally we will
- # consider these extensions equivalent to `.$(OBJEXT)'. We
- # CANNOT rewrite the target (i.e., automagically replace `.o'
- # and `.obj' by `.$(OBJEXT)' in the output), or warn the user
- # that (s)he'd better use `.$(OBJEXT)', because Automake itself
- # output suffix rules for `.o' or `.obj'...
- $dest = '.$(OBJEXT)' if ($dest eq '.o' || $dest eq '.obj');
-
- # Reading the comments near the declaration of $suffix_rules might
- # help to understand the update of $suffix_rules that follows...
-
- # Register $dest as a possible destination from $src.
- # We might have the create the \hash.
- if (exists $suffix_rules->{$src})
- {
- $suffix_rules->{$src}{$dest} = [ $dest, 1 ];
- }
- else
- {
- $suffix_rules->{$src} = { $dest => [ $dest, 1 ] };
- }
-
- # If we know how to transform $dest in something else, then
- # we know how to transform $src in that "something else".
- if (exists $suffix_rules->{$dest})
- {
- for my $dest2 (keys %{$suffix_rules->{$dest}})
- {
- my $dist = $suffix_rules->{$dest}{$dest2}[1] + 1;
- # Overwrite an existing $src->$dest2 path only if
- # the path via $dest which is shorter.
- if (! exists $suffix_rules->{$src}{$dest2}
- || $suffix_rules->{$src}{$dest2}[1] > $dist)
- {
- $suffix_rules->{$src}{$dest2} = [ $dest, $dist ];
- }
- }
- }
-
- # Similarly, any extension that can be derived into $src
- # can be derived into the same extenstions as $src can.
- my @dest2 = keys %{$suffix_rules->{$src}};
- for my $src2 (keys %$suffix_rules)
- {
- if (exists $suffix_rules->{$src2}{$src})
- {
- for my $dest2 (@dest2)
- {
- my $dist = $suffix_rules->{$src}{$dest2} + 1;
- # Overwrite an existing $src2->$dest2 path only if
- # the path via $src is shorter.
- if (! exists $suffix_rules->{$src2}{$dest2}
- || $suffix_rules->{$src2}{$dest2}[1] > $dist)
- {
- $suffix_rules->{$src2}{$dest2} = [ $src, $dist ];
- }
- }
- }
- }
-}
-
-# @CONDS
-# rule_define ($TARGET, $SOURCE, $OWNER, $COND, $WHERE)
-# -----------------------------------------------------
-# Define a new rule. $TARGET is the rule name. $SOURCE
-# is the filename the rule comes from. $OWNER is the
-# owner of the rule (TARGET_AUTOMAKE or TARGET_USER).
-# $COND is the Condition under which the rule is defined.
-# $WHERE is the Location where the rule is defined.
-# Returns a (possibly empty) list of Conditions where the rule
-# should be defined.
-sub rule_define ($$$$$)
-{
- my ($target, $source, $owner, $cond, $where) = @_;
-
- prog_error "$where is not a reference"
- unless ref $where;
- prog_error "$cond is not a reference"
- unless ref $cond;
-
- # Don't even think about defining a rule in condition FALSE.
- return () if $cond == FALSE;
-
- # For now `foo:' will override `foo$(EXEEXT):'. This is temporary,
- # though, so we emit a warning.
- (my $noexe = $target) =~ s,\$\(EXEEXT\)$,,;
- if ($noexe ne $target
- && exists $targets{$noexe}
- && exists $targets{$noexe}{$cond}
- && $target_name{$noexe}{$cond} ne $target)
- {
- # The no-exeext option enables this feature.
- if (! option 'no-exeext')
- {
- msg ('obsolete', $targets{$noexe}{$cond},
- "deprecated feature: target `$noexe' overrides "
- . "`$noexe\$(EXEEXT)'\n"
- . "change your target to read `$noexe\$(EXEEXT)'");
- msg ('obsolete', $where, "target `$target' was defined here");
- }
- # Don't `return ()' now, as this might hide target clashes
- # detected below.
- }
-
- # For now on, strip off $(EXEEXT) from $target, so we can diagnose
- # a clash if `ctags$(EXEEXT):' is redefined after `ctags:'.
- my $realtarget = $target;
- $target = $noexe;
-
- # A GNU make-style pattern rule has a single "%" in the target name.
- msg ('portability', $where,
- "`%'-style pattern rules are a GNU make extension")
- if $target =~ /^[^%]*%[^%]*$/;
-
- # Diagnose target redefinitions.
- if (exists $target_source{$target}{$cond})
- {
- # Sanity checks.
- prog_error ("\$target_source{$target}{$cond} exists, but \$target_owner"
- . " doesn't.")
- unless exists $target_owner{$target}{$cond};
- prog_error ("\$target_source{$target}{$cond} exists, but \$targets"
- . " doesn't.")
- unless exists $targets{$target}{$cond};
- prog_error ("\$target_source{$target}{$cond} exists, but \$target_name"
- . " doesn't.")
- unless exists $target_name{$target}{$cond};
-
- my $oldowner = $target_owner{$target}{$cond};
-
- # Don't mention true conditions in diagnostics.
- my $condmsg =
- $cond == TRUE ? '' : " in condition `" . $cond->human . "'";
-
- if ($owner == TARGET_USER)
- {
- if ($oldowner == TARGET_USER)
- {
- # Ignore `%'-style pattern rules. We'd need the
- # dependencies to detect duplicates, and they are
- # already diagnosed as unportable by -Wportability.
- if ($target !~ /^[^%]*%[^%]*$/)
- {
- ## FIXME: Presently we can't diagnose duplcate user rules
- ## because we doesn't distinguish rules with commands
- ## from rules that only add dependencies. E.g.,
- ## .PHONY: foo
- ## .PHONY: bar
- ## is legitimate. (This is phony.test.)
-
- # msg ('syntax', $where,
- # "redefinition of `$target'$condmsg...", partial => 1);
- # msg_cond_target ('syntax', $cond, $target,
- # "... `$target' previously defined here");
- }
- # Return so we don't redefine the rule in our tables,
- # don't check for ambiguous condition, etc. The rule
- # will be output anyway beauce &read_am_file ignore the
- # return code.
- return ();
- }
- else
- {
- # Since we parse the user Makefile.am before reading
- # the Automake fragments, this condition should never happen.
- prog_error ("user target `$target' seen after Automake's "
- . "definition\nfrom `$targets{$target}$condmsg'");
- }
- }
- else # $owner == TARGET_AUTOMAKE
- {
- if ($oldowner == TARGET_USER)
- {
- # -am targets listed in %dependencies support a -local
- # variant. If the user tries to override TARGET or
- # TARGET-am for which there exists a -local variant,
- # just tell the user to use it.
- my $hint = 0;
- my $noam = $target;
- $noam =~ s/-am$//;
- if (exists $dependencies{"$noam-am"})
- {
- $hint = "consider using $target-local instead of $target";
- }
-
- msg_cond_target ('override', $cond, $target,
- "user target `$target' defined here"
- . "$condmsg...", partial => 1);
- msg ('override', $where,
- "... overrides Automake target `$target' defined here",
- partial => $hint);
- msg_cond_target ('override', $cond, $target, $hint)
- if $hint;
-
- # Don't overwrite the user definition of TARGET.
- return ();
- }
- else # $oldowner == TARGET_AUTOMAKE
- {
- # Automake should ignore redefinitions of its own
- # rules if they came from the same file. This makes
- # it easier to process a Makefile fragment several times.
- # Hower it's an error if the target is defined in many
- # files. E.g., the user might be using bin_PROGRAMS = ctags
- # which clashes with our `ctags' rule.
- # (It would be more accurate if we had a way to compare
- # the *content* of both rules. Then $targets_source would
- # be useless.)
- my $oldsource = $target_source{$target}{$cond};
- return () if $source eq $oldsource;
-
- msg ('syntax', $where, "redefinition of `$target'$condmsg...",
- partial => 1);
- msg_cond_target ('syntax', $cond, $target,
- "... `$target' previously defined here");
- return ();
- }
- }
- # Never reached.
- prog_error ("Unreachable place reached.");
- }
-
- # Conditions for which the rule should be defined.
- my @conds = $cond;
-
- # Check ambiguous conditional definitions.
- my ($message, $ambig_cond) =
- target_conditions ($target)->ambiguous_p ($target, $cond);
- if ($message) # We have an ambiguty.
- {
- if ($owner == TARGET_USER)
- {
- # For user rules, just diagnose the ambiguity.
- msg 'syntax', $where, "$message ...", partial => 1;
- msg_cond_target ('syntax', $ambig_cond, $target,
- "... `$target' previously defined here");
- return ();
- }
- else
- {
- # FIXME: for Automake rules, we can't diagnose ambiguities yet.
- # The point is that Automake doesn't propagate conditions
- # everywhere. For instance &handle_PROGRAMS doesn't care if
- # bin_PROGRAMS was defined conditionally or not.
- # On the following input
- # if COND1
- # foo:
- # ...
- # else
- # bin_PROGRAMS = foo
- # endif
- # &handle_PROGRAMS will attempt to define a `foo:' rule
- # in condition TRUE (which conflicts with COND1). Fixing
- # this in &handle_PROGRAMS and siblings seems hard: you'd
- # have to explain &file_contents what to do with a
- # condition. So for now we do our best *here*. If `foo:'
- # was already defined in condition COND1 and we want to define
- # it in condition TRUE, then define it only in condition !COND1.
- # (See cond14.test and cond15.test for some test cases.)
- my $defined_conds = target_conditions ($target);
- @conds = ();
- for my $undefined_cond ($defined_conds->invert->conds)
- {
- push @conds, $cond->merge ($undefined_cond);
- }
- # No conditions left to define the rule.
- # Warn, because our workaround is meaningless in this case.
- if (scalar @conds == 0)
- {
- msg 'syntax', $where, "$message ...", partial => 1;
- msg_cond_target ('syntax', $ambig_cond, $target,
- "... `$target' previously defined here");
- return ();
- }
- }
- }
-
- # Finally define this rule.
- for my $c (@conds)
- {
- $targets{$target}{$c} = $where->clone;
- $target_source{$target}{$c} = $source;
- $target_owner{$target}{$c} = $owner;
- $target_name{$target}{$c} = $realtarget;
- }
-
- # We honor inference rules with multiple targets because many
- # make support this and people use it. However this is disallowed
- # by POSIX. We'll print a warning later.
- my $target_count = 0;
- my $inference_rule_count = 0;
- for my $t (split (' ', $target))
- {
- ++$target_count;
- # Check the rule for being a suffix rule. If so, store in a hash.
- # Either it's a rule for two known extensions...
- if ($t =~ /^($KNOWN_EXTENSIONS_PATTERN)($KNOWN_EXTENSIONS_PATTERN)$/
- # ...or it's a rule with unknown extensions (.i.e, the rule
- # looks like `.foo.bar:' but `.foo' or `.bar' are not
- # declared in SUFFIXES and are not known language
- # extensions). Automake will complete SUFFIXES from
- # @suffixes automatically (see handle_footer).
- || ($t =~ /$SUFFIX_RULE_PATTERN/o && accept_extensions($1)))
- {
- ++$inference_rule_count;
- register_suffix_rule ($where, $1, $2);
- }
- }
-
- # POSIX allow multiple targets befor the colon, but disallow
- # definitions of multiple Inference rules. It's also
- # disallowed to mix plain targets with inference rules.
- msg ('portability', $where,
- "Inference rules can have only one target before the colon (POSIX).")
- if $inference_rule_count > 0 && $target_count > 1;
-
- return @conds;
-}
-
-
-# See if a target exists.
-sub target_defined
-{
- my ($target) = @_;
- return exists $targets{$target};
-}
-
-
-################################################################
-
# &check_trailing_slash ($WHERE, $LINE)
# --------------------------------------
# Return 1 iff $LINE ends with a slash.
# For now we have to output all definitions of user rules
# and can't diagnose duplicates (see the comment in
# rule_define). So we go on and ignore the return value.
- rule_define ($1, $amfile, TARGET_USER, $cond, $where);
+ Automake::Rule::define ($1, $amfile, RULE_USER, $cond, $where);
check_variable_expansions ($_, $where);
# Free-lance dependency. Output the rule for all the
# targets instead of one by one.
my @undefined_conds =
- rule_define ($targets, $file,
- $is_am ? TARGET_AUTOMAKE : TARGET_USER,
- $cond, $where);
+ Automake::Rule::define ($targets, $file,
+ $is_am ? RULE_AUTOMAKE : RULE_USER,
+ $cond, $where);
for my $undefined_cond (@undefined_conds)
{
my $condparagraph = $paragraph;
# the Makefile, don't print anything. This allows files
# like README, AUTHORS, or THANKS to be generated.
next
- if !$suppress && target_defined ($file);
+ if !$suppress && rule $file;
msg ($suppress ? 'note' : 'error', $where, "$message$trailer");
}
--- /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::Item;
+use strict;
+use Carp;
+
+use Automake::ChannelDefs;
+use Automake::DisjConditions;
+
+=head1 NAME
+
+Automake::Item - base class for Automake::Variable and Automake::Rule
+
+=head1 DESCRIPTION
+
+=head2 Methods
+
+=over 4
+
+=item C<new Automake::Item $name>
+
+Create and return an empty Item called C<$name>.
+
+=cut
+
+sub new ($$)
+{
+ my ($class, $name) = @_;
+ my $self = {
+ name => $name,
+ defs => {},
+ conds => {},
+ };
+ bless $self, $class;
+ return $self;
+}
+
+=item C<$item-E<gt>name>
+
+Return the name of C<$item>.
+
+=cut
+
+sub name ($)
+{
+ my ($self) = @_;
+ return $self->{'name'};
+}
+
+=item C<$item-E<gt>def ($cond)>
+
+Return the definition for this item in condition C<$cond>, if it
+exists. Return 0 otherwise.
+
+=cut
+
+sub def ($$)
+{
+ my ($self, $cond) = @_;
+ return $self->{'defs'}{$cond} if exists $self->{'defs'}{$cond};
+ return 0;
+}
+
+=item C<$item-E<gt>rdef ($cond)>
+
+Return the definition for this item in condition C<$cond>. Abort with
+an internal error if the item 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" . $self->dump)
+ unless $d;
+ return $d;
+}
+
+=item C<$item-E<gt>set ($cond, $def)>
+
+Add a new definition to an existing item.
+
+=cut
+
+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 an item is defined in.
+
+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'}});
+}
+
+=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);
+}
+
+
+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:
--- /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::ItemDef;
+use strict;
+use Carp;
+
+=head1 NAME
+
+Automake::ItemDef - base class for Automake::VarDef and Automake::RuleDef
+
+=head1 DESCRIPTION
+
+=head2 Methods
+
+=over 4
+
+=item C<my $def = Automake::new ($comment, $location, $owner)>
+
+Create a new Makefile-item definition.
+
+C<$comment> is any comment preceding the definition. (Because
+Automake reorders items 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<$owner> specifies who owns the rule.
+
+=cut
+
+sub new ($$$$)
+{
+ my ($class, $comment, $location, $owner) = @_;
+
+ my $self = {
+ comment => $comment,
+ location => $location,
+ owner => $owner,
+ };
+ bless $self, $class;
+
+ return $self;
+}
+
+=item C<$def-E<gt>comment>
+
+=item C<$def-E<gt>location>
+
+=item C<$def-E<gt>owner>
+
+Accessors to the various constituents of an C<ItemDef>. See the
+documentation of C<new>'s arguments for a description of these.
+
+=cut
+
+sub comment ($)
+{
+ my ($self) = @_;
+ return $self->{'comment'};
+}
+
+sub location ($)
+{
+ my ($self) = @_;
+ return $self->{'location'};
+}
+
+sub owner ($)
+{
+ my ($self) = @_;
+ return $self->{'owner'};
+}
+
+=head1 SEE ALSO
+
+L<Automake::VarDef>, and L<Automake::RuleDef>.
+
+=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:
DisjConditions.pm \
FileUtils.pm \
General.pm \
+ Item.pm \
+ ItemDef.pm \
Location.pm \
Options.pm \
+ Rule.pm \
+ RuleDef.pm \
Struct.pm \
Variable.pm \
VarDef.pm \
DisjConditions.pm \
FileUtils.pm \
General.pm \
+ Item.pm \
+ ItemDef.pm \
Location.pm \
Options.pm \
+ Rule.pm \
+ RuleDef.pm \
Struct.pm \
Variable.pm \
VarDef.pm \
--- /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::Rule;
+use strict;
+use Carp;
+
+use Automake::Item;
+use Automake::RuleDef;
+use Automake::ChannelDefs;
+use Automake::Channels;
+use Automake::Options;
+use Automake::Condition qw (TRUE FALSE);
+use Automake::DisjConditions;
+require Exporter;
+use vars '@ISA', '@EXPORT', '@EXPORT_OK';
+@ISA = qw/Automake::Item Exporter/;
+@EXPORT = qw (reset register_suffix_rule suffix_rules_count
+ suffixes rules $suffix_rules $KNOWN_EXTENSIONS_PATTERN
+ depend %dependencies %actions accept_extensions
+ reject_rule msg_rule msg_cond_rule err_rule err_cond_rule
+ rule rrule ruledef rruledef);
+
+=head1 NAME
+
+Automake::Rule - support for rules definitions
+
+=head1 SYNOPSIS
+
+ use Automake::Rule;
+ use Automake::RuleDef;
+
+
+=head1 DESCRIPTION
+
+This package provides support for Makefile rule definitions.
+
+An C<Automake::Rule> is a rule name associated to possibly
+many conditional definitions. These definitions are instances
+of C<Automake::RuleDef>.
+
+Therefore obtaining the value of a rule under a given
+condition involves two lookups. One to look up the rule,
+and one to look up the conditional definition:
+
+ my $rule = rule $name;
+ if ($rule)
+ {
+ my $def = $rule->def ($cond);
+ if ($def)
+ {
+ return $def->location;
+ }
+ ...
+ }
+ ...
+
+when it is known that the rule and the definition
+being looked up exist, the above can be simplified to
+
+ return rule ($name)->def ($cond)->location; # do not write this.
+
+but is better written
+
+ return rrule ($name)->rrule ($cond)->location;
+
+or even
+
+ return rruledef ($name, $cond)->location;
+
+The I<r> variants of the C<rule>, C<def>, and C<ruledef> methods add
+an extra test to ensure that the lookup succeeded, and will diagnose
+failures as internal errors (with a message which is much more
+informative than Perl's warning about calling a method on a
+non-object).
+
+=head2 Global variables
+
+=over 4
+
+=cut
+
+my $_SUFFIX_RULE_PATTERN =
+ '^(\.[a-zA-Z0-9_(){}$+@]+)(\.[a-zA-Z0-9_(){}$+@]+)' . "\$";
+
+# Suffixes found during a run.
+use vars '@_suffixes';
+
+# Same as $suffix_rules (declared below), but records only the
+# default rules supplied by the languages Automake supports.
+use vars '$_suffix_rules_default';
+
+=item C<%dependencies>
+
+Holds the dependencies of targets which dependencies are factored.
+Typically, C<.PHONY> will appear in plenty of F<*.am> files, but must
+be output once. Arguably all pure dependencies could be subject to
+this factorization, but it is not unpleasant to have paragraphs in
+Makefile: keeping related stuff altogether.
+
+=cut
+
+use vars '%dependencies';
+
+=item <%actions>
+
+Holds the factored actions. Tied to C<%dependencies>, i.e., filled
+only when keys exists in C<%dependencies>.
+
+=cut
+
+use vars '%actions';
+
+=item <$suffix_rules>
+
+This maps the source extension for all suffix rule seen to
+a C<\hash> whose keys are the possible output extensions.
+
+Note that this is transitively closed by construction:
+if we have
+ exists $suffix_rules{$ext1}{$ext2}
+ && exists $suffix_rules{$ext2}{$ext3}
+then we also have
+ exists $suffix_rules{$ext1}{$ext3}
+
+So it's easy to check whether C<.foo> can be transformed to
+C<.$(OBJEXT)> by checking whether
+C<$suffix_rules{'.foo'}{'.$(OBJEXT)'}> exists. This will work even if
+transforming C<.foo> to C<.$(OBJEXT)> involves a chain of several
+suffix rules.
+
+The value of C<$suffix_rules{$ext1}{$ext2}> is the a pair
+C<[ $next_sfx, $dist ]> where C<$next_sfx> is target suffix
+for the next rule to use to reach C<$ext2>, and C<$dist> the
+distance to C<$ext2'>.
+
+The content of this variable should be updated via the
+C<register_suffix_rule> function.
+
+=cut
+
+use vars '$suffix_rules';
+
+=item C<$KNOWN_EXTENSIONS_PATTERN>
+
+Pattern that matches all know input extensions (i.e. extensions used
+by the languages supported by Automake). Using this pattern (instead
+of `\..*$') to match extensions allows Automake to support dot-less
+extensions.
+
+New extension should be registered with C<accept_extensions>.
+
+=cut
+
+use vars qw ($KNOWN_EXTENSIONS_PATTERN @_known_extensions_list);
+$KNOWN_EXTENSIONS_PATTERN = "";
+@_known_extensions_list = ();
+
+=back
+
+=head2 Error reporting functions
+
+In these functions, C<$rule> can be either a rule name, or
+an instance of C<Automake::Rule>.
+
+=over 4
+
+=item C<err_rule ($rule, $message, [%options])>
+
+Uncategorized errors about rules.
+
+=cut
+
+sub err_rule ($$;%)
+{
+ msg_rule ('error', @_);
+}
+
+=item C<err_cond_rule ($cond, $rule, $message, [%options])>
+
+Uncategorized errors about conditional rules.
+
+=cut
+
+sub err_cond_rule ($$$;%)
+{
+ msg_cond_rule ('error', @_);
+}
+
+=item C<msg_cond_rule ($channel, $cond, $rule, $message, [%options])>
+
+Messages about conditional rules.
+
+=cut
+
+sub msg_cond_rule ($$$$;%)
+{
+ my ($channel, $cond, $rule, $msg, %opts) = @_;
+ my $r = ref ($rule) ? $rule : rrule ($rule);
+ msg $channel, $r->rdef ($cond)->location, $msg, %opts;
+}
+
+=item C<msg_rule ($channel, $targetname, $message, [%options])>
+
+Messages about rules.
+
+=cute
+
+sub msg_rule ($$$;%)
+{
+ my ($channel, $rule, $msg, %opts) = @_;
+ my $r = ref ($rule) ? $rule : rrule ($rule);
+ # Don't know which condition is concerned. Pick any.
+ my $cond = $r->conditions->one_cond;
+ msg_cond_rule ($channel, $cond, $r, $msg, %opts);
+}
+
+
+=item C<$bool = reject_rule ($rule, $error_msg)>
+
+Bail out with C<$error_msg> if a rule with name C<$rule> has been
+defined.
+
+Return true iff C<$rule> is defined.
+
+=cut
+
+sub reject_rule ($$)
+{
+ my ($rule, $msg) = @_;
+ if (rule ($rule))
+ {
+ err_rule $rule, $msg;
+ return 1;
+ }
+ return 0;
+}
+
+=back
+
+=head2 Administrative functions
+
+=over 4
+
+=item C<accept_extensions (@exts)>
+
+Update C<$KNOWN_EXTENSIONS_PATTERN> to recognize the extensions
+listed C<@exts>. Extensions should contain a dot if needed.
+
+=cut
+
+sub accept_extensions (@)
+{
+ push @_known_extensions_list, @_;
+ $KNOWN_EXTENSIONS_PATTERN =
+ '(?:' . join ('|', map (quotemeta, @_known_extensions_list)) . ')';
+}
+
+=item C<rules>
+
+Returns the list of all L<Automake::Rule> instances. (I.e., all
+rules defined so far.)
+
+=cut
+
+use vars '%_rule_dict';
+sub rules ()
+{
+ return values %_rule_dict;
+}
+
+
+=item C<Automake::Rule::reset>
+
+The I<forget all> function. Clears all know rules and reset some
+other internal data.
+
+=cut
+
+sub reset()
+{
+ %_rule_dict = ();
+ @_suffixes = ();
+ # The first time we initialize the variables,
+ # we save the value of $suffix_rules.
+ if (defined $_suffix_rules_default)
+ {
+ $suffix_rules = $_suffix_rules_default;
+ }
+ else
+ {
+ $_suffix_rules_default = $suffix_rules;
+ }
+
+ %dependencies =
+ (
+ # Texinfoing.
+ 'dvi' => [],
+ 'dvi-am' => [],
+ 'pdf' => [],
+ 'pdf-am' => [],
+ 'ps' => [],
+ 'ps-am' => [],
+ 'info' => [],
+ 'info-am' => [],
+ 'html' => [],
+ 'html-am' => [],
+
+ # Installing/uninstalling.
+ 'install-data-am' => [],
+ 'install-exec-am' => [],
+ 'uninstall-am' => [],
+
+ 'install-man' => [],
+ 'uninstall-man' => [],
+
+ 'install-info' => [],
+ 'install-info-am' => [],
+ 'uninstall-info' => [],
+
+ 'installcheck-am' => [],
+
+ # Cleaning.
+ 'clean-am' => [],
+ 'mostlyclean-am' => [],
+ 'maintainer-clean-am' => [],
+ 'distclean-am' => [],
+ 'clean' => [],
+ 'mostlyclean' => [],
+ 'maintainer-clean' => [],
+ 'distclean' => [],
+
+ # Tarballing.
+ 'dist-all' => [],
+
+ # Phoning.
+ '.PHONY' => [],
+ );
+ %actions = ();
+}
+
+=item C<register_suffix_rule ($where, $src, $dest)>
+
+Register a suffix rules defined on C<$where> that transform
+files ending in C<$src> into files ending in C<$dest>.
+
+This upgrades the C<$suffix_rules> variables.
+
+=cut
+
+sub register_suffix_rule ($$$)
+{
+ my ($where, $src, $dest) = @_;
+
+ verb "Sources ending in $src become $dest";
+ push @_suffixes, $src, $dest;
+
+ # When tranforming sources to objects, Automake uses the
+ # %suffix_rules to move from each source extension to
+ # `.$(OBJEXT)', not to `.o' or `.obj'. However some people
+ # define suffix rules for `.o' or `.obj', so internally we will
+ # consider these extensions equivalent to `.$(OBJEXT)'. We
+ # CANNOT rewrite the target (i.e., automagically replace `.o'
+ # and `.obj' by `.$(OBJEXT)' in the output), or warn the user
+ # that (s)he'd better use `.$(OBJEXT)', because Automake itself
+ # output suffix rules for `.o' or `.obj'...
+ $dest = '.$(OBJEXT)' if ($dest eq '.o' || $dest eq '.obj');
+
+ # Reading the comments near the declaration of $suffix_rules might
+ # help to understand the update of $suffix_rules that follows...
+
+ # Register $dest as a possible destination from $src.
+ # We might have the create the \hash.
+ if (exists $suffix_rules->{$src})
+ {
+ $suffix_rules->{$src}{$dest} = [ $dest, 1 ];
+ }
+ else
+ {
+ $suffix_rules->{$src} = { $dest => [ $dest, 1 ] };
+ }
+
+ # If we know how to transform $dest in something else, then
+ # we know how to transform $src in that "something else".
+ if (exists $suffix_rules->{$dest})
+ {
+ for my $dest2 (keys %{$suffix_rules->{$dest}})
+ {
+ my $dist = $suffix_rules->{$dest}{$dest2}[1] + 1;
+ # Overwrite an existing $src->$dest2 path only if
+ # the path via $dest which is shorter.
+ if (! exists $suffix_rules->{$src}{$dest2}
+ || $suffix_rules->{$src}{$dest2}[1] > $dist)
+ {
+ $suffix_rules->{$src}{$dest2} = [ $dest, $dist ];
+ }
+ }
+ }
+
+ # Similarly, any extension that can be derived into $src
+ # can be derived into the same extenstions as $src can.
+ my @dest2 = keys %{$suffix_rules->{$src}};
+ for my $src2 (keys %$suffix_rules)
+ {
+ if (exists $suffix_rules->{$src2}{$src})
+ {
+ for my $dest2 (@dest2)
+ {
+ my $dist = $suffix_rules->{$src}{$dest2} + 1;
+ # Overwrite an existing $src2->$dest2 path only if
+ # the path via $src is shorter.
+ if (! exists $suffix_rules->{$src2}{$dest2}
+ || $suffix_rules->{$src2}{$dest2}[1] > $dist)
+ {
+ $suffix_rules->{$src2}{$dest2} = [ $src, $dist ];
+ }
+ }
+ }
+ }
+}
+
+=item C<$count = suffix_rules_count>
+
+Return the number of suffix rules added while processing the current
+F<Makefile> (excluding predefined suffix rules).
+
+=cut
+
+sub suffix_rules_count ()
+{
+ return (scalar keys %$suffix_rules) - (scalar keys %$_suffix_rules_default);
+}
+
+=item C<@list = suffixes>
+
+Return the list of known suffixes.
+
+=cut
+
+sub suffixes ()
+{
+ return @_suffixes;
+}
+
+=item C<rule ($rulename)>
+
+Return the C<Automake::Rule> object for the rule
+named C<$rulename> if defined. Return 0 otherwise.
+
+=cut
+
+sub rule ($)
+{
+ my ($name) = @_;
+ # Strip $(EXEEXT) from $name, so we can diagnose
+ # a clash if `ctags$(EXEEXT):' is redefined after `ctags:'.
+ $name =~ s,\$\(EXEEXT\)$,,;
+ return $_rule_dict{$name} if exists $_rule_dict{$name};
+ return 0;
+}
+
+=item C<rule ($rulename, $cond>
+
+Return the C<Automake::RuleDef> object for the rule named
+C<$rulename> if defined in condition C<$cond>. Return false
+if the condition or the rule does not exist.
+
+=cut
+
+sub ruledef ($$)
+{
+ my ($name, $cond) = @_;
+ my $rule = rule $name;
+ return $rule && $rule->def ($cond);
+}
+
+=item C<rrule ($rulename)
+
+Return the C<Automake::Rule> object for the variable named
+C<$rulename>. 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 rule's existence.
+
+=cut
+
+sub rrule ($)
+{
+ my ($name) = @_;
+ my $r = rule $name;
+ prog_error ("undefined rule $name\n" . &rules_dump)
+ unless $r;
+ return $r;
+}
+
+=item C<rruledef ($varname, $cond)>
+
+Return the C<Automake::RuleDef> object for the rule named
+C<$rulename> if defined in condition C<$cond>. Abort with an internal
+error if the condition or the rule does not exist.
+
+=cut
+
+sub rruledef ($$)
+{
+ my ($name, $cond) = @_;
+ return rrule ($name)->rdef ($cond);
+}
+
+# Create the variable if it does not exist.
+# This is used only by other functions in this package.
+sub _crule ($)
+{
+ my ($name) = @_;
+ my $r = rule $name;
+ return $r if $r;
+ return _new Automake::Rule $name;
+}
+
+sub _new ($$)
+{
+ my ($class, $name) = @_;
+
+ # Strip $(EXEEXT) from $name, so we can diagnose
+ # a clash if `ctags$(EXEEXT):' is redefined after `ctags:'.
+ (my $keyname = $name) =~ s,\$\(EXEEXT\)$,,;
+
+ my $self = Automake::Item::new ($class, $name);
+ $_rule_dict{$keyname} = $self;
+ return $self;
+}
+
+
+=itcem C<@conds = define ($rulename, $source, $owner, $cond, $where)>
+
+Define a new rule. C<$rulename> is the list of targets. C<$source>
+is the filename the rule comes from. C<$owner> is the owner of the
+rule (C<RULE_AUTOMAKE> or C<RULE_USER>). C<$cond> is the
+C<Automake::Condition> under which the rule is defined. C<$where> is
+the C<Automake::Location> where the rule is defined.
+
+Returns a (possibly empty) list of C<Automake::Condition>s where the
+rule's definition should be output.
+
+=cut
+
+sub define ($$$$$)
+{
+ my ($target, $source, $owner, $cond, $where) = @_;
+
+ prog_error "$where is not a reference"
+ unless ref $where;
+ prog_error "$cond is not a reference"
+ unless ref $cond;
+
+ # Don't even think about defining a rule in condition FALSE.
+ return () if $cond == FALSE;
+
+ # For now `foo:' will override `foo$(EXEEXT):'. This is temporary,
+ # though, so we emit a warning.
+ (my $noexe = $target) =~ s,\$\(EXEEXT\)$,,;
+ my $noexerule = rule $noexe;
+ my $tdef = $noexerule ? $noexerule->def ($cond) : undef;
+
+ if ($noexe ne $target
+ && $tdef
+ && $noexerule->name ne $target)
+ {
+ print "1. $noexe\n";
+ print "2. $target\n";
+ print "3. " . $noexerule->name . "\n";
+ # The no-exeext option enables this feature.
+ if (! option 'no-exeext')
+ {
+ msg ('obsolete', $tdef->location,
+ "deprecated feature: target `$noexe' overrides "
+ . "`$noexe\$(EXEEXT)'\n"
+ . "change your target to read `$noexe\$(EXEEXT)'");
+ msg ('obsolete', $where, "target `$target' was defined here");
+ }
+ # Don't `return ()' now, as this might hide target clashes
+ # detected below.
+ }
+
+
+ # A GNU make-style pattern rule has a single "%" in the target name.
+ msg ('portability', $where,
+ "`%'-style pattern rules are a GNU make extension")
+ if $target =~ /^[^%]*%[^%]*$/;
+
+ # Diagnose target redefinitions.
+ if ($tdef)
+ {
+ my $oldowner = $tdef->owner;
+ # Ok, it's the name target, but the name maybe different because
+ # `foo$(EXEEXT)' and `foo' have the same key in our table.
+ my $oldname = $tdef->name;
+
+ # Don't mention true conditions in diagnostics.
+ my $condmsg =
+ $cond == TRUE ? '' : " in condition `" . $cond->human . "'";
+
+ if ($owner == RULE_USER)
+ {
+ if ($oldowner == RULE_USER)
+ {
+ # Ignore `%'-style pattern rules. We'd need the
+ # dependencies to detect duplicates, and they are
+ # already diagnosed as unportable by -Wportability.
+ if ($target !~ /^[^%]*%[^%]*$/)
+ {
+ ## FIXME: Presently we can't diagnose duplcate user rules
+ ## because we doesn't distinguish rules with commands
+ ## from rules that only add dependencies. E.g.,
+ ## .PHONY: foo
+ ## .PHONY: bar
+ ## is legitimate. (This is phony.test.)
+
+ # msg ('syntax', $where,
+ # "redefinition of `$target'$condmsg...", partial => 1);
+ # msg_cond_rule ('syntax', $cond, $target,
+ # "... `$target' previously defined here");
+ }
+ # Return so we don't redefine the rule in our tables,
+ # don't check for ambiguous condition, etc. The rule
+ # will be output anyway beauce &read_am_file ignore the
+ # return code.
+ return ();
+ }
+ else
+ {
+ # Since we parse the user Makefile.am before reading
+ # the Automake fragments, this condition should never happen.
+ prog_error ("user target `$target'$condmsg seen after Automake's"
+ . " definition\nfrom " . $tdef->source);
+ }
+ }
+ else # $owner == RULE_AUTOMAKE
+ {
+ if ($oldowner == RULE_USER)
+ {
+ # -am targets listed in %dependencies support a -local
+ # variant. If the user tries to override TARGET or
+ # TARGET-am for which there exists a -local variant,
+ # just tell the user to use it.
+ my $hint = 0;
+ my $noam = $target;
+ $noam =~ s/-am$//;
+ if (exists $dependencies{"$noam-am"})
+ {
+ $hint = "consider using $target-local instead of $target";
+ }
+
+ msg_cond_rule ('override', $cond, $target,
+ "user target `$target' defined here"
+ . "$condmsg...", partial => 1);
+ msg ('override', $where,
+ "... overrides Automake target `$oldname' defined here",
+ partial => $hint);
+ msg_cond_rule ('override', $cond, $target, $hint)
+ if $hint;
+
+ # Don't overwrite the user definition of TARGET.
+ return ();
+ }
+ else # $oldowner == RULE_AUTOMAKE
+ {
+ # Automake should ignore redefinitions of its own
+ # rules if they came from the same file. This makes
+ # it easier to process a Makefile fragment several times.
+ # Hower it's an error if the target is defined in many
+ # files. E.g., the user might be using bin_PROGRAMS = ctags
+ # which clashes with our `ctags' rule.
+ # (It would be more accurate if we had a way to compare
+ # the *content* of both rules. Then $targets_source would
+ # be useless.)
+ my $oldsource = $tdef->source;
+ return () if $source eq $oldsource && $target eq $oldname;
+
+ msg ('syntax', $where, "redefinition of `$target'$condmsg...",
+ partial => 1);
+ msg_cond_rule ('syntax', $cond, $target,
+ "... `$oldname' previously defined here");
+ return ();
+ }
+ }
+ # Never reached.
+ prog_error ("Unreachable place reached.");
+ }
+
+ # Conditions for which the rule should be defined.
+ my @conds = $cond;
+
+ # Check ambiguous conditional definitions.
+ my $rule = _crule $target;
+ my ($message, $ambig_cond) = $rule->conditions->ambiguous_p ($target, $cond);
+ if ($message) # We have an ambiguty.
+ {
+ if ($owner == RULE_USER)
+ {
+ # For user rules, just diagnose the ambiguity.
+ msg 'syntax', $where, "$message ...", partial => 1;
+ msg_cond_rule ('syntax', $ambig_cond, $target,
+ "... `$target' previously defined here");
+ return ();
+ }
+ else
+ {
+ # FIXME: for Automake rules, we can't diagnose ambiguities yet.
+ # The point is that Automake doesn't propagate conditions
+ # everywhere. For instance &handle_PROGRAMS doesn't care if
+ # bin_PROGRAMS was defined conditionally or not.
+ # On the following input
+ # if COND1
+ # foo:
+ # ...
+ # else
+ # bin_PROGRAMS = foo
+ # endif
+ # &handle_PROGRAMS will attempt to define a `foo:' rule
+ # in condition TRUE (which conflicts with COND1). Fixing
+ # this in &handle_PROGRAMS and siblings seems hard: you'd
+ # have to explain &file_contents what to do with a
+ # condition. So for now we do our best *here*. If `foo:'
+ # was already defined in condition COND1 and we want to define
+ # it in condition TRUE, then define it only in condition !COND1.
+ # (See cond14.test and cond15.test for some test cases.)
+ @conds = ();
+ for my $undefined_cond ($rule->conditions->invert->conds)
+ {
+ push @conds, $cond->merge ($undefined_cond);
+ }
+ # No conditions left to define the rule.
+ # Warn, because our workaround is meaningless in this case.
+ if (scalar @conds == 0)
+ {
+ msg 'syntax', $where, "$message ...", partial => 1;
+ msg_cond_rule ('syntax', $ambig_cond, $target,
+ "... `$target' previously defined here");
+ return ();
+ }
+ }
+ }
+
+ # Finally define this rule.
+ for my $c (@conds)
+ {
+ my $def = new Automake::RuleDef ($target, '', $where->clone,
+ $owner, $source);
+ $rule->set ($c, $def);
+ }
+
+ # We honor inference rules with multiple targets because many
+ # make support this and people use it. However this is disallowed
+ # by POSIX. We'll print a warning later.
+ my $target_count = 0;
+ my $inference_rule_count = 0;
+
+ for my $t (split (' ', $target))
+ {
+ ++$target_count;
+ # Check the rule for being a suffix rule. If so, store in a hash.
+ # Either it's a rule for two known extensions...
+ if ($t =~ /^($KNOWN_EXTENSIONS_PATTERN)($KNOWN_EXTENSIONS_PATTERN)$/
+ # ...or it's a rule with unknown extensions (.i.e, the rule
+ # looks like `.foo.bar:' but `.foo' or `.bar' are not
+ # declared in SUFFIXES and are not known language
+ # extensions). Automake will complete SUFFIXES from
+ # @suffixes automatically (see handle_footer).
+
+
+ || ($t =~ /$_SUFFIX_RULE_PATTERN/o && accept_extensions($1)))
+ {
+ ++$inference_rule_count;
+ register_suffix_rule ($where, $1, $2);
+ }
+ }
+
+ # POSIX allow multiple targets befor the colon, but disallow
+ # definitions of multiple Inference rules. It's also
+ # disallowed to mix plain targets with inference rules.
+ msg ('portability', $where,
+ "Inference rules can have only one target before the colon (POSIX).")
+ if $inference_rule_count > 0 && $target_count > 1;
+
+ return @conds;
+}
+
+=item C<depend ($target, @deps)>
+
+Adds C<@deps> to the dependencies of target C<$target>. This should
+be used only with factored targets (those appearing in
+C<%dependendees>).
+
+=cut
+
+sub depend ($@)
+{
+ my ($category, @dependendees) = @_;
+ push (@{$dependencies{$category}}, @dependendees);
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<Automake::RuleDef>, 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:
--- /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::RuleDef;
+use strict;
+use Carp;
+use Automake::ChannelDefs;
+use Automake::ItemDef;
+
+require Exporter;
+use vars '@ISA', '@EXPORT';
+@ISA = qw/Automake::ItemDef Exporter/;
+@EXPORT = qw (&RULE_AUTOMAKE &RULE_USER);
+
+=head1 NAME
+
+Automake::RuleDef - a class for rule definitions
+
+=head1 SYNOPSIS
+
+ use Automake::RuleDef;
+ use Automake::Location;
+
+=head1 DESCRIPTION
+
+This class gather data related to one Makefile-rule definition.
+
+=head2 Constants
+
+=over 4
+
+=item C<RULE_AUTOMAKE>, C<RULE_USER>
+
+Possible owners for rules.
+
+=cut
+
+use constant RULE_AUTOMAKE => 0; # Rule defined by Automake.
+use constant RULE_USER => 1; # Rule defined in the user's Makefile.am.
+
+sub new ($$$$$)
+{
+ my ($class, $name, $comment, $location, $owner, $source) = @_;
+
+ my $self = Automake::ItemDef::new ($class, $comment, $location, $owner);
+ $self->{'source'} = $source;
+ $self->{'name'} = $name;
+ return $self;
+}
+
+sub source ($)
+{
+ my ($self) = @_;
+ return $self->{'source'};
+}
+
+sub name ($)
+{
+ my ($self) = @_;
+ return $self->{'name'};
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<Automake::Rule>, L<Automake::ItemDef>.
+
+=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:
use strict;
use Carp;
use Automake::ChannelDefs;
+use Automake::ItemDef;
require Exporter;
use vars '@ISA', '@EXPORT';
-@ISA = qw/Exporter/;
+@ISA = qw/Automake::ItemDef Exporter/;
@EXPORT = qw (&VAR_AUTOMAKE &VAR_CONFIGURE &VAR_MAKEFILE
&VAR_ASIS &VAR_PRETTY &VAR_SILENT &VAR_SORTED);
=head2 Methods
+C<VarDef> defines the following methods in addition to those inherited
+from L<Automake::ItemDef>.
+
=over 4
-=item C<my $def = Automake::new ($varname, $value, $comment, $location, $type, $owner, $pretty)>
+=item C<my $def = new Automake::VarDef ($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.
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;
-
+ my $self = Automake::ItemDef::new ($class, $comment, $location, $owner);
+ $self->{'value'} = $value;
+ $self->{'type'} = $type;
+ $self->{'pretty'} = $pretty;
+ $self->{'seen'} = 0;
return $self;
}
=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
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) = @_;
=head1 SEE ALSO
-L<Automake::Variable>.
+L<Automake::Variable>, L<Automake::ItemDef>.
=cut
package Automake::Variable;
use strict;
use Carp;
+
use Automake::Channels;
use Automake::ChannelDefs;
use Automake::Configure_ac;
+use Automake::Item;
use Automake::VarDef;
use Automake::Condition qw (TRUE FALSE);
use Automake::DisjConditions;
require Exporter;
use vars '@ISA', '@EXPORT', '@EXPORT_OK';
-@ISA = qw/Exporter/;
+@ISA = qw/Automake::Item Exporter/;
@EXPORT = qw (err_var msg_var msg_cond_var reject_var
var rvar vardef rvardef
variables
The I<r> variants of the C<var>, C<def>, and C<vardef> methods add an
extra test to ensure that the lookup succeeded, and will diagnose
-failures as internal errors (which a message which is much more
+failures as internal errors (with a message which is much more
informative than Perl's warning about calling a method on a
non-object).
msg_cond_var $channel, $cond, $v, $msg, %opts;
}
-=item C<reject_var ($varname, $error_msg)>
+=item C<$bool = reject_var ($varname, $error_msg)>
-Bail out with C<$ERROR_MSG> if a variable with name C<$VARNAME> has
+Bail out with C<$error_msg> if a variable with name C<$varname> has
been defined.
+Return true iff C<$varname> is defined.
+
=cut
-# $BOOL
-# reject_var ($VARNAME, $ERROR_MSG)
-# -----------------------------
sub reject_var ($$)
{
my ($var, $msg) = @_;
=item C<vardef ($varname, $cond)>
Return the C<Automake::VarDef> object for the variable named
-C<$varname> if defined in condition C<$cond>. Return the empty list
+C<$varname> if defined in condition C<$cond>. Return false
if the condition or the variable does not exist.
=cut
Return the C<Automake::VarDef> object for the variable named
C<$varname> if defined in condition C<$cond>. Abort with an internal
-error if the variable or the variable does not exist.
+error if the condition or the variable does not exist.
=cut
=head2 Methods
-Here are the methods of the C<Automake::Variable> instances.
+C<Automake::Variable> is a subclass of C<Automake::Item>. See
+that package for inherited methods.
+
+Here are the methods specific to the C<Automake::Variable> instances.
Use the C<define> function, described latter, to create such objects.
=over 4
sub _new ($$)
{
my ($class, $name) = @_;
- my $self = {
- name => $name,
- defs => {},
- conds => {},
- scanned => 0,
- };
- bless $self, $class;
+ my $self = Automake::Item::new ($class, $name);
+ $self->{'scanned'} = 0;
$_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 0 otherwise.
-
-=cut
-
-sub def ($$)
-{
- my ($self, $cond) = @_;
- return $self->{'defs'}{$cond} if exists $self->{'defs'}{$cond};
- return 0;
-}
-
-=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" . $self->dump)
- 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
}
}
-=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, $parent_cond])>
Warn if the variable is conditionally defined. C<$parent> is the name
# line numbers with random bits of text.
$def = new Automake::VarDef ($var, $value, $comment, $where->clone,
$type, $owner, $pretty);
- $self->_set ($cond, $def);
+ $self->set ($cond, $def);
push @_var_order, $var;
# No need to adjust the owner later as we have overridden
Makefile.am:3: while processing library `libfoo.a'
program.am: target `libfoo.a$(EXEEXT)' was defined here
Makefile.am:1: while processing program `libfoo.a'
-program.am: redefinition of `libfoo.a'...
+program.am: redefinition of `libfoo.a$(EXEEXT)'...
Makefile.am:1: while processing program `libfoo.a'
library.am: ... `libfoo.a' previously defined here
Makefile.am:3: while processing library `libfoo.a'
tags.am: redefinition of `ctags'...
-program.am: ... `ctags' previously defined here
+program.am: ... `ctags$(EXEEXT)' previously defined here
Makefile.am:6: while processing program `ctags'
EOF