summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Paulmier <matthias.paulmier@etu.u-bordeaux.fr>2018-06-06 15:46:24 +0200
committerMatthias Paulmier <matthias.paulmier@etu.u-bordeaux.fr>2018-06-22 14:18:34 +0200
commit3d672eb1ef8572ac257652cab0ab416bd32be024 (patch)
treed76bcdce3ed92705b608efd54be35ae0482df7e1
parent9a93513b42a698ba9ac46a88ccb5fbcceea4daac (diff)
downloadautomake-3d672eb1ef8572ac257652cab0ab416bd32be024.tar.gz
lib: fix Automake::Variable
Some methods added to this module were not working properly because they depend on others which stayed in automake.in * ConfVars.pm: Added this module to put the methods in question. * CondStack.pm: Module that takes care of the conditional stack. * Utils.pm: Added some needed utility functions for the above to run properly. * File.pm: Methods that looks at files' content. * local.mk: Added the new modules.
-rwxr-xr-xbin/automake.in320
-rw-r--r--lib/Automake/CondStack.pm150
-rw-r--r--lib/Automake/ConfVars.pm71
-rw-r--r--lib/Automake/File.pm247
-rw-r--r--lib/Automake/Utils.pm189
-rw-r--r--lib/Automake/Variable.pm35
-rw-r--r--lib/Automake/local.mk4
7 files changed, 663 insertions, 353 deletions
diff --git a/bin/automake.in b/bin/automake.in
index fb9779882..18a6fbf3e 100755
--- a/bin/automake.in
+++ b/bin/automake.in
@@ -57,6 +57,7 @@ use Automake::Channels;
use Automake::ChannelDefs;
use Automake::Configure_ac;
use Automake::FileUtils;
+use Automake::File;
use Automake::Location;
use Automake::Condition qw/TRUE FALSE/;
use Automake::DisjConditions;
@@ -68,6 +69,8 @@ use Automake::RuleDef;
use Automake::Wrap 'makefile_wrap';
use Automake::Language;
use Automake::Utils;
+use Automake::CondStack;
+use Automake::ConfVars;
use File::Basename;
use File::Spec;
use Carp;
@@ -5528,132 +5531,6 @@ sub pretty_print_rule
################################################################
-## -------------------------------- ##
-## Handling the conditional stack. ##
-## -------------------------------- ##
-
-
-# $STRING
-# make_conditional_string ($NEGATE, $COND)
-# ----------------------------------------
-sub make_conditional_string
-{
- my ($negate, $cond) = @_;
- $cond = "${cond}_TRUE"
- unless $cond =~ /^TRUE|FALSE$/;
- $cond = Automake::Condition::conditional_negate ($cond)
- if $negate;
- return $cond;
-}
-
-
-my %_am_macro_for_cond =
- (
- AMDEP => "one of the compiler tests\n"
- . " AC_PROG_CC, AC_PROG_CXX, AC_PROG_OBJC, AC_PROG_OBJCXX,\n"
- . " AM_PROG_AS, AM_PROG_GCJ, AM_PROG_UPC",
- am__fastdepCC => 'AC_PROG_CC',
- am__fastdepCCAS => 'AM_PROG_AS',
- am__fastdepCXX => 'AC_PROG_CXX',
- am__fastdepGCJ => 'AM_PROG_GCJ',
- am__fastdepOBJC => 'AC_PROG_OBJC',
- am__fastdepOBJCXX => 'AC_PROG_OBJCXX',
- am__fastdepUPC => 'AM_PROG_UPC'
- );
-
-# $COND
-# cond_stack_if ($NEGATE, $COND, $WHERE)
-# --------------------------------------
-sub cond_stack_if
-{
- my ($negate, $cond, $where) = @_;
-
- if (! $configure_cond{$cond} && $cond !~ /^TRUE|FALSE$/)
- {
- my $text = "$cond does not appear in AM_CONDITIONAL";
- my $scope = US_LOCAL;
- if (exists $_am_macro_for_cond{$cond})
- {
- my $mac = $_am_macro_for_cond{$cond};
- $text .= "\n The usual way to define '$cond' is to add ";
- $text .= ($mac =~ / /) ? $mac : "'$mac'";
- $text .= "\n to '$configure_ac' and run 'aclocal' and 'autoconf' again";
- # These warnings appear in Automake files (depend2.am),
- # so there is no need to display them more than once:
- $scope = US_GLOBAL;
- }
- error $where, $text, uniq_scope => $scope;
- }
-
- push (@cond_stack, make_conditional_string ($negate, $cond));
-
- return new Automake::Condition (@cond_stack);
-}
-
-
-# $COND
-# cond_stack_else ($NEGATE, $COND, $WHERE)
-# ----------------------------------------
-sub cond_stack_else
-{
- my ($negate, $cond, $where) = @_;
-
- if (! @cond_stack)
- {
- error $where, "else without if";
- return FALSE;
- }
-
- $cond_stack[$#cond_stack] =
- Automake::Condition::conditional_negate ($cond_stack[$#cond_stack]);
-
- # If $COND is given, check against it.
- if (defined $cond)
- {
- $cond = make_conditional_string ($negate, $cond);
-
- error ($where, "else reminder ($negate$cond) incompatible with "
- . "current conditional: $cond_stack[$#cond_stack]")
- if $cond_stack[$#cond_stack] ne $cond;
- }
-
- return new Automake::Condition (@cond_stack);
-}
-
-
-# $COND
-# cond_stack_endif ($NEGATE, $COND, $WHERE)
-# -----------------------------------------
-sub cond_stack_endif
-{
- my ($negate, $cond, $where) = @_;
- my $old_cond;
-
- if (! @cond_stack)
- {
- error $where, "endif without if";
- return TRUE;
- }
-
- # If $COND is given, check against it.
- if (defined $cond)
- {
- $cond = make_conditional_string ($negate, $cond);
-
- error ($where, "endif reminder ($negate$cond) incompatible with "
- . "current conditional: $cond_stack[$#cond_stack]")
- if $cond_stack[$#cond_stack] ne $cond;
- }
-
- pop @cond_stack;
-
- return new Automake::Condition (@cond_stack);
-}
-
-
-
-
-
## ------------------------ ##
## Handling the variables. ##
## ------------------------ ##
@@ -6111,197 +5988,6 @@ sub read_main_am_file
################################################################
-# $STRING
-# flatten ($ORIGINAL_STRING)
-# --------------------------
-sub flatten
-{
- $_ = shift;
-
- s/\\\n//somg;
- s/\s+/ /g;
- s/^ //;
- s/ $//;
-
- return $_;
-}
-
-
-# transform_token ($TOKEN, \%PAIRS, $KEY)
-# ---------------------------------------
-# Return the value associated to $KEY in %PAIRS, as used on $TOKEN
-# (which should be ?KEY? or any of the special %% requests)..
-sub transform_token ($\%$)
-{
- my ($token, $transform, $key) = @_;
- my $res = $transform->{$key};
- prog_error "Unknown key '$key' in '$token'" unless defined $res;
- return $res;
-}
-
-
-# transform ($TOKEN, \%PAIRS)
-# ---------------------------
-# If ($TOKEN, $VAL) is in %PAIRS:
-# - replaces %KEY% with $VAL,
-# - enables/disables ?KEY? and ?!KEY?,
-# - replaces %?KEY% with TRUE or FALSE.
-sub transform ($\%)
-{
- my ($token, $transform) = @_;
-
- # %KEY%.
- # Must be before the following pattern to exclude the case
- # when there is neither IFTRUE nor IFFALSE.
- if ($token =~ /^%([\w\-]+)%$/)
- {
- return transform_token ($token, %$transform, $1);
- }
- # %?KEY%.
- elsif ($token =~ /^%\?([\w\-]+)%$/)
- {
- return transform_token ($token, %$transform, $1) ? 'TRUE' : 'FALSE';
- }
- # ?KEY? and ?!KEY?.
- elsif ($token =~ /^ \? (!?) ([\w\-]+) \? $/x)
- {
- my $neg = ($1 eq '!') ? 1 : 0;
- my $val = transform_token ($token, %$transform, $2);
- return (!!$val == $neg) ? '##%' : '';
- }
- else
- {
- prog_error "Unknown request format: $token";
- }
-}
-
-# $TEXT
-# preprocess_file ($MAKEFILE, [%TRANSFORM])
-# -----------------------------------------
-# Load a $MAKEFILE, apply the %TRANSFORM, and return the result.
-# No extra parsing or post-processing is done (i.e., recognition of
-# rules declaration or of make variables definitions).
-sub preprocess_file
-{
- my ($file, %transform) = @_;
-
- # Complete %transform with global options.
- # Note that %transform goes last, so it overrides global options.
- %transform = ( 'MAINTAINER-MODE'
- => $seen_maint_mode ? subst ('MAINTAINER_MODE_TRUE') : '',
-
- 'XZ' => !! option 'dist-xz',
- 'LZIP' => !! option 'dist-lzip',
- 'BZIP2' => !! option 'dist-bzip2',
- 'COMPRESS' => !! option 'dist-tarZ',
- 'GZIP' => ! option 'no-dist-gzip',
- 'SHAR' => !! option 'dist-shar',
- 'ZIP' => !! option 'dist-zip',
-
- 'INSTALL-INFO' => ! option 'no-installinfo',
- 'INSTALL-MAN' => ! option 'no-installman',
- 'CK-NEWS' => !! option 'check-news',
-
- 'SUBDIRS' => !! var ('SUBDIRS'),
- 'TOPDIR_P' => $relative_dir eq '.',
-
- 'BUILD' => ($seen_canonical >= AC_CANONICAL_BUILD),
- 'HOST' => ($seen_canonical >= AC_CANONICAL_HOST),
- 'TARGET' => ($seen_canonical >= AC_CANONICAL_TARGET),
-
- 'LIBTOOL' => !! var ('LIBTOOL'),
- 'NONLIBTOOL' => 1,
- %transform);
-
- if (! defined ($_ = $am_file_cache{$file}))
- {
- verb "reading $file";
- # Swallow the whole file.
- my $fc_file = new Automake::XFile "< $file";
- my $saved_dollar_slash = $/;
- undef $/;
- $_ = $fc_file->getline;
- $/ = $saved_dollar_slash;
- $fc_file->close;
- # Remove ##-comments.
- # Besides we don't need more than two consecutive new-lines.
- s/(?:$IGNORE_PATTERN|(?<=\n\n)\n+)//gom;
- # Remember the contents of the just-read file.
- $am_file_cache{$file} = $_;
- }
-
- # Substitute Automake template tokens.
- s/(?: % \?? [\w\-]+ %
- | \? !? [\w\-]+ \?
- )/transform($&, %transform)/gex;
- # transform() may have added some ##%-comments to strip.
- # (we use '##%' instead of '##' so we can distinguish ##%##%##% from
- # ####### and do not remove the latter.)
- s/^[ \t]*(?:##%)+.*\n//gm;
-
- return $_;
-}
-
-
-# @PARAGRAPHS
-# make_paragraphs ($MAKEFILE, [%TRANSFORM])
-# -----------------------------------------
-# Load a $MAKEFILE, apply the %TRANSFORM, and return it as a list of
-# paragraphs.
-sub make_paragraphs
-{
- my ($file, %transform) = @_;
- $transform{FIRST} = !$transformed_files{$file};
- $transformed_files{$file} = 1;
-
- my @lines = split /(?<!\\)\n/, preprocess_file ($file, %transform);
- my @res;
-
- while (defined ($_ = shift @lines))
- {
- my $paragraph = $_;
- # If we are a rule, eat as long as we start with a tab.
- if (/$RULE_PATTERN/smo)
- {
- while (defined ($_ = shift @lines) && $_ =~ /^\t/)
- {
- $paragraph .= "\n$_";
- }
- unshift (@lines, $_);
- }
-
- # If we are a comments, eat as much comments as you can.
- elsif (/$COMMENT_PATTERN/smo)
- {
- while (defined ($_ = shift @lines)
- && $_ =~ /$COMMENT_PATTERN/smo)
- {
- $paragraph .= "\n$_";
- }
- unshift (@lines, $_);
- }
-
- push @res, $paragraph;
- }
-
- return @res;
-}
-
-
-# $CONTENTS
-# file_contents ($BASENAME, $WHERE, [%TRANSFORM])
-# -----------------------------------------------
-# Return contents of a file from $libdir/am, automatically skipping
-# macros or rules which are already known.
-sub file_contents
-{
- my ($basename, $where, %transform) = @_;
- my ($comments, $variables, $rules) =
- file_contents_internal (1, "$libdir/am/$basename.am", $where,
- %transform);
- return "$comments$variables$rules";
-}
-
# @PREFIX
# am_primary_prefixes ($PRIMARY, $CAN_DIST, @PREFIXES)
diff --git a/lib/Automake/CondStack.pm b/lib/Automake/CondStack.pm
new file mode 100644
index 000000000..5d5260719
--- /dev/null
+++ b/lib/Automake/CondStack.pm
@@ -0,0 +1,150 @@
+# Copyright (C) 2018 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+
+package Automake::CondStack;
+
+use 5.006;
+use strict;
+
+use Exporter;
+use Automake::Condition qw (TRUE FALSE);
+use Automake::Global;
+use Automake::Channels;
+use Automake::ChannelDefs;
+
+use vars qw (@ISA @EXPORT);
+
+@ISA = qw (Exporter);
+@EXPORT = qw (cond_stack_if cond_stack_else cond_stack_endif);
+
+my %_am_macro_for_cond =
+ (
+ AMDEP => "one of the compiler tests\n"
+ . " AC_PROG_CC, AC_PROG_CXX, AC_PROG_OBJC, AC_PROG_OBJCXX,\n"
+ . " AM_PROG_AS, AM_PROG_GCJ, AM_PROG_UPC",
+ am__fastdepCC => 'AC_PROG_CC',
+ am__fastdepCCAS => 'AM_PROG_AS',
+ am__fastdepCXX => 'AC_PROG_CXX',
+ am__fastdepGCJ => 'AM_PROG_GCJ',
+ am__fastdepOBJC => 'AC_PROG_OBJC',
+ am__fastdepOBJCXX => 'AC_PROG_OBJCXX',
+ am__fastdepUPC => 'AM_PROG_UPC'
+ );
+
+
+# $STRING
+# _make_conditional_string ($NEGATE, $COND)
+# ----------------------------------------
+sub _make_conditional_string
+{
+ my ($negate, $cond) = @_;
+ $cond = "${cond}_TRUE"
+ unless $cond =~ /^TRUE|FALSE$/;
+ $cond = Automake::Condition::conditional_negate ($cond)
+ if $negate;
+ return $cond;
+}
+
+
+# $COND
+# cond_stack_if ($NEGATE, $COND, $WHERE)
+# --------------------------------------
+sub cond_stack_if
+{
+ my ($negate, $cond, $where) = @_;
+
+ if (! $configure_cond{$cond} && $cond !~ /^TRUE|FALSE$/)
+ {
+ my $text = "$cond does not appear in AM_CONDITIONAL";
+ my $scope = US_LOCAL;
+ if (exists $_am_macro_for_cond{$cond})
+ {
+ my $mac = $_am_macro_for_cond{$cond};
+ $text .= "\n The usual way to define '$cond' is to add ";
+ $text .= ($mac =~ / /) ? $mac : "'$mac'";
+ $text .= "\n to '$configure_ac' and run 'aclocal' and 'autoconf' again";
+ # These warnings appear in Automake files (depend2.am),
+ # so there is no need to display them more than once:
+ $scope = US_GLOBAL;
+ }
+ error $where, $text, uniq_scope => $scope;
+ }
+
+ push (@cond_stack, _make_conditional_string ($negate, $cond));
+
+ return new Automake::Condition (@cond_stack);
+}
+
+
+# $COND
+# cond_stack_else ($NEGATE, $COND, $WHERE)
+# ----------------------------------------
+sub cond_stack_else
+{
+ my ($negate, $cond, $where) = @_;
+
+ if (! @cond_stack)
+ {
+ error $where, "else without if";
+ return FALSE;
+ }
+
+ $cond_stack[$#cond_stack] =
+ Automake::Condition::conditional_negate ($cond_stack[$#cond_stack]);
+
+ # If $COND is given, check against it.
+ if (defined $cond)
+ {
+ $cond = _make_conditional_string ($negate, $cond);
+
+ error ($where, "else reminder ($negate$cond) incompatible with "
+ . "current conditional: $cond_stack[$#cond_stack]")
+ if $cond_stack[$#cond_stack] ne $cond;
+ }
+
+ return new Automake::Condition (@cond_stack);
+}
+
+
+# $COND
+# cond_stack_endif ($NEGATE, $COND, $WHERE)
+# -----------------------------------------
+sub cond_stack_endif
+{
+ my ($negate, $cond, $where) = @_;
+ my $old_cond;
+
+ if (! @cond_stack)
+ {
+ error $where, "endif without if";
+ return TRUE;
+ }
+
+ # If $COND is given, check against it.
+ if (defined $cond)
+ {
+ $cond = _make_conditional_string ($negate, $cond);
+
+ error ($where, "endif reminder ($negate$cond) incompatible with "
+ . "current conditional: $cond_stack[$#cond_stack]")
+ if $cond_stack[$#cond_stack] ne $cond;
+ }
+
+ pop @cond_stack;
+
+ return new Automake::Condition (@cond_stack);
+}
+
+1;
diff --git a/lib/Automake/ConfVars.pm b/lib/Automake/ConfVars.pm
new file mode 100644
index 000000000..8d7f362b0
--- /dev/null
+++ b/lib/Automake/ConfVars.pm
@@ -0,0 +1,71 @@
+# Copyright (C) 2018 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+
+# Like define_variable, but define a variable to be the configure
+# substitution by the same name.
+
+package Automake::ConfVars;
+
+use 5.006;
+use strict;
+
+use Exporter;
+use Automake::ChannelDefs;
+use Automake::Channels;
+use Automake::Condition qw (TRUE FALSE);
+use Automake::Config;
+use Automake::File;
+use Automake::Global;
+use Automake::Location;
+use Automake::Utils;
+use Automake::VarDef;
+use Automake::Variable;
+
+use vars qw (@ISA @EXPORT);
+
+@ISA = qw (Exporter);
+@EXPORT = qw (define_standard_variables);
+
+
+sub _define_configure_variable ($)
+{
+ my ($var) = @_;
+ # Some variables we do not want to output. For instance it
+ # would be a bad idea to output `U = @U@` when `@U@` can be
+ # substituted as `\`.
+ my $pretty = exists $ignored_configure_vars{$var} ? VAR_SILENT : VAR_ASIS;
+ Automake::Variable::define ($var, VAR_CONFIGURE, '', TRUE, subst ($var),
+ '', $configure_vars{$var}, $pretty);
+}
+
+
+# A helper for read_main_am_file which initializes configure variables
+# 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);
+
+ foreach my $var (sort keys %configure_vars)
+ {
+ _define_configure_variable ($var);
+ }
+
+ $output_vars .= $comments . $rules;
+}
+
+1;
diff --git a/lib/Automake/File.pm b/lib/Automake/File.pm
new file mode 100644
index 000000000..77cc062e0
--- /dev/null
+++ b/lib/Automake/File.pm
@@ -0,0 +1,247 @@
+# Copyright (C) 2018 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+
+package Automake::File;
+
+use 5.006;
+use strict;
+
+use Exporter;
+use Automake::ChannelDefs;
+use Automake::Channels;
+use Automake::Condition qw (TRUE FALSE);
+use Automake::CondStack;
+use Automake::Config;
+use Automake::Global;
+use Automake::Location;
+use Automake::Rule;
+use Automake::RuleDef;
+use Automake::Utils;
+use Automake::VarDef;
+use Automake::Variable;
+
+use vars qw (@ISA @EXPORT);
+
+@ISA = qw (Exporter);
+@EXPORT = qw (file_contents_internal file_contents);
+
+# ($COMMENT, $VARIABLES, $RULES)
+# file_contents_internal ($IS_AM, $FILE, $WHERE, [%TRANSFORM])
+# ------------------------------------------------------------
+# Return contents of a file from $libdir/am, automatically skipping
+# macros or rules which are already known. $IS_AM iff the caller is
+# reading an Automake file (as opposed to the user's Makefile.am).
+sub file_contents_internal
+{
+ my ($is_am, $file, $where, %transform) = @_;
+
+ $where->set ($file);
+
+ my $result_vars = '';
+ my $result_rules = '';
+ my $comment = '';
+ my $spacing = '';
+
+ # The following flags are used to track rules spanning across
+ # multiple paragraphs.
+ my $is_rule = 0; # 1 if we are processing a rule.
+ my $discard_rule = 0; # 1 if the current rule should not be output.
+
+ # We save the conditional stack on entry, and then check to make
+ # sure it is the same on exit. This lets us conditionally include
+ # other files.
+ my @saved_cond_stack = @cond_stack;
+ my $cond = new Automake::Condition (@cond_stack);
+
+ foreach (make_paragraphs ($file, %transform))
+ {
+ # FIXME: no line number available.
+ $where->set ($file);
+
+ # Sanity checks.
+ error $where, "blank line following trailing backslash:\n$_"
+ if /\\$/;
+ error $where, "comment following trailing backslash:\n$_"
+ if /\\#/;
+
+ if (/^$/)
+ {
+ $is_rule = 0;
+ # Stick empty line before the incoming macro or rule.
+ $spacing = "\n";
+ }
+ elsif (/$COMMENT_PATTERN/mso)
+ {
+ $is_rule = 0;
+ # Stick comments before the incoming macro or rule.
+ $comment = "$_\n";
+ }
+
+ # Handle inclusion of other files.
+ elsif (/$INCLUDE_PATTERN/o)
+ {
+ if ($cond != FALSE)
+ {
+ my $file = ($is_am ? "$libdir/am/" : '') . $1;
+ $where->push_context ("'$file' included from here");
+ # N-ary '.=' fails.
+ my ($com, $vars, $rules)
+ = file_contents_internal ($is_am, $file, $where, %transform);
+ $where->pop_context;
+ $comment .= $com;
+ $result_vars .= $vars;
+ $result_rules .= $rules;
+ }
+ }
+
+ # Handling the conditionals.
+ elsif (/$IF_PATTERN/o)
+ {
+ $cond = cond_stack_if ($1, $2, $file);
+ }
+ elsif (/$ELSE_PATTERN/o)
+ {
+ $cond = cond_stack_else ($1, $2, $file);
+ }
+ elsif (/$ENDIF_PATTERN/o)
+ {
+ $cond = cond_stack_endif ($1, $2, $file);
+ }
+
+ # Handling rules.
+ elsif (/$RULE_PATTERN/mso)
+ {
+ $is_rule = 1;
+ $discard_rule = 0;
+ # Separate relationship from optional actions: the first
+ # `new-line tab" not preceded by backslash (continuation
+ # line).
+ my $paragraph = $_;
+ /^(.*?)(?:(?<!\\)\n(\t.*))?$/s;
+ my ($relationship, $actions) = ($1, $2 || '');
+
+ # Separate targets from dependencies: the first colon.
+ $relationship =~ /^([^:]+\S+) *: *(.*)$/som;
+ my ($targets, $dependencies) = ($1, $2);
+ # Remove the escaped new lines.
+ # I don't know why, but I have to use a tmp $flat_deps.
+ my $flat_deps = flatten ($dependencies);
+ my @deps = split (' ', $flat_deps);
+
+ foreach (split (' ', $targets))
+ {
+ # FIXME: 1. We are not robust to people defining several targets
+ # at once, only some of them being in %dependencies. The
+ # actions from the targets in %dependencies are usually generated
+ # from the content of %actions, but if some targets in $targets
+ # are not in %dependencies the ELSE branch will output
+ # a rule for all $targets (i.e. the targets which are both
+ # in %dependencies and $targets will have two rules).
+
+ # FIXME: 2. The logic here is not able to output a
+ # multi-paragraph rule several time (e.g. for each condition
+ # it is defined for) because it only knows the first paragraph.
+
+ # FIXME: 3. We are not robust to people defining a subset
+ # of a previously defined "multiple-target" rule. E.g.
+ # 'foo:' after 'foo bar:'.
+
+ # Output only if not in FALSE.
+ if (defined $dependencies{$_} && $cond != FALSE)
+ {
+ depend ($_, @deps);
+ register_action ($_, $actions);
+ }
+ else
+ {
+ # Free-lance dependency. Output the rule for all the
+ # targets instead of one by one.
+ my @undefined_conds =
+ Automake::Rule::define ($targets, $file,
+ $is_am ? RULE_AUTOMAKE : RULE_USER,
+ $cond, $where);
+ for my $undefined_cond (@undefined_conds)
+ {
+ my $condparagraph = $paragraph;
+ $condparagraph =~ s/^/$undefined_cond->subst_string/gme;
+ $result_rules .= "$spacing$comment$condparagraph\n";
+ }
+ if (scalar @undefined_conds == 0)
+ {
+ # Remember to discard next paragraphs
+ # if they belong to this rule.
+ # (but see also FIXME: #2 above.)
+ $discard_rule = 1;
+ }
+ $comment = $spacing = '';
+ last;
+ }
+ }
+ }
+
+ elsif (/$ASSIGNMENT_PATTERN/mso)
+ {
+ my ($var, $type, $val) = ($1, $2, $3);
+ error $where, "variable '$var' with trailing backslash"
+ if /\\$/;
+
+ $is_rule = 0;
+
+ Automake::Variable::define ($var,
+ $is_am ? VAR_AUTOMAKE : VAR_MAKEFILE,
+ $type, $cond, $val, $comment, $where,
+ VAR_ASIS)
+ if $cond != FALSE;
+
+ $comment = $spacing = '';
+ }
+ else
+ {
+ # This isn't an error; it is probably some tokens which
+ # configure is supposed to replace, such as '@SET-MAKE@',
+ # or some part of a rule cut by an if/endif.
+ if (! $cond->false && ! ($is_rule && $discard_rule))
+ {
+ s/^/$cond->subst_string/gme;
+ $result_rules .= "$spacing$comment$_\n";
+ }
+ $comment = $spacing = '';
+ }
+ }
+
+ error ($where, @cond_stack ?
+ "unterminated conditionals: @cond_stack" :
+ "too many conditionals closed in include file")
+ if "@saved_cond_stack" ne "@cond_stack";
+
+ return ($comment, $result_vars, $result_rules);
+}
+
+
+# $CONTENTS
+# file_contents ($BASENAME, $WHERE, [%TRANSFORM])
+# -----------------------------------------------
+# Return contents of a file from $libdir/am, automatically skipping
+# macros or rules which are already known.
+sub file_contents
+{
+ my ($basename, $where, %transform) = @_;
+ my ($comments, $variables, $rules) =
+ file_contents_internal (1, "$libdir/am/$basename.am", $where,
+ %transform);
+ return "$comments$variables$rules";
+}
+
+1;
diff --git a/lib/Automake/Utils.pm b/lib/Automake/Utils.pm
index 832b74e05..aafb911cd 100644
--- a/lib/Automake/Utils.pm
+++ b/lib/Automake/Utils.pm
@@ -18,15 +18,19 @@ package Automake::Utils;
use 5.006;
use strict;
use Exporter;
-use Automake::Rule;
use Automake::Global;
use Automake::Location;
-use Automake::Condition;
+use Automake::Options;
+use Automake::XFile;
+use Automake::ChannelDefs;
+use Automake::Variable;
+use Automake::Rule;
use vars qw (@ISA @EXPORT);
@ISA = qw (Exporter);
-@EXPORT = qw (var_SUFFIXES_trigger locate_aux_dir subst);
+@EXPORT = qw (var_SUFFIXES_trigger locate_aux_dir subst
+ make_paragraphs flatten);
# var_SUFFIXES_trigger ($TYPE, $VALUE)
# ------------------------------------
@@ -80,4 +84,183 @@ sub subst ($)
return '@' . $text . '@';
}
+
+# transform_token ($TOKEN, \%PAIRS, $KEY)
+# ---------------------------------------
+# Return the value associated to $KEY in %PAIRS, as used on $TOKEN
+# (which should be ?KEY? or any of the special %% requests)..
+sub transform_token ($\%$)
+{
+ my ($token, $transform, $key) = @_;
+ my $res = $transform->{$key};
+ prog_error "Unknown key '$key' in '$token'" unless defined $res;
+ return $res;
+}
+
+
+# transform ($TOKEN, \%PAIRS)
+# ---------------------------
+# If ($TOKEN, $VAL) is in %PAIRS:
+# - replaces %KEY% with $VAL,
+# - enables/disables ?KEY? and ?!KEY?,
+# - replaces %?KEY% with TRUE or FALSE.
+sub transform ($\%)
+{
+ my ($token, $transform) = @_;
+
+ # %KEY%.
+ # Must be before the following pattern to exclude the case
+ # when there is neither IFTRUE nor IFFALSE.
+ if ($token =~ /^%([\w\-]+)%$/)
+ {
+ return transform_token ($token, %$transform, $1);
+ }
+ # %?KEY%.
+ elsif ($token =~ /^%\?([\w\-]+)%$/)
+ {
+ return transform_token ($token, %$transform, $1) ? 'TRUE' : 'FALSE';
+ }
+ # ?KEY? and ?!KEY?.
+ elsif ($token =~ /^ \? (!?) ([\w\-]+) \? $/x)
+ {
+ my $neg = ($1 eq '!') ? 1 : 0;
+ my $val = transform_token ($token, %$transform, $2);
+ return (!!$val == $neg) ? '##%' : '';
+ }
+ else
+ {
+ prog_error "Unknown request format: $token";
+ }
+}
+
+
+# $TEXT
+# preprocess_file ($MAKEFILE, [%TRANSFORM])
+# -----------------------------------------
+# Load a $MAKEFILE, apply the %TRANSFORM, and return the result.
+# No extra parsing or post-processing is done (i.e., recognition of
+# rules declaration or of make variables definitions).
+sub preprocess_file
+{
+ my ($file, %transform) = @_;
+
+ # Complete %transform with global options.
+ # Note that %transform goes last, so it overrides global options.
+ %transform = ( 'MAINTAINER-MODE'
+ => $seen_maint_mode ? subst ('MAINTAINER_MODE_TRUE') : '',
+
+ 'XZ' => !! option 'dist-xz',
+ 'LZIP' => !! option 'dist-lzip',
+ 'BZIP2' => !! option 'dist-bzip2',
+ 'COMPRESS' => !! option 'dist-tarZ',
+ 'GZIP' => ! option 'no-dist-gzip',
+ 'SHAR' => !! option 'dist-shar',
+ 'ZIP' => !! option 'dist-zip',
+
+ 'INSTALL-INFO' => ! option 'no-installinfo',
+ 'INSTALL-MAN' => ! option 'no-installman',
+ 'CK-NEWS' => !! option 'check-news',
+
+ 'SUBDIRS' => !! Automake::Variable::var ('SUBDIRS'),
+ 'TOPDIR_P' => $relative_dir eq '.',
+
+ 'BUILD' => ($seen_canonical >= AC_CANONICAL_BUILD),
+ 'HOST' => ($seen_canonical >= AC_CANONICAL_HOST),
+ 'TARGET' => ($seen_canonical >= AC_CANONICAL_TARGET),
+
+ 'LIBTOOL' => !! Automake::Variable::var ('LIBTOOL'),
+ 'NONLIBTOOL' => 1,
+ %transform);
+
+ if (! defined ($_ = $am_file_cache{$file}))
+ {
+ verb "reading $file";
+ # Swallow the whole file.
+ my $fc_file = new Automake::XFile "< $file";
+ my $saved_dollar_slash = $/;
+ undef $/;
+ $_ = $fc_file->getline;
+ $/ = $saved_dollar_slash;
+ $fc_file->close;
+ # Remove ##-comments.
+ # Besides we don't need more than two consecutive new-lines.
+ s/(?:$IGNORE_PATTERN|(?<=\n\n)\n+)//gom;
+ # Remember the contents of the just-read file.
+ $am_file_cache{$file} = $_;
+ }
+
+ # Substitute Automake template tokens.
+ s/(?: % \?? [\w\-]+ %
+ | \? !? [\w\-]+ \?
+ )/transform($&, %transform)/gex;
+ # transform() may have added some ##%-comments to strip.
+ # (we use '##%' instead of '##' so we can distinguish ##%##%##% from
+ # ####### and do not remove the latter.)
+ s/^[ \t]*(?:##%)+.*\n//gm;
+
+ return $_;
+}
+
+
+# @PARAGRAPHS
+# make_paragraphs ($MAKEFILE, [%TRANSFORM])
+# -----------------------------------------
+# Load a $MAKEFILE, apply the %TRANSFORM, and return it as a list of
+# paragraphs.
+sub make_paragraphs
+{
+ my ($file, %transform) = @_;
+ $transform{FIRST} = !$transformed_files{$file};
+ $transformed_files{$file} = 1;
+
+ my @lines = split /(?<!\\)\n/, preprocess_file ($file, %transform);
+ my @res;
+
+ while (defined ($_ = shift @lines))
+ {
+ my $paragraph = $_;
+ # If we are a rule, eat as long as we start with a tab.
+ if (/$RULE_PATTERN/smo)
+ {
+ while (defined ($_ = shift @lines) && $_ =~ /^\t/)
+ {
+ $paragraph .= "\n$_";
+ }
+ unshift (@lines, $_);
+ }
+
+ # If we are a comments, eat as much comments as you can.
+ elsif (/$COMMENT_PATTERN/smo)
+ {
+ while (defined ($_ = shift @lines)
+ && $_ =~ /$COMMENT_PATTERN/smo)
+ {
+ $paragraph .= "\n$_";
+ }
+ unshift (@lines, $_);
+ }
+
+ push @res, $paragraph;
+ }
+
+ return @res;
+}
+
+
+# $STRING
+# flatten ($ORIGINAL_STRING)
+# --------------------------
+sub flatten
+{
+ $_ = shift;
+
+ s/\\\n//somg;
+ s/\s+/ /g;
+ s/^ //;
+ s/ $//;
+
+ return $_;
+}
+
+
1;
diff --git a/lib/Automake/Variable.pm b/lib/Automake/Variable.pm
index ac04a94cf..39573d4f6 100644
--- a/lib/Automake/Variable.pm
+++ b/lib/Automake/Variable.pm
@@ -32,6 +32,7 @@ use Automake::Wrap 'makefile_wrap';
use Automake::Global;
use Automake::Location;
use Automake::Utils;
+use Automake::File;
require Exporter;
use vars '@ISA', '@EXPORT', '@EXPORT_OK';
@@ -52,8 +53,7 @@ use vars '@ISA', '@EXPORT', '@EXPORT_OK';
define_verbose_tagvar
define_pretty_variable
define_variable
- define_files_variable
- define_standard_variables);
+ define_files_variable);
=head1 NAME
@@ -1789,35 +1789,4 @@ sub define_files_variable ($\@$$)
}
-# Like define_variable, but define a variable to be the configure
-# substitution by the same name.
-sub _define_configure_variable ($)
-{
- my ($var) = @_;
- # Some variables we do not want to output. For instance it
- # would be a bad idea to output `U = @U@` when `@U@` can be
- # substituted as `\`.
- my $pretty = exists $ignored_configure_vars{$var} ? VAR_SILENT : VAR_ASIS;
- define ($var, VAR_CONFIGURE, '', TRUE, subst ($var),
- '', $configure_vars{$var}, $pretty);
-}
-
-
-# A helper for read_main_am_file which initializes configure variables
-# 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);
-
- foreach my $var (sort keys %configure_vars)
- {
- _define_configure_variable ($var);
- }
-
- $output_vars .= $comments . $rules;
-}
-
1;
diff --git a/lib/Automake/local.mk b/lib/Automake/local.mk
index 79d28a596..a0b2ea462 100644
--- a/lib/Automake/local.mk
+++ b/lib/Automake/local.mk
@@ -24,8 +24,11 @@ dist_perllib_DATA = \
%D%/ChannelDefs.pm \
%D%/Channels.pm \
%D%/Condition.pm \
+ %D%/CondStack.pm \
%D%/Configure_ac.pm \
+ %D%/ConfVars.pm \
%D%/DisjConditions.pm \
+ %D%/File.pm \
%D%/FileUtils.pm \
%D%/General.pm \
%D%/Global.pm \
@@ -37,6 +40,7 @@ dist_perllib_DATA = \
%D%/Options.pm \
%D%/Rule.pm \
%D%/RuleDef.pm \
+ %D%/Utils.pm \
%D%/Variable.pm \
%D%/VarDef.pm \
%D%/Version.pm \