]> git.ipfire.org Git - thirdparty/automake.git/commitdiff
lib: Add new modules
authorMatthias Paulmier <matthias.paulmier@etu.u-bordeaux.fr>
Wed, 20 Jun 2018 14:57:02 +0000 (16:57 +0200)
committerMatthias Paulmier <matthias.paulmier@etu.u-bordeaux.fr>
Fri, 22 Jun 2018 12:20:37 +0000 (14:20 +0200)
In an effort to move out as much as possible from the main script, we create
these modules to host the methods.

* LangHandling: This module host all the functions for handling
  languages (functions that define obj directories of the language, rewrite
  the file extention...).
* SilentRules: Declares functions for handling silent rules.
* Requires: Functions for requiring configuration files.

bin/automake.in
lib/Automake/LangHandling.pm [new file with mode: 0644]
lib/Automake/Requires.pm [new file with mode: 0644]
lib/Automake/SilentRules.pm [new file with mode: 0644]
lib/Automake/local.mk

index 4b5eee4483f72cf8b8ae09d549c3423adef57c1c..556780eb2ec6d1a8582e5de1764022cbd9419583 100755 (executable)
@@ -72,6 +72,9 @@ use Automake::Utils;
 use Automake::CondStack;
 use Automake::ConfVars;
 use Automake::Errors;
+use Automake::LangHandling;
+use Automake::SilentRules;
+use Automake::Requires;
 use File::Basename;
 use File::Spec;
 use Carp;
@@ -110,7 +113,6 @@ sub handle_options ();
 sub handle_programs ();
 sub handle_python ();
 sub handle_scripts ();
-sub handle_silent ();
 sub handle_subdirs ();
 sub handle_tags ();
 sub handle_targets ();
@@ -590,66 +592,6 @@ sub backname
     return join ('/', @res) || '.';
 }
 
-################################################################
-
-# Silent rules handling functions.
-
-# verbose_flag (NAME)
-# -------------------
-# Contents of '%VERBOSE%' variable to expand before rule command.
-sub verbose_flag
-{
-    my ($name) = @_;
-    return '$(' . verbose_var ($name) . ')';
-}
-
-sub verbose_nodep_flag
-{
-    my ($name) = @_;
-    return '$(' . verbose_var ($name) . subst ('am__nodep') . ')';
-}
-
-# silent_flag
-# -----------
-# Contents of %SILENT%: variable to expand to '@' when silent.
-sub silent_flag ()
-{
-    return verbose_flag ('at');
-}
-
-# Engage the needed silent rules machinery for assorted texinfo commands.
-sub define_verbose_texinfo ()
-{
-  my @tagvars = ('DVIPS', 'MAKEINFO', 'INFOHTML', 'TEXI2DVI', 'TEXI2PDF');
-  foreach my $tag (@tagvars)
-    {
-      define_verbose_tagvar($tag);
-    }
-  define_verbose_var('texinfo', '-q');
-  define_verbose_var('texidevnull', '> /dev/null');
-}
-
-# Engage the needed silent rules machinery for 'libtool --silent'.
-sub define_verbose_libtool ()
-{
-    define_verbose_var ('lt', '--silent');
-    return verbose_flag ('lt');
-}
-
-sub handle_silent ()
-{
-    # Define "$(AM_V_P)", expanding to a shell conditional that can be
-    # used in make recipes to determine whether we are being run in
-    # silent mode or not.  The choice of the name derives from the LISP
-    # convention of appending the letter 'P' to denote a predicate (see
-    # also "the '-P' convention" in the Jargon File); we do so for lack
-    # of a better convention.
-    define_verbose_var ('P', 'false', ':');
-    # *Always* provide the user with '$(AM_V_GEN)', unconditionally.
-    define_verbose_tagvar ('GEN');
-    define_verbose_var ('at', '@');
-}
-
 
 ################################################################
 
@@ -701,32 +643,6 @@ sub shadow_unconditionally
   return "\$($varname)"
 }
 
-# check_user_variables (@LIST)
-# ----------------------------
-# Make sure each variable VAR in @LIST does not exist, suggest using AM_VAR
-# otherwise.
-sub check_user_variables
-{
-  my @dont_override = @_;
-  foreach my $flag (@dont_override)
-    {
-      my $var = var $flag;
-      if ($var)
-       {
-         for my $cond ($var->conditions->conds)
-           {
-             if ($var->rdef ($cond)->owner == VAR_MAKEFILE)
-               {
-                 msg_cond_var ('gnu', $cond, $flag,
-                               "'$flag' is a user variable, "
-                               . "you should not override it;\n"
-                               . "use 'AM_$flag' instead");
-               }
-           }
-       }
-    }
-}
-
 # Call finish function for each language that was used.
 sub handle_languages ()
 {
@@ -5059,416 +4975,6 @@ sub check_gnits_standards ()
     }
 }
 
