automake-patches
[Top][All Lists]
Advanced

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

multiple derivations rules for the same input suffix (PR/37)


From: Alexandre Duret-Lutz
Subject: multiple derivations rules for the same input suffix (PR/37)
Date: Fri, 28 Jun 2002 20:39:46 +0200
User-agent: Gnus/5.090007 (Oort Gnus v0.07) Emacs/21.2 (i386-debian-linux-gnu)

>>> "Bob" == Bob Ham <address@hidden> writes:

 Bob> On Wed, 2002-06-26 at 19:22, Alexandre Duret-Lutz wrote:
 >> Suffix rules are expected to work... except in your case :)

 Bob> Ack :(

 >> Presently suffix rules cannot share the same input suffix 
 >> (see PR/37 and the FIXME on %suffix_rules in the code).

 Bob> Err.. what is PR/37?

Praseodymium.  The fact that it has atomic number 37 instead of
59 means the universe the severly broken <wink>.

 Bob> And do you have any idea when this might be fixed?  Is it in the TODO
 Bob> for 1.6.3, 1.7, 2.0, or at all?

I've started to work on a patch (appended) for this.  For now
I've only tested it on the `suffix*.test' tests of the test
suite (I'm running a full `make check' now, but my machine is
horribly slow and I have to leave).

The patch is against CVS HEAD (i.e. future Automake 1.7).
That's seem too big to include on the 1.6.x branch.


2002-06-28  Alexandre Duret-Lutz  <address@hidden>

        Handle multiple suffix rules with the same input extension.
        For PR automake/37.

        * automake.in (suffix_rules_default): New variable.
        (suffix_rules): Redefine as a hash of hashes of pairs.
        (initialize_per_input): Setup suffix_rules_default from
        suffix_rules on first call, an override suffix_rules
        with suffix_rules_default on following calls.
        (struct) <output_extension>: New attribute.
        (register_language): Set the default for output_extension.
        Call register_suffix_rule for each suffix.
        (derive_suffix, handle_languages): Adjust to the new definition
        of $suffix.
        (register_suffix_rule): New function.
        (rule_define): Call register_suffix_rule.
        * tests/suffix8.test, tests/suffix9.test: New files.

Index: automake.in
===================================================================
RCS file: /cvs/automake/automake/automake.in,v
retrieving revision 1.1312
diff -u -r1.1312 automake.in
--- automake.in 27 Jun 2002 19:31:59 -0000      1.1312
+++ automake.in 28 Jun 2002 18:22:16 -0000
@@ -59,7 +59,10 @@
         'compile'  => "\$",
         # Flag to require compilation without linking (-c).
         'compile_flag' => "\$",
-        'extensions'      => '@',
+        'extensions' => '@',
+       # A regex to compute the extension of the product
+       # (defaults to `s/\..*$/\..\$(OBJEXT)/')
+       'output_extension' => "\$",
         'flags' => "\$",
 
        # The file to use when generating rules for this language.
@@ -432,6 +435,9 @@
 # Options set via AM_INIT_AUTOMAKE.
 my $global_options = '';
 
+# Same as $suffix_rules (declared below), but records only the
+# default rules supplied by the languages Automake supports.
+my $suffix_rules_default;
 
 
 ################################################################
@@ -567,12 +573,26 @@
 # trailing `/'.
 my %de_ansi_files;
 
-# This maps the source extension of a suffix rule to its
-# corresponding output extension.
-# FIXME: because this hash maps one input extension to one output
-# extension, Automake cannot handle two suffix rules with the same
-# input extension.
-my %suffix_rules;
+# 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;
@@ -748,7 +768,17 @@
 
     %de_ansi_files = ();
 
-    %suffix_rules = ();
+
+    # 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 = '';
 
@@ -839,6 +869,9 @@
                   'Name' => 'Header',
                   'extensions' => ['.h', '.H', '.hxx', '.h++', '.hh',
                                    '.hpp', '.inc'],
+                  # Die if someone try to compute the output extension
+                  # for this language.
+                  'output_extension' => '//; die',
                   # Nothing to do.
                   '_finish' => sub { });
 
@@ -850,6 +883,7 @@
                   'compile' => '$(YACC) $(YFLAGS) $(AM_YFLAGS)',
                   'compiler' => 'YACCCOMPILE',
                   'extensions' => ['.y'],
+                  'output_extension' => 'tr/y/c/',
                   'rule_file' => 'yacc',
                   '_finish' => \&lang_yacc_finish,
                   '_target_hook' => \&lang_yacc_target_hook);
@@ -861,6 +895,7 @@
                   'compiler' => 'YACCCOMPILE',
                   'compile' => '$(YACC) $(YFLAGS) $(AM_YFLAGS)',
                   'extensions' => ['.y++', '.yy', '.yxx', '.ypp'],
