From fb62d77e15dabcc9faa5db14007191bd9bb9059f Mon Sep 17 00:00:00 2001 From: Matthias Paulmier Date: Wed, 20 Jun 2018 16:57:02 +0200 Subject: lib: Add new modules 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 | 899 +------------------------------------------ lib/Automake/LangHandling.pm | 484 +++++++++++++++++++++++ lib/Automake/Requires.pm | 424 ++++++++++++++++++++ lib/Automake/SilentRules.pm | 73 ++++ lib/Automake/local.mk | 3 + 5 files changed, 987 insertions(+), 896 deletions(-) create mode 100644 lib/Automake/LangHandling.pm create mode 100644 lib/Automake/Requires.pm create mode 100644 lib/Automake/SilentRules.pm diff --git a/bin/automake.in b/bin/automake.in index 4b5eee448..556780eb2 100755 --- a/bin/automake.in +++ b/bin/automake.in @@ -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 index 000000000..bfbbb003c --- /dev/null +++ b/lib/Automake/LangHandling.pm @@ -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 . + +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 index 000000000..dbb1c10ed --- /dev/null +++ b/lib/Automake/Requires.pm @@ -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 index 000000000..70729160d --- /dev/null +++ b/lib/Automake/SilentRules.pm @@ -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; diff --git a/lib/Automake/local.mk b/lib/Automake/local.mk index bdc7aa066..2a9c43faf 100644 --- a/lib/Automake/local.mk +++ b/lib/Automake/local.mk @@ -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 \ -- cgit v1.2.1