-################################################################
-#
-# Functions to handle files of each language.
-
-# Each 'lang_X_rewrite($DIRECTORY, $BASE, $EXT)' function follows a
-# simple formula: Return value is LANG_SUBDIR if the resulting object
-# file should be in a subdir if the source file is, LANG_PROCESS if
-# file is to be dealt with, LANG_IGNORE otherwise.
-
-# Much of the actual processing is handled in
-# handle_single_transform.  These functions exist so that
-# auxiliary information can be recorded for a later cleanup pass.
-# Note that the calls to these functions are computed, so don't bother
-# searching for their precise names in the source.
-
-# This is just a convenience function that can be used to determine
-# when a subdir object should be used.
-sub lang_sub_obj ()
-{
-    return option 'subdir-objects' ? LANG_SUBDIR : LANG_PROCESS;
-}
-
-# Rewrite a single header file.
-sub lang_header_rewrite
-{
-    # Header files are simply ignored.
-    return LANG_IGNORE;
-}
-
-# Rewrite a single Vala source file.
-sub lang_vala_rewrite
-{
-    my ($directory, $base, $ext) = @_;
-
-    (my $newext = $ext) =~ s/vala$/c/;
-    return (LANG_SUBDIR, $newext);
-}
-
-# Rewrite a single yacc/yacc++ file.
-sub lang_yacc_rewrite
-{
-    my ($directory, $base, $ext) = @_;
-
-    my $r = lang_sub_obj;
-    (my $newext = $ext) =~ tr/y/c/;
-    return ($r, $newext);
-}
-sub lang_yaccxx_rewrite { lang_yacc_rewrite (@_); };
-
-# Rewrite a single lex/lex++ file.
-sub lang_lex_rewrite
-{
-    my ($directory, $base, $ext) = @_;
-
-    my $r = lang_sub_obj;
-    (my $newext = $ext) =~ tr/l/c/;
-    return ($r, $newext);
-}
-sub lang_lexxx_rewrite { lang_lex_rewrite (@_); };
-
-# Rewrite a single Java file.
-sub lang_java_rewrite
-{
-    return LANG_SUBDIR;
-}
-
-# The lang_X_finish functions are called after all source file
-# processing is done.  Each should handle defining rules for the
-# language, etc.  A finish function is only called if a source file of
-# the appropriate type has been seen.
-
-sub lang_vala_finish_target
-{
-  my ($self, $name) = @_;
-
-  my $derived = canonicalize ($name);
-  my $var = var "${derived}_SOURCES";
-  return unless $var;
-
-  my @vala_sources = grep { /\.(vala|vapi)$/ } ($var->value_as_list_recursive);
-
-  # For automake bug#11229.
-  return unless @vala_sources;
-
-  foreach my $vala_file (@vala_sources)
-    {
-      my $c_file = $vala_file;
-      if ($c_file =~ s/(.*)\.vala$/$1.c/)
-        {
-          $c_file = "\$(srcdir)/$c_file";
-          $output_rules .= "$c_file: \$(srcdir)/${derived}_vala.stamp\n"
-            . "\t\@if test -f \$@; then :; else rm -f \$(srcdir)/${derived}_vala.stamp; fi\n"
-            . "\t\@if test -f \$@; then :; else \\\n"
-            . "\t  \$(MAKE) \$(AM_MAKEFLAGS) \$(srcdir)/${derived}_vala.stamp; \\\n"
-            . "\tfi\n";
-         $clean_files{$c_file} = MAINTAINER_CLEAN;
-        }
-    }
-
-  # Add rebuild rules for generated header and vapi files
-  my $flags = var ($derived . '_VALAFLAGS');
-  if ($flags)
-    {
-      my $lastflag = '';
-      foreach my $flag ($flags->value_as_list_recursive)
-       {
-         if (grep (/$lastflag/, ('-H', '-h', '--header', '--internal-header',
-                                 '--vapi', '--internal-vapi', '--gir')))
-           {
-             my $headerfile = "\$(srcdir)/$flag";
-             $output_rules .= "$headerfile: \$(srcdir)/${derived}_vala.stamp\n"
-               . "\t\@if test -f \$@; then :; else rm -f \$(srcdir)/${derived}_vala.stamp; fi\n"
-               . "\t\@if test -f \$@; then :; else \\\n"
-               . "\t  \$(MAKE) \$(AM_MAKEFLAGS) \$(srcdir)/${derived}_vala.stamp; \\\n"
-               . "\tfi\n";
-
-             # valac is not used when building from dist tarballs
-             # distribute the generated files
-             push_dist_common ($headerfile);
-             $clean_files{$headerfile} = MAINTAINER_CLEAN;
-           }
-         $lastflag = $flag;
-       }
-    }
-
-  my $compile = $self->compile;
-
-  # Rewrite each occurrence of 'AM_VALAFLAGS' in the compile
-  # rule into '${derived}_VALAFLAGS' if it exists.
-  my $val = "${derived}_VALAFLAGS";
-  $compile =~ s/\(AM_VALAFLAGS\)/\($val\)/
-    if set_seen ($val);
-
-  # VALAFLAGS is a user variable (per GNU Standards),
-  # it should not be overridden in the Makefile...
-  check_user_variables 'VALAFLAGS';
-
-  my $dirname = dirname ($name);
-
-  # Only generate C code, do not run C compiler
-  $compile .= " -C";
-
-  my $verbose = verbose_flag ('VALAC');
-  my $silent = silent_flag ();
-  my $stampfile = "\$(srcdir)/${derived}_vala.stamp";
-
-  $output_rules .=
-    "\$(srcdir)/${derived}_vala.stamp: @vala_sources\n".
-# Since the C files generated from the vala sources depend on the
-# ${derived}_vala.stamp file, we must ensure its timestamp is older than
-# those of the C files generated by the valac invocation below (this is
-# especially important on systems with sub-second timestamp resolution).
-# Thus we need to create the stamp file *before* invoking valac, and to
-# move it to its final location only after valac has been invoked.
-    "\t${silent}rm -f \$\@ && echo stamp > \$\@-t\n".
-    "\t${verbose}\$(am__cd) \$(srcdir) && $compile @vala_sources\n".
-    "\t${silent}mv -f \$\@-t \$\@\n";
-
-  push_dist_common ($stampfile);
-
-  $clean_files{$stampfile} = MAINTAINER_CLEAN;
-}
-
-# Add output rules to invoke valac and create stamp file as a witness
-# to handle multiple outputs. This function is called after all source
-# file processing is done.
-sub lang_vala_finish ()
-{
-  my ($self) = @_;
-
-  foreach my $prog (keys %known_programs)
-    {
-      lang_vala_finish_target ($self, $prog);
-    }
-
-  while (my ($name) = each %known_libraries)
-    {
-      lang_vala_finish_target ($self, $name);
-    }
-}
-
-# The built .c files should be cleaned only on maintainer-clean
-# as the .c files are distributed. This function is called for each
-# .vala source file.
-sub lang_vala_target_hook
-{
-  my ($self, $aggregate, $output, $input, %transform) = @_;
-
-  $clean_files{$output} = MAINTAINER_CLEAN;
-}
-
-# This is a yacc helper which is called whenever we have decided to
-# compile a yacc file.
-sub lang_yacc_target_hook
-{
-    my ($self, $aggregate, $output, $input, %transform) = @_;
-
-    # If some relevant *YFLAGS variable contains the '-d' flag, we'll
-    # have to to generate special code.
-    my $yflags_contains_minus_d = 0;
-
-    foreach my $pfx ("", "${aggregate}_")
-      {
-       my $yflagsvar = var ("${pfx}YFLAGS");
-       next unless $yflagsvar;
-       # We cannot work reliably with conditionally-defined YFLAGS.
-       if ($yflagsvar->has_conditional_contents)
-         {
-           msg_var ('unsupported', $yflagsvar,
-                    "'${pfx}YFLAGS' cannot have conditional contents");
-         }
-       else
-         {
-           $yflags_contains_minus_d = 1
-             if grep (/^-d$/, $yflagsvar->value_as_list_recursive);
-         }
-      }
-
-    if ($yflags_contains_minus_d)
-      {
-       # Found a '-d' that applies to the compilation of this file.
-       # Add a dependency for the generated header file, and arrange
-       # for that file to be included in the distribution.
-
-       # The extension of the output file (e.g., '.c' or '.cxx').
-       # We'll need it to compute the name of the generated header file.
-       (my $output_ext = basename ($output)) =~ s/.*(\.[^.]+)$/$1/;
-
-       # We know that a yacc input should be turned into either a C or
-       # C++ output file.  We depend on this fact (here and in yacc.am),
-       # so check that it really holds.
-       my $lang = $languages{$extension_map{$output_ext}};
-       prog_error "invalid output name '$output' for yacc file '$input'"
-         if (!$lang || ($lang->name ne 'c' && $lang->name ne 'cxx'));
-
-       (my $header_ext = $output_ext) =~ s/c/h/g;
-        # Quote $output_ext in the regexp, so that dots in it are taken
-        # as literal dots, not as metacharacters.
-       (my $header = $output) =~ s/\Q$output_ext\E$/$header_ext/;
-
-       foreach my $cond (Automake::Rule::define (${header}, 'internal',
-                                                 RULE_AUTOMAKE, TRUE,
-                                                 INTERNAL))
-         {
-           my $condstr = $cond->subst_string;
-           $output_rules .=
-             "$condstr${header}: $output\n"
-             # Recover from removal of $header
-             . "$condstr\t\@if test ! -f \$@; then rm -f $output; else :; fi\n"
-             . "$condstr\t\@if test ! -f \$@; then \$(MAKE) \$(AM_MAKEFLAGS) $output; else :; fi\n";
-         }
-       # Distribute the generated file, unless its .y source was
-       # listed in a nodist_ variable.  (handle_source_transform()
-       # will set DIST_SOURCE.)
-       push_dist_common ($header)
-         if $transform{'DIST_SOURCE'};
-
-       # The GNU rules say that yacc/lex output files should be removed
-       # by maintainer-clean.  However, if the files are not distributed,
-       # then we want to remove them with "make clean"; otherwise,
-       # "make distcheck" will fail.
-       $clean_files{$header} = $transform{'DIST_SOURCE'} ? MAINTAINER_CLEAN : CLEAN;
-      }
-    # See the comment above for $HEADER.
-    $clean_files{$output} = $transform{'DIST_SOURCE'} ? MAINTAINER_CLEAN : CLEAN;
-}
-
-# This is a lex helper which is called whenever we have decided to
-# compile a lex file.
-sub lang_lex_target_hook
-{
-    my ($self, $aggregate, $output, $input, %transform) = @_;
-    # The GNU rules say that yacc/lex output files should be removed
-    # by maintainer-clean.  However, if the files are not distributed,
-    # then we want to remove them with "make clean"; otherwise,
-    # "make distcheck" will fail.
-    $clean_files{$output} = $transform{'DIST_SOURCE'} ? MAINTAINER_CLEAN : CLEAN;
-}
-
-# This is a helper for both lex and yacc.
-sub yacc_lex_finish_helper ()
-{
-  return if defined $language_scratch{'lex-yacc-done'};
-  $language_scratch{'lex-yacc-done'} = 1;
-
-  # FIXME: for now, no line number.
-  require_conf_file ($configure_ac, FOREIGN, 'ylwrap');
-  define_variable ('YLWRAP', "$am_config_aux_dir/ylwrap", INTERNAL);
-}
-
-sub lang_yacc_finish ()
-{
-  return if defined $language_scratch{'yacc-done'};
-  $language_scratch{'yacc-done'} = 1;
-
-  reject_var 'YACCFLAGS', "'YACCFLAGS' obsolete; use 'YFLAGS' instead";
-
-  yacc_lex_finish_helper;
-}
-
-
-sub lang_lex_finish ()
-{
-  return if defined $language_scratch{'lex-done'};
-  $language_scratch{'lex-done'} = 1;
-
-  yacc_lex_finish_helper;
-}
-
-
-# Given a hash table of linker names, pick the name that has the most
-# precedence.  This is lame, but something has to have global
-# knowledge in order to eliminate the conflict.  Add more linkers as
-# required.
-sub resolve_linker
-{
-    my (%linkers) = @_;
-
-    foreach my $l (qw(GCJLINK OBJCXXLINK CXXLINK F77LINK FCLINK OBJCLINK UPCLINK))
-    {
-       return $l if defined $linkers{$l};
-    }
-    return 'LINK';
-}
-
-# Called to indicate that an extension was used.
-sub saw_extension
-{
-    my ($ext) = @_;
-    $extension_seen{$ext} = 1;
-}
-
-# register_language (%ATTRIBUTE)
-# ------------------------------
-# Register a single language.
-# Each %ATTRIBUTE is of the form ATTRIBUTE => VALUE.
-sub register_language
-{
-  my (%option) = @_;
-
-  # Set the defaults.
-  $option{'autodep'} = 'no'
-    unless defined $option{'autodep'};
-  $option{'linker'} = ''
-    unless defined $option{'linker'};
-  $option{'flags'} = []
-    unless defined $option{'flags'};
-  $option{'output_extensions'} = sub { return ( '.$(OBJEXT)', '.lo' ) }
-    unless defined $option{'output_extensions'};
-  $option{'nodist_specific'} = 0
-    unless defined $option{'nodist_specific'};
-
-  my $lang = new Automake::Language (%option);
-
-  # Fill indexes.
-  $extension_map{$_} = $lang->name foreach @{$lang->extensions};
-  $languages{$lang->name} = $lang;
-  my $link = $lang->linker;
-  if ($link)
-    {
-      if (exists $link_languages{$link})
-       {
-         prog_error ("'$link' has different definitions in "
-                     . $lang->name . " and " . $link_languages{$link}->name)
-           if $lang->link ne $link_languages{$link}->link;
-       }
-      else
-       {
-         $link_languages{$link} = $lang;
-       }
-    }
-
-  # Update the pattern of known extensions.
-  accept_extensions (@{$lang->extensions});
-
-  # Update the suffix rules map.
-  foreach my $suffix (@{$lang->extensions})
-    {
-      foreach my $dest ($lang->output_extensions->($suffix))
-       {
-         register_suffix_rule (INTERNAL, $suffix, $dest);
-       }
-    }
-}
-
-# derive_suffix ($EXT, $OBJ)
-# --------------------------
-# This function is used to find a path from a user-specified suffix $EXT
-# to $OBJ or to some other suffix we recognize internally, e.g. 'cc'.
-sub derive_suffix
-{
-  my ($source_ext, $obj) = @_;
-
-  while (!$extension_map{$source_ext} && $source_ext ne $obj)
-    {
-      my $new_source_ext = next_in_suffix_chain ($source_ext, $obj);
-      last if not defined $new_source_ext;
-      $source_ext = $new_source_ext;
-    }
-
-  return $source_ext;
-}
-
-
-# Pretty-print something and append to '$output_rules'.
-sub pretty_print_rule
-{
-    $output_rules .= makefile_wrap (shift, shift, @_);
-}
-
 
 ################################################################
 