+                  'output_extension' => 'tr/y/c/',
                   '_finish' => \&lang_yacc_finish,
                   '_target_hook' => \&lang_yacc_target_hook);
 
@@ -873,6 +908,7 @@
                   'compile' => '$(LEX) $(LFLAGS) $(AM_LFLAGS)',
                   'compiler' => 'LEXCOMPILE',
                   'extensions' => ['.l'],
+                  'output_extension' => 'tr/l/c/',
                   '_finish' => \&lang_lex_finish,
                   '_target_hook' => \&lang_lex_target_hook);
 register_language ('name' => 'lexxx',
@@ -883,6 +919,7 @@
                   'compile' => '$(LEX) $(LFLAGS) $(AM_LFLAGS)',
                   'compiler' => 'LEXCOMPILE',
                   'extensions' => ['.l++', '.ll', '.lxx', '.lpp'],
+                  'output_extension' => 'tr/l/c/',
                   '_finish' => \&lang_lex_finish,
                   '_target_hook' => \&lang_lex_target_hook);
 
@@ -1669,12 +1706,10 @@
                  && $lang->flags eq 'CFLAGS'
                  && defined $options{'subdir-objects'});
 
-           # FIXME: this is a temporary hack to compute a possible
-           # derived extension.  This is not used by depend2.am.
-           (my $der_ext = $ext) =~ tr/yl/cc/;
-
-           # Another yacc/lex hack.
-           my $destfile = '$*' . $der_ext;
+           # Compute the derived extension.
+           # This is not used by depend2.am.
+           my $der_ext = $ext;
+           eval '$der_ext =~ ' . $lang->output_extension;
 
            $output_rules .=
              file_contents ($rule_file,
@@ -1800,7 +1835,8 @@
     # 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 > 1;
+      if $need_link || ((scalar keys %$suffix_rules)
+                       - (scalar keys %$suffix_rules_default)) > 1;
 
     if ($needs_c)
       {
@@ -5301,24 +5337,35 @@
 # Each %ATTRIBUTE is of the form ATTRIBUTE => VALUE.
 sub register_language (%)
 {
-    my (%option) = @_;
+  my (%option) = @_;
 
-    # Set the defaults.
-    $option{'ansi'} = 0
-      unless defined $option{'ansi'};
-    $option{'autodep'} = 'no'
-      unless defined $option{'autodep'};
-    $option{'linker'} = ''
-      unless defined $option{'linker'};
-
-    my $lang = new Language (%option);
-
-    # Fill indexes.
-    grep ($extension_map{$_} = $lang->name, @{$lang->extensions});
-    $languages{$lang->name} = $lang;
-
-    # Update the pattern of known extensions.
-    accept_extensions (@{$lang->extensions});
+  # Set the defaults.
+  $option{'ansi'} = 0
+    unless defined $option{'ansi'};
+  $option{'autodep'} = 'no'
+    unless defined $option{'autodep'};
+  $option{'linker'} = ''
+    unless defined $option{'linker'};
+  $option{'output_extension'} = 's/\..*$/.\$(OBJEXT)/'
+    unless defined $option{'output_extension'};
+
+  my $lang = new Language (%option);
+
+  # Fill indexes.
+  grep ($extension_map{$_} = $lang->name, @{$lang->extensions});
+  $languages{$lang->name} = $lang;
+
+  # Update the pattern of known extensions.
+  accept_extensions (@{$lang->extensions});
+
+  # Upate the $suffix_rule map.
+  foreach my $suffix (@{$lang->extensions})
+    {
+      my $dest = $suffix;
+      eval '$dest =~ ' . $lang->output_extension;
+      # Don't register anything if the above `eval' died.
+      &register_suffix_rule ('internal', $suffix, $dest) unless $@;
+    }
 }
 
 # derive_suffix ($EXT, $OBJ)
@@ -5327,16 +5374,17 @@
 # to $OBJ or to some other suffix we recognize internally, eg `cc'.
 sub derive_suffix ($$)
 {
-    my ($source_ext, $obj) = @_;
+  my ($source_ext, $obj) = @_;
 
-    while (! $extension_map{$source_ext}
-          && $source_ext ne $obj
-          && defined $suffix_rules{$source_ext})
+  while (! $extension_map{$source_ext}
+        && $source_ext ne $obj
+        && exists $suffix_rules->{$source_ext}
+        && exists $suffix_rules->{$source_ext}{$obj})
     {
-       $source_ext = $suffix_rules{$source_ext};
+      $source_ext = $suffix_rules->{$source_ext}{$obj}[0];
     }
 
-    return $source_ext;
+  return $source_ext;
 }
 
 
@@ -6766,6 +6814,77 @@
 ## Handling rules.  ##
 ## ---------------- ##
 
+sub register_suffix_rule ($$$)
+{
+  my ($where, $src, $dest) = @_;
+
+  verbose "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 ];
+               }
+           }
+       }
+    }
+}
+
 # $BOOL
 # rule_define ($TARGET, $IS_AM, $COND, $WHERE)
 # --------------------------------------------
@@ -6823,22 +6942,7 @@
   # (see handle_footer).
       || ($target =~ /$SUFFIX_RULE_PATTERN/o && accept_extensions($1)))
   {
-      my $internal_ext = $2;
-
-      # 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'...
-      $internal_ext = '.$(OBJEXT)' if ($2 eq '.o' || $2 eq '.obj');
-
-      $suffix_rules{$1} = $internal_ext;
-      verbose "Sources ending in $1 become $2";
-      push @suffixes, $1, $2;
+    register_suffix_rule ($where, $1, $2);
   }
 
   return 1;
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/automake/automake/tests/Makefile.am,v
retrieving revision 1.410
diff -u -r1.410 Makefile.am
--- tests/Makefile.am   19 Jun 2002 19:57:39 -0000      1.410
+++ tests/Makefile.am   28 Jun 2002 18:22:16 -0000
@@ -349,6 +349,8 @@
 suffix5.test \
 suffix6.test \
 suffix7.test \
+suffix8.test \
+suffix9.test \
 symlink.test \
 symlink2.test \
 symlink3.test \
Index: tests/Makefile.in
===================================================================
RCS file: /cvs/automake/automake/tests/Makefile.in,v
retrieving revision 1.530
diff -u -r1.530 Makefile.in
--- tests/Makefile.in   26 Jun 2002 19:13:56 -0000      1.530
+++ tests/Makefile.in   28 Jun 2002 18:22:16 -0000
@@ -436,6 +436,8 @@
 suffix5.test \
 suffix6.test \
 suffix7.test \
+suffix8.test \
+suffix9.test \
 symlink.test \
 symlink2.test \
 symlink3.test \
Index: tests/suffix8.test
===================================================================
RCS file: tests/suffix8.test
diff -N tests/suffix8.test
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ tests/suffix8.test  28 Jun 2002 18:22:17 -0000
@@ -0,0 +1,56 @@
+#! /bin/sh
+
+# Test to make sure Automake supports multiple derivations for the same suffix.
+# PR/37
+
+required='gcc libtoolize'
+. $srcdir/defs || exit 1
+
+set -e
+
+cat >>configure.in <<'END'
+AM_PROG_LIBTOOL
+AC_OUTPUT
+END
+
+cat >Makefile.am << 'END'
+bin_PROGRAMS = foo
+lib_LTLIBRARIES = libfoo.la
+
+foo_SOURCES = foo.x_
+libfoo_la_SOURCES = bar.x_
+
+.x_.y_:
+       cp $< $@
+
+.y_.o:
+       cp $< $@
+
+.y_.z_:
+       cp $< $@
+
+.z_.lo:
+       cp $< $@
+
+print:
+       @echo BEGIN: $(foo_OBJECTS) :END
+       @echo BEGIN: $(libfoo_la_OBJECTS) :END
+
+test: $(foo_OBJECTS) $(libfoo_la_OBJECTS)
+       test -f foo.$(OBJEXT)
+       test -f bar.lo
+END
+
+echo 'int main() { return 0; }' > foo.x_
+cp foo.x_ bar.x_
+
+libtoolize
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE -a
+./configure
+env OBJEXT=foo $MAKE -e SHELL=/bin/sh print >stdout
+cat stdout
+grep 'BEGIN: foo.foo :END' stdout
+grep 'BEGIN: bar.lo :END' stdout
+$MAKE test
Index: tests/suffix9.test
===================================================================
RCS file: tests/suffix9.test
diff -N tests/suffix9.test
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ tests/suffix9.test  28 Jun 2002 18:22:17 -0000
@@ -0,0 +1,47 @@
+#! /bin/sh
+
+# Make sure that Automake choose the shorter route between suffixes
+# (related to PR/37)
+
+. $srcdir/defs || exit 1
+
+set -e
+
+echo AC_PROG_CC >>configure.in
+
+#  x_ -> y -> c -> o
+#   \________/
+#
+# Automake should follow the bottom route: x_ -> c -> o because
+# it is shorter.
+#
+# It should not take the "-> y ->" route.  We use `y' here so that
+# then Automake will complains that YACC is not defined and the test will
+# fail when this happens.
+
+cat >Makefile.am << 'END'
+bin_PROGRAMS = foo
+foo_SOURCES = foo.x_
+
+.x_.y:
+       cp $< $@
+.x_.c:
+       cp $< $@
+END
+
+$ACLOCAL
+$AUTOMAKE -a
+
+# Idem with the rules the another order.
+
+cat >Makefile.am << 'END'
+bin_PROGRAMS = foo
+foo_SOURCES = foo.x_
+
+.x_.c:
+       cp $< $@
+.x_.y:
+       cp $< $@
+END
+
+$AUTOMAKE -a

-- 
Alexandre Duret-Lutz




reply via email to

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