automake-patches
[Top][All Lists]
Advanced

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

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


From: Alexandre Duret-Lutz
Subject: FYI: multiple derivations rules for the same input suffix (PR/37)
Date: Mon, 01 Jul 2002 18:10:44 +0200
User-agent: Gnus/5.090007 (Oort Gnus v0.07) Emacs/21.2 (i386-debian-linux-gnu)

I'm checking in this (on HEAD).

2002-07-01  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_extensions>: New attribute.
        (register_language): Set the default for output_extensions.
        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, tests/suffix10.test:
        New files.
        * tests/Makefile.am (TESTS): Add them.

Index: automake.in
===================================================================
RCS file: /cvs/automake/automake/automake.in,v
retrieving revision 1.1313
diff -u -r1.1313 automake.in
--- automake.in 30 Jun 2002 22:44:12 -0000      1.1313
+++ automake.in 1 Jul 2002 16:05:30 -0000
@@ -59,7 +59,11 @@
         'compile'  => "\$",
         # Flag to require compilation without linking (-c).
         'compile_flag' => "\$",
-        'extensions'      => '@',
+        'extensions' => '@',
+       # A subroutine to compute a list of possible extensions of
+       # the product given the input extensions.
+       # (defaults to a subroutine which returns ('.$(OBJEXT)', '.lo'))
+       'output_extensions' => "\$",
         'flags' => "\$",
 
        # The file to use when generating rules for this language.
@@ -449,6 +453,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;
 
 
 ################################################################
@@ -584,12 +591,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;
@@ -772,7 +793,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 = '';
 
@@ -865,6 +896,8 @@
                   'Name' => 'Header',
                   'extensions' => ['.h', '.H', '.hxx', '.h++', '.hh',
                                    '.hpp', '.inc'],
+                  # No output.
+                  'output_extensions' => sub { return () },
                   # Nothing to do.
                   '_finish' => sub { });
 
@@ -876,6 +909,8 @@
                   'compile' => '$(YACC) $(YFLAGS) $(AM_YFLAGS)',
                   'compiler' => 'YACCCOMPILE',
                   'extensions' => ['.y'],
+                  'output_extensions' => sub { (my $ext = $_[0]) =~ tr/y/c/;
+                                               return ($ext,) },
                   'rule_file' => 'yacc',
                   '_finish' => \&lang_yacc_finish,
                   '_target_hook' => \&lang_yacc_target_hook);
@@ -887,6 +922,8 @@
                   'compiler' => 'YACCCOMPILE',
                   'compile' => '$(YACC) $(YFLAGS) $(AM_YFLAGS)',
                   'extensions' => ['.y++', '.yy', '.yxx', '.ypp'],
+                  'output_extensions' => sub { (my $ext = $_[0]) =~ tr/y/c/;
+                                               return ($ext,) },
                   '_finish' => \&lang_yacc_finish,
                   '_target_hook' => \&lang_yacc_target_hook);
 
@@ -899,6 +936,8 @@
                   'compile' => '$(LEX) $(LFLAGS) $(AM_LFLAGS)',
                   'compiler' => 'LEXCOMPILE',
                   'extensions' => ['.l'],
+                  'output_extensions' => sub { (my $ext = $_[0]) =~ tr/l/c/;
+                                               return ($ext,) },
                   '_finish' => \&lang_lex_finish,
                   '_target_hook' => \&lang_lex_target_hook);
 register_language ('name' => 'lexxx',
@@ -909,6 +948,8 @@
                   'compile' => '$(LEX) $(LFLAGS) $(AM_LFLAGS)',
                   'compiler' => 'LEXCOMPILE',
                   'extensions' => ['.l++', '.ll', '.lxx', '.lpp'],
+                  'output_extensions' => sub { (my $ext = $_[0]) =~ tr/l/c/;
+                                               return ($ext,) },
                   '_finish' => \&lang_lex_finish,
                   '_target_hook' => \&lang_lex_target_hook);
 
@@ -1695,12 +1736,9 @@
                  && $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 a possible derived extension.
+           # This is not used by depend2.am.
+           my $der_ext = (&{$lang->output_extensions} ($ext))[0];
 
            $output_rules .=
              file_contents ($rule_file,
@@ -1821,7 +1859,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)
       {
@@ -5281,24 +5320,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'};
+  $option{'output_extensions'} = sub { return ( '.$(OBJEXT)', '.lo' ) }
+    unless defined $option{'output_extensions'};
 
-    # 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;
+  my $lang = new Language (%option);
 
-    # Update the pattern of known extensions.
-    accept_extensions (@{$lang->extensions});
+  # 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})
+    {
+      foreach my $dest (&{$lang->output_extensions} ($suffix))
+       {
+         &register_suffix_rule ('internal', $suffix, $dest);
+       }
+    }
 }
 
 # derive_suffix ($EXT, $OBJ)
@@ -5307,16 +5357,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;
 }
 
 
@@ -6752,6 +6803,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)
 # --------------------------------------------
@@ -6809,22 +6931,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.411
diff -u -r1.411 Makefile.am
--- tests/Makefile.am   30 Jun 2002 22:44:13 -0000      1.411
+++ tests/Makefile.am   1 Jul 2002 16:05:30 -0000
@@ -354,6 +354,9 @@
 suffix5.test \
 suffix6.test \
 suffix7.test \
+suffix8.test \
+suffix9.test \
+suffix10.test \
 symlink.test \
 symlink2.test \
 symlink3.test \
Index: tests/Makefile.in
===================================================================
RCS file: /cvs/automake/automake/tests/Makefile.in,v
retrieving revision 1.531
diff -u -r1.531 Makefile.in
--- tests/Makefile.in   30 Jun 2002 22:44:13 -0000      1.531
+++ tests/Makefile.in   1 Jul 2002 16:05:30 -0000
@@ -441,6 +441,9 @@
 suffix5.test \
 suffix6.test \
 suffix7.test \
+suffix8.test \
+suffix9.test \
+suffix10.test \
 symlink.test \
 symlink2.test \
 symlink3.test \
Index: tests/suffix10.test
===================================================================
RCS file: tests/suffix10.test
diff -N tests/suffix10.test
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ tests/suffix10.test 1 Jul 2002 16:05:30 -0000
@@ -0,0 +1,37 @@
+#! /bin/sh
+
+# Make sure that derivations work with .lo too.
+# (related to PR/37)
+
+required='libtoolize bison'
+. $srcdir/defs || exit 1
+
+set -e
+
+cat >>configure.in <<EOF
+AC_PROG_CC
+AC_PROG_YACC
+AC_PROG_LIBTOOL
+AC_OUTPUT
+EOF
+
+
+cat >Makefile.am << 'END'
+lib_LTLIBRARIES = libfoo.la
+libfoo_la_SOURCES = foo.x_
+
+.x_.y:
+       cp $< $@
+
+print:
+       echo BEGIN: $(libfoo_la_OBJECTS) :END
+END
+
+libtoolize --force
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE --add-missing
+./configure
+$MAKE print >stdout
+cat stdout
+grep 'BEGIN: foo.lo :END' stdout
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  1 Jul 2002 16:05:30 -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  1 Jul 2002 16:05:30 -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]