]> git.ipfire.org Git - thirdparty/automake.git/commitdiff
lib: fix Automake::Variable
authorMatthias Paulmier <matthias.paulmier@etu.u-bordeaux.fr>
Wed, 6 Jun 2018 13:46:24 +0000 (15:46 +0200)
committerMatthias Paulmier <matthias.paulmier@etu.u-bordeaux.fr>
Fri, 22 Jun 2018 12:18:34 +0000 (14:18 +0200)
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.

bin/automake.in
lib/Automake/CondStack.pm [new file with mode: 0644]
lib/Automake/ConfVars.pm [new file with mode: 0644]
lib/Automake/File.pm [new file with mode: 0644]
lib/Automake/Utils.pm
lib/Automake/Variable.pm
lib/Automake/local.mk

index fb9779882e795031f2c465becfe8d0bb6144cd7c..18a6fbf3e5b2c4c156bde70dff919be53e0d4959 100755 (executable)
@@ -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 (file)
index 0000000..5d52607
--- /dev/null
@@ -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 (file)
index 0000000..8d7f362
--- /dev/null
@@ -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 (file)
index 0000000..77cc062
--- /dev/null
@@ -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;
index 832b74e05c1125d4af7b4ba3ef6e76ee3ef660f5..aafb911cd6afc3fd2b748dba4a532568e20beb4c 100644 (file)
@@ -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;
index ac04a94cf88bb743df4d19be9c66a729108f8533..39573d4f6816efea5abcbdcb713552b37e4d0440 100644 (file)
@@ -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;
index 79d28a5960d530bd2098d7688b3d5afbc478bdab..a0b2ea462faee20dc8ea7365b4b7ba632bbd9295 100644 (file)
@@ -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 \