@@ -6237,405 +5743,6 @@ sub am_install_var
   return map { [$result{$_}->clone, $_] } @l;
 }
 
-
-################################################################
-
-# push_required_file ($DIR, $FILE, $FULLFILE)
-# -------------------------------------------
-# Push the given file onto DIST_COMMON.
-sub push_required_file
-{
-  my ($dir, $file, $fullfile) = @_;
-
-  # If the file to be distributed is in the same directory of the
-  # currently processed Makefile.am, then we want to distribute it
-  # from this same Makefile.am.
-  if ($dir eq $relative_dir)
-    {
-      push_dist_common ($file);
-    }
-  # This is needed to allow a construct in a non-top-level Makefile.am
-  # to require a file in the build-aux directory (see at least the test
-  # script 'test-driver-is-distributed.sh').  This is related to the
-  # automake bug#9546.  Note that the use of $config_aux_dir instead
-  # of $am_config_aux_dir here is deliberate and necessary.
-  elsif ($dir eq $config_aux_dir)
-    {
-      push_dist_common ("$am_config_aux_dir/$file");
-    }
-  # FIXME: another spacial case, for AC_LIBOBJ/AC_LIBSOURCE support.
-  # We probably need some refactoring of this function and its callers,
-  # to have a more explicit and systematic handling of all the special
-  # cases; but, since there are only two of them, this is low-priority
-  # ATM.
-  elsif ($config_libobj_dir && $dir eq $config_libobj_dir)
-    {
-      # Avoid unsightly '/.'s.
-      my $am_config_libobj_dir =
-        '$(top_srcdir)' .
-        ($config_libobj_dir eq '.' ? "" : "/$config_libobj_dir");
-      $am_config_libobj_dir =~ s|/*$||;
-      push_dist_common ("$am_config_libobj_dir/$file");
-    }
-  elsif ($relative_dir eq '.' && ! is_make_dir ($dir))
-    {
-      # If we are doing the topmost directory, and the file is in a
-      # subdir which does not have a Makefile, then we distribute it
-      # here.
-
-      # If a required file is above the source tree, it is important
-      # to prefix it with '$(srcdir)' so that no VPATH search is
-      # performed.  Otherwise problems occur with Make implementations
-      # that rewrite and simplify rules whose dependencies are found in a
-      # VPATH location.  Here is an example with OSF1/Tru64 Make.
-      #
-      #   % cat Makefile
-      #   VPATH = sub
-      #   distdir: ../a
-      #                  echo ../a
-      #   % ls
-      #   Makefile a
-      #   % make
-      #   echo a
-      #   a
-      #
-      # Dependency '../a' was found in 'sub/../a', but this make
-      # implementation simplified it as 'a'.  (Note that the sub/
-      # directory does not even exist.)
-      #
-      # This kind of VPATH rewriting seems hard to cancel.  The
-      # distdir.am hack against VPATH rewriting works only when no
-      # simplification is done, i.e., for dependencies which are in
-      # subdirectories, not in enclosing directories.  Hence, in
-      # the latter case we use a full path to make sure no VPATH
-      # search occurs.
-      $fullfile = '$(srcdir)/' . $fullfile
-       if $dir =~ m,^\.\.(?:$|/),;
-
-      push_dist_common ($fullfile);
-    }
-  else
-    {
-      prog_error "a Makefile in relative directory $relative_dir " .
-                 "can't add files in directory $dir to DIST_COMMON";
-    }
-}
-
-
-# If a file name appears as a key in this hash, then it has already
-# been checked for.  This allows us not to report the same error more
-# than once.
-my %required_file_not_found = ();
-
-# required_file_check_or_copy ($WHERE, $DIRECTORY, $FILE)
-# -------------------------------------------------------
-# Verify that the file must exist in $DIRECTORY, or install it.
-sub required_file_check_or_copy
-{
-  my ($where, $dir, $file) = @_;
-
-  my $fullfile = "$dir/$file";
-  my $found_it = 0;
-  my $dangling_sym = 0;
-
-  if (-l $fullfile && ! -f $fullfile)
-    {
-      $dangling_sym = 1;
-    }
-  elsif (dir_has_case_matching_file ($dir, $file))
-    {
-      $found_it = 1;
-    }
-
-  # '--force-missing' only has an effect if '--add-missing' is
-  # specified.
-  return
-    if $found_it && (! $add_missing || ! $force_missing);
-
-  # If we've already looked for it, we're done.  You might wonder why we
-  # don't do this before searching for the file.  If we do that, then
-  # something like AC_OUTPUT([subdir/foo foo]) will fail to put 'foo.in'
-  # into $(DIST_COMMON).
-  if (! $found_it)
-    {
-      return if defined $required_file_not_found{$fullfile};
-      $required_file_not_found{$fullfile} = 1;
-    }
-  if ($dangling_sym && $add_missing)
-    {
-      unlink ($fullfile);
-    }
-
-  my $trailer = '';
-  my $trailer2 = '';
-  my $suppress = 0;
-
-  # Only install missing files according to our desired
-  # strictness level.
-  my $message = "required file '$fullfile' not found";
-  if ($add_missing)
-    {
-      if (-f "$libdir/$file")
-        {
-          $suppress = 1;
-
-          # Install the missing file.  Symlink if we
-          # can, copy if we must.  Note: delete the file
-          # first, in case it is a dangling symlink.
-          $message = "installing '$fullfile'";
-
-          # The license file should not be volatile.
-          if ($file eq "COPYING")
-            {
-              $message .= " using GNU General Public License v3 file";
-              $trailer2 = "\n    Consider adding the COPYING file"
-                        . " to the version control system"
-                        . "\n    for your code, to avoid questions"
-                        . " about which license your project uses";
-            }
-
-          # Windows Perl will hang if we try to delete a
-          # file that doesn't exist.
-          unlink ($fullfile) if -f $fullfile;
-          if ($symlink_exists && ! $copy_missing)
-            {
-              if (! symlink ("$libdir/$file", $fullfile)
-                  || ! -e $fullfile)
-                {
-                  $suppress = 0;
-                  $trailer = "; error while making link: $!";
-                }
-            }
-          elsif (system ('cp', "$libdir/$file", $fullfile))
-            {
-              $suppress = 0;
-              $trailer = "\n    error while copying";
-            }
-          set_dir_cache_file ($dir, $file);
-        }
-    }
-  else
-    {
-      $trailer = "\n  'automake --add-missing' can install '$file'"
-        if -f "$libdir/$file";
-    }
-
-  # If --force-missing was specified, and we have
-  # actually found the file, then do nothing.
-  return
-    if $found_it && $force_missing;
-
-  # If we couldn't install the file, but it is a target in
-  # the Makefile, don't print anything.  This allows files
-  # like README, AUTHORS, or THANKS to be generated.
-  return
-    if !$suppress && rule $file;
-
-  msg ($suppress ? 'note' : 'error', $where, "$message$trailer$trailer2");
-}
-
-
-# require_file_internal ($WHERE, $MYSTRICT, $DIRECTORY, $QUEUE, @FILES)
-# ---------------------------------------------------------------------
-# Verify that the file must exist in $DIRECTORY, or install it.
-# $MYSTRICT is the strictness level at which this file becomes required.
-# Worker threads may queue up the action to be serialized by the master,
-# if $QUEUE is true
-sub require_file_internal
-{
-  my ($where, $mystrict, $dir, $queue, @files) = @_;
-
-  return
-    unless $strictness >= $mystrict;
-
-  foreach my $file (@files)
-    {
-      push_required_file ($dir, $file, "$dir/$file");
-      if ($queue)
-        {
-          queue_required_file_check_or_copy ($required_conf_file_queue,
-                                             QUEUE_CONF_FILE, $relative_dir,
-                                             $where, $mystrict, @files);
-        }
-      else
-        {
-          required_file_check_or_copy ($where, $dir, $file);
-        }
-    }
-}
-
-# require_file ($WHERE, $MYSTRICT, @FILES)
-# ----------------------------------------
-sub require_file
-{
-    my ($where, $mystrict, @files) = @_;
-    require_file_internal ($where, $mystrict, $relative_dir, 0, @files);
-}
-
-# require_file_with_macro ($COND, $MACRO, $MYSTRICT, @FILES)
-# ----------------------------------------------------------
-sub require_file_with_macro
-{
-    my ($cond, $macro, $mystrict, @files) = @_;
-    $macro = rvar ($macro) unless ref $macro;
-    require_file ($macro->rdef ($cond)->location, $mystrict, @files);
-}
-
-# require_libsource_with_macro ($COND, $MACRO, $MYSTRICT, @FILES)
-# ---------------------------------------------------------------
-# Require an AC_LIBSOURCEd file.  If AC_CONFIG_LIBOBJ_DIR was called, it
-# must be in that directory.  Otherwise expect it in the current directory.
-sub require_libsource_with_macro
-{
-    my ($cond, $macro, $mystrict, @files) = @_;
-    $macro = rvar ($macro) unless ref $macro;
-    if ($config_libobj_dir)
-      {
-       require_file_internal ($macro->rdef ($cond)->location, $mystrict,
-                              $config_libobj_dir, 0, @files);
-      }
-    else
-      {
-       require_file ($macro->rdef ($cond)->location, $mystrict, @files);
-      }
-}
-
-# queue_required_file_check_or_copy ($QUEUE, $KEY, $DIR, $WHERE,
-#                                    $MYSTRICT, @FILES)
-# --------------------------------------------------------------
-sub queue_required_file_check_or_copy
-{
-    my ($queue, $key, $dir, $where, $mystrict, @files) = @_;
-    my @serial_loc;
-    if (ref $where)
-      {
-        @serial_loc = (QUEUE_LOCATION, $where->serialize ());
-      }
-    else
-      {
-        @serial_loc = (QUEUE_STRING, $where);
-      }
-    $queue->enqueue ($key, $dir, @serial_loc, $mystrict, 0 + @files, @files);
-}
-
-# require_queued_file_check_or_copy ($QUEUE)
-# ------------------------------------------
-sub require_queued_file_check_or_copy
-{
-    my ($queue) = @_;
-    my $where;
-    my $dir = $queue->dequeue ();
-    my $loc_key = $queue->dequeue ();
-    if ($loc_key eq QUEUE_LOCATION)
-      {
-       $where = Automake::Location::deserialize ($queue);
-      }
-    elsif ($loc_key eq QUEUE_STRING)
-      {
-       $where = $queue->dequeue ();
-      }
-    else
-      {
-       prog_error "unexpected key $loc_key";
-      }
-    my $mystrict = $queue->dequeue ();
-    my $nfiles = $queue->dequeue ();
-    my @files;
-    push @files, $queue->dequeue ()
-      foreach (1 .. $nfiles);
-    return
-      unless $strictness >= $mystrict;
-    foreach my $file (@files)
-      {
-        required_file_check_or_copy ($where, $config_aux_dir, $file);
-      }
-}
-
-# require_conf_file ($WHERE, $MYSTRICT, @FILES)
-# ---------------------------------------------
-# Looks in configuration path, as specified by AC_CONFIG_AUX_DIR.
-sub require_conf_file
-{
-    my ($where, $mystrict, @files) = @_;
-    my $queue = defined $required_conf_file_queue ? 1 : 0;
-    require_file_internal ($where, $mystrict, $config_aux_dir,
-                           $queue, @files);
-}
-
-
-# require_conf_file_with_macro ($COND, $MACRO, $MYSTRICT, @FILES)
-# ---------------------------------------------------------------
-sub require_conf_file_with_macro
-{
-    my ($cond, $macro, $mystrict, @files) = @_;
-    require_conf_file (rvar ($macro)->rdef ($cond)->location,
-                      $mystrict, @files);
-}
-
-################################################################
-
-# require_build_directory ($DIRECTORY)
-# ------------------------------------
-# Emit rules to create $DIRECTORY if needed, and return
-# the file that any target requiring this directory should be made
-# dependent upon.
-# We don't want to emit the rule twice, and want to reuse it
-# for directories with equivalent names (e.g., 'foo/bar' and './foo//bar').
-sub require_build_directory
-{
-  my $directory = shift;
-
-  return $directory_map{$directory} if exists $directory_map{$directory};
-
-  my $cdir = File::Spec->canonpath ($directory);
-
-  if (exists $directory_map{$cdir})
-    {
-      my $stamp = $directory_map{$cdir};
-      $directory_map{$directory} = $stamp;
-      return $stamp;
-    }
-
-  my $dirstamp = "$cdir/\$(am__dirstamp)";
-
-  $directory_map{$directory} = $dirstamp;
-  $directory_map{$cdir} = $dirstamp;
-
-  # Set a variable for the dirstamp basename.
-  define_pretty_variable ('am__dirstamp', TRUE, INTERNAL,
-                         '$(am__leading_dot)dirstamp');
-
-  # Directory must be removed by 'make distclean'.
-  $clean_files{$dirstamp} = DIST_CLEAN;
-
-  $output_rules .= ("$dirstamp:\n"
-                   . "\t\@\$(MKDIR_P) $directory\n"
-                   . "\t\@: > $dirstamp\n");
-
-  return $dirstamp;
-}
-
-# require_build_directory_maybe ($FILE)
-# -------------------------------------
-# If $FILE lies in a subdirectory, emit a rule to create this
-# directory and return the file that $FILE should be made
-# dependent upon.  Otherwise, just return the empty string.
-sub require_build_directory_maybe
-{
-    my $file = shift;
-    my $directory = dirname ($file);
-
-    if ($directory ne '.')
-    {
-       return require_build_directory ($directory);
-    }
-    else
-    {
-       return '';
-    }
-}
-
-
 ################################################################
 
 # generate_makefile ($MAKEFILE_AM, $MAKEFILE_IN)
diff --git a/lib/Automake/LangHandling.pm b/lib/Automake/LangHandling.pm
new file mode 100644 (file)
index 0000000..bfbbb00
--- /dev/null
@@ -0,0 +1,484 @@
+# 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 2
+# 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 <https://www.gnu.org/licenses/>.
+
+package Automake::LangHandling;
+
+use Automake::Condition qw (TRUE FALSE);
+use Automake::ChannelDefs;
+use Automake::Global;
+use Automake::Language;
+use Automake::Location;
+use Automake::Options;
+use Automake::Requires;
+use Automake::Rule;
+use Automake::SilentRules;
+use Automake::Utils;
+use Automake::Variable;
+use Automake::VarDef;
+use Automake::Wrap qw (makefile_wrap);
+use Exporter;
+use File::Basename;
+
+use vars '@ISA', '@EXPORT';
+
+@ISA = qw (Exporter);
+
+@EXPORT = qw (check_user_variables lang_sub_obj lang_header_rewrite
+             lang_vala_rewrite lang_yacc_rewrite lang_yaccxx_rewrite
+             lang_lex_rewrite lang_lexxx_rewrite lang_java_rewrite
+             lang_vala_finish_target lang_vala_finish
+             lang_vala_target_hook lang_yacc_target_hook
+             lang_lex_target_hook yacc_lex_finish_helper
+             lang_yacc_finish lang_lex_finish resolve_linker
+             saw_extension register_language derive_suffix
+             pretty_print_rule);
+
+# check_user_variables (@LIST)
+# ----------------------------
+# Make sure each variable VAR in @LIST does not exist, suggest using AM_VAR
+# otherwise.
+sub check_user_variables
+{
+  my @dont_override = @_;
+  foreach my $flag (@dont_override)
+    {
+      my $var = var $flag;
+      if ($var)
+       {
+         for my $cond ($var->conditions->conds)
+           {
+             if ($var->rdef ($cond)->owner == VAR_MAKEFILE)
+               {
+                 msg_cond_var ('gnu', $cond, $flag,
+                               "'$flag' is a user variable, "
+                               . "you should not override it;\n"
+                               . "use 'AM_$flag' instead");
+               }
+           }
+       }
+    }
+}
+
+################################################################
+#
+# Functions to handle files of each language.
+
+# Each 'lang_X_rewrite($DIRECTORY, $BASE, $EXT)' function follows a
+# simple formula: Return value is LANG_SUBDIR if the resulting object
+# file should be in a subdir if the source file is, LANG_PROCESS if
+# file is to be dealt with, LANG_IGNORE otherwise.
+
+# Much of the actual processing is handled in
+# handle_single_transform.  These functions exist so that
+# auxiliary information can be recorded for a later cleanup pass.
+# Note that the calls to these functions are computed, so don't bother
+# searching for their precise names in the source.
+
+# This is just a convenience function that can be used to determine
+# when a subdir object should be used.
+sub lang_sub_obj ()
+{
+    return option 'subdir-objects' ? LANG_SUBDIR : LANG_PROCESS;
+}
+
+# Rewrite a single header file.
+sub lang_header_rewrite
+{
+    # Header files are simply ignored.
+    return LANG_IGNORE;
+}
+
+# Rewrite a single Vala source file.
+sub lang_vala_rewrite
+{
+    my ($directory, $base, $ext) = @_;
+
+    (my $newext = $ext) =~ s/vala$/c/;
+    return (LANG_SUBDIR, $newext);
+}
+
+# Rewrite a single yacc/yacc++ file.
+sub lang_yacc_rewrite
+{
+    my ($directory, $base, $ext) = @_;
+
+    my $r = lang_sub_obj;
+    (my $newext = $ext) =~ tr/y/c/;
+    return ($r, $newext);
+}
+sub lang_yaccxx_rewrite { lang_yacc_rewrite (@_); };
+
+# Rewrite a single lex/lex++ file.
+sub lang_lex_rewrite
+{
+    my ($directory, $base, $ext) = @_;
+
+    my $r = lang_sub_obj;
+    (my $newext = $ext) =~ tr/l/c/;
+    return ($r, $newext);
+}
+sub lang_lexxx_rewrite { lang_lex_rewrite (@_); };
+
+# Rewrite a single Java file.
+sub lang_java_rewrite
+{
+    return LANG_SUBDIR;
+}
+
+# The lang_X_finish functions are called after all source file
+# processing is done.  Each should handle defining rules for the
+# language, etc.  A finish function is only called if a source file of
+# the appropriate type has been seen.
+
+sub lang_vala_finish_target
+{
+  my ($self, $name) = @_;
+
+  my $derived = canonicalize ($name);
+  my $var = var "${derived}_SOURCES";
+  return unless $var;
+
+  my @vala_sources = grep { /\.(vala|vapi)$/ } ($var->value_as_list_recursive);
+
+  # For automake bug#11229.
+  return unless @vala_sources;
+
+  foreach my $vala_file (@vala_sources)
+    {
+      my $c_file = $vala_file;
+      if ($c_file =~ s/(.*)\.vala$/$1.c/)
+        {
+          $c_file = "\$(srcdir)/$c_file";
+          $output_rules .= "$c_file: \$(srcdir)/${derived}_vala.stamp\n"
+            . "\t\@if test -f \$@; then :; else rm -f \$(srcdir)/${derived}_vala.stamp; fi\n"
+            . "\t\@if test -f \$@; then :; else \\\n"
+            . "\t  \$(MAKE) \$(AM_MAKEFLAGS) \$(srcdir)/${derived}_vala.stamp; \\\n"
+            . "\tfi\n";
+         $clean_files{$c_file} = MAINTAINER_CLEAN;
+        }
+    }
+
+  # Add rebuild rules for generated header and vapi files
+  my $flags = var ($derived . '_VALAFLAGS');
+  if ($flags)
+    {
+      my $lastflag = '';
+      foreach my $flag ($flags->value_as_list_recursive)
+       {
+         if (grep (/$lastflag/, ('-H', '-h', '--header', '--internal-header',
+                                 '--vapi', '--internal-vapi', '--gir')))
+           {
+             my $headerfile = "\$(srcdir)/$flag";
+             $output_rules .= "$headerfile: \$(srcdir)/${derived}_vala.stamp\n"
+               . "\t\@if test -f \$@; then :; else rm -f \$(srcdir)/${derived}_vala.stamp; fi\n"
+               . "\t\@if test -f \$@; then :; else \\\n"
+               . "\t  \$(MAKE) \$(AM_MAKEFLAGS) \$(srcdir)/${derived}_vala.stamp; \\\n"
+               . "\tfi\n";
+
+             # valac is not used when building from dist tarballs
+             # distribute the generated files
+             push_dist_common ($headerfile);
+             $clean_files{$headerfile} = MAINTAINER_CLEAN;
+           }
+         $lastflag = $flag;
+       }
+    }
+
+  my $compile = $self->compile;
+
+  # Rewrite each occurrence of 'AM_VALAFLAGS' in the compile
+  # rule into '${derived}_VALAFLAGS' if it exists.
+  my $val = "${derived}_VALAFLAGS";
+  $compile =~ s/\(AM_VALAFLAGS\)/\($val\)/
+    if set_seen ($val);
+
+  # VALAFLAGS is a user variable (per GNU Standards),
+  # it should not be overridden in the Makefile...
+  check_user_variables 'VALAFLAGS';
+
+  my $dirname = dirname ($name);
+
+  # Only generate C code, do not run C compiler
+  $compile .= " -C";
+
+  my $verbose = verbose_flag ('VALAC');
+  my $silent = silent_flag ();
+  my $stampfile = "\$(srcdir)/${derived}_vala.stamp";
+
+  $output_rules .=
+    "\$(srcdir)/${derived}_vala.stamp: @vala_sources\n".
+# Since the C files generated from the vala sources depend on the
+# ${derived}_vala.stamp file, we must ensure its timestamp is older than
+# those of the C files generated by the valac invocation below (this is
+# especially important on systems with sub-second timestamp resolution).
+# Thus we need to create the stamp file *before* invoking valac, and to
+# move it to its final location only after valac has been invoked.
+    "\t${silent}rm -f \$\@ && echo stamp > \$\@-t\n".
+    "\t${verbose}\$(am__cd) \$(srcdir) && $compile @vala_sources\n".
+    "\t${silent}mv -f \$\@-t \$\@\n";
+
+  push_dist_common ($stampfile);
+
+  $clean_files{$stampfile} = MAINTAINER_CLEAN;
+}
+
+# Add output rules to invoke valac and create stamp file as a witness
+# to handle multiple outputs. This function is called after all source
+# file processing is done.
+sub lang_vala_finish ()
+{
+  my ($self) = @_;
+
+  foreach my $prog (keys %known_programs)
+    {
+      lang_vala_finish_target ($self, $prog);
+    }
+
+  while (my ($name) = each %known_libraries)
+    {
+      lang_vala_finish_target ($self, $name);
+    }
+}
+
+# The built .c files should be cleaned only on maintainer-clean
+# as the .c files are distributed. This function is called for each
+# .vala source file.
+sub lang_vala_target_hook
+{
+  my ($self, $aggregate, $output, $input, %transform) = @_;
+
+  $clean_files{$output} = MAINTAINER_CLEAN;
+}
+
+# This is a yacc helper which is called whenever we have decided to
+# compile a yacc file.
+sub lang_yacc_target_hook
+{
+    my ($self, $aggregate, $output, $input, %transform) = @_;
+
+    # If some relevant *YFLAGS variable contains the '-d' flag, we'll
+    # have to to generate special code.
+    my $yflags_contains_minus_d = 0;
+
+    foreach my $pfx ("", "${aggregate}_")
+      {
+       my $yflagsvar = var ("${pfx}YFLAGS");
+       next unless $yflagsvar;
+       # We cannot work reliably with conditionally-defined YFLAGS.
+       if ($yflagsvar->has_conditional_contents)
+         {
+           msg_var ('unsupported', $yflagsvar,
+                    "'${pfx}YFLAGS' cannot have conditional contents");
+         }
+       else
+         {
+           $yflags_contains_minus_d = 1
+             if grep (/^-d$/, $yflagsvar->value_as_list_recursive);
+         }
+      }
+
+    if ($yflags_contains_minus_d)
+      {
+       # Found a '-d' that applies to the compilation of this file.
+       # Add a dependency for the generated header file, and arrange
+       # for that file to be included in the distribution.
+
+       # The extension of the output file (e.g., '.c' or '.cxx').
+       # We'll need it to compute the name of the generated header file.
+       (my $output_ext = basename ($output)) =~ s/.*(\.[^.]+)$/$1/;
+
+       # We know that a yacc input should be turned into either a C or
+       # C++ output file.  We depend on this fact (here and in yacc.am),
+       # so check that it really holds.
+       my $lang = $languages{$extension_map{$output_ext}};
+       prog_error "invalid output name '$output' for yacc file '$input'"
+         if (!$lang || ($lang->name ne 'c' && $lang->name ne 'cxx'));
+
+       (my $header_ext = $output_ext) =~ s/c/h/g;
+        # Quote $output_ext in the regexp, so that dots in it are taken
+        # as literal dots, not as metacharacters.
+       (my $header = $output) =~ s/\Q$output_ext\E$/$header_ext/;
+
+       foreach my $cond (Automake::Rule::define (${header}, 'internal',
+                                                 RULE_AUTOMAKE, TRUE,
+                                                 INTERNAL))
+         {
+           my $condstr = $cond->subst_string;
+           $output_rules .=
+             "$condstr${header}: $output\n"
+             # Recover from removal of $header
+             . "$condstr\t\@if test ! -f \$@; then rm -f $output; else :; fi\n"
+             . "$condstr\t\@if test ! -f \$@; then \$(MAKE) \$(AM_MAKEFLAGS) $output; else :; fi\n";
+         }
+       # Distribute the generated file, unless its .y source was
+       # listed in a nodist_ variable.  (handle_source_transform()
+       # will set DIST_SOURCE.)
+       push_dist_common ($header)
+         if $transform{'DIST_SOURCE'};
+
+       # The GNU rules say that yacc/lex output files should be removed
+       # by maintainer-clean.  However, if the files are not distributed,
+       # then we want to remove them with "make clean"; otherwise,
+       # "make distcheck" will fail.
+       $clean_files{$header} = $transform{'DIST_SOURCE'} ? MAINTAINER_CLEAN : CLEAN;
+      }
+    # See the comment above for $HEADER.
+    $clean_files{$output} = $transform{'DIST_SOURCE'} ? MAINTAINER_CLEAN : CLEAN;
+}
+
+# This is a lex helper which is called whenever we have decided to
+# compile a lex file.
+sub lang_lex_target_hook
+{
+    my ($self, $aggregate, $output, $input, %transform) = @_;
+    # The GNU rules say that yacc/lex output files should be removed
+    # by maintainer-clean.  However, if the files are not distributed,
+    # then we want to remove them with "make clean"; otherwise,
+    # "make distcheck" will fail.
+    $clean_files{$output} = $transform{'DIST_SOURCE'} ? MAINTAINER_CLEAN : CLEAN;
+}
+
+# This is a helper for both lex and yacc.
+sub yacc_lex_finish_helper ()
+{
+  return if defined $language_scratch{'lex-yacc-done'};
+  $language_scratch{'lex-yacc-done'} = 1;
+
+  # FIXME: for now, no line number.
+  require_conf_file ($configure_ac, FOREIGN, 'ylwrap');
+  define_variable ('YLWRAP', "$am_config_aux_dir/ylwrap", INTERNAL);
+}
+
+sub lang_yacc_finish ()
+{
+  return if defined $language_scratch{'yacc-done'};
+  $language_scratch{'yacc-done'} = 1;
+
+  reject_var 'YACCFLAGS', "'YACCFLAGS' obsolete; use 'YFLAGS' instead";
+
+  yacc_lex_finish_helper;
+}
+
+
+sub lang_lex_finish ()
+{
+  return if defined $language_scratch{'lex-done'};
+  $language_scratch{'lex-done'} = 1;
+
+  yacc_lex_finish_helper;
+}
+
+
+# Given a hash table of linker names, pick the name that has the most
+# precedence.  This is lame, but something has to have global
+# knowledge in order to eliminate the conflict.  Add more linkers as
+# required.
+sub resolve_linker
+{
+    my (%linkers) = @_;
+
+    foreach my $l (qw(GCJLINK OBJCXXLINK CXXLINK F77LINK FCLINK OBJCLINK UPCLINK))
+    {
+       return $l if defined $linkers{$l};
+    }
+    return 'LINK';
+}
+
+# Called to indicate that an extension was used.
+sub saw_extension
+{
+    my ($ext) = @_;
+    $extension_seen{$ext} = 1;
+}
+
+# register_language (%ATTRIBUTE)
+# ------------------------------
+# Register a single language.
+# Each %ATTRIBUTE is of the form ATTRIBUTE => VALUE.
+sub register_language
+{
+  my (%option) = @_;
+
+  # Set the defaults.
+  $option{'autodep'} = 'no'
+    unless defined $option{'autodep'};
+  $option{'linker'} = ''
+    unless defined $option{'linker'};
+  $option{'flags'} = []
+    unless defined $option{'flags'};
+  $option{'output_extensions'} = sub { return ( '.$(OBJEXT)', '.lo' ) }
+    unless defined $option{'output_extensions'};
+  $option{'nodist_specific'} = 0
+    unless defined $option{'nodist_specific'};
+
+  my $lang = new Automake::Language (%option);
+
+  # Fill indexes.
+  $extension_map{$_} = $lang->name foreach @{$lang->extensions};
+  $languages{$lang->name} = $lang;
+  my $link = $lang->linker;
+  if ($link)
+    {
+      if (exists $link_languages{$link})
+       {
+         prog_error ("'$link' has different definitions in "
+                     . $lang->name . " and " . $link_languages{$link}->name)
+           if $lang->link ne $link_languages{$link}->link;
+       }
+      else
+       {
+         $link_languages{$link} = $lang;
+       }
+    }
+
+  # Update the pattern of known extensions.
+  accept_extensions (@{$lang->extensions});
+
+  # Update the suffix rules map.
+  foreach my $suffix (@{$lang->extensions})
+    {
+      foreach my $dest ($lang->output_extensions->($suffix))
+       {
+         register_suffix_rule (INTERNAL, $suffix, $dest);
+       }
+    }
+}
+
+# derive_suffix ($EXT, $OBJ)
+# --------------------------
+# This function is used to find a path from a user-specified suffix $EXT
+# to $OBJ or to some other suffix we recognize internally, e.g. 'cc'.
+sub derive_suffix
+{
+  my ($source_ext, $obj) = @_;
+
+  while (!$extension_map{$source_ext} && $source_ext ne $obj)
+    {
+      my $new_source_ext = next_in_suffix_chain ($source_ext, $obj);
+      last if not defined $new_source_ext;
+      $source_ext = $new_source_ext;
+    }
+
+  return $source_ext;
+}
+
+
+# Pretty-print something and append to '$output_rules'.
+sub pretty_print_rule
+{
+    $output_rules .= makefile_wrap (shift, shift, @_);
+}
+
+1;
diff --git a/lib/Automake/Requires.pm b/lib/Automake/Requires.pm
new file mode 100644 (file)
index 0000000..dbb1c10
--- /dev/null
@@ -0,0 +1,424 @@
+package Automake::Requires;
+
+use Automake::ChannelDefs;
+use Automake::Channels;
+use Automake::Condition qw (TRUE FALSE);
+use Automake::Config;
+use Automake::FileUtils;
+use Automake::Global;
+use Automake::Location;
+use Automake::Options;
+use Automake::Rule;
+use Automake::Utils;
+use Automake::Variable;
+use File::Basename;
+
+use Exporter;
+
+use vars '@ISA', '@EXPORT';
+
+@ISA = qw (Exporter);
+
+@EXPORT = qw (push_required_file required_file_check_or_copy
+    require_file_internal require_file require_file_with_macro
+    require_libsource_with_macro queue_required_file_check_or_copy
+    require_queued_file_check_or_copy require_conf_file
+    require_conf_file_with_macro require_build_directory
+    require_build_directory_maybe);
+
+# push_required_file ($DIR, $FILE, $FULLFILE)
+# -------------------------------------------
+# Push the given file onto DIST_COMMON.
+sub push_required_file
+{
+  my ($dir, $file, $fullfile) = @_;
+
+  # If the file to be distributed is in the same directory of the
+  # currently processed Makefile.am, then we want to distribute it
+  # from this same Makefile.am.
+  if ($dir eq $relative_dir)
+    {
+      push_dist_common ($file);
+    }
+  # This is needed to allow a construct in a non-top-level Makefile.am
+  # to require a file in the build-aux directory (see at least the test
+  # script 'test-driver-is-distributed.sh').  This is related to the
+  # automake bug#9546.  Note that the use of $config_aux_dir instead
+  # of $am_config_aux_dir here is deliberate and necessary.
+  elsif ($dir eq $config_aux_dir)
+    {
+      push_dist_common ("$am_config_aux_dir/$file");
+    }
+  # FIXME: another spacial case, for AC_LIBOBJ/AC_LIBSOURCE support.
+  # We probably need some refactoring of this function and its callers,
+  # to have a more explicit and systematic handling of all the special
+  # cases; but, since there are only two of them, this is low-priority
+  # ATM.
+  elsif ($config_libobj_dir && $dir eq $config_libobj_dir)
+    {
+      # Avoid unsightly '/.'s.
+      my $am_config_libobj_dir =
+        '$(top_srcdir)' .
+        ($config_libobj_dir eq '.' ? "" : "/$config_libobj_dir");
+      $am_config_libobj_dir =~ s|/*$||;
+      push_dist_common ("$am_config_libobj_dir/$file");
+    }
+  elsif ($relative_dir eq '.' && ! is_make_dir ($dir))
+    {
+      # If we are doing the topmost directory, and the file is in a
+      # subdir which does not have a Makefile, then we distribute it
+      # here.
+
+      # If a required file is above the source tree, it is important
+      # to prefix it with '$(srcdir)' so that no VPATH search is
+      # performed.  Otherwise problems occur with Make implementations
+      # that rewrite and simplify rules whose dependencies are found in a
+      # VPATH location.  Here is an example with OSF1/Tru64 Make.
+      #
+      #   % cat Makefile
+      #   VPATH = sub
+      #   distdir: ../a
+      #                  echo ../a
+      #   % ls
+      #   Makefile a
+      #   % make
+      #   echo a
+      #   a
+      #
+      # Dependency '../a' was found in 'sub/../a', but this make
+      # implementation simplified it as 'a'.  (Note that the sub/
+      # directory does not even exist.)
+      #
+      # This kind of VPATH rewriting seems hard to cancel.  The
+      # distdir.am hack against VPATH rewriting works only when no
+      # simplification is done, i.e., for dependencies which are in
+      # subdirectories, not in enclosing directories.  Hence, in
+      # the latter case we use a full path to make sure no VPATH
+      # search occurs.
+      $fullfile = '$(srcdir)/' . $fullfile
+       if $dir =~ m,^\.\.(?:$|/),;
+
+      push_dist_common ($fullfile);
+    }
+  else
+    {
+      prog_error "a Makefile in relative directory $relative_dir " .
+                 "can't add files in directory $dir to DIST_COMMON";
+    }
+}
+
+
+# If a file name appears as a key in this hash, then it has already
+# been checked for.  This allows us not to report the same error more
+# than once.
+my %required_file_not_found = ();
+
+# required_file_check_or_copy ($WHERE, $DIRECTORY, $FILE)
+# -------------------------------------------------------
+# Verify that the file must exist in $DIRECTORY, or install it.
+sub required_file_check_or_copy
+{
+  my ($where, $dir, $file) = @_;
+
+  my $fullfile = "$dir/$file";
+  my $found_it = 0;
+  my $dangling_sym = 0;
+
+  if (-l $fullfile && ! -f $fullfile)
+    {
+      $dangling_sym = 1;
+    }
+  elsif (dir_has_case_matching_file ($dir, $file))
+    {
+      $found_it = 1;
+    }
+
+  # '--force-missing' only has an effect if '--add-missing' is
+  # specified.
+  return
+    if $found_it && (! $add_missing || ! $force_missing);
+
+  # If we've already looked for it, we're done.  You might wonder why we
+  # don't do this before searching for the file.  If we do that, then
+  # something like AC_OUTPUT([subdir/foo foo]) will fail to put 'foo.in'
+  # into $(DIST_COMMON).
+  if (! $found_it)
+    {
+      return if defined $required_file_not_found{$fullfile};
+      $required_file_not_found{$fullfile} = 1;
+    }
+  if ($dangling_sym && $add_missing)
+    {
+      unlink ($fullfile);
+    }
+
+  my $trailer = '';
+  my $trailer2 = '';
+  my $suppress = 0;
+
+  # Only install missing files according to our desired
+  # strictness level.
+  my $message = "required file '$fullfile' not found";
+  if ($add_missing)
+    {
+      if (-f "$libdir/$file")
+        {
+          $suppress = 1;
+
+          # Install the missing file.  Symlink if we
+          # can, copy if we must.  Note: delete the file
+          # first, in case it is a dangling symlink.
+          $message = "installing '$fullfile'";
+
+          # The license file should not be volatile.
+          if ($file eq "COPYING")
+            {
+              $message .= " using GNU General Public License v3 file";
+              $trailer2 = "\n    Consider adding the COPYING file"
+                        . " to the version control system"
+                        . "\n    for your code, to avoid questions"
+                        . " about which license your project uses";
+            }
+
+          # Windows Perl will hang if we try to delete a
+          # file that doesn't exist.
+          unlink ($fullfile) if -f $fullfile;
+          if ($symlink_exists && ! $copy_missing)
+            {
+              if (! symlink ("$libdir/$file", $fullfile)
+                  || ! -e $fullfile)
+                {
+                  $suppress = 0;
+                  $trailer = "; error while making link: $!";
+                }
+            }
+          elsif (system ('cp', "$libdir/$file", $fullfile))
+            {
+              $suppress = 0;
+              $trailer = "\n    error while copying";
+            }
+          set_dir_cache_file ($dir, $file);
+        }
+    }
+  else
+    {
+      $trailer = "\n  'automake --add-missing' can install '$file'"
+        if -f "$libdir/$file";
+    }
+
+  # If --force-missing was specified, and we have
+  # actually found the file, then do nothing.
+  return
+    if $found_it && $force_missing;
+
+  # If we couldn't install the file, but it is a target in
+  # the Makefile, don't print anything.  This allows files
+  # like README, AUTHORS, or THANKS to be generated.
+  return
+    if !$suppress && rule $file;
+
+  msg ($suppress ? 'note' : 'error', $where, "$message$trailer$trailer2");
+}
+
+
+# require_file_internal ($WHERE, $MYSTRICT, $DIRECTORY, $QUEUE, @FILES)
+# ---------------------------------------------------------------------
+# Verify that the file must exist in $DIRECTORY, or install it.
+# $MYSTRICT is the strictness level at which this file becomes required.
+# Worker threads may queue up the action to be serialized by the master,
+# if $QUEUE is true
+sub require_file_internal
+{
+  my ($where, $mystrict, $dir, $queue, @files) = @_;
+
+  return
+    unless $strictness >= $mystrict;
+
+  foreach my $file (@files)
+    {
+      push_required_file ($dir, $file, "$dir/$file");
+      if ($queue)
+        {
+          queue_required_file_check_or_copy ($required_conf_file_queue,
+                                             QUEUE_CONF_FILE, $relative_dir,
+                                             $where, $mystrict, @files);
+        }
+      else
+        {
+          required_file_check_or_copy ($where, $dir, $file);
+        }
+    }
+}
+
+# require_file ($WHERE, $MYSTRICT, @FILES)
+# ----------------------------------------
+sub require_file
+{
+    my ($where, $mystrict, @files) = @_;
+    require_file_internal ($where, $mystrict, $relative_dir, 0, @files);
+}
+
+# require_file_with_macro ($COND, $MACRO, $MYSTRICT, @FILES)
+# ----------------------------------------------------------
+sub require_file_with_macro
+{
+    my ($cond, $macro, $mystrict, @files) = @_;
+    $macro = rvar ($macro) unless ref $macro;
+    require_file ($macro->rdef ($cond)->location, $mystrict, @files);
+}
+
+# require_libsource_with_macro ($COND, $MACRO, $MYSTRICT, @FILES)
+# ---------------------------------------------------------------
+# Require an AC_LIBSOURCEd file.  If AC_CONFIG_LIBOBJ_DIR was called, it
+# must be in that directory.  Otherwise expect it in the current directory.
+sub require_libsource_with_macro
+{
+    my ($cond, $macro, $mystrict, @files) = @_;
+    $macro = rvar ($macro) unless ref $macro;
+    if ($config_libobj_dir)
+      {
+       require_file_internal ($macro->rdef ($cond)->location, $mystrict,
+                              $config_libobj_dir, 0, @files);
+      }
+    else
+      {
+       require_file ($macro->rdef ($cond)->location, $mystrict, @files);
+      }
+}
+
+# queue_required_file_check_or_copy ($QUEUE, $KEY, $DIR, $WHERE,
+#                                    $MYSTRICT, @FILES)
+# --------------------------------------------------------------
+sub queue_required_file_check_or_copy
+{
+    my ($queue, $key, $dir, $where, $mystrict, @files) = @_;
+    my @serial_loc;
+    if (ref $where)
+      {
+        @serial_loc = (QUEUE_LOCATION, $where->serialize ());
+      }
+    else
+      {
+        @serial_loc = (QUEUE_STRING, $where);
+      }
+    $queue->enqueue ($key, $dir, @serial_loc, $mystrict, 0 + @files, @files);
+}
+
+# require_queued_file_check_or_copy ($QUEUE)
+# ------------------------------------------
+sub require_queued_file_check_or_copy
+{
+    my ($queue) = @_;
+    my $where;
+    my $dir = $queue->dequeue ();
+    my $loc_key = $queue->dequeue ();
+    if ($loc_key eq QUEUE_LOCATION)
+      {
+       $where = Automake::Location::deserialize ($queue);
+      }
+    elsif ($loc_key eq QUEUE_STRING)
+      {
+       $where = $queue->dequeue ();
+      }
+    else
+      {
+       prog_error "unexpected key $loc_key";
+      }
+    my $mystrict = $queue->dequeue ();
+    my $nfiles = $queue->dequeue ();
+    my @files;
+    push @files, $queue->dequeue ()
+      foreach (1 .. $nfiles);
+    return
+      unless $strictness >= $mystrict;
+    foreach my $file (@files)
+      {
+        required_file_check_or_copy ($where, $config_aux_dir, $file);
+      }
+}
+
+# require_conf_file ($WHERE, $MYSTRICT, @FILES)
+# ---------------------------------------------
+# Looks in configuration path, as specified by AC_CONFIG_AUX_DIR.
+sub require_conf_file
+{
+    my ($where, $mystrict, @files) = @_;
+    my $queue = defined $required_conf_file_queue ? 1 : 0;
+    require_file_internal ($where, $mystrict, $config_aux_dir,
+                           $queue, @files);
+}
+
+
+# require_conf_file_with_macro ($COND, $MACRO, $MYSTRICT, @FILES)
+# ---------------------------------------------------------------
+sub require_conf_file_with_macro
+{
+    my ($cond, $macro, $mystrict, @files) = @_;
+    require_conf_file (rvar ($macro)->rdef ($cond)->location,
+                      $mystrict, @files);
+}
+
+################################################################
+
+# require_build_directory ($DIRECTORY)
+# ------------------------------------
+# Emit rules to create $DIRECTORY if needed, and return
+# the file that any target requiring this directory should be made
+# dependent upon.
+# We don't want to emit the rule twice, and want to reuse it
+# for directories with equivalent names (e.g., 'foo/bar' and './foo//bar').
+sub require_build_directory
+{
+  my $directory = shift;
+
+  return $directory_map{$directory} if exists $directory_map{$directory};
+
+  my $cdir = File::Spec->canonpath ($directory);
+
+  if (exists $directory_map{$cdir})
+    {
+      my $stamp = $directory_map{$cdir};
+      $directory_map{$directory} = $stamp;
+      return $stamp;
+    }
+
+  my $dirstamp = "$cdir/\$(am__dirstamp)";
+
+  $directory_map{$directory} = $dirstamp;
+  $directory_map{$cdir} = $dirstamp;
+
+  # Set a variable for the dirstamp basename.
+  define_pretty_variable ('am__dirstamp', TRUE, INTERNAL,
+                         '$(am__leading_dot)dirstamp');
+
+  # Directory must be removed by 'make distclean'.
+  $clean_files{$dirstamp} = DIST_CLEAN;
+
+  $output_rules .= ("$dirstamp:\n"
+                   . "\t\@\$(MKDIR_P) $directory\n"
+                   . "\t\@: > $dirstamp\n");
+
+  return $dirstamp;
+}
+
+# require_build_directory_maybe ($FILE)
+# -------------------------------------
+# If $FILE lies in a subdirectory, emit a rule to create this
+# directory and return the file that $FILE should be made
+# dependent upon.  Otherwise, just return the empty string.
+sub require_build_directory_maybe
+{
+    my $file = shift;
+    my $directory = dirname ($file);
+
+    if ($directory ne '.')
+      {
+       return require_build_directory ($directory);
+      }
+    else
+      {
+       return '';
+      }
+}
+
+1;
diff --git a/lib/Automake/SilentRules.pm b/lib/Automake/SilentRules.pm
new file mode 100644 (file)
index 0000000..7072916
--- /dev/null
@@ -0,0 +1,73 @@
+package Automake::SilentRules;
+
+use Automake::Utils;
+use Automake::Variable;
+use Exporter;
+
+use vars '@ISA', '@EXPORT';
+
+@ISA = qw (Exporter);
+
+@EXPORT = qw (verbose_flag verbose_nodep_flag silent_flag
+             define_verbose_texinfo define_verbose_libtool
+             handle_silent);
+
+# Silent rules handling functions.
+
+# verbose_flag (NAME)
+# -------------------
+# Contents of '%VERBOSE%' variable to expand before rule command.
+sub verbose_flag
+{
+    my ($name) = @_;
+    return '$(' . verbose_var ($name) . ')';
+}
+
+sub verbose_nodep_flag
+{
+    my ($name) = @_;
+    return '$(' . verbose_var ($name) . subst ('am__nodep') . ')';
+}
+
+# silent_flag
+# -----------
+# Contents of %SILENT%: variable to expand to '@' when silent.
+sub silent_flag ()
+{
+    return verbose_flag ('at');
+}
+
+# Engage the needed silent rules machinery for assorted texinfo commands.
+sub define_verbose_texinfo ()
+{
+  my @tagvars = ('DVIPS', 'MAKEINFO', 'INFOHTML', 'TEXI2DVI', 'TEXI2PDF');
+  foreach my $tag (@tagvars)
+    {
+      define_verbose_tagvar($tag);
+    }
+  define_verbose_var('texinfo', '-q');
+  define_verbose_var('texidevnull', '> /dev/null');
+}
+
+# Engage the needed silent rules machinery for 'libtool --silent'.
+sub define_verbose_libtool ()
+{
+    define_verbose_var ('lt', '--silent');
+    return verbose_flag ('lt');
+}
+
+sub handle_silent ()
+{
+    # Define "$(AM_V_P)", expanding to a shell conditional that can be
+    # used in make recipes to determine whether we are being run in
+    # silent mode or not.  The choice of the name derives from the LISP
+    # convention of appending the letter 'P' to denote a predicate (see
+    # also "the '-P' convention" in the Jargon File); we do so for lack
+    # of a better convention.
+    define_verbose_var ('P', 'false', ':');
+    # *Always* provide the user with '$(AM_V_GEN)', unconditionally.
+    define_verbose_tagvar ('GEN');
+    define_verbose_var ('at', '@');
+}
+
+1;
index bdc7aa066a6b08d54edd8d9005609b0166c6e288..2a9c43faf6c223e9427dfb768969dcf6d57448fc 100644 (file)
@@ -36,11 +36,14 @@ dist_perllib_DATA = \
   %D%/Getopt.pm \
   %D%/Item.pm \
   %D%/ItemDef.pm \
+  %D%/LangHandling.pm \
   %D%/Language.pm \
   %D%/Location.pm \
   %D%/Options.pm \
+  %D%/Requires.pm \
   %D%/Rule.pm \
   %D%/RuleDef.pm \
+  %D%/SilentRules.pm \
   %D%/Utils.pm \
   %D%/VarAppend.pm \
   %D%/Variable.pm \