#!@PERL@ -w # automake - create Makefile.in from Makefile.am -*- perl -*- # @configure_input@ # Copyright (C) 1994-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, 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 . # Originally written by David Mackenzie . # Perl reimplementation by Tom Tromey , and # Alexandre Duret-Lutz . package Automake; use strict; BEGIN { unshift (@INC, '@datadir@/@PACKAGE@-@APIVERSION@') unless $ENV{AUTOMAKE_UNINSTALLED}; # Override SHELL. This is required on DJGPP so that system() uses # bash, not COMMAND.COM which doesn't quote arguments properly. # Other systems aren't expected to use $SHELL when Automake # runs, but it should be safe to drop the "if DJGPP" guard if # it turns up other systems need the same thing. After all, # if SHELL is used, ./configure's SHELL is always better than # the user's SHELL (which may be something like tcsh). $ENV{'SHELL'} = '@SHELL@' if exists $ENV{'DJDIR'}; } use Automake::Config; BEGIN { if ($perl_threads) { require threads; import threads; require Thread::Queue; import Thread::Queue; } } use Automake::ChannelDefs; use Automake::Channels; use Automake::CondStack; use Automake::Condition qw/TRUE FALSE/; use Automake::ConfVars; use Automake::Configure_ac; use Automake::DisjConditions; use Automake::Errors; use Automake::End; use Automake::File; use Automake::FileUtils; use Automake::General; use Automake::Global; use Automake::HandleConfigure; use Automake::LangHandling; use Automake::Language; use Automake::Location; use Automake::Options; use Automake::Requires; use Automake::Rule; use Automake::RuleDef; use Automake::SilentRules; use Automake::Standards; use Automake::Texi; use Automake::Utils; use Automake::VarDef; use Automake::Variable; use Automake::Wrap 'makefile_wrap'; use Automake::XFile; use File::Basename; use File::Spec; use Carp; ## ----------------------- ## ## Subroutine prototypes. ## ## ----------------------- ## sub check_canonical_spelling; sub check_directories_in_var; sub check_libobjs_sources; sub check_trailing_slash ($\$); sub check_typos (); sub define_compiler_variable; sub define_linker_variable; sub define_objects_from_sources; sub define_per_target_linker_variable; sub do_check_merge_target (); sub generate_makefile; sub handle_ALLOCA; sub handle_LIBOBJS; sub handle_LIBOBJS_or_ALLOCA; sub handle_all; sub handle_clean; sub handle_compile (); sub handle_data (); sub handle_dist (); sub handle_factored_dependencies (); sub handle_footer (); sub handle_gettext (); sub handle_headers (); sub handle_install (); sub handle_languages (); sub handle_lib_objects; sub handle_libraries (); sub handle_libtool (); sub handle_ltlibraries (); sub handle_makefile; sub handle_makefiles_serial (); sub handle_makefiles_threaded; sub handle_man_pages (); sub handle_minor_options (); sub handle_options (); sub handle_per_suffix_test; sub handle_programs (); sub handle_scripts (); sub handle_single_transform; sub handle_source_transform; sub handle_subdirs (); sub handle_tags (); sub handle_targets (); sub handle_tests (); sub handle_tests_dejagnu (); sub handle_user_recursion (); sub initialize_per_input (); sub is_valid_test_extension; sub parse_arguments (); sub print_autodist_files; sub read_am_file; sub read_main_am_file; sub target_cmp; sub usage (); sub user_phony_rule; sub version (); ################################################################ Automake::Variable::hook ('SUFFIXES', \&var_SUFFIXES_trigger); ################################################################ # initialize_per_input () # ----------------------- # (Re)-Initialize per-Makefile.am variables. sub initialize_per_input () { reset_local_duplicates (); $relative_dir = undef; $output_deps_greatest_timestamp = 0; $output_vars = ''; $output_all = ''; $output_header = ''; $output_rules = ''; $output_trailer = ''; Automake::Options::reset; Automake::Variable::reset; Automake::Rule::reset; @cond_stack = (); @include_stack = (); @all = (); @check = (); @check_tests = (); %clean_files = (); %compile_clean_files = (); # We always include '.'. This isn't strictly correct. %libtool_clean_directories = ('.' => 1); @sources = (); @dist_sources = (); %object_map = (); %object_compilation_map = (); %directory_map = (); %dep_files = (); @dist_targets = (); @dist_common = (); $handle_dist_run = 0; @proglist = (); @liblist = (); @ltliblist = (); @dup_shortnames = (); %known_programs = (); %known_libraries = (); %extension_seen = (); %language_scratch = (); %lang_specific_files = (); $need_link = 0; $must_handle_compiled_objects = 0; %transformed_files = (); } ################################################################ # Initialize our list of languages that are internally supported. my @cpplike_flags = qw{ $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) }; # C. register_language ('name' => 'c', 'Name' => 'C', 'config_vars' => ['CC'], 'autodep' => '', 'flags' => ['CFLAGS', 'CPPFLAGS'], 'ccer' => 'CC', 'compiler' => 'COMPILE', 'compile' => "\$(CC) @cpplike_flags \$(AM_CFLAGS) \$(CFLAGS)", 'lder' => 'CCLD', 'ld' => '$(CC)', 'linker' => 'LINK', 'link' => '$(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'compile_flag' => '-c', 'output_flag' => '-o', 'libtool_tag' => 'CC', 'extensions' => ['.c']); # C++. register_language ('name' => 'cxx', 'Name' => 'C++', 'config_vars' => ['CXX'], 'linker' => 'CXXLINK', 'link' => '$(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'autodep' => 'CXX', 'flags' => ['CXXFLAGS', 'CPPFLAGS'], 'compile' => "\$(CXX) @cpplike_flags \$(AM_CXXFLAGS) \$(CXXFLAGS)", 'ccer' => 'CXX', 'compiler' => 'CXXCOMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'libtool_tag' => 'CXX', 'lder' => 'CXXLD', 'ld' => '$(CXX)', 'pure' => 1, 'extensions' => ['.c++', '.cc', '.cpp', '.cxx', '.C']); # Objective C. register_language ('name' => 'objc', 'Name' => 'Objective C', 'config_vars' => ['OBJC'], 'linker' => 'OBJCLINK', 'link' => '$(OBJCLD) $(AM_OBJCFLAGS) $(OBJCFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'autodep' => 'OBJC', 'flags' => ['OBJCFLAGS', 'CPPFLAGS'], 'compile' => "\$(OBJC) @cpplike_flags \$(AM_OBJCFLAGS) \$(OBJCFLAGS)", 'ccer' => 'OBJC', 'compiler' => 'OBJCCOMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'lder' => 'OBJCLD', 'ld' => '$(OBJC)', 'pure' => 1, 'extensions' => ['.m']); # Objective C++. register_language ('name' => 'objcxx', 'Name' => 'Objective C++', 'config_vars' => ['OBJCXX'], 'linker' => 'OBJCXXLINK', 'link' => '$(OBJCXXLD) $(AM_OBJCXXFLAGS) $(OBJCXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'autodep' => 'OBJCXX', 'flags' => ['OBJCXXFLAGS', 'CPPFLAGS'], 'compile' => "\$(OBJCXX) @cpplike_flags \$(AM_OBJCXXFLAGS) \$(OBJCXXFLAGS)", 'ccer' => 'OBJCXX', 'compiler' => 'OBJCXXCOMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'lder' => 'OBJCXXLD', 'ld' => '$(OBJCXX)', 'pure' => 1, 'extensions' => ['.mm']); # Unified Parallel C. register_language ('name' => 'upc', 'Name' => 'Unified Parallel C', 'config_vars' => ['UPC'], 'linker' => 'UPCLINK', 'link' => '$(UPCLD) $(AM_UPCFLAGS) $(UPCFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'autodep' => 'UPC', 'flags' => ['UPCFLAGS', 'CPPFLAGS'], 'compile' => "\$(UPC) @cpplike_flags \$(AM_UPCFLAGS) \$(UPCFLAGS)", 'ccer' => 'UPC', 'compiler' => 'UPCCOMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'lder' => 'UPCLD', 'ld' => '$(UPC)', 'pure' => 1, 'extensions' => ['.upc']); # Headers. register_language ('name' => 'header', 'Name' => 'Header', 'extensions' => ['.h', '.H', '.hxx', '.h++', '.hh', '.hpp', '.inc'], # No output. 'output_extensions' => sub { return () }, # Nothing to do. '_finish' => sub { }); # Vala register_language ('name' => 'vala', 'Name' => 'Vala', 'config_vars' => ['VALAC'], 'flags' => [], 'compile' => '$(VALAC) $(AM_VALAFLAGS) $(VALAFLAGS)', 'ccer' => 'VALAC', 'compiler' => 'VALACOMPILE', 'extensions' => ['.vala'], 'output_extensions' => sub { (my $ext = $_[0]) =~ s/vala$/c/; return ($ext,) }, 'rule_file' => 'vala', '_finish' => \&lang_vala_finish, '_target_hook' => \&lang_vala_target_hook, 'nodist_specific' => 1); # Yacc (C & C++). register_language ('name' => 'yacc', 'Name' => 'Yacc', 'config_vars' => ['YACC'], 'flags' => ['YFLAGS'], 'compile' => '$(YACC) $(AM_YFLAGS) $(YFLAGS)', 'ccer' => 'YACC', 'compiler' => 'YACCCOMPILE', 'extensions' => ['.y'], 'output_extensions' => sub { (my $ext = $_[0]) =~ tr/y/c/; return ($ext,) }, 'rule_file' => 'yacc', '_finish' => \&lang_yacc_finish, '_target_hook' => \&lang_yacc_target_hook, 'nodist_specific' => 1); register_language ('name' => 'yaccxx', 'Name' => 'Yacc (C++)', 'config_vars' => ['YACC'], 'rule_file' => 'yacc', 'flags' => ['YFLAGS'], 'ccer' => 'YACC', 'compiler' => 'YACCCOMPILE', 'compile' => '$(YACC) $(AM_YFLAGS) $(YFLAGS)', 'extensions' => ['.y++', '.yy', '.yxx', '.ypp'], 'output_extensions' => sub { (my $ext = $_[0]) =~ tr/y/c/; return ($ext,) }, '_finish' => \&lang_yacc_finish, '_target_hook' => \&lang_yacc_target_hook, 'nodist_specific' => 1); # Lex (C & C++). register_language ('name' => 'lex', 'Name' => 'Lex', 'config_vars' => ['LEX'], 'rule_file' => 'lex', 'flags' => ['LFLAGS'], 'compile' => '$(LEX) $(AM_LFLAGS) $(LFLAGS)', 'ccer' => 'LEX', 'compiler' => 'LEXCOMPILE', 'extensions' => ['.l'], 'output_extensions' => sub { (my $ext = $_[0]) =~ tr/l/c/; return ($ext,) }, '_finish' => \&lang_lex_finish, '_target_hook' => \&lang_lex_target_hook, 'nodist_specific' => 1); register_language ('name' => 'lexxx', 'Name' => 'Lex (C++)', 'config_vars' => ['LEX'], 'rule_file' => 'lex', 'flags' => ['LFLAGS'], 'compile' => '$(LEX) $(AM_LFLAGS) $(LFLAGS)', 'ccer' => 'LEX', 'compiler' => 'LEXCOMPILE', 'extensions' => ['.l++', '.ll', '.lxx', '.lpp'], 'output_extensions' => sub { (my $ext = $_[0]) =~ tr/l/c/; return ($ext,) }, '_finish' => \&lang_lex_finish, '_target_hook' => \&lang_lex_target_hook, 'nodist_specific' => 1); # Assembler. register_language ('name' => 'asm', 'Name' => 'Assembler', 'config_vars' => ['CCAS', 'CCASFLAGS'], 'flags' => ['CCASFLAGS'], # Users can set AM_CCASFLAGS to include DEFS, INCLUDES, # or anything else required. They can also set CCAS. # Or simply use Preprocessed Assembler. 'compile' => '$(CCAS) $(AM_CCASFLAGS) $(CCASFLAGS)', 'ccer' => 'CCAS', 'compiler' => 'CCASCOMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'extensions' => ['.s']); # Preprocessed Assembler. register_language ('name' => 'cppasm', 'Name' => 'Preprocessed Assembler', 'config_vars' => ['CCAS', 'CCASFLAGS'], 'autodep' => 'CCAS', 'flags' => ['CCASFLAGS', 'CPPFLAGS'], 'compile' => "\$(CCAS) @cpplike_flags \$(AM_CCASFLAGS) \$(CCASFLAGS)", 'ccer' => 'CPPAS', 'compiler' => 'CPPASCOMPILE', 'libtool_tag' => 'CC', 'compile_flag' => '-c', 'output_flag' => '-o', 'extensions' => ['.S', '.sx']); # Fortran 77 register_language ('name' => 'f77', 'Name' => 'Fortran 77', 'config_vars' => ['F77'], 'linker' => 'F77LINK', 'link' => '$(F77LD) $(AM_FFLAGS) $(FFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'flags' => ['FFLAGS'], 'compile' => '$(F77) $(AM_FFLAGS) $(FFLAGS)', 'ccer' => 'F77', 'compiler' => 'F77COMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'libtool_tag' => 'F77', 'lder' => 'F77LD', 'ld' => '$(F77)', 'pure' => 1, 'extensions' => ['.f', '.for']); # Fortran register_language ('name' => 'fc', 'Name' => 'Fortran', 'config_vars' => ['FC'], 'linker' => 'FCLINK', 'link' => '$(FCLD) $(AM_FCFLAGS) $(FCFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'flags' => ['FCFLAGS'], 'compile' => '$(FC) $(AM_FCFLAGS) $(FCFLAGS)', 'ccer' => 'FC', 'compiler' => 'FCCOMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'libtool_tag' => 'FC', 'lder' => 'FCLD', 'ld' => '$(FC)', 'pure' => 1, 'extensions' => ['.f90', '.f95', '.f03', '.f08']); # Preprocessed Fortran register_language ('name' => 'ppfc', 'Name' => 'Preprocessed Fortran', 'config_vars' => ['FC'], 'linker' => 'FCLINK', 'link' => '$(FCLD) $(AM_FCFLAGS) $(FCFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'lder' => 'FCLD', 'ld' => '$(FC)', 'flags' => ['FCFLAGS', 'CPPFLAGS'], 'ccer' => 'PPFC', 'compiler' => 'PPFCCOMPILE', 'compile' => "\$(FC) @cpplike_flags \$(AM_FCFLAGS) \$(FCFLAGS)", 'compile_flag' => '-c', 'output_flag' => '-o', 'libtool_tag' => 'FC', 'pure' => 1, 'extensions' => ['.F90','.F95', '.F03', '.F08']); # Preprocessed Fortran 77 # # The current support for preprocessing Fortran 77 just involves # passing "$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) # $(CPPFLAGS)" as additional flags to the Fortran 77 compiler, since # this is how GNU Make does it; see the "GNU Make Manual, Edition 0.51 # for 'make' Version 3.76 Beta" (specifically, from info file # '(make)Catalogue of Rules'). # # A better approach would be to write an Autoconf test # (i.e. AC_PROG_FPP) for a Fortran 77 preprocessor, because not all # Fortran 77 compilers know how to do preprocessing. The Autoconf # macro AC_PROG_FPP should test the Fortran 77 compiler first for # preprocessing capabilities, and then fall back on cpp (if cpp were # available). register_language ('name' => 'ppf77', 'Name' => 'Preprocessed Fortran 77', 'config_vars' => ['F77'], 'linker' => 'F77LINK', 'link' => '$(F77LD) $(AM_FFLAGS) $(FFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'lder' => 'F77LD', 'ld' => '$(F77)', 'flags' => ['FFLAGS', 'CPPFLAGS'], 'ccer' => 'PPF77', 'compiler' => 'PPF77COMPILE', 'compile' => "\$(F77) @cpplike_flags \$(AM_FFLAGS) \$(FFLAGS)", 'compile_flag' => '-c', 'output_flag' => '-o', 'libtool_tag' => 'F77', 'pure' => 1, 'extensions' => ['.F']); # Ratfor. register_language ('name' => 'ratfor', 'Name' => 'Ratfor', 'config_vars' => ['F77'], 'linker' => 'F77LINK', 'link' => '$(F77LD) $(AM_FFLAGS) $(FFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'lder' => 'F77LD', 'ld' => '$(F77)', 'flags' => ['RFLAGS', 'FFLAGS'], # FIXME also FFLAGS. 'compile' => '$(F77) $(AM_FFLAGS) $(FFLAGS) $(AM_RFLAGS) $(RFLAGS)', 'ccer' => 'F77', 'compiler' => 'RCOMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'libtool_tag' => 'F77', 'pure' => 1, 'extensions' => ['.r']); # Java via gcj. register_language ('name' => 'java', 'Name' => 'Java', 'config_vars' => ['GCJ'], 'linker' => 'GCJLINK', 'link' => '$(GCJLD) $(AM_GCJFLAGS) $(GCJFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@', 'autodep' => 'GCJ', 'flags' => ['GCJFLAGS'], 'compile' => '$(GCJ) $(AM_GCJFLAGS) $(GCJFLAGS)', 'ccer' => 'GCJ', 'compiler' => 'GCJCOMPILE', 'compile_flag' => '-c', 'output_flag' => '-o', 'libtool_tag' => 'GCJ', 'lder' => 'GCJLD', 'ld' => '$(GCJ)', 'pure' => 1, 'extensions' => ['.java', '.class', '.zip', '.jar']); ################################################################ # Handle AUTOMAKE_OPTIONS variable. Return 0 on error, 1 otherwise. sub handle_options () { my $var = var ('AUTOMAKE_OPTIONS'); if ($var) { if ($var->has_conditional_contents) { msg_var ('unsupported', $var, "'AUTOMAKE_OPTIONS' cannot have conditional contents"); } my @options = map { { option => $_->[1], where => $_->[0] } } $var->value_as_list_recursive (cond_filter => TRUE, location => 1); return 0 unless process_option_list (@options); } if ($strictness == GNITS) { set_option ('readme-alpha', INTERNAL); set_option ('std-options', INTERNAL); set_option ('check-news', INTERNAL); } return 1; } # Call finish function for each language that was used. sub handle_languages () { if (! option 'no-dependencies') { # Include auto-dep code. Don't include it if DEP_FILES would # be empty. if (keys %extension_seen && keys %dep_files) { my @dep_files = sort keys %dep_files; # Set location of depcomp. define_variable ('depcomp', "\$(SHELL) $am_config_aux_dir/depcomp", INTERNAL); define_variable ('am__maybe_remake_depfiles', 'depfiles', INTERNAL); define_variable ('am__depfiles_remade', "@dep_files", INTERNAL); $output_rules .= "\n"; my @dist_rms; foreach my $depfile (@dep_files) { push @dist_rms, "\t-rm -f $depfile"; # Generate each 'include' directive individually. Several # make implementations (IRIX 6, Solaris 10, FreeBSD 8) will # fail to properly include several files resulting from a # variable expansion. Just Generating many separate includes # seems thus safest. $output_rules .= subst ('AMDEP_TRUE') . subst ('am__include') . " " . subst('am__quote') . $depfile . subst('am__quote') . " " . "# am--include-marker\n"; } require_conf_file ("$am_file.am", FOREIGN, 'depcomp'); $output_rules .= file_contents ( 'depend', new Automake::Location, 'DISTRMS' => join ("\n", @dist_rms)); } } else { define_variable ('depcomp', '', INTERNAL); define_variable ('am__maybe_remake_depfiles', '', INTERNAL); } my %done; # Is the C linker needed? my $needs_c = 0; foreach my $ext (sort keys %extension_seen) { next unless $extension_map{$ext}; my $lang = $languages{$extension_map{$ext}}; my $rule_file = $lang->rule_file || 'depend2'; # Get information on $LANG. my $pfx = $lang->autodep; my $fpfx = ($pfx eq '') ? 'CC' : $pfx; my ($AMDEP, $FASTDEP) = (option 'no-dependencies' || $lang->autodep eq 'no') ? ('FALSE', 'FALSE') : ('AMDEP', "am__fastdep$fpfx"); my $verbose = verbose_flag ($lang->ccer || 'GEN'); my $verbose_nodep = ($AMDEP eq 'FALSE') ? $verbose : verbose_nodep_flag ($lang->ccer || 'GEN'); my $silent = silent_flag (); my %transform = ('EXT' => $ext, 'PFX' => $pfx, 'FPFX' => $fpfx, 'AMDEP' => $AMDEP, 'FASTDEP' => $FASTDEP, '-c' => $lang->compile_flag || '', # These are not used, but they need to be defined # so transform() do not complain. SUBDIROBJ => 0, 'DERIVED-EXT' => 'BUG', DIST_SOURCE => 1, VERBOSE => $verbose, 'VERBOSE-NODEP' => $verbose_nodep, SILENT => $silent, ); # Generate the appropriate rules for this extension. if (((! option 'no-dependencies') && $lang->autodep ne 'no') || defined $lang->compile) { # Compute a possible derived extension. # This is not used by depend2.am. my $der_ext = ($lang->output_extensions->($ext))[0]; # When we output an inference rule like '.c.o:' we # have two cases to consider: either subdir-objects # is used, or it is not. # # In the latter case the rule is used to build objects # in the current directory, and dependencies always # go into './$(DEPDIR)/'. We can hard-code this value. # # In the former case the rule can be used to build # objects in sub-directories too. Dependencies should # go into the appropriate sub-directories, e.g., # 'sub/$(DEPDIR)/'. The value of this directory # needs to be computed on-the-fly. # # DEPBASE holds the name of this directory, plus the # basename part of the object file (extensions Po, TPo, # Plo, TPlo will be added later as appropriate). It is # either hardcoded, or a shell variable ('$depbase') that # will be computed by the rule. my $depbase = option ('subdir-objects') ? '$$depbase' : '$(DEPDIR)/$*'; $output_rules .= file_contents ($rule_file, new Automake::Location, %transform, GENERIC => 1, 'DERIVED-EXT' => $der_ext, DEPBASE => $depbase, BASE => '$*', SOURCE => '$<', SOURCEFLAG => $sourceflags{$ext} || '', OBJ => '$@', OBJOBJ => '$@', LTOBJ => '$@', COMPILE => '$(' . $lang->compiler . ')', LTCOMPILE => '$(LT' . $lang->compiler . ')', -o => $lang->output_flag, SUBDIROBJ => !! option 'subdir-objects'); } # Now include code for each specially handled object with this # language. my %seen_files = (); foreach my $file (@{$lang_specific_files{$lang->name}}) { my ($derived, $source, $obj, $myext, $srcext, %file_transform) = @$file; # We might see a given object twice, for instance if it is # used under different conditions. next if defined $seen_files{$obj}; $seen_files{$obj} = 1; prog_error ("found " . $lang->name . " in handle_languages, but compiler not defined") unless defined $lang->compile; my $obj_compile = $lang->compile; # Rewrite each occurrence of 'AM_$flag' in the compile # rule into '${derived}_$flag' if it exists. for my $flag (@{$lang->flags}) { my $val = "${derived}_$flag"; $obj_compile =~ s/\(AM_$flag\)/\($val\)/ if set_seen ($val); } my $libtool_tag = ''; if ($lang->libtool_tag && exists $libtool_tags{$lang->libtool_tag}) { $libtool_tag = '--tag=' . $lang->libtool_tag . ' ' } my $ptltflags = "${derived}_LIBTOOLFLAGS"; $ptltflags = 'AM_LIBTOOLFLAGS' unless set_seen $ptltflags; my $ltverbose = define_verbose_libtool (); my $obj_ltcompile = "\$(LIBTOOL) $ltverbose $libtool_tag\$($ptltflags) \$(LIBTOOLFLAGS) " . "--mode=compile $obj_compile"; # We _need_ '-o' for per object rules. my $output_flag = $lang->output_flag || '-o'; my $depbase = dirname ($obj); $depbase = '' if $depbase eq '.'; $depbase .= '/' unless $depbase eq ''; $depbase .= '$(DEPDIR)/' . basename ($obj); $output_rules .= file_contents ($rule_file, new Automake::Location, %transform, GENERIC => 0, DEPBASE => $depbase, BASE => $obj, SOURCE => $source, SOURCEFLAG => $sourceflags{$srcext} || '', # Use $myext and not '.o' here, in case # we are actually building a new source # file -- e.g. via yacc. OBJ => "$obj$myext", OBJOBJ => "$obj.obj", LTOBJ => "$obj.lo", VERBOSE => $verbose, 'VERBOSE-NODEP' => $verbose_nodep, SILENT => $silent, COMPILE => $obj_compile, LTCOMPILE => $obj_ltcompile, -o => $output_flag, %file_transform); } # The rest of the loop is done once per language. next if defined $done{$lang}; $done{$lang} = 1; # Load the language dependent Makefile chunks. my %lang = map { uc ($_) => 0 } keys %languages; $lang{uc ($lang->name)} = 1; $output_rules .= file_contents ('lang-compile', new Automake::Location, %transform, %lang); # If the source to a program consists entirely of code from a # 'pure' language, for instance C++ or Fortran 77, then we # don't need the C compiler code. However if we run into # something unusual then we do generate the C code. There are # probably corner cases here that do not work properly. # People linking Java code to Fortran code deserve pain. $needs_c ||= ! $lang->pure; define_compiler_variable ($lang) if ($lang->compile); define_linker_variable ($lang) if ($lang->link); require_variables ("$am_file.am", $lang->Name . " source seen", TRUE, @{$lang->config_vars}); # Call the finisher. $lang->finish; # Flags listed in '->flags' are user variables (per GNU Standards), # they should not be overridden in the Makefile... my @dont_override = @{$lang->flags}; # ... and so is LDFLAGS. push @dont_override, 'LDFLAGS' if $lang->link; check_user_variables @dont_override; } # If the project is entirely C++ or entirely Fortran 77 (i.e., 1 # suffix rule was learned), don't bother with the C stuff. But if # anything else creeps in, then use it. my @languages_seen = map { $languages{$extension_map{$_}}->name } (keys %extension_seen); @languages_seen = uniq (@languages_seen); $needs_c = 1 if @languages_seen > 1; if ($need_link || $needs_c) { define_compiler_variable ($languages{'c'}) unless defined $done{$languages{'c'}}; define_linker_variable ($languages{'c'}); } } # Check to make sure a source defined in LIBOBJS is not explicitly # mentioned. This is a separate function (as opposed to being inlined # in handle_source_transform) because it isn't always appropriate to # do this check. sub check_libobjs_sources { my ($one_file, $unxformed) = @_; foreach my $prefix ('', 'EXTRA_', 'dist_', 'nodist_', 'dist_EXTRA_', 'nodist_EXTRA_') { my @files; my $varname = $prefix . $one_file . '_SOURCES'; my $var = var ($varname); if ($var) { @files = $var->value_as_list_recursive; } elsif ($prefix eq '') { @files = ($unxformed . '.c'); } else { next; } foreach my $file (@files) { err_var ($prefix . $one_file . '_SOURCES', "automatically discovered file '$file' should not" . " be explicitly mentioned") if defined $libsources{$file}; } } } # @OBJECTS # handle_single_transform ($VAR, $TOPPARENT, $DERIVED, $OBJ, $FILE, %TRANSFORM) # ----------------------------------------------------------------------------- # Does much of the actual work for handle_source_transform. # Arguments are: # $VAR is the name of the variable that the source filenames come from # $TOPPARENT is the name of the _SOURCES variable which is being processed # $DERIVED is the name of resulting executable or library # $OBJ is the object extension (e.g., '.lo') # $FILE the source file to transform # %TRANSFORM contains extras arguments to pass to file_contents # when producing explicit rules # Result is a list of the names of objects # %linkers_used will be updated with any linkers needed sub handle_single_transform { my ($var, $topparent, $derived, $obj, $_file, %transform) = @_; my @files = ($_file); my @result = (); # Turn sources into objects. We use a while loop like this # because we might add to @files in the loop. while (scalar @files > 0) { $_ = shift @files; # Configure substitutions in _SOURCES variables are errors. if (/^\@.*\@$/) { my $parent_msg = ''; $parent_msg = "\nand is referred to from '$topparent'" if $topparent ne $var->name; err_var ($var, "'" . $var->name . "' includes configure substitution '$_'" . $parent_msg . ";\nconfigure " . "substitutions are not allowed in _SOURCES variables"); next; } # If the source file is in a subdirectory then the '.o' is put # into the current directory, unless the subdir-objects option # is in effect. # Split file name into base and extension. next if ! /^(?:(.*)\/)?([^\/]*)($KNOWN_EXTENSIONS_PATTERN)$/; my $full = $_; my $directory = $1 || ''; my $base = $2; my $extension = $3; # We must generate a rule for the object if it requires its own flags. my $renamed = 0; my ($linker, $object); # This records whether we've seen a derived source file (e.g., yacc # or lex output). my $derived_source; # This holds the 'aggregate context' of the file we are # currently examining. If the file is compiled with # per-object flags, then it will be the name of the object. # Otherwise it will be 'AM'. This is used by the target hook # language function. my $aggregate = 'AM'; $extension = derive_suffix ($extension, $obj); my $lang; if ($extension_map{$extension} && ($lang = $languages{$extension_map{$extension}})) { # Found the language, so see what it says. saw_extension ($extension); # Do we have per-executable flags for this executable? my $have_per_exec_flags = 0; my @peflags = @{$lang->flags}; push @peflags, 'LIBTOOLFLAGS' if $obj eq '.lo'; foreach my $flag (@peflags) { if (set_seen ("${derived}_$flag")) { $have_per_exec_flags = 1; last; } } # Note: computed subr call. The language rewrite function # should return one of the LANG_* constants. It could # also return a list whose first value is such a constant # and whose second value is a new source extension which # should be applied. This means this particular language # generates another source file which we must then process # further. my $subr = \&{'lang_' . $lang->name . '_rewrite'}; defined &$subr or $subr = \&lang_sub_obj; my ($r, $source_extension) = &$subr ($directory, $base, $extension, $obj, $have_per_exec_flags, $var); # Skip this entry if we were asked not to process it. next if $r == LANG_IGNORE; # Now extract linker and other info. $linker = $lang->linker; my $this_obj_ext; if (defined $source_extension) { $this_obj_ext = $source_extension; $derived_source = 1; } else { $this_obj_ext = $obj; $derived_source = 0; # Don't ever place built object files in $(srcdir), # even when sources are specified explicitly as (say) # '$(srcdir)/foo.c' or '$(top_srcdir)/foo.c'. # See automake bug#13928. my @d = split '/', $directory; if (@d > 0 && option 'subdir-objects') { my $d = $d[0]; if ($d eq '$(srcdir)' or $d eq '${srcdir}') { shift @d; } elsif ($d eq '$(top_srcdir)' or $d eq '${top_srcdir}') { $d[0] = '$(top_builddir)'; } $directory = join '/', @d; } } $object = $base . $this_obj_ext; if ($have_per_exec_flags) { # We have a per-executable flag in effect for this # object. In this case we rewrite the object's # name to ensure it is unique. # We choose the name 'DERIVED_OBJECT' to ensure (1) uniqueness, # and (2) continuity between invocations. However, this will # result in a name that is too long for losing systems, in some # situations. So we attempt to shorten automatically under # subdir-objects, and provide _SHORTNAME to override as a last # resort. If subdir-object is in effect, it's usually # unnecessary to use the complete 'DERIVED_OBJECT' (that is # often the result from %canon_reldir%/%C% usage) since objects # are placed next to their source file. Generally, this means # it is already unique within that directory (see below for an # exception). Thus, we try to avoid unnecessarily long file # names by stripping the directory components of # 'DERIVED_OBJECT'. This allows avoiding explicit _SHORTNAME # usage in many cases. EXCEPTION: If two (or more) targets in # different directories but with the same base name (after # canonicalization), using target-specific FLAGS, link the same # object, then this logic clashes. Thus, we don't strip if # this is detected. my $dname = $derived; if ($directory ne '' && option 'subdir-objects' && none { $dname =~ /$_[0]$/ } @dup_shortnames) { # At this point, we don't clear information about what # parts of $derived are truly file name components. We can # determine that by comparing against the canonicalization # of $directory. my $dir = $directory . "/"; my $cdir = canonicalize ($dir); my $dir_len = length ($dir); # Make sure we only strip full file name components. This # is done by repeatedly trying to find cdir at the # beginning. Each iteration removes one file name # component from the end of cdir. while ($dir_len > 0 && index ($derived, $cdir) != 0) { # Eventually $dir_len becomes 0. $dir_len = rindex ($dir, "/", $dir_len - 2) + 1; $cdir = substr ($cdir, 0, $dir_len); } $dname = substr ($derived, $dir_len); } my $var = var ($derived . '_SHORTNAME'); if ($var) { # FIXME: should use the same Condition as # the _SOURCES variable. But this is really # silly overkill -- nobody should have # conditional shortnames. $dname = $var->variable_value; } $object = $dname . '-' . $object; prog_error ($lang->name . " flags defined without compiler") if ! defined $lang->compile; $renamed = 1; } # If rewrite said it was ok, put the object into a subdir. if ($directory ne '') { if ($r == LANG_SUBDIR) { $object = $directory . '/' . $object; } else { # Since the next major version of automake (2.0) will # make the behaviour so far only activated with the # 'subdir-object' option mandatory, it's better if we # start warning users not using that option. # As suggested by Peter Johansson, we strive to avoid # the warning when it would be irrelevant, i.e., if # all source files sit in "current" directory. msg_var 'unsupported', $var, "source file '$full' is in a subdirectory," . "\nbut option 'subdir-objects' is disabled"; msg 'unsupported', INTERNAL, <<'EOF', uniq_scope => US_GLOBAL; possible forward-incompatibility. At least a source file is in a subdirectory, but the 'subdir-objects' automake option hasn't been enabled. For now, the corresponding output object file(s) will be placed in the top-level directory. However, this behaviour will change in future Automake versions: they will unconditionally cause object files to be placed in the same subdirectory of the corresponding sources. You are advised to start using 'subdir-objects' option throughout your project, to avoid future incompatibilities. EOF } } # If the object file has been renamed (because per-target # flags are used) we cannot compile the file with an # inference rule: we need an explicit rule. # # If the source is in a subdirectory and the object is in # the current directory, we also need an explicit rule. # # If both source and object files are in a subdirectory # (this happens when the subdir-objects option is used), # then the inference will work. # # The latter case deserves a historical note. When the # subdir-objects option was added on 1999-04-11 it was # thought that inferences rules would work for # subdirectory objects too. Later, on 1999-11-22, # automake was changed to output explicit rules even for # subdir-objects. Nobody remembers why, but this occurred # soon after the merge of the user-dep-gen-branch so it # might be related. In late 2003 people complained about # the size of the generated Makefile.ins (libgcj, with # 2200+ subdir objects was reported to have a 9MB # Makefile), so we now rely on inference rules again. # Maybe we'll run across the same issue as in the past, # but at least this time we can document it. However since # dependency tracking has evolved it is possible that # our old problem no longer exists. # Using inference rules for subdir-objects has been tested # with GNU make, Solaris make, Ultrix make, BSD make, # HP-UX make, and OSF1 make successfully. if ($renamed || ($directory ne '' && ! option 'subdir-objects') # We must also use specific rules for a nodist_ source # if its language requests it. || ($lang->nodist_specific && ! $transform{'DIST_SOURCE'})) { my $obj_sans_ext = substr ($object, 0, - length ($this_obj_ext)); my $full_ansi; if ($directory ne '') { $full_ansi = $directory . '/' . $base . $extension; } else { $full_ansi = $base . $extension; } my @specifics = ($full_ansi, $obj_sans_ext, # Only use $this_obj_ext in the derived # source case because in the other case we # *don't* want $(OBJEXT) to appear here. ($derived_source ? $this_obj_ext : '.o'), $extension); # If we renamed the object then we want to use the # per-executable flag name. But if this is simply a # subdir build then we still want to use the AM_ flag # name. if ($renamed) { unshift @specifics, $derived; $aggregate = $derived; } else { unshift @specifics, 'AM'; } # Each item on this list is a reference to a list consisting # of four values followed by additional transform flags for # file_contents. The four values are the derived flag prefix # (e.g. for 'foo_CFLAGS', it is 'foo'), the name of the # source file, the base name of the output file, and # the extension for the object file. push (@{$lang_specific_files{$lang->name}}, [@specifics, %transform]); } } elsif ($extension eq $obj) { # This is probably the result of a direct suffix rule. # In this case we just accept the rewrite. $object = "$base$extension"; $object = "$directory/$object" if $directory ne ''; $linker = ''; } else { # No error message here. Used to have one, but it was # very unpopular. # FIXME: we could potentially do more processing here, # perhaps treating the new extension as though it were a # new source extension (as above). This would require # more restructuring than is appropriate right now. next; } err_am "object '$object' created by '$full' and '$object_map{$object}'" if (defined $object_map{$object} && $object_map{$object} ne $full); my $comp_val = (($object =~ /\.lo$/) ? COMPILE_LIBTOOL : COMPILE_ORDINARY); (my $comp_obj = $object) =~ s/\.lo$/.\$(OBJEXT)/; if (defined $object_compilation_map{$comp_obj} && $object_compilation_map{$comp_obj} != 0 # Only see the error once. && ($object_compilation_map{$comp_obj} != (COMPILE_LIBTOOL | COMPILE_ORDINARY)) && $object_compilation_map{$comp_obj} != $comp_val) { err_am "object '$comp_obj' created both with libtool and without"; } $object_compilation_map{$comp_obj} |= $comp_val; if (defined $lang) { # Let the language do some special magic if required. $lang->target_hook ($aggregate, $object, $full, %transform); } if ($derived_source) { prog_error ($lang->name . " has automatic dependency tracking") if $lang->autodep ne 'no'; # Make sure this new source file is handled next. That will # make it appear to be at the right place in the list. unshift (@files, $object); # Distribute derived sources unless the source they are # derived from is not. push_dist_common ($object) unless ($topparent =~ /^(?:nobase_)?nodist_/); next; } $linkers_used{$linker} = 1; push (@result, $object); if (! defined $object_map{$object}) { my @dep_list = (); $object_map{$object} = $full; # If resulting object is in subdir, we need to make # sure the subdir exists at build time. if ($object =~ /\//) { # FIXME: check that $DIRECTORY is somewhere in the # project # For Java, the way we're handling it right now, a # '..' component doesn't make sense. if ($lang && $lang->name eq 'java' && $object =~ /(\/|^)\.\.\//) { err_am "'$full' should not contain a '..' component"; } # Make sure *all* objects files in the subdirectory are # removed by "make mostlyclean". Not only this is more # efficient than listing the object files to be removed # individually (which would cause an 'rm' invocation for # each of them -- very inefficient, see bug#10697), it # would also leave stale object files in the subdirectory # whenever a source file there is removed or renamed. $compile_clean_files{"$directory/*.\$(OBJEXT)"} = MOSTLY_CLEAN; if ($object =~ /\.lo$/) { # If we have a libtool object, then we also must remove # any '.lo' objects in its same subdirectory. $compile_clean_files{"$directory/*.lo"} = MOSTLY_CLEAN; # Remember to cleanup .libs/ in this directory. $libtool_clean_directories{$directory} = 1; } push (@dep_list, require_build_directory ($directory)); # If we're generating dependencies, we also want # to make sure that the appropriate subdir of the # .deps directory is created. push (@dep_list, require_build_directory ($directory . '/$(DEPDIR)')) unless option 'no-dependencies'; } pretty_print_rule ($object . ':', "\t", @dep_list) if scalar @dep_list > 0; } # Transform .o or $o file into .P file (for automatic # dependency code). # Properly flatten multiple adjacent slashes, as Solaris 10 make # might fail over them in an include statement. # Leading double slashes may be special, as per Posix, so deal # with them carefully. if ($lang && $lang->autodep ne 'no') { my $depfile = $object; $depfile =~ s/\.([^.]*)$/.P$1/; $depfile =~ s/\$\(OBJEXT\)$/o/; my $maybe_extra_leading_slash = ''; $maybe_extra_leading_slash = '/' if $depfile =~ m,^//[^/],; $depfile =~ s,/+,/,g; my $basename = basename ($depfile); # This might make $dirname empty, but we account for that below. (my $dirname = dirname ($depfile)) =~ s/\/*$//; $dirname = $maybe_extra_leading_slash . $dirname; $dep_files{$dirname . '/$(DEPDIR)/' . $basename} = 1; } } return @result; } # $LINKER # define_objects_from_sources ($VAR, $OBJVAR, $NODEFINE, $ONE_FILE, # $OBJ, $PARENT, $TOPPARENT, $WHERE, %TRANSFORM) # --------------------------------------------------------------------------- # Define an _OBJECTS variable for a _SOURCES variable (or subvariable) # # Arguments are: # $VAR is the name of the _SOURCES variable # $OBJVAR is the name of the _OBJECTS variable if known (otherwise # it will be generated and returned). # $NODEFINE is a boolean: if true, $OBJVAR will not be defined (but # work done to determine the linker will be). # $ONE_FILE is the canonical (transformed) name of object to build # $OBJ is the object extension (i.e. either '.o' or '.lo'). # $TOPPARENT is the _SOURCES variable being processed. # $WHERE context into which this definition is done # %TRANSFORM extra arguments to pass to file_contents when producing # rules # # Result is a pair ($LINKER, $OBJVAR): # $LINKER is a boolean, true if a linker is needed to deal with the objects sub define_objects_from_sources { my ($var, $objvar, $nodefine, $one_file, $obj, $topparent, $where, %transform) = @_; my $needlinker = ""; transform_variable_recursively ($var, $objvar, 'am__objects', $nodefine, $where, # The transform code to run on each filename. sub { my ($subvar, $val, $cond, $full_cond) = @_; my @trans = handle_single_transform ($subvar, $topparent, $one_file, $obj, $val, %transform); $needlinker = "true" if @trans; return @trans; }); return $needlinker; } # handle_source_transform ($CANON_TARGET, $TARGET, $OBJEXT, $WHERE, %TRANSFORM) # ----------------------------------------------------------------------------- # Handle SOURCE->OBJECT transform for one program or library. # Arguments are: # canonical (transformed) name of target to build # actual target of object to build # object extension (i.e., either '.o' or '$o') # location of the source variable # extra arguments to pass to file_contents when producing rules # Return the name of the linker variable that must be used. # Empty return means just use 'LINK'. sub handle_source_transform { # one_file is canonical name. unxformed is given name. obj is # object extension. my ($one_file, $unxformed, $obj, $where, %transform) = @_; my $linker = ''; # No point in continuing if _OBJECTS is defined. return if reject_var ($one_file . '_OBJECTS', $one_file . '_OBJECTS should not be defined'); my %used_pfx = (); my $needlinker; %linkers_used = (); foreach my $prefix ('', 'EXTRA_', 'dist_', 'nodist_', 'dist_EXTRA_', 'nodist_EXTRA_') { my $varname = $prefix . $one_file . "_SOURCES"; my $var = var $varname; next unless $var; # We are going to define _OBJECTS variables using the prefix. # Then we glom them all together. So we can't use the null # prefix here as we need it later. my $xpfx = ($prefix eq '') ? 'am_' : $prefix; # Keep track of which prefixes we saw. $used_pfx{$xpfx} = 1 unless $prefix =~ /EXTRA_/; push @sources, "\$($varname)"; push @dist_sources, shadow_unconditionally ($varname, $where) unless (option ('no-dist') || $prefix =~ /^nodist_/); $needlinker |= define_objects_from_sources ($varname, $xpfx . $one_file . '_OBJECTS', !!($prefix =~ /EXTRA_/), $one_file, $obj, $varname, $where, DIST_SOURCE => ($prefix !~ /^nodist_/), %transform); } if ($needlinker) { $linker ||= resolve_linker (%linkers_used); } my @keys = sort keys %used_pfx; if (scalar @keys == 0) { # The default source for libfoo.la is libfoo.c, but for # backward compatibility we first look at libfoo_la.c, # if no default source suffix is given. my $old_default_source = "$one_file.c"; my $ext_var = var ('AM_DEFAULT_SOURCE_EXT'); my $default_source_ext = $ext_var ? variable_value ($ext_var) : '.c'; msg_var ('unsupported', $ext_var, $ext_var->name . " can assume at most one value") if $default_source_ext =~ /[\t ]/; (my $default_source = $unxformed) =~ s,(\.[^./\\]*)?$,$default_source_ext,; # TODO: Remove this backward-compatibility hack in Automake 2.0. if ($old_default_source ne $default_source && !$ext_var && (rule $old_default_source || rule '$(srcdir)/' . $old_default_source || rule '${srcdir}/' . $old_default_source || -f $old_default_source)) { my $loc = $where->clone; $loc->pop_context; msg ('obsolete', $loc, "the default source for '$unxformed' has been changed " . "to '$default_source'.\n(Using '$old_default_source' for " . "backward compatibility.)"); $default_source = $old_default_source; } # If a rule exists to build this source with a $(srcdir) # prefix, use that prefix in our variables too. This is for # the sake of BSD Make. if (rule '$(srcdir)/' . $default_source || rule '${srcdir}/' . $default_source) { $default_source = '$(srcdir)/' . $default_source; } define_variable ($one_file . "_SOURCES", $default_source, $where); push (@sources, $default_source); push (@dist_sources, $default_source); %linkers_used = (); my (@result) = handle_single_transform ($one_file . '_SOURCES', $one_file . '_SOURCES', $one_file, $obj, $default_source, %transform); $linker ||= resolve_linker (%linkers_used); define_pretty_variable ($one_file . '_OBJECTS', TRUE, $where, @result); } else { @keys = map { '$(' . $_ . $one_file . '_OBJECTS)' } @keys; define_pretty_variable ($one_file . '_OBJECTS', TRUE, $where, @keys); } # If we want to use 'LINK' we must make sure it is defined. if ($linker eq '') { $need_link = 1; } return $linker; } # handle_lib_objects ($XNAME, $VAR) # --------------------------------- # Special-case ALLOCA and LIBOBJS substitutions in _LDADD or _LIBADD variables. # Also, generate _DEPENDENCIES variable if appropriate. # Arguments are: # transformed name of object being built, or empty string if no object # name of _LDADD/_LIBADD-type variable to examine # Returns 1 if LIBOBJS seen, 0 otherwise. sub handle_lib_objects { my ($xname, $varname) = @_; my $var = var ($varname); prog_error "'$varname' undefined" unless $var; prog_error "unexpected variable name '$varname'" unless $varname =~ /^(.*)(?:LIB|LD)ADD$/; my $prefix = $1 || 'AM_'; my $seen_libobjs = 0; my $flagvar = 0; transform_variable_recursively ($varname, $xname . '_DEPENDENCIES', 'am__DEPENDENCIES', ! $xname, INTERNAL, # Transformation function, run on each filename. sub { my ($subvar, $val, $cond, $full_cond) = @_; if ($val =~ /^-/) { # Skip -lfoo and -Ldir silently; these are explicitly allowed. if ($val !~ /^-[lL]/ && # Skip -dlopen and -dlpreopen; these are explicitly allowed # for Libtool libraries or programs. (Actually we are a bit # lax here since this code also applies to non-libtool # libraries or programs, for which -dlopen and -dlopreopen # are pure nonsense. Diagnosing this doesn't seem very # important: the developer will quickly get complaints from # the linker.) $val !~ /^-dl(?:pre)?open$/ && # Only get this error once. ! $flagvar) { $flagvar = 1; # FIXME: should display a stack of nested variables # as context when $var != $subvar. err_var ($var, "linker flags such as '$val' belong in " . "'${prefix}LDFLAGS'"); } return (); } elsif ($val !~ /^\@.*\@$/) { # Assume we have a file of some sort, and output it into the # dependency variable. Autoconf substitutions are not output; # rarely is a new dependency substituted into e.g. foo_LDADD # -- but bad things (e.g. -lX11) are routinely substituted. # Note that LIBOBJS and ALLOCA are exceptions to this rule, # and handled specially below. return $val; } elsif ($val =~ /^\@(LT)?LIBOBJS\@$/) { handle_LIBOBJS ($subvar, $cond, $1); $seen_libobjs = 1; return $val; } elsif ($val =~ /^\@(LT)?ALLOCA\@$/) { handle_ALLOCA ($subvar, $cond, $1); return $val; } else { return (); } }); return $seen_libobjs; } # handle_LIBOBJS_or_ALLOCA ($VAR, $BASE) # -------------------------------------- # Definitions common to LIBOBJS and ALLOCA. # VAR should be one of LIBOBJS, LTLIBOBJS, ALLOCA, or LTALLOCA. # BASE should be one base file name from AC_LIBSOURCE, or alloca. sub handle_LIBOBJS_or_ALLOCA { my ($var, $base) = @_; my $dir = ''; # If LIBOBJS files must be built in another directory we have # to define LIBOBJDIR and ensure the files get cleaned. # Otherwise LIBOBJDIR can be left undefined, and the cleaning # is achieved by 'rm -f *.$(OBJEXT)' in compile.am. if ($config_libobj_dir && $relative_dir ne $config_libobj_dir) { if (option 'subdir-objects') { # In the top-level Makefile we do not use $(top_builddir), because # we are already there, and since the targets are built without # a $(top_builddir), it helps BSD Make to match them with # dependencies. $dir = "$config_libobj_dir/" if $config_libobj_dir ne '.'; $dir = backname ($relative_dir) . "/$dir" if $relative_dir ne '.'; define_variable ('LIBOBJDIR', "$dir", INTERNAL); if ($dir && !defined $clean_files{"$dir$base.\$(OBJEXT)"}) { my $dirstamp = require_build_directory ($dir); $output_rules .= "$dir$base.\$(OBJEXT): $dirstamp\n"; $output_rules .= "$dir$base.lo: $dirstamp\n" if ($var =~ /^LT/); } # libtool might create .$(OBJEXT) as a side-effect of using # LTLIBOBJS or LTALLOCA. $clean_files{"$dir$base.\$(OBJEXT)"} = MOSTLY_CLEAN; $clean_files{"$dir$base.lo"} = MOSTLY_CLEAN if ($var =~ /^LT/); } else { error ("'\$($var)' cannot be used outside '$config_libobj_dir' if" . " 'subdir-objects' is not set"); } } return $dir; } sub handle_LIBOBJS { my ($var, $cond, $lt) = @_; my $myobjext = $lt ? 'lo' : 'o'; $lt ||= ''; $var->requires_variables ("\@${lt}LIBOBJS\@ used", $lt . 'LIBOBJS') if ! keys %libsources; foreach my $iter (keys %libsources) { my $dir = ''; if ($iter =~ /^(.*)(\.[cly])$/) { saw_extension ($2); saw_extension ('.c'); $dir = handle_LIBOBJS_or_ALLOCA ("${lt}LIBOBJS", $1); } if ($iter =~ /\.h$/) { require_libsource_with_macro ($cond, $var, FOREIGN, $iter); } elsif ($iter ne 'alloca.c') { my $rewrite = $iter; $rewrite =~ s/\.c$/.P$myobjext/; $dep_files{$dir . '$(DEPDIR)/' . $rewrite} = 1; $rewrite = "^" . quotemeta ($iter) . "\$"; # Only require the file if it is not a built source. my $bs = var ('BUILT_SOURCES'); if (! $bs || ! grep (/$rewrite/, $bs->value_as_list_recursive)) { require_libsource_with_macro ($cond, $var, FOREIGN, $iter); } } } } sub handle_ALLOCA { my ($var, $cond, $lt) = @_; my $myobjext = $lt ? 'lo' : 'o'; $lt ||= ''; my $dir = handle_LIBOBJS_or_ALLOCA ("${lt}ALLOCA", "alloca"); $dir eq '' and $dir = './'; $var->requires_variables ("\@${lt}ALLOCA\@ used", $lt . 'ALLOCA'); $dep_files{$dir . '$(DEPDIR)/alloca.P' . $myobjext} = 1; require_libsource_with_macro ($cond, $var, FOREIGN, 'alloca.c'); saw_extension ('.c'); } # Canonicalize a name, and check to make sure the non-canonical name # is never used. Returns canonical name. Arguments are name and a # list of suffixes to check for. sub check_canonical_spelling { my ($name, @suffixes) = @_; my $xname = canonicalize ($name); if ($xname ne $name) { foreach my $xt (@suffixes) { reject_var ("$name$xt", "use '$xname$xt', not '$name$xt'"); } } return $xname; } # Set up the compile suite. sub handle_compile () { return if ! $must_handle_compiled_objects; # Boilerplate. my $default_includes = ''; if (! option 'nostdinc') { my @incs = ('-I.', subst ('am__isrc')); my $var = var 'CONFIG_HEADER'; if ($var) { foreach my $hdr (split (' ', $var->variable_value)) { push @incs, '-I' . dirname ($hdr); } } # We want '-I. -I$(srcdir)', but the latter -I is redundant # and unaesthetic in non-VPATH builds. We use `-I.@am__isrc@` # instead. It will be replaced by '-I.' or '-I. -I$(srcdir)'. # Items in CONFIG_HEADER are never in $(srcdir) so it is safe # to just put @am__isrc@ right after '-I.', without a space. ($default_includes = ' ' . uniq (@incs)) =~ s/ @/@/; } my (@mostly_rms, @dist_rms); foreach my $item (sort keys %compile_clean_files) { if ($compile_clean_files{$item} == MOSTLY_CLEAN) { push (@mostly_rms, "\t-rm -f $item"); } elsif ($compile_clean_files{$item} == DIST_CLEAN) { push (@dist_rms, "\t-rm -f $item"); } else { prog_error 'invalid entry in %compile_clean_files'; } } my $filename = "$libdir/am/compile.am"; my %transform = ( 'DEFAULT_INCLUDES' => $default_includes, 'MOSTLYRMS' => join ("\n", @mostly_rms), 'DISTRMS' => join ("\n", @dist_rms) ); my @paragraphs = make_paragraphs (preprocess_file ($filename, %transform)); my ($coms, $vars, $rules) = file_contents_internal (1, $filename, new Automake::Location, \@paragraphs, %transform); $output_rules .= "$coms$rules"; } # Handle libtool rules. sub handle_libtool () { return unless var ('LIBTOOL'); # Libtool requires some files, but only at top level. # (Starting with Libtool 2.0 we do not have to bother. These # requirements are done with AC_REQUIRE_AUX_FILE.) require_conf_file_with_macro (TRUE, 'LIBTOOL', FOREIGN, @libtool_files) if $relative_dir eq '.' && ! $libtool_new_api; my @libtool_rms; foreach my $item (sort keys %libtool_clean_directories) { my $dir = ($item eq '.') ? '' : "$item/"; # .libs is for Unix, _libs for DOS. push (@libtool_rms, "\t-rm -rf ${dir}.libs ${dir}_libs"); } check_user_variables 'LIBTOOLFLAGS'; # Output the libtool compilation rules. $output_rules .= file_contents ('libtool', new Automake::Location, LTRMS => join ("\n", @libtool_rms)); } # Check for duplicate targets sub handle_targets () { my %seen = (); my @dups = (); @proglist = am_install_var ('progs', 'PROGRAMS', 'bin', 'sbin', 'libexec', 'pkglibexec', 'noinst', 'check'); @liblist = am_install_var ('libs', 'LIBRARIES', 'lib', 'pkglib', 'noinst', 'check'); @ltliblist = am_install_var ('ltlib', 'LTLIBRARIES', 'noinst', 'lib', 'pkglib', 'check'); # Record duplications that may arise after canonicalization of the # base names, in order to prevent object file clashes in the presence # of target-specific *FLAGS my @targetlist = (@proglist, @liblist, @ltliblist); foreach my $pair (@targetlist) { my $base = canonicalize (basename (@$pair[1])); push (@dup_shortnames, $base) if ($seen{$base}); $seen{$base} = $base; } } sub handle_programs () { return if ! @proglist; $must_handle_compiled_objects = 1; my $seen_global_libobjs = var ('LDADD') && handle_lib_objects ('', 'LDADD'); foreach my $pair (@proglist) { my ($where, $one_file) = @$pair; my $seen_libobjs = 0; my $obj = '.$(OBJEXT)'; $known_programs{$one_file} = $where; # Canonicalize names and check for misspellings. my $xname = check_canonical_spelling ($one_file, '_LDADD', '_LDFLAGS', '_SOURCES', '_OBJECTS', '_DEPENDENCIES'); $where->push_context ("while processing program '$one_file'"); $where->set (INTERNAL->get); my $linker = handle_source_transform ($xname, $one_file, $obj, $where, NONLIBTOOL => 1, LIBTOOL => 0); if (var ($xname . "_LDADD")) { $seen_libobjs = handle_lib_objects ($xname, $xname . '_LDADD'); } else { # User didn't define prog_LDADD override. So do it. define_variable ($xname . '_LDADD', '$(LDADD)', $where); # This does a bit too much work. But we need it to # generate _DEPENDENCIES when appropriate. if (var ('LDADD')) { $seen_libobjs = handle_lib_objects ($xname, 'LDADD'); } } reject_var ($xname . '_LIBADD', "use '${xname}_LDADD', not '${xname}_LIBADD'"); set_seen ($xname . '_DEPENDENCIES'); set_seen ('EXTRA_' . $xname . '_DEPENDENCIES'); set_seen ($xname . '_LDFLAGS'); # Determine program to use for link. my($xlink, $vlink) = define_per_target_linker_variable ($linker, $xname); $vlink = verbose_flag ($vlink || 'GEN'); # If the resulting program lies in a subdirectory, # ensure that the directory exists before we need it. my $dirstamp = require_build_directory_maybe ($one_file); $libtool_clean_directories{dirname ($one_file)} = 1; $output_rules .= file_contents ('program', $where, PROGRAM => $one_file, XPROGRAM => $xname, XLINK => $xlink, VERBOSE => $vlink, DIRSTAMP => $dirstamp, EXEEXT => '$(EXEEXT)'); if ($seen_libobjs || $seen_global_libobjs) { if (var ($xname . '_LDADD')) { check_libobjs_sources ($xname, $xname . '_LDADD'); } elsif (var ('LDADD')) { check_libobjs_sources ($xname, 'LDADD'); } } } } sub handle_libraries () { return if ! @liblist; $must_handle_compiled_objects = 1; my @prefix = am_primary_prefixes ('LIBRARIES', 0, 'lib', 'pkglib', 'noinst', 'check'); if (@prefix) { my $var = rvar ($prefix[0] . '_LIBRARIES'); $var->requires_variables ('library used', 'RANLIB'); } define_variable ('AR', 'ar', INTERNAL); define_variable ('ARFLAGS', 'cru', INTERNAL); define_verbose_tagvar ('AR'); foreach my $pair (@liblist) { my ($where, $onelib) = @$pair; my $seen_libobjs = 0; # Check that the library fits the standard naming convention. my $bn = basename ($onelib); if ($bn !~ /^lib.*\.a$/) { $bn =~ s/^(?:lib)?(.*?)(?:\.[^.]*)?$/lib$1.a/; my $suggestion = dirname ($onelib) . "/$bn"; $suggestion =~ s|^\./||g; msg ('error-gnu/warn', $where, "'$onelib' is not a standard library name\n" . "did you mean '$suggestion'?") } ($known_libraries{$onelib} = $bn) =~ s/\.a$//; $where->push_context ("while processing library '$onelib'"); $where->set (INTERNAL->get); my $obj = '.$(OBJEXT)'; # Canonicalize names and check for misspellings. my $xlib = check_canonical_spelling ($onelib, '_LIBADD', '_SOURCES', '_OBJECTS', '_DEPENDENCIES', '_AR'); if (! var ($xlib . '_AR')) { define_variable ($xlib . '_AR', '$(AR) $(ARFLAGS)', $where); } # Generate support for conditional object inclusion in # libraries. if (var ($xlib . '_LIBADD')) { if (handle_lib_objects ($xlib, $xlib . '_LIBADD')) { $seen_libobjs = 1; } } else { define_variable ($xlib . "_LIBADD", '', $where); } reject_var ($xlib . '_LDADD', "use '${xlib}_LIBADD', not '${xlib}_LDADD'"); # Make sure we at look at this. set_seen ($xlib . '_DEPENDENCIES'); set_seen ('EXTRA_' . $xlib . '_DEPENDENCIES'); handle_source_transform ($xlib, $onelib, $obj, $where, NONLIBTOOL => 1, LIBTOOL => 0); # If the resulting library lies in a subdirectory, # make sure this directory will exist. my $dirstamp = require_build_directory_maybe ($onelib); my $verbose = verbose_flag ('AR'); my $silent = silent_flag (); $output_rules .= file_contents ('library', $where, VERBOSE => $verbose, SILENT => $silent, LIBRARY => $onelib, XLIBRARY => $xlib, DIRSTAMP => $dirstamp); if ($seen_libobjs) { if (var ($xlib . '_LIBADD')) { check_libobjs_sources ($xlib, $xlib . '_LIBADD'); } } if (! $seen_ar) { msg ('extra-portability', $where, "'$onelib': linking libraries using a non-POSIX\n" . "archiver requires 'AM_PROG_AR' in '$configure_ac'") } } } sub handle_ltlibraries () { return if ! @ltliblist; $must_handle_compiled_objects = 1; my @prefix = am_primary_prefixes ('LTLIBRARIES', 0, 'lib', 'pkglib', 'noinst', 'check'); if (@prefix) { my $var = rvar ($prefix[0] . '_LTLIBRARIES'); $var->requires_variables ('Libtool library used', 'LIBTOOL'); } my %instdirs = (); my %instsubdirs = (); my %instconds = (); my %liblocations = (); # Location (in Makefile.am) of each library. foreach my $key (@prefix) { # Get the installation directory of each library. my $dir = $key; my $strip_subdir = 1; if ($dir =~ /^nobase_/) { $dir =~ s/^nobase_//; $strip_subdir = 0; } my $var = rvar ($key . '_LTLIBRARIES'); # We reject libraries which are installed in several places # in the same condition, because we can only specify one # '-rpath' option. $var->traverse_recursively (sub { my ($var, $val, $cond, $full_cond) = @_; my $hcond = $full_cond->human; my $where = $var->rdef ($cond)->location; my $ldir = ''; $ldir = '/' . dirname ($val) if (!$strip_subdir); # A library cannot be installed in different directories # in overlapping conditions. if (exists $instconds{$val}) { my ($msg, $acond) = $instconds{$val}->ambiguous_p ($val, $full_cond); if ($msg) { error ($where, $msg, partial => 1); my $dirtxt = "installed " . ($strip_subdir ? "in" : "below") . " '$dir'"; $dirtxt = "built for '$dir'" if $dir eq 'EXTRA' || $dir eq 'noinst' || $dir eq 'check'; my $dircond = $full_cond->true ? "" : " in condition $hcond"; error ($where, "'$val' should be $dirtxt$dircond ...", partial => 1); my $hacond = $acond->human; my $adir = $instdirs{$val}{$acond}; my $adirtxt = "installed in '$adir'"; $adirtxt = "built for '$adir'" if ($adir eq 'EXTRA' || $adir eq 'noinst' || $adir eq 'check'); my $adircond = $acond->true ? "" : " in condition $hacond"; my $onlyone = ($dir ne $adir) ? ("\nLibtool libraries can be built for only one " . "destination") : ""; error ($liblocations{$val}{$acond}, "... and should also be $adirtxt$adircond.$onlyone"); return; } } else { $instconds{$val} = new Automake::DisjConditions; } $instdirs{$val}{$full_cond} = $dir; $instsubdirs{$val}{$full_cond} = $ldir; $liblocations{$val}{$full_cond} = $where; $instconds{$val} = $instconds{$val}->merge ($full_cond); }, sub { return (); }, skip_ac_subst => 1); } foreach my $pair (@ltliblist) { my ($where, $onelib) = @$pair; my $seen_libobjs = 0; my $obj = '.lo'; # Canonicalize names and check for misspellings. my $xlib = check_canonical_spelling ($onelib, '_LIBADD', '_LDFLAGS', '_SOURCES', '_OBJECTS', '_DEPENDENCIES'); # Check that the library fits the standard naming convention. my $libname_rx = '^lib.*\.la'; my $ldvar = var ("${xlib}_LDFLAGS") || var ('AM_LDFLAGS'); my $ldvar2 = var ('LDFLAGS'); if (($ldvar && grep (/-module/, $ldvar->value_as_list_recursive)) || ($ldvar2 && grep (/-module/, $ldvar2->value_as_list_recursive))) { # Relax name checking for libtool modules. $libname_rx = '\.la'; } my $bn = basename ($onelib); if ($bn !~ /$libname_rx$/) { my $type = 'library'; if ($libname_rx eq '\.la') { $bn =~ s/^(lib|)(.*?)(?:\.[^.]*)?$/$1$2.la/; $type = 'module'; } else { $bn =~ s/^(?:lib)?(.*?)(?:\.[^.]*)?$/lib$1.la/; } my $suggestion = dirname ($onelib) . "/$bn"; $suggestion =~ s|^\./||g; msg ('error-gnu/warn', $where, "'$onelib' is not a standard libtool $type name\n" . "did you mean '$suggestion'?") } ($known_libraries{$onelib} = $bn) =~ s/\.la$//; $where->push_context ("while processing Libtool library '$onelib'"); $where->set (INTERNAL->get); # Make sure we look at these. set_seen ($xlib . '_LDFLAGS'); set_seen ($xlib . '_DEPENDENCIES'); set_seen ('EXTRA_' . $xlib . '_DEPENDENCIES'); # Generate support for conditional object inclusion in # libraries. if (var ($xlib . '_LIBADD')) { if (handle_lib_objects ($xlib, $xlib . '_LIBADD')) { $seen_libobjs = 1; } } else { define_variable ($xlib . "_LIBADD", '', $where); } reject_var ("${xlib}_LDADD", "use '${xlib}_LIBADD', not '${xlib}_LDADD'"); my $linker = handle_source_transform ($xlib, $onelib, $obj, $where, NONLIBTOOL => 0, LIBTOOL => 1); # Determine program to use for link. my($xlink, $vlink) = define_per_target_linker_variable ($linker, $xlib); $vlink = verbose_flag ($vlink || 'GEN'); my $rpathvar = "am_${xlib}_rpath"; my $rpath = "\$($rpathvar)"; foreach my $rcond ($instconds{$onelib}->conds) { my $val; if ($instdirs{$onelib}{$rcond} eq 'EXTRA' || $instdirs{$onelib}{$rcond} eq 'noinst' || $instdirs{$onelib}{$rcond} eq 'check') { # It's an EXTRA_ library, so we can't specify -rpath, # because we don't know where the library will end up. # The user probably knows, but generally speaking automake # doesn't -- and in fact configure could decide # dynamically between two different locations. $val = ''; } else { $val = ('-rpath $(' . $instdirs{$onelib}{$rcond} . 'dir)'); $val .= $instsubdirs{$onelib}{$rcond} if defined $instsubdirs{$onelib}{$rcond}; } if ($rcond->true) { # If $rcond is true there is only one condition and # there is no point defining an helper variable. $rpath = $val; } else { define_pretty_variable ($rpathvar, $rcond, INTERNAL, $val); } } # If the resulting library lies in a subdirectory, # make sure this directory will exist. my $dirstamp = require_build_directory_maybe ($onelib); # Remember to cleanup .libs/ in this directory. my $dirname = dirname $onelib; $libtool_clean_directories{$dirname} = 1; $output_rules .= file_contents ('ltlibrary', $where, LTLIBRARY => $onelib, XLTLIBRARY => $xlib, RPATH => $rpath, XLINK => $xlink, VERBOSE => $vlink, DIRSTAMP => $dirstamp); if ($seen_libobjs) { if (var ($xlib . '_LIBADD')) { check_libobjs_sources ($xlib, $xlib . '_LIBADD'); } } if (! $seen_ar) { msg ('extra-portability', $where, "'$onelib': linking libtool libraries using a non-POSIX\n" . "archiver requires 'AM_PROG_AR' in '$configure_ac'") } } } # See if any _SOURCES variable were misspelled. sub check_typos () { # It is ok if the user sets this particular variable. set_seen 'AM_LDFLAGS'; foreach my $primary ('SOURCES', 'LIBADD', 'LDADD', 'LDFLAGS', 'DEPENDENCIES') { foreach my $var (variables $primary) { my $varname = $var->name; # A configure variable is always legitimate. next if exists $configure_vars{$varname}; for my $cond ($var->conditions->conds) { $varname =~ /^(?:EXTRA_)?(?:nobase_)?(?:dist_|nodist_)?(.*)_[[:alnum:]]+$/; msg_var ('syntax', $var, "variable '$varname' is defined but no" . " program or\nlibrary has '$1' as canonical name" . " (possible typo)") unless $var->rdef ($cond)->seen; } } } } sub handle_scripts () { # NOTE we no longer automatically clean SCRIPTS, because it is # useful to sometimes distribute scripts verbatim. This happens # e.g. in Automake itself. am_install_var ('-candist', 'scripts', 'SCRIPTS', 'bin', 'sbin', 'libexec', 'pkglibexec', 'pkgdata', 'noinst', 'check'); } sub handle_man_pages () { reject_var 'MANS', "'MANS' is an anachronism; use 'man_MANS'"; # Find all the sections in use. We do this by first looking for # "standard" sections, and then looking for any additional # sections used in man_MANS. my (%sections, %notrans_sections, %trans_sections, %notrans_vars, %trans_vars, %notrans_sect_vars, %trans_sect_vars); # We handle nodist_ for uniformity. man pages aren't distributed # by default so it isn't actually very important. foreach my $npfx ('', 'notrans_') { foreach my $pfx ('', 'dist_', 'nodist_') { # Add more sections as needed. foreach my $section ('0'..'9', 'n', 'l') { my $varname = $npfx . $pfx . 'man' . $section . '_MANS'; if (var ($varname)) { $sections{$section} = 1; $varname = '$(' . $varname . ')'; if ($npfx eq 'notrans_') { $notrans_sections{$section} = 1; $notrans_sect_vars{$varname} = 1; } else { $trans_sections{$section} = 1; $trans_sect_vars{$varname} = 1; } push_dist_common ($varname) if $pfx eq 'dist_'; } } my $varname = $npfx . $pfx . 'man_MANS'; my $var = var ($varname); if ($var) { foreach ($var->value_as_list_recursive) { # A page like 'foo.1c' goes into man1dir. if (/\.([0-9a-z])([a-z]*)$/) { $sections{$1} = 1; if ($npfx eq 'notrans_') { $notrans_sections{$1} = 1; } else { $trans_sections{$1} = 1; } } } $varname = '$(' . $varname . ')'; if ($npfx eq 'notrans_') { $notrans_vars{$varname} = 1; } else { $trans_vars{$varname} = 1; } push_dist_common ($varname) if $pfx eq 'dist_'; } } } return unless %sections; my @unsorted_deps; # Build section independent variables. my $have_notrans = %notrans_vars; my @notrans_list = sort keys %notrans_vars; my $have_trans = %trans_vars; my @trans_list = sort keys %trans_vars; # Now for each section, generate an install and uninstall rule. # Sort sections so output is deterministic. foreach my $section (sort keys %sections) { # Build section dependent variables. my $notrans_mans = $have_notrans || exists $notrans_sections{$section}; my $trans_mans = $have_trans || exists $trans_sections{$section}; my (%notrans_this_sect, %trans_this_sect); my $expr = 'man' . $section . '_MANS'; foreach my $varname (keys %notrans_sect_vars) { if ($varname =~ /$expr/) { $notrans_this_sect{$varname} = 1; } } foreach my $varname (keys %trans_sect_vars) { if ($varname =~ /$expr/) { $trans_this_sect{$varname} = 1; } } my @notrans_sect_list = sort keys %notrans_this_sect; my @trans_sect_list = sort keys %trans_this_sect; @unsorted_deps = (keys %notrans_vars, keys %trans_vars, keys %notrans_this_sect, keys %trans_this_sect); my @deps = sort @unsorted_deps; $output_rules .= file_contents ('mans', new Automake::Location, SECTION => $section, DEPS => "@deps", NOTRANS_MANS => $notrans_mans, NOTRANS_SECT_LIST => "@notrans_sect_list", HAVE_NOTRANS => $have_notrans, NOTRANS_LIST => "@notrans_list", TRANS_MANS => $trans_mans, TRANS_SECT_LIST => "@trans_sect_list", HAVE_TRANS => $have_trans, TRANS_LIST => "@trans_list"); } @unsorted_deps = (keys %notrans_vars, keys %trans_vars, keys %notrans_sect_vars, keys %trans_sect_vars); my @mans = sort @unsorted_deps; $output_vars .= file_contents ('mans-vars', new Automake::Location, MANS => "@mans"); push (@all, '$(MANS)') unless option 'no-installman'; } sub handle_data () { am_install_var ('-noextra', '-candist', 'data', 'DATA', 'data', 'dataroot', 'doc', 'dvi', 'html', 'pdf', 'ps', 'sysconf', 'sharedstate', 'localstate', 'pkgdata', 'lisp', 'noinst', 'check'); } sub handle_tags () { my @config; foreach my $spec (@config_headers) { my ($out, @ins) = split_config_file_spec ($spec); foreach my $in (@ins) { # If the config header source is in this directory, # require it. push @config, basename ($in) if $relative_dir eq dirname ($in); } } define_variable ('am__tagged_files', '$(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)' . "@config", INTERNAL); if (rvar('am__tagged_files')->value_as_list_recursive || var ('ETAGS_ARGS') || var ('SUBDIRS')) { $output_rules .= file_contents ('tags', new Automake::Location); set_seen 'TAGS_DEPENDENCIES'; } else { reject_var ('TAGS_DEPENDENCIES', "it doesn't make sense to define 'TAGS_DEPENDENCIES'" . " without\nsources or 'ETAGS_ARGS'"); # Every Makefile must define some sort of TAGS rule. # Otherwise, it would be possible for a top-level "make TAGS" # to fail because some subdirectory failed. Ditto ctags and # cscope. $output_rules .= "tags TAGS:\n\n" . "ctags CTAGS:\n\n" . "cscope cscopelist:\n\n"; } } # user_phony_rule ($NAME) # ----------------------- # Return false if rule $NAME does not exist. Otherwise, # declare it as phony, complete its definition (in case it is # conditional), and return its Automake::Rule instance. sub user_phony_rule { my ($name) = @_; my $rule = rule $name; if ($rule) { depend ('.PHONY', $name); # Define $NAME in all condition where it is not already defined, # so that it is always OK to depend on $NAME. for my $c ($rule->not_always_defined_in_cond (TRUE)->conds) { Automake::Rule::define ($name, 'internal', RULE_AUTOMAKE, $c, INTERNAL); $output_rules .= $c->subst_string . "$name:\n"; } } return $rule; } # Handle 'dist' target. sub handle_dist () { # Substitutions for distdir.am my %transform; # Define DIST_SUBDIRS. This must always be done, regardless of the # no-dist setting: target like 'distclean' or 'maintainer-clean' use it. my $subdirs = var ('SUBDIRS'); if ($subdirs) { # If SUBDIRS is conditionally defined, then set DIST_SUBDIRS # to all possible directories, and use it. If DIST_SUBDIRS is # defined, just use it. # Note that we check DIST_SUBDIRS first on purpose, so that # we don't call has_conditional_contents for now reason. # (In the past one project used so many conditional subdirectories # that calling has_conditional_contents on SUBDIRS caused # automake to grow to 150Mb -- this should not happen with # the current implementation of has_conditional_contents, # but it's more efficient to avoid the call anyway.) if (var ('DIST_SUBDIRS')) { } elsif ($subdirs->has_conditional_contents) { define_pretty_variable ('DIST_SUBDIRS', TRUE, INTERNAL, uniq ($subdirs->value_as_list_recursive)); } else { # We always define this because that is what 'distclean' # wants. define_pretty_variable ('DIST_SUBDIRS', TRUE, INTERNAL, '$(SUBDIRS)'); } } # The remaining definitions are only required when a dist target is used. return if option 'no-dist'; # At least one of the archive formats must be enabled. if ($relative_dir eq '.') { my $archive_defined = option 'no-dist-gzip' ? 0 : 1; $archive_defined ||= grep { option "dist-$_" } qw(shar zip tarZ bzip2 lzip xz); error (option 'no-dist-gzip', "no-dist-gzip specified but no dist-* specified,\n" . "at least one archive format must be enabled") unless $archive_defined; } # Look for common files that should be included in distribution. # If the aux dir is set, and it does not have a Makefile.am, then # we check for these files there as well. my $check_aux = 0; if ($relative_dir eq '.' && $config_aux_dir_set_in_configure_ac) { if (! is_make_dir ($config_aux_dir)) { $check_aux = 1; } } foreach my $cfile (@common_files) { if (dir_has_case_matching_file ($relative_dir, $cfile) # The file might be absent, but if it can be built it's ok. || rule $cfile) { push_dist_common ($cfile); } # Don't use 'elsif' here because a file might meaningfully # appear in both directories. if ($check_aux && dir_has_case_matching_file ($config_aux_dir, $cfile)) { push_dist_common ("$config_aux_dir/$cfile") } } # We might copy elements from @configure_dist_common to # @dist_common if we think we need to. If the file appears in our # directory, we would have discovered it already, so we don't # check that. But if the file is in a subdir without a Makefile, # we want to distribute it here if we are doing '.'. Ugly! # Also, in some corner cases, it's possible that the following code # will cause the same file to appear in the $(DIST_COMMON) variables # of two distinct Makefiles; but this is not a problem, since the # 'distdir' target in 'lib/am/distdir.am' can deal with the same # file being distributed multiple times. # See also automake bug#9651. if ($relative_dir eq '.') { foreach my $file (@configure_dist_common) { my $dir = dirname ($file); push_dist_common ($file) if ($dir eq '.' || ! is_make_dir ($dir)); } @configure_dist_common = (); } # $(am__DIST_COMMON): files to be distributed automatically. Will be # appended to $(DIST_COMMON) in the generated Makefile. # Use 'sort' so that the expansion of $(DIST_COMMON) in the generated # Makefile is deterministic, in face of m4 and/or perl randomizations # (see automake bug#17908). define_pretty_variable ('am__DIST_COMMON', TRUE, INTERNAL, uniq (sort @dist_common)); # Now that we've processed @dist_common, disallow further attempts # to modify it. $handle_dist_run = 1; $transform{'DISTCHECK-HOOK'} = !! rule 'distcheck-hook'; $transform{'GETTEXT'} = $seen_gettext && !$seen_gettext_external; # If the target 'dist-hook' exists, make sure it is run. This # allows users to do random weird things to the distribution # before it is packaged up. push (@dist_targets, 'dist-hook') if user_phony_rule 'dist-hook'; $transform{'DIST-TARGETS'} = join (' ', @dist_targets); my $flm = option ('filename-length-max'); my $filename_filter = $flm ? '.' x $flm->[1] : ''; $output_rules .= file_contents ('distdir', new Automake::Location, %transform, FILENAME_FILTER => $filename_filter); } # check_directories_in_var ($VARIABLE) # ------------------------------------ # Recursively check all items in variables $VARIABLE as directories sub check_directories_in_var { my ($var) = @_; $var->traverse_recursively (sub { my ($var, $val, $cond, $full_cond) = @_; check_directory ($val, $var->rdef ($cond)->location, $relative_dir); return (); }, undef, skip_ac_subst => 1); } sub handle_subdirs () { my $subdirs = var ('SUBDIRS'); return unless $subdirs; check_directories_in_var $subdirs; my $dsubdirs = var ('DIST_SUBDIRS'); check_directories_in_var $dsubdirs if $dsubdirs; $output_rules .= file_contents ('subdirs', new Automake::Location); rvar ('RECURSIVE_TARGETS')->rdef (TRUE)->{'pretty'} = VAR_SORTED; # Gross! } sub handle_headers () { my @r = am_install_var ('-defaultdist', 'header', 'HEADERS', 'include', 'oldinclude', 'pkginclude', 'noinst', 'check'); foreach (@r) { next unless $_->[1] =~ /\..*$/; saw_extension ($&); } } sub handle_gettext () { return if ! $seen_gettext || $relative_dir ne '.'; my $subdirs = var 'SUBDIRS'; if (! $subdirs) { err_ac "AM_GNU_GETTEXT used but SUBDIRS not defined"; return; } # Perform some sanity checks to help users get the right setup. # We disable these tests when po/ doesn't exist in order not to disallow # unusual gettext setups. # # Bruno Haible: # | The idea is: # | # | 1) If a package doesn't have a directory po/ at top level, it # | will likely have multiple po/ directories in subpackages. # | # | 2) It is useful to warn for the absence of intl/ if AM_GNU_GETTEXT # | is used without 'external'. It is also useful to warn for the # | presence of intl/ if AM_GNU_GETTEXT([external]) is used. Both # | warnings apply only to the usual layout of packages, therefore # | they should both be disabled if no po/ directory is found at # | top level. if (-d 'po') { my @subdirs = $subdirs->value_as_list_recursive; msg_var ('syntax', $subdirs, "AM_GNU_GETTEXT used but 'po' not in SUBDIRS") if ! grep ($_ eq 'po', @subdirs); # intl/ is not required when AM_GNU_GETTEXT is called with the # 'external' option and AM_GNU_GETTEXT_INTL_SUBDIR is not called. msg_var ('syntax', $subdirs, "AM_GNU_GETTEXT used but 'intl' not in SUBDIRS") if (! ($seen_gettext_external && ! $seen_gettext_intl) && ! grep ($_ eq 'intl', @subdirs)); # intl/ should not be used with AM_GNU_GETTEXT([external]), except # if AM_GNU_GETTEXT_INTL_SUBDIR is called. msg_var ('syntax', $subdirs, "'intl' should not be in SUBDIRS when " . "AM_GNU_GETTEXT([external]) is used") if ($seen_gettext_external && ! $seen_gettext_intl && grep ($_ eq 'intl', @subdirs)); } require_file ($ac_gettext_location, GNU, 'ABOUT-NLS'); } # Emit makefile footer. sub handle_footer () { reject_rule ('.SUFFIXES', "use variable 'SUFFIXES', not target '.SUFFIXES'"); # Note: AIX 4.1 /bin/make will fail if any suffix rule appears # before .SUFFIXES. So we make sure that .SUFFIXES appears before # anything else, by sticking it right after the default: target. $output_header .= ".SUFFIXES:\n"; my $suffixes = var 'SUFFIXES'; my @suffixes = Automake::Rule::suffixes; if (@suffixes || $suffixes) { # Make sure SUFFIXES has unique elements. Sort them to ensure # the output remains consistent. However, $(SUFFIXES) is # always at the start of the list, unsorted. This is done # because make will choose rules depending on the ordering of # suffixes, and this lets the user have some control. Push # actual suffixes, and not $(SUFFIXES). Some versions of make # do not like variable substitutions on the .SUFFIXES line. my @user_suffixes = ($suffixes ? $suffixes->value_as_list_recursive : ()); my %suffixes = map { $_ => 1 } @suffixes; delete @suffixes{@user_suffixes}; $output_header .= (".SUFFIXES: " . join (' ', @user_suffixes, sort keys %suffixes) . "\n"); } $output_trailer .= file_contents ('footer', new Automake::Location); } # Generate 'make install' rules. sub handle_install () { $output_rules .= file_contents ('install', new Automake::Location, maybe_BUILT_SOURCES => (set_seen ('BUILT_SOURCES') ? (" \$(BUILT_SOURCES)\n" . "\t\$(MAKE) \$(AM_MAKEFLAGS)") : ''), 'installdirs-local' => (user_phony_rule ('installdirs-local') ? ' installdirs-local' : ''), am__installdirs => variable_value ('am__installdirs') || ''); } # handle_all ($MAKEFILE) #----------------------- # Deal with 'all' and 'all-am'. sub handle_all { my ($makefile) = @_; # Output 'all-am'. # Put this at the beginning for the sake of non-GNU makes. This # is still wrong if these makes can run parallel jobs. But it is # right enough. unshift (@all, basename ($makefile)); foreach my $spec (@config_headers) { my ($out, @ins) = split_config_file_spec ($spec); push (@all, basename ($out)) if dirname ($out) eq $relative_dir; } # Install 'all' hooks. push (@all, "all-local") if user_phony_rule "all-local"; pretty_print_rule ("all-am:", "\t\t", @all); depend ('.PHONY', 'all-am', 'all'); # Output 'all'. my @local_headers = (); push @local_headers, '$(BUILT_SOURCES)' if var ('BUILT_SOURCES'); foreach my $spec (@config_headers) { my ($out, @ins) = split_config_file_spec ($spec); push @local_headers, basename ($out) if dirname ($out) eq $relative_dir; } if (@local_headers) { # We need to make sure config.h is built before we recurse. # We also want to make sure that built sources are built # before any ordinary 'all' targets are run. We can't do this # by changing the order of dependencies to the "all" because # that breaks when using parallel makes. Instead we handle # things explicitly. $output_all .= ("all: @local_headers" . "\n\t" . '$(MAKE) $(AM_MAKEFLAGS) ' . (var ('SUBDIRS') ? 'all-recursive' : 'all-am') . "\n\n"); depend ('.MAKE', 'all'); } else { $output_all .= "all: " . (var ('SUBDIRS') ? 'all-recursive' : 'all-am') . "\n\n"; } } # Generate helper targets for user-defined recursive targets, where needed. sub handle_user_recursion () { return unless @extra_recursive_targets; define_pretty_variable ('am__extra_recursive_targets', TRUE, INTERNAL, map { "$_-recursive" } @extra_recursive_targets); my $aux = var ('SUBDIRS') ? 'recursive' : 'am'; foreach my $target (@extra_recursive_targets) { # This allows the default target's rules to be overridden in # Makefile.am. user_phony_rule ($target); depend ("$target", "$target-$aux"); depend ("$target-am", "$target-local"); # Every user-defined recursive target 'foo' *must* have a valid # associated 'foo-local' rule; we define it as an empty rule by # default, so that the user can transparently extend it in his # own Makefile.am. pretty_print_rule ("$target-local:", '', ''); # $target-recursive might as well be undefined, so do not add # it here; it's taken care of in subdirs.am anyway. depend (".PHONY", "$target-am", "$target-local"); } } # Handle check merge target specially. sub do_check_merge_target () { # Include user-defined local form of target. push @check_tests, 'check-local' if user_phony_rule 'check-local'; # The check target must depend on the local equivalent of # 'all', to ensure all the primary targets are built. Then it # must build the local check rules. $output_rules .= "check-am: all-am\n"; if (@check) { pretty_print_rule ("\t\$(MAKE) \$(AM_MAKEFLAGS)", "\t ", @check); depend ('.MAKE', 'check-am'); } if (@check_tests) { pretty_print_rule ("\t\$(MAKE) \$(AM_MAKEFLAGS)", "\t ", @check_tests); depend ('.MAKE', 'check-am'); } depend '.PHONY', 'check', 'check-am'; # Handle recursion. We have to honor BUILT_SOURCES like for 'all:'. $output_rules .= ("check: " . (var ('BUILT_SOURCES') ? "\$(BUILT_SOURCES)\n\t\$(MAKE) \$(AM_MAKEFLAGS) " : '') . (var ('SUBDIRS') ? 'check-recursive' : 'check-am') . "\n"); depend ('.MAKE', 'check') if var ('BUILT_SOURCES'); } # Handle all 'clean' targets. sub handle_clean { my ($makefile) = @_; # Clean the files listed in user variables if they exist. $clean_files{'$(MOSTLYCLEANFILES)'} = MOSTLY_CLEAN if var ('MOSTLYCLEANFILES'); $clean_files{'$(CLEANFILES)'} = CLEAN if var ('CLEANFILES'); $clean_files{'$(DISTCLEANFILES)'} = DIST_CLEAN if var ('DISTCLEANFILES'); $clean_files{'$(MAINTAINERCLEANFILES)'} = MAINTAINER_CLEAN if var ('MAINTAINERCLEANFILES'); # Built sources are automatically removed by maintainer-clean. $clean_files{'$(BUILT_SOURCES)'} = MAINTAINER_CLEAN if var ('BUILT_SOURCES'); # Compute a list of "rm"s to run for each target. my %rms = (MOSTLY_CLEAN, [], CLEAN, [], DIST_CLEAN, [], MAINTAINER_CLEAN, []); foreach my $file (keys %clean_files) { my $when = $clean_files{$file}; prog_error 'invalid entry in %clean_files' unless exists $rms{$when}; my $rm = "rm -f $file"; # If file is a variable, make sure when don't call 'rm -f' without args. $rm ="test -z \"$file\" || $rm" if ($file =~ /^\s*\$(\(.*\)|\{.*\})\s*$/); push @{$rms{$when}}, "\t-$rm\n"; } $output_rules .= file_contents ('clean', new Automake::Location, MOSTLYCLEAN_RMS => join ('', sort @{$rms{&MOSTLY_CLEAN}}), CLEAN_RMS => join ('', sort @{$rms{&CLEAN}}), DISTCLEAN_RMS => join ('', sort @{$rms{&DIST_CLEAN}}), MAINTAINER_CLEAN_RMS => join ('', sort @{$rms{&MAINTAINER_CLEAN}}), MAKEFILE => basename $makefile, ); } # Subroutine for handle_factored_dependencies() to let '.PHONY' and # other '.TARGETS' be last. This is meant to be used as a comparison # subroutine passed to the sort built-int. sub target_cmp { return 0 if $a eq $b; my $a1 = substr ($a, 0, 1); my $b1 = substr ($b, 0, 1); if ($a1 ne $b1) { return -1 if $b1 eq '.'; return 1 if $a1 eq '.'; } return $a cmp $b; } # Handle everything related to gathered targets. sub handle_factored_dependencies () { # Reject bad hooks. foreach my $utarg ('uninstall-data-local', 'uninstall-data-hook', 'uninstall-exec-local', 'uninstall-exec-hook', 'uninstall-dvi-local', 'uninstall-html-local', 'uninstall-info-local', 'uninstall-pdf-local', 'uninstall-ps-local') { my $x = $utarg; $x =~ s/-.*-/-/; reject_rule ($utarg, "use '$x', not '$utarg'"); } reject_rule ('install-local', "use 'install-data-local' or 'install-exec-local', " . "not 'install-local'"); reject_rule ('install-hook', "use 'install-data-hook' or 'install-exec-hook', " . "not 'install-hook'"); # Install the -local hooks. foreach (keys %dependencies) { # Hooks are installed on the -am targets. s/-am$// or next; depend ("$_-am", "$_-local") if user_phony_rule "$_-local"; } # Install the -hook hooks. # FIXME: Why not be as liberal as we are with -local hooks? foreach ('install-exec', 'install-data', 'uninstall') { if (user_phony_rule "$_-hook") { depend ('.MAKE', "$_-am"); register_action("$_-am", ("\t\@\$(NORMAL_INSTALL)\n" . "\t\$(MAKE) \$(AM_MAKEFLAGS) $_-hook")); } } # All the required targets are phony. depend ('.PHONY', keys %required_targets); # Actually output gathered targets. foreach (sort target_cmp keys %dependencies) { # If there is nothing about this guy, skip it. next unless (@{$dependencies{$_}} || $actions{$_} || $required_targets{$_}); # Define gathered targets in undefined conditions. # FIXME: Right now we must handle .PHONY as an exception, # because people write things like # .PHONY: myphonytarget # to append dependencies. This would not work if Automake # refrained from defining its own .PHONY target as it does # with other overridden targets. # Likewise for '.MAKE' and '.PRECIOUS'. my @undefined_conds = (TRUE,); if ($_ ne '.PHONY' && $_ ne '.MAKE' && $_ ne '.PRECIOUS') { @undefined_conds = Automake::Rule::define ($_, 'internal', RULE_AUTOMAKE, TRUE, INTERNAL); } my @uniq_deps = uniq (sort @{$dependencies{$_}}); foreach my $cond (@undefined_conds) { my $condstr = $cond->subst_string; pretty_print_rule ("$condstr$_:", "$condstr\t", @uniq_deps); $output_rules .= $actions{$_} if defined $actions{$_}; $output_rules .= "\n"; } } } sub handle_tests_dejagnu () { push (@check_tests, 'check-DEJAGNU'); $output_rules .= file_contents ('dejagnu', new Automake::Location); } # handle_per_suffix_test ($TEST_SUFFIX, [%TRANSFORM]) #---------------------------------------------------- sub handle_per_suffix_test { my ($test_suffix, %transform) = @_; my ($pfx, $generic, $am_exeext); if ($test_suffix eq '') { $pfx = ''; $generic = 0; $am_exeext = 'FALSE'; } else { prog_error ("test suffix '$test_suffix' lacks leading dot") unless $test_suffix =~ m/^\.(.*)/; $pfx = uc ($1) . '_'; $generic = 1; $am_exeext = exists $configure_vars{'EXEEXT'} ? 'am__EXEEXT' : 'FALSE'; } # The "test driver" program, deputed to handle tests protocol used by # test scripts. By default, it's assumed that no protocol is used, so # we fall back to the old behaviour, implemented by the 'test-driver' # auxiliary script. if (! var "${pfx}LOG_DRIVER") { require_conf_file ("parallel-tests", FOREIGN, 'test-driver'); define_variable ("${pfx}LOG_DRIVER", "\$(SHELL) $am_config_aux_dir/test-driver", INTERNAL); } my $driver = '$(' . $pfx . 'LOG_DRIVER)'; my $driver_flags = '$(AM_' . $pfx . 'LOG_DRIVER_FLAGS)' . ' $(' . $pfx . 'LOG_DRIVER_FLAGS)'; my $compile = "${pfx}LOG_COMPILE"; define_variable ($compile, '$(' . $pfx . 'LOG_COMPILER)' . ' $(AM_' . $pfx . 'LOG_FLAGS)' . ' $(' . $pfx . 'LOG_FLAGS)', INTERNAL); $output_rules .= file_contents ('check2', new Automake::Location, GENERIC => $generic, DRIVER => $driver, DRIVER_FLAGS => $driver_flags, COMPILE => '$(' . $compile . ')', EXT => $test_suffix, am__EXEEXT => $am_exeext, %transform); } # is_valid_test_extension ($EXT) # ------------------------------ # Return true if $EXT can appear in $(TEST_EXTENSIONS), return false # otherwise. sub is_valid_test_extension { my $ext = shift; return 1 if ($ext =~ /^\.[a-zA-Z_][a-zA-Z0-9_]*$/); return 1 if (exists $configure_vars{'EXEEXT'} && $ext eq subst ('EXEEXT')); return 0; } sub handle_tests () { if (option 'dejagnu') { handle_tests_dejagnu; } else { foreach my $c ('DEJATOOL', 'RUNTEST', 'RUNTESTFLAGS') { reject_var ($c, "'$c' defined but 'dejagnu' not in " . "'AUTOMAKE_OPTIONS'"); } } if (var ('TESTS')) { push (@check_tests, 'check-TESTS'); my $check_deps = "@check"; $output_rules .= file_contents ('check', new Automake::Location, SERIAL_TESTS => !! option 'serial-tests', CHECK_DEPS => $check_deps); # Tests that are known programs should have $(EXEEXT) appended. # For matching purposes, we need to adjust XFAIL_TESTS as well. append_exeext { exists $known_programs{$_[0]} } 'TESTS'; append_exeext { exists $known_programs{$_[0]} } 'XFAIL_TESTS' if (var ('XFAIL_TESTS')); if (! option 'serial-tests') { define_variable ('TEST_SUITE_LOG', 'test-suite.log', INTERNAL); my $suff = '.test'; my $at_exeext = ''; my $handle_exeext = exists $configure_vars{'EXEEXT'}; if ($handle_exeext) { $at_exeext = subst ('EXEEXT'); $suff = $at_exeext . ' ' . $suff; } if (! var 'TEST_EXTENSIONS') { define_variable ('TEST_EXTENSIONS', $suff, INTERNAL); } my $var = var 'TEST_EXTENSIONS'; # Currently, we are not able to deal with conditional contents # in TEST_EXTENSIONS. if ($var->has_conditional_contents) { msg_var 'unsupported', $var, "'TEST_EXTENSIONS' cannot have conditional contents"; } my @test_suffixes = $var->value_as_list_recursive; if ((my @invalid_test_suffixes = grep { !is_valid_test_extension $_ } @test_suffixes) > 0) { error $var->rdef (TRUE)->location, "invalid test extensions: @invalid_test_suffixes"; } @test_suffixes = grep { is_valid_test_extension $_ } @test_suffixes; if ($handle_exeext) { unshift (@test_suffixes, $at_exeext) unless $test_suffixes[0] eq $at_exeext; } unshift (@test_suffixes, ''); transform_variable_recursively ('TESTS', 'TEST_LOGS', 'am__testlogs', 1, INTERNAL, sub { my ($subvar, $val, $cond, $full_cond) = @_; my $obj = $val; return $obj if $val =~ /^\@.*\@$/; $obj =~ s/\$\(EXEEXT\)$//o; if ($val =~ /(\$\((top_)?srcdir\))\//o) { msg ('error', $subvar->rdef ($cond)->location, "using '$1' in TESTS is currently broken: '$val'"); } foreach my $test_suffix (@test_suffixes) { next if $test_suffix eq $at_exeext || $test_suffix eq ''; return substr ($obj, 0, length ($obj) - length ($test_suffix)) . '.log' if substr ($obj, - length ($test_suffix)) eq $test_suffix; } my $base = $obj; $obj .= '.log'; handle_per_suffix_test ('', OBJ => $obj, BASE => $base, SOURCE => $val); return $obj; }); my $nhelper=1; my $prev = 'TESTS'; my $post = ''; my $last_suffix = $test_suffixes[$#test_suffixes]; my $cur = ''; foreach my $test_suffix (@test_suffixes) { if ($test_suffix eq $last_suffix) { $cur = 'TEST_LOGS'; } else { $cur = 'am__test_logs' . $nhelper; } define_variable ($cur, '$(' . $prev . ':' . $test_suffix . $post . '=.log)', INTERNAL); $post = '.log'; $prev = $cur; $nhelper++; if ($test_suffix ne $at_exeext && $test_suffix ne '') { handle_per_suffix_test ($test_suffix, OBJ => '', BASE => '$*', SOURCE => '$<'); } } $clean_files{'$(TEST_LOGS)'} = MOSTLY_CLEAN; $clean_files{'$(TEST_LOGS:.log=.trs)'} = MOSTLY_CLEAN; $clean_files{'$(TEST_SUITE_LOG)'} = MOSTLY_CLEAN; } } } sub handle_minor_options () { if (option 'readme-alpha') { if ($relative_dir eq '.') { if ($package_version !~ /^$GNITS_VERSION_PATTERN$/) { msg ('error-gnits', $package_version_location, "version '$package_version' doesn't follow " . "Gnits standards"); } if (defined $1 && -f 'README-alpha') { # This means we have an alpha release. See # GNITS_VERSION_PATTERN for details. push_dist_common ('README-alpha'); } } } } ################################################################ ## ------------------------ ## ## Handling the variables. ## ## ------------------------ ## # TODO: Look for a better file for `define_verbose_libtool' to move these to # Automake::Variable # define_compiler_variable ($LANG) # -------------------------------- # Define a compiler variable. We also handle defining the 'LT' # version of the command when using libtool. sub define_compiler_variable { my ($lang) = @_; my ($var, $value) = ($lang->compiler, $lang->compile); my $libtool_tag = ''; $libtool_tag = '--tag=' . $lang->libtool_tag . ' ' if $lang->libtool_tag && exists $libtool_tags{$lang->libtool_tag}; define_variable ($var, $value, INTERNAL); if (var ('LIBTOOL')) { my $verbose = define_verbose_libtool (); define_variable ("LT$var", "\$(LIBTOOL) $verbose $libtool_tag\$(AM_LIBTOOLFLAGS)" . " \$(LIBTOOLFLAGS) --mode=compile $value", INTERNAL); } define_verbose_tagvar ($lang->ccer || 'GEN'); } sub define_linker_variable { my ($lang) = @_; my $libtool_tag = ''; $libtool_tag = '--tag=' . $lang->libtool_tag . ' ' if $lang->libtool_tag && exists $libtool_tags{$lang->libtool_tag}; # CCLD = $(CC). define_variable ($lang->lder, $lang->ld, INTERNAL); # CCLINK = $(CCLD) blah blah... my $link = ''; if (var ('LIBTOOL')) { my $verbose = define_verbose_libtool (); $link = "\$(LIBTOOL) $verbose $libtool_tag\$(AM_LIBTOOLFLAGS) " . "\$(LIBTOOLFLAGS) --mode=link "; } define_variable ($lang->linker, $link . $lang->link, INTERNAL); define_variable ($lang->compiler, $lang, INTERNAL); define_verbose_tagvar ($lang->lder || 'GEN'); } sub define_per_target_linker_variable { my ($linker, $target) = @_; # If the user wrote a custom link command, we don't define ours. return "${target}_LINK" if set_seen "${target}_LINK"; my $xlink = $linker ? $linker : 'LINK'; my $lang = $link_languages{$xlink}; prog_error "Unknown language for linker variable '$xlink'" unless $lang; my $link_command = $lang->link; if (var 'LIBTOOL') { my $libtool_tag = ''; $libtool_tag = '--tag=' . $lang->libtool_tag . ' ' if $lang->libtool_tag && exists $libtool_tags{$lang->libtool_tag}; my $verbose = define_verbose_libtool (); $link_command = "\$(LIBTOOL) $verbose $libtool_tag\$(AM_LIBTOOLFLAGS) \$(LIBTOOLFLAGS) " . "--mode=link " . $link_command; } # Rewrite each occurrence of 'AM_$flag' in the link # command into '${derived}_$flag' if it exists. my $orig_command = $link_command; my @flags = (@{$lang->flags}, 'LDFLAGS'); push @flags, 'LIBTOOLFLAGS' if var 'LIBTOOL'; for my $flag (@flags) { my $val = "${target}_$flag"; $link_command =~ s/\(AM_$flag\)/\($val\)/ if set_seen ($val); } # If the computed command is the same as the generic command, use # the command linker variable. return ($lang->linker, $lang->lder) if $link_command eq $orig_command; define_variable ("${target}_LINK", $link_command, INTERNAL); return ("${target}_LINK", $lang->lder); } ################################################################ # check_trailing_slash ($WHERE, $LINE) # ------------------------------------ # Return 1 iff $LINE ends with a slash. # Might modify $LINE. sub check_trailing_slash ($\$) { my ($where, $line) = @_; # Ignore '##' lines. return 0 if $$line =~ /$IGNORE_PATTERN/o; # Catch and fix a common error. msg "syntax", $where, "whitespace following trailing backslash" if $$line =~ s/\\\s+\n$/\\\n/; return $$line =~ /\\$/; } # read_am_file ($AMFILE, $WHERE, $RELDIR) # --------------------------------------- # Read $AMFILE file name which is located in $RELDIR, and set up # global variables resetted by '&generate_makefile'. Simultaneously # copy lines from $AMFILE into '$output_trailer', or define variables # as appropriate. # # NOTE: We put rules in the trailer section. We want user rules to # come after our generated stuff. sub read_am_file { my ($amfile, $where, $reldir) = @_; my $canon_reldir = &canonicalize ($reldir); my $am_file = new Automake::XFile ("< $amfile"); verb "reading $amfile"; # Keep track of the youngest output dependency. my $mtime = mtime $amfile; $output_deps_greatest_timestamp = $mtime if $mtime > $output_deps_greatest_timestamp; my $spacing = ''; my $comment = ''; my $blank = 0; my $saw_bk = 0; my $var_look = VAR_ASIS; use constant IN_VAR_DEF => 0; use constant IN_RULE_DEF => 1; use constant IN_COMMENT => 2; my $prev_state = IN_RULE_DEF; while ($_ = $am_file->getline) { $where->set ("$amfile:$."); if (/$IGNORE_PATTERN/o) { # Merely delete comments beginning with two hashes. } elsif (/$WHITE_PATTERN/o) { error $where, "blank line following trailing backslash" if $saw_bk; # Stick a single white line before the incoming macro or rule. $spacing = "\n"; $blank = 1; # Flush all comments seen so far. if ($comment ne '') { $output_vars .= $comment; $comment = ''; } } elsif (/$COMMENT_PATTERN/o) { # Stick comments before the incoming macro or rule. Make # sure a blank line precedes the first block of comments. $spacing = "\n" unless $blank; $blank = 1; $comment .= $spacing . $_; $spacing = ''; $prev_state = IN_COMMENT; } else { last; } $saw_bk = check_trailing_slash ($where, $_); } # We save the conditional stack on entry, and then check to make # sure it is the same on exit. This lets us conditionally include # other files. my @saved_cond_stack = @cond_stack; my $cond = new Automake::Condition (@cond_stack); my $last_var_name = ''; my $last_var_type = ''; my $last_var_value = ''; my $last_where; # FIXME: shouldn't use $_ in this loop; it is too big. while ($_) { $where->set ("$amfile:$."); # Make sure the line is \n-terminated. chomp; $_ .= "\n"; # Don't look at MAINTAINER_MODE_TRUE here. That shouldn't be # used by users. @MAINT@ is an anachronism now. $_ =~ s/\@MAINT\@//g unless $seen_maint_mode; my $new_saw_bk = check_trailing_slash ($where, $_); if ($reldir eq '.') { # If present, eat the following '_' or '/', converting # "%reldir%/foo" and "%canon_reldir%_foo" into plain "foo" # when $reldir is '.'. $_ =~ s,%(D|reldir)%/,,g; $_ =~ s,%(C|canon_reldir)%_,,g; } $_ =~ s/%(D|reldir)%/${reldir}/g; $_ =~ s/%(C|canon_reldir)%/${canon_reldir}/g; if (/$IGNORE_PATTERN/o) { # Merely delete comments beginning with two hashes. # Keep any backslash from the previous line. $new_saw_bk = $saw_bk; } elsif (/$WHITE_PATTERN/o) { # Stick a single white line before the incoming macro or rule. $spacing = "\n"; error $where, "blank line following trailing backslash" if $saw_bk; } elsif (/$COMMENT_PATTERN/o) { error $where, "comment following trailing backslash" if $saw_bk && $prev_state != IN_COMMENT; # Stick comments before the incoming macro or rule. $comment .= $spacing . $_; $spacing = ''; $prev_state = IN_COMMENT; } elsif ($saw_bk) { if ($prev_state == IN_RULE_DEF) { my $cond = new Automake::Condition @cond_stack; $output_trailer .= $cond->subst_string; $output_trailer .= $_; } elsif ($prev_state == IN_COMMENT) { # If the line doesn't start with a '#', add it. # We do this because a continued comment like # # A = foo \ # bar \ # baz # is not portable. BSD make doesn't honor # escaped newlines in comments. s/^#?/#/; $comment .= $spacing . $_; } else # $prev_state == IN_VAR_DEF { $last_var_value .= ' ' unless $last_var_value =~ /\s$/; $last_var_value .= $_; if (!/\\$/) { Automake::Variable::define ($last_var_name, VAR_MAKEFILE, $last_var_type, $cond, $last_var_value, $comment, $last_where, VAR_ASIS) if $cond != FALSE; $comment = $spacing = ''; } } } elsif (/$IF_PATTERN/o) { $cond = cond_stack_if ($1, $2, $where); } elsif (/$ELSE_PATTERN/o) { $cond = cond_stack_else ($1, $2, $where); } elsif (/$ENDIF_PATTERN/o) { $cond = cond_stack_endif ($1, $2, $where); } elsif (/$RULE_PATTERN/o) { # Found a rule. $prev_state = IN_RULE_DEF; # For now we have to output all definitions of user rules # and can't diagnose duplicates (see the comment in # Automake::Rule::define). So we go on and ignore the return value. Automake::Rule::define ($1, $amfile, RULE_USER, $cond, $where); check_variable_expansions ($_, $where); $output_trailer .= $comment . $spacing; my $cond = new Automake::Condition @cond_stack; $output_trailer .= $cond->subst_string; $output_trailer .= $_; $comment = $spacing = ''; } elsif (/$ASSIGNMENT_PATTERN/o) { # Found a macro definition. $prev_state = IN_VAR_DEF; $last_var_name = $1; $last_var_type = $2; $last_var_value = $3; $last_where = $where->clone; if ($3 ne '' && substr ($3, -1) eq "\\") { # We preserve the '\' because otherwise the long lines # that are generated will be truncated by broken # 'sed's. $last_var_value = $3 . "\n"; } # Normally we try to output variable definitions in the # same format they were input. However, POSIX compliant # systems are not required to support lines longer than # 2048 bytes (most notably, some sed implementation are # limited to 4000 bytes, and sed is used by config.status # to rewrite Makefile.in into Makefile). Moreover nobody # would really write such long lines by hand since it is # hardly maintainable. So if a line is longer that 1000 # bytes (an arbitrary limit), assume it has been # automatically generated by some tools, and flatten the # variable definition. Otherwise, keep the variable as it # as been input. $var_look = VAR_PRETTY if length ($last_var_value) >= 1000; if (!/\\$/) { Automake::Variable::define ($last_var_name, VAR_MAKEFILE, $last_var_type, $cond, $last_var_value, $comment, $last_where, $var_look) if $cond != FALSE; $comment = $spacing = ''; $var_look = VAR_ASIS; } } elsif (/$INCLUDE_PATTERN/o) { my $path = $1; if ($path =~ s/^\$\(top_srcdir\)\///) { push (@include_stack, "\$\(top_srcdir\)/$path"); # Distribute any included file. # Always use the $(top_srcdir) prefix in DIST_COMMON, # otherwise OSF make will implicitly copy the included # file in the build tree during "make distdir" to satisfy # the dependency. # (subdir-am-cond.sh and subdir-ac-cond.sh will fail) push_dist_common ("\$\(top_srcdir\)/$path"); } else { $path =~ s/\$\(srcdir\)\///; push (@include_stack, "\$\(srcdir\)/$path"); # Always use the $(srcdir) prefix in DIST_COMMON, # otherwise OSF make will implicitly copy the included # file in the build tree during "make distdir" to satisfy # the dependency. # (subdir-am-cond.sh and subdir-ac-cond.sh will fail) push_dist_common ("\$\(srcdir\)/$path"); $path = $relative_dir . "/" . $path if $relative_dir ne '.'; } my $new_reldir = File::Spec->abs2rel ($path, $relative_dir); $new_reldir = '.' if $new_reldir !~ s,/[^/]*$,,; $where->push_context ("'$path' included from here"); read_am_file ($path, $where, $new_reldir); $where->pop_context; } else { # This isn't an error; it is probably a continued rule. # In fact, this is what we assume. $prev_state = IN_RULE_DEF; check_variable_expansions ($_, $where); $output_trailer .= $comment . $spacing; my $cond = new Automake::Condition @cond_stack; $output_trailer .= $cond->subst_string; $output_trailer .= $_; $comment = $spacing = ''; error $where, "'#' comment at start of rule is unportable" if $_ =~ /^\t\s*\#/; } $saw_bk = $new_saw_bk; $_ = $am_file->getline; } $output_trailer .= $comment; error ($where, "trailing backslash on last line") if $saw_bk; error ($where, (@cond_stack ? "unterminated conditionals: @cond_stack" : "too many conditionals closed in include file")) if "@saved_cond_stack" ne "@cond_stack"; } # Copyright on generated Makefile.ins. my $gen_copyright = "\ # Copyright (C) 1994-$RELEASE_YEAR Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. "; # read_main_am_file ($MAKEFILE_AM, $MAKEFILE_IN) # ---------------------------------------------- sub read_main_am_file { my ($amfile, $infile) = @_; # This supports the strange variable tricks we are about to play. prog_error ("variable defined before read_main_am_file\n" . variables_dump ()) if (scalar (variables) > 0); # Generate copyright header for generated Makefile.in. # We do discard the output of predefined variables, handled below. $output_vars = ("# " . basename ($infile) . " generated by automake " . $VERSION . " from " . basename ($amfile) . ".\n"); $output_vars .= '# ' . subst ('configure_input') . "\n"; $output_vars .= $gen_copyright; # We want to predefine as many variables as possible. This lets # the user set them with '+=' in Makefile.am. define_standard_variables; # Read user file, which might override some of our values. read_am_file ($amfile, new Automake::Location, '.'); } ################################################################ # generate_makefile ($MAKEFILE_AM, $MAKEFILE_IN) # ---------------------------------------------- # Generate a Makefile.in given the name of the corresponding Makefile and # the name of the file output by config.status. sub generate_makefile { my ($makefile_am, $makefile_in) = @_; # Reset all the Makefile.am related variables. initialize_per_input; # AUTOMAKE_OPTIONS can contains -W flags to disable or enable # warnings for this file. So hold any warning issued before # we have processed AUTOMAKE_OPTIONS. buffer_messages ('warning'); # $OUTPUT is encoded. If it contains a ":" then the first element # is the real output file, and all remaining elements are input # files. We don't scan or otherwise deal with these input files, # other than to mark them as dependencies. See the subroutine # 'scan_autoconf_files' for details. my ($makefile, @inputs) = split (/:/, $output_files{$makefile_in}); $relative_dir = dirname ($makefile); read_main_am_file ($makefile_am, $makefile_in); if (not handle_options) { # Process buffered warnings. flush_messages; # Fatal error. Just return, so we can continue with next file. return; } # Process buffered warnings. flush_messages; # There are a few install-related variables that you should not define. foreach my $var ('PRE_INSTALL', 'POST_INSTALL', 'NORMAL_INSTALL') { my $v = var $var; if ($v) { my $def = $v->def (TRUE); prog_error "$var not defined in condition TRUE" unless $def; reject_var $var, "'$var' should not be defined" if $def->owner != VAR_AUTOMAKE; } } # Catch some obsolete variables. msg_var ('obsolete', 'INCLUDES', "'INCLUDES' is the old name for 'AM_CPPFLAGS' (or '*_CPPFLAGS')") if var ('INCLUDES'); # Must do this after reading .am file. define_variable ('subdir', $relative_dir, INTERNAL); # If DIST_SUBDIRS is defined, make sure SUBDIRS is, so that # recursive rules are enabled. define_pretty_variable ('SUBDIRS', TRUE, INTERNAL, '') if var 'DIST_SUBDIRS' && ! var 'SUBDIRS'; # Check first, because we might modify some state. check_gnu_standards; check_gnits_standards; handle_configure ($makefile_am, $makefile_in, $makefile, @inputs); handle_gettext; handle_targets; handle_libraries; handle_ltlibraries; handle_programs; handle_scripts; handle_silent; # These must be run after all the sources are scanned. They use # variables defined by handle_libraries(), handle_ltlibraries(), # or handle_programs(). handle_compile; handle_languages; handle_libtool; # Variables used by distdir.am and tags.am. define_pretty_variable ('SOURCES', TRUE, INTERNAL, @sources); if (! option 'no-dist') { define_pretty_variable ('DIST_SOURCES', TRUE, INTERNAL, @dist_sources); } handle_texinfo; handle_emacs_lisp; handle_python; handle_java; handle_man_pages; handle_data; handle_headers; handle_subdirs; handle_user_recursion; handle_tags; handle_minor_options; # Must come after handle_programs so that %known_programs is up-to-date. handle_tests; # This must come after most other rules. handle_dist; handle_footer; do_check_merge_target; handle_all ($makefile); # FIXME: Gross! if (var ('lib_LTLIBRARIES') && var ('bin_PROGRAMS')) { $output_rules .= "install-binPROGRAMS: install-libLTLIBRARIES\n\n"; } if (var ('nobase_lib_LTLIBRARIES') && var ('bin_PROGRAMS')) { $output_rules .= "install-binPROGRAMS: install-nobase_libLTLIBRARIES\n\n"; } handle_install; handle_clean ($makefile); handle_factored_dependencies; # Comes last, because all the above procedures may have # defined or overridden variables. $output_vars .= output_variables; check_typos; if ($exit_code != 0) { verb "not writing $makefile_in because of earlier errors"; return; } my $am_relative_dir = dirname ($makefile_am); mkdir ($am_relative_dir, 0755) if ! -d $am_relative_dir; # We make sure that 'all:' is the first target. my $output = "$output_vars$output_all$output_header$output_rules$output_trailer"; # Decide whether we must update the output file or not. # We have to update in the following situations. # * $force_generation is set. # * any of the output dependencies is younger than the output # * the contents of the output is different (this can happen # if the project has been populated with a file listed in # @common_files since the last run). # Output's dependencies are split in two sets: # * dependencies which are also configure dependencies # These do not change between each Makefile.am # * other dependencies, specific to the Makefile.am being processed # (such as the Makefile.am itself, or any Makefile fragment # it includes). my $timestamp = mtime $makefile_in; if (! $force_generation && $configure_deps_greatest_timestamp < $timestamp && $output_deps_greatest_timestamp < $timestamp && $output eq contents ($makefile_in)) { verb "$makefile_in unchanged"; # No need to update. return; } if (-e $makefile_in) { unlink ($makefile_in) or fatal "cannot remove $makefile_in: $!"; } my $gm_file = new Automake::XFile "> $makefile_in"; verb "creating $makefile_in"; print $gm_file $output; } ################################################################ # Helper function for usage(). sub print_autodist_files { my @lcomm = uniq (sort @_); my @four; format USAGE_FORMAT = @<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<< $four[0], $four[1], $four[2], $four[3] . local $~ = "USAGE_FORMAT"; my $cols = 4; my $rows = int(@lcomm / $cols); my $rest = @lcomm % $cols; if ($rest) { $rows++; } else { $rest = $cols; } for (my $y = 0; $y < $rows; $y++) { @four = ("", "", "", ""); for (my $x = 0; $x < $cols; $x++) { last if $y + 1 == $rows && $x == $rest; my $idx = (($x > $rest) ? ($rows * $rest + ($rows - 1) * ($x - $rest)) : ($rows * $x)); $idx += $y; $four[$x] = $lcomm[$idx]; } write; } } sub usage () { print "Usage: $0 [OPTION]... [Makefile]... Generate Makefile.in for configure from Makefile.am. Operation modes: --help print this help, then exit --version print version number, then exit -v, --verbose verbosely list files processed --no-force only update Makefile.in's that are out of date -W, --warnings=CATEGORY report the warnings falling in CATEGORY Dependency tracking: -i, --ignore-deps disable dependency tracking code --include-deps enable dependency tracking code Flavors: --foreign set strictness to foreign --gnits set strictness to gnits --gnu set strictness to gnu Library files: -a, --add-missing add missing standard files to package --libdir=DIR set directory storing library files --print-libdir print directory storing library files -c, --copy with -a, copy missing files (default is symlink) -f, --force-missing force update of standard files "; Automake::ChannelDefs::usage; print "\nFiles automatically distributed if found " . "(always):\n"; print_autodist_files @common_files; print "\nFiles automatically distributed if found " . "(under certain conditions):\n"; print_autodist_files @common_sometimes; print ' Report bugs to <@PACKAGE_BUGREPORT@>. GNU Automake home page: <@PACKAGE_URL@>. General help using GNU software: . '; # --help always returns 0 per GNU standards. exit 0; } sub version () { print < This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Tom Tromey and Alexandre Duret-Lutz . EOF # --version always returns 0 per GNU standards. exit 0; } ################################################################ # Parse command line. sub parse_arguments () { my $strict = 'gnu'; my $ignore_deps = 0; my @warnings = (); my %cli_options = ( 'version' => \&version, 'help' => \&usage, 'libdir=s' => \$libdir, 'print-libdir' => sub { print "$libdir\n"; exit 0; }, 'gnu' => sub { $strict = 'gnu'; }, 'gnits' => sub { $strict = 'gnits'; }, 'foreign' => sub { $strict = 'foreign'; }, 'include-deps' => sub { $ignore_deps = 0; }, 'i|ignore-deps' => sub { $ignore_deps = 1; }, 'no-force' => sub { $force_generation = 0; }, 'f|force-missing' => \$force_missing, 'a|add-missing' => \$add_missing, 'c|copy' => \$copy_missing, 'v|verbose' => sub { setup_channel 'verb', silent => 0; }, 'W|warnings=s' => \@warnings, ); use Automake::Getopt (); Automake::Getopt::parse_options %cli_options; set_strictness ($strict); my $cli_where = new Automake::Location; set_global_option ('no-dependencies', $cli_where) if $ignore_deps; for my $warning (@warnings) { parse_warnings ('-W', $warning); } return unless @ARGV; my $errspec = 0; foreach my $arg (@ARGV) { fatal ("empty argument\nTry '$0 --help' for more information") if ($arg eq ''); # Handle $local:$input syntax. my ($local, @rest) = split (/:/, $arg); @rest = ("$local.in",) unless @rest; my $input = locate_am @rest; if ($input) { push @input_files, $input; $output_files{$input} = join (':', ($local, @rest)); } else { error "no Automake input file found for '$arg'"; $errspec = 1; } } fatal "no input file found among supplied arguments" if $errspec && ! @input_files; } # handle_makefile ($MAKEFILE) # --------------------------- sub handle_makefile { my ($file) = @_; ($am_file = $file) =~ s/\.in$//; if (! -f ($am_file . '.am')) { error "'$am_file.am' does not exist"; } else { # Any warning setting now local to this Makefile.am. dup_channel_setup; generate_makefile ($am_file . '.am', $file); # Back out any warning setting. drop_channel_setup; } } # Deal with all makefiles, without threads. sub handle_makefiles_serial () { foreach my $file (@input_files) { handle_makefile ($file); } } # handle_makefiles_threaded ($NTHREADS) # ------------------------------------- # Deal with all makefiles, using threads. The general strategy is to # spawn NTHREADS worker threads, dispatch makefiles to them, and let the # worker threads push back everything that needs serialization: # * warning and (normal) error messages, for stable stderr output # order and content (avoiding duplicates, for example), # * races when installing aux files (and respective messages), # * races when collecting aux files for distribution. # # The latter requires that the makefile that deals with the aux dir # files be handled last, done by the master thread. sub handle_makefiles_threaded { my ($nthreads) = @_; # The file queue distributes all makefiles, the message queues # collect all serializations needed for respective files. my $file_queue = Thread::Queue->new; my %msg_queues; foreach my $file (@input_files) { $msg_queues{$file} = Thread::Queue->new; } verb "spawning $nthreads worker threads"; my @threads = (1 .. $nthreads); foreach my $t (@threads) { $t = threads->new (sub { while (my $file = $file_queue->dequeue) { verb "handling $file"; my $queue = $msg_queues{$file}; setup_channel_queue ($queue, QUEUE_MESSAGE); $required_conf_file_queue = $queue; handle_makefile ($file); $queue->enqueue (undef); setup_channel_queue (undef, undef); $required_conf_file_queue = undef; } return $exit_code; }); } # Queue all makefiles. verb "queuing " . @input_files . " input files"; $file_queue->enqueue (@input_files, (undef) x @threads); # Collect and process serializations. foreach my $file (@input_files) { verb "dequeuing messages for " . $file; reset_local_duplicates (); my $queue = $msg_queues{$file}; while (my $key = $queue->dequeue) { if ($key eq QUEUE_MESSAGE) { pop_channel_queue ($queue); } elsif ($key eq QUEUE_CONF_FILE) { require_queued_file_check_or_copy ($queue); } else { prog_error "unexpected key $key"; } } } foreach my $t (@threads) { my @exit_thread = $t->join; $exit_code = $exit_thread[0] if ($exit_thread[0] > $exit_code); } } ################################################################ # Parse the WARNINGS environment variable. parse_WARNINGS; # Parse command line. parse_arguments; $configure_ac = require_configure_ac; # Do configure.ac scan only once. scan_autoconf_files (($ENV{AUTOCONF} || '@am_AUTOCONF@') . " "); if (! @input_files) { my $msg = ''; $msg = "\nDid you forget AC_CONFIG_FILES([Makefile]) in $configure_ac?" if -f 'Makefile.am'; fatal ("no 'Makefile.am' found for any configure output$msg"); } my $nthreads = get_number_of_threads (); if ($perl_threads && $nthreads >= 1) { handle_makefiles_threaded ($nthreads); } else { handle_makefiles_serial (); } exit $exit_code;