#!@PERL@ # -*- perl -*- # @configure_input@ eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}' if $running_under_some_shell; # automake - create Makefile.in from Makefile.am # Copyright (C) 1994 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # Originally written by David Mackenzie . # Perl reimplementation by Tom Tromey . # Parameters set by configure. Not to be changed. $VERSION = "@VERSION@"; $prefix = "@prefix@"; $am_dir = "@datadir@/@PACKAGE@"; # String constants. $IGNORE_PATTERN = "^##([^#].*)?\$"; $WHITE_PATTERN = "^[ \t]*\$"; $COMMENT_PATTERN = "^#"; $RULE_PATTERN = "^([a-zA-Z_.][-.a-zA-Z0-9_.]*) *:"; $MACRO_PATTERN = "^([A-Za-z][A-Za-z0-9_]*)[ \t]*=[ \t]*(.*)\$"; # Constants to define the "strictness" level. $NORMAL = 0; $GNU = 1; $GNITS = 2; # Variables global to entire run. # Strictness level. $strictness = $NORMAL; # This is TRUE if GNU make specific automatic dependency generation # code should be included in generated Makefile.in. $use_dependencies = 1; # This holds our (eventual) exit status. We don't actually exit until # we have processed all input files. $exit_status = 0; # From the Perl manual. $symlink_exists = (eval 'symlink ("", "");', $@ eq ''); # TRUE if missing standard files should be installed. $install_missing = 0; &initialize_global_constants; # Parse command line. @input_files = &parse_arguments (@ARGV); # Now do all the work on each file. foreach $am_file (@input_files) { if (! -f ($am_file . '.am')) { &am_error ('no such file'); } else { &generate_makefile ($am_file); } } exit $exit_status; ################################################################ # Parse command line. sub parse_arguments { local (@arglist) = @_; local (@make_list); while ($#arglist >= 0) { if ($arglist[0] eq "--version") { print "Automake version $VERSION\n"; exit 0; } elsif ($arglist[0] eq "--help") { &usage; } elsif ($arglist[0] =~ /^--amdir=(.+)$/) { $am_dir = $1; } elsif ($arglist[0] eq '--amdir') { &require_argument (@arglist); shift (@arglist); $am_dir = $arglist[0]; } elsif ($arglist[0] =~ /^--strictness=(.+)$/) { &set_strictness ($1); } elsif ($arglist[0] eq '--strictness') { &require_argument (@arglist); shift (@arglist); &set_strictness ($arglist[0]); } elsif ($arglist[0] eq '--include-deps') { $use_dependencies = 0; } elsif ($arglist[0] =~ /^--output-dir=(.*)$/) { # Set output directory. $output_directory = $1; } elsif ($arglist[0] eq '--output-dir') { &require_argument (@arglist); shift (@arglist); $output_directory = $arglist[0]; } elsif ($arglist[0] eq '--install-missing') { $install_missing = 1; } elsif ($arglist[0] eq '--') { # Stop option processing. shift (@arglist); push (@make_list, @arglist); last; } elsif ($arglist[0] =~ /^-/) { die "automake: unrecognized option -- \`$arglist[0]'\n"; } else { push (@make_list, $arglist[0]); } shift (@arglist); } if ($#make_list < 0) { # Look around for some files. push (@make_list, 'Makefile') if -f 'Makefile.am'; foreach (<*/Makefile.am>) { s/\.am$//; push (@make_list, $_); } die "automake: no \"Makefile.am\" found or specified\n" if $#make_list < 0; } return (@make_list); } # Ensure argument exists, or die. sub require_argument { local ($arg, @arglist) = @_; die "automake: no argument given for option \`$arg'\n" if $#arglist >= 0; } ################################################################ # Generate a Makefile.in given the name of the corresponding Makefile. sub generate_makefile { local ($makefile) = @_; print "creating ", $makefile, ".in\n"; &initialize_per_input; $relative_dir = &dirname ($makefile); # FIXME with new 'dist' target, don't need Makefile.in. Probably # should remove it here. &push_dist_common ('Makefile.in', 'Makefile.am'); push (@sources, '$(SOURCES)') if defined $contents{'SOURCES'}; push (@objects, '$(OBJECTS)') if defined $contents{'OBJECTS'}; # This is always the default target. This gives us freedom to do # things in whatever order is convenient. $output_rules .= "default: all\n\n"; push (@phony, 'default'); &read_am_file ($makefile . '.am'); # Check first, because we might modify some state. &check_gnu_standards; &check_gnits_standards; &handle_libraries; &handle_programs; &handle_scripts; # Re-init SOURCES and OBJECTS. FIXME other code shouldn't depend # on this (but currently does). $contents{'SOURCES'} = join (' ', @sources); $contents{'OBJECTS'} = join (' ', @objects); &handle_texinfo; &handle_man_pages; &handle_data; &handle_headers; &handle_subdirs; &handle_configure; &handle_tags; &handle_dist; &handle_dependencies; &handle_footer; &handle_merge_targets; &handle_installdirs; &handle_clean; &handle_phony; if (! -d ($output_directory . '/' . $relative_dir)) { &mkdir ($output_directory . '/' . $relative_dir); } if (! open (GM_FILE, "> " . $output_directory . '/' . $makefile . ".in")) { &am_error ("cannot open:", $!); return; } print GM_FILE $output_vars; print GM_FILE $output_rules; print GM_FILE $output_trailer; close (GM_FILE); } ################################################################ # Return object extension. Just once, put some code into the output. sub get_object_extension { if (! $dir_holds_sources) { # Boilerplate. $output_vars .= &file_contents ('compile-vars'); $output_rules .= &file_contents ('compile'); &push_phony_cleaners ('compile'); # Check for automatic de-ANSI-fication. $dir_holds_sources = '.o'; push (@suffixes, '.c', '.o'); push (@clean, 'compile'); if (defined $contents{'@kr@'}) { $dir_holds_sources = '.$(kr)o'; push (@suffixes, '._c', '._o'); &require_file ($NORMAL, 'ansi2knr.c'); &require_file ($NORMAL, 'ansi2knr.1'); $output_vars .= &file_contents ('kr-vars'); $output_rules .= &file_contents ('compile-kr'); $output_rules .= &file_contents ('clean-kr'); push (@clean, 'kr'); &push_phony_cleaners ('kr'); } } return $dir_holds_sources; } # Handle SOURCE->OBJECT transform for one program or library. sub handle_source_transform { local ($one_file, $obj) = @_; # Look for file_SOURCES and file_OBJECTS. if (defined $contents{$one_file . "_SOURCES"}) { if (! defined $contents{$one_file . "_OBJECTS"}) { # Turn sources into objects. local (@files) = split (/\s+/, $contents{$one_file . "_SOURCES"}); # Ugh: Perl syntax vs Emacs. local ($krc1, $krc2) = ('\.\$\{kr\}c', '\.\$\(kr\)c'); local (@result) = (); foreach (@files) { if (/^(.*)\.[yl]$/) { # Automatically include generated .c file in # distribution. &push_dist_common ($1 . '.c'); } # Transform source files into .o files. s/\.cc$/$obj/g; s/$krc1$/$obj/g; s/$krc2$/$obj/g; s/\.[cCmylfs]$/$obj/g; push (@result, $_); } &pretty_print ($one_file . "_OBJECTS =", '', @result); } else { &am_error ($one_file . '_OBJECTS', 'should not be defined'); } push (@sources, '$(' . $one_file . "_SOURCES)"); push (@objects, '$(' . $one_file . "_OBJECTS)"); } else { $output_vars .= ($one_file . "_SOURCES = " . $one_file . ".c\n" . $one_file . "_OBJECTS = ". $one_file . $obj . "\n"); push (@sources, $one_file . '.c'); push (@objects, $one_file . $obj); } if (defined $contents{'CONFIG_HEADER'}) { $output_rules .= ('$(' . $one_file . "_OBJECTS): " . $contents{'CONFIG_HEADER'} . "\n"); } return @result; } # Handle C programs. sub handle_programs { local (@proglist) = &am_install_var ('-clean', 'programs', 'PROGRAMS', 'bin', 'sbin', 'libexec', 'noinst'); # FIXME error if PROGRAMS defined but no blah_PROGRAMS defined. return if $#proglist < 0; local ($obj) = &get_object_extension; local ($one_file, $munge); local ($fcont) = &file_contents ('program'); foreach $one_file (@proglist) { &handle_source_transform ($one_file, $obj); if (! defined $contents{$one_file . "_LDADD"}) { # User didn't define prog_LDADD override. So do it. $output_vars .= $one_file . '_LDADD = $(LDADD)' . "\n"; } ($munge = $fcont) =~ s/\@PROGRAM\@/$one_file/g; $output_rules .= $munge; } } # Handle libraries. sub handle_libraries { local (@liblist) = &am_install_var ('-no-all', '-clean', 'libraries', 'LIBRARIES', 'lib', 'pkglib', 'noinst'); # FIXME error if LIBRARIES defined but no blah_LIBRARIES defined. return if $#liblist < 0; # Generate _LIBFILES variables. Too bad we can't do this in # am_install_var. local ($onedir, $onelib); local (@outlist); foreach $onedir ('lib', 'pkglib', 'noinst') { if (defined $contents{$onedir . '_LIBRARIES'}) { @outlist = (); foreach $onelib (split (/\s+/, $contents{$onedir . '_LIBRARIES'})) { push (@outlist, 'lib' . $onelib . '.a'); } &pretty_print ($onedir . '_LIBFILES =', '', @outlist); } } push (@all, '$(LIBFILES)'); local ($obj) = &get_object_extension; local ($template) = &file_contents ('library'); local ($munge); foreach $onelib (@liblist) { if (! defined $contents{$onelib . '_LIBADD'}) { # Generate support for conditional object inclusion in # libraries. $output_vars .= $onelib . "_LIBADD =\n"; } &handle_source_transform ($onelib, $obj); ($munge = $template) =~ s/\@LIBRARY\@/$onelib/g; $output_rules .= $munge; } # Turn "foo" into "libfoo.a" and include macro definition. grep (($_ = 'lib' . $_ . '.a') && 0, @liblist); if (! defined $contents{'LIBFILES'}) { &pretty_print ('LIBFILES = ', '', @liblist); } $output_vars .= &file_contents ('libraries-vars'); } # Handle scripts. sub handle_scripts { &am_install_var ('-clean', 'scripts', 'SCRIPTS', 'bin', 'sbin', 'libexec', 'noinst'); } # Handle all Texinfo source. sub handle_texinfo { local ($texis) = &am_variable ('TEXINFOS'); return if ! $texis; local (@texis) = split (/\s+/, $texis); if ($#texis > 0) { &am_error ('sorry, only one file allowed in `TEXINFOS\''); return; } local ($infobase); ($infobase = $texis[0]) =~ s/\.texi$//; # If 'version.texi' is referenced by input file, then include # automatic versioning capability. system ("grep version.texi " . $relative_dir . "/" . $texis[0] . " > /dev/null 2>&1"); if (! ($? >> 8)) { # Got a hit. push (@texis, 'version.texi'); &push_dist_common ('version.texi', 'stamp-vti'); push (@clean, 'vti'); local ($tfile); ($tfile = &file_contents ('texi-version')) =~ s/\@TEXI\@/$texis[0]/g; $output_rules = $output_rules . $tfile; &push_phony_cleaners ('vti'); &require_file ($NORMAL, 'mdate-sh'); } # If user specified file_TEXINFOS, then use that as explicit # dependency list. if (defined $contents{$infobase . "_TEXINFOS"}) { push (@texis, "\$" . $infobase . '_TEXINFOS'); &push_dist_common ("\$" . $infobase . '_TEXINFOS'); } if ($#texis >= 0) { $output_rules .= ($infobase . ".info: " . join (' ', @texis) . "\n\n"); } # Some boilerplate. $output_vars .= &file_contents ('texinfos-vars'); $output_rules .= &file_contents ('texinfos'); push (@phony, 'install-info', 'uninstall-info'); # How to clean. local ($crules) = &file_contents ('texi-clean'); $crules =~ s/\@TEXI\@/$infobase/g; $output_rules .= $crules; &push_phony_cleaners ('info'); push (@suffixes, '.texi', '.info', '.dvi'); push (@uninstall, 'uninstall-info'); push (@clean, 'info'); push (@info, '$(INFO_DEPS)'); push (@dvi, '$(DVIS)'); push (@installdirs, '$(infodir)'); # Make sure documentation is made and installed first. unshift (@install_data, 'install-info'); unshift (@all, 'info'); $output_vars .= ("INFOS = " . $infobase . ".info*\n" . "INFO_DEPS = " . $infobase . ".info\n" . "DVIS = " . $infobase . ".dvi\n\n"); # Do some error checking. &require_file ($NORMAL, 'texinfo.tex'); } # Handle any man pages. sub handle_man_pages { return if ! defined $contents{'MANS'}; # We generate the manpage install code by hand to avoid the use of # basename in the generated Makefile. local (@mans) = split (/\s+/, $contents{'MANS'}); local (%sections, %inames, %secmap, %fullsecmap); foreach (@mans) { # FIXME: statement without effect: /^(.*)\.([0-9])([a-z]*)$/; $sections{$2} = 1; $inames{$1} = $_; $secmap{$1} = $2; $fullsecmap{$1} = $2 . $3; } # Generate list of install dirs. $output_rules .= "install-man:\n"; foreach (keys %sections) { push (@installdirs, '$(mandir)/man' . $_); $output_rules .= ("\t" . '$(top_srcdir)/mkinstalldirs $(mandir)/man' . $_ . "\n"); } push (@phony, 'install-man'); # Generate install target. local ($key); foreach $key (keys %inames) { $_ = $install_man_format; s/\@SECTION\@/$secmap{$key}/g; s/\@MAN\@/$inames{$key}/g; s/\@FULLSECT\@/$fullsecmap{$key}/g; s/\@MANBASE\@/$key/g; $output_rules .= $_; } $output_rules .= "\n"; $output_rules .= "uninstall-man:\n"; foreach $key (keys %inames) { $_ = $uninstall_man_format; s/\@SECTION\@/$secmap{$key}/g; s/\@MAN\@/$inames{$key}/g; s/\@FULLSECT\@/$fullsecmap{$key}/g; s/\@MANBASE\@/$key/g; $output_rules .= $_; } $output_rules .= "\n"; push (@phony, 'uninstall-man'); $output_vars .= &file_contents ('mans-vars'); push (@install_data, 'install-man'); push (@uninstall, 'uninstall-man'); push (@all, '$(MANS)'); } # Handle DATA variables. sub handle_data { &am_install_var ('data', 'DATA', 'data', 'sysconf', 'sharedstate', 'localstate', 'pkgdata', 'noinst'); } # Handle TAGS. sub handle_tags { local ($tagging) = 0; push (@phony, 'tags'); if (defined $contents{'SUBDIRS'}) { $output_rules .= &file_contents ('tags'); $tagging = 1; } elsif ($dir_holds_sources || defined $contents{'ETAGS_ARGS'}) { $output_rules .= &file_contents ('tags-subd'); push (@phony, 'id'); $tagging = 1; } if ($tagging) { $output_rules .= &file_contents ('tags-clean'); push (@clean, 'tags'); &push_phony_cleaners ('tags'); } else { # 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. $output_rules .= "tags: TAGS\nTAGS:\n\n"; } } # Handle 'dist' target. sub handle_dist { # Look for common files that should be included in distribution. local ($cfile); foreach $cfile (@common_files) { if (-f ($relative_dir . "/" . $cfile)) { &push_dist_common ($cfile); } } &pretty_print ("DIST_COMMON =", '', keys (%dist_common)); $output_vars .= "\n"; # Some boilerplate. $output_vars .= &file_contents ('dist-vars'); if ($relative_dir ne '.') { # In a subdirectory. $output_vars .= "subdir = " . $relative_dir . "\n\n"; $output_rules .= &file_contents ('dist-subd'); } else { $output_rules .= &file_contents (defined $contents{'SUBDIRS'} ? 'dist-subd-top' : 'dist'); } push (@phony, 'dist'); } # Handle auto-dependency code. sub handle_dependencies { if ($use_dependencies) { # Include GNU-make-specific auto-dep code. if ($dir_holds_sources) { $output_rules .= &file_contents ('depend'); } } else { # Include any auto-generated deps that are present. if (-d ($relative_dir . "/.deps") && -f ($relative_dir . "/.deps/.P")) { local ($depfile); local ($gpat) = $relative_dir . "/.deps/*.P"; foreach $depfile (<${gpat}>) { if (! open (DEP_FILE, $depfile)) { &am_error ("couldn't open $depfile", $!); next; } # Slurp entire file. $output_rules .= join ('', ); close (DEP_FILE); } $output_rules .= "\n"; } } } # Handle subdirectories. sub handle_subdirs { return if ! defined $contents{'SUBDIRS'}; $output_rules .= &file_contents ('subdirs'); # Push a bunch of phony targets. local ($phonies); foreach $phonies ('-data', '-exec', 'dirs') { push (@phony, 'install' . $phonies . '-recursive'); push (@phony, 'uninstall' . $phonies . '-recursive'); } foreach $phonies ('all', 'check', 'installcheck', 'info', 'dvi') { push (@phony, $phonies . '-recursive'); } &push_phony_cleaners ('recursive'); push (@all, "all-recursive"); push (@check, "check-recursive"); push (@installcheck, "installcheck-recursive"); push (@info, "info-recursive"); push (@dvi, "dvi-recursive"); $recursive_install = 1; } # Handle remaking and configure stuff. sub handle_configure { if ($relative_dir ne '.') { # In subdirectory. $output_rules .= &file_contents ('remake-subd'); } else { &require_file ($NORMAL, 'configure.in'); # FIXME require 'configure'? What if autoconf hasn't been run # yet? if (defined $contents{'SUBDIRS'}) { # We required AC_PROG_MAKE_SET. system ("grep AC_PROG_MAKE_SET configure.in > /dev/null 2>&1"); if ($? >> 8) { # Nope. &am_error ("AC_PROG_MAKE_SET must be used in configure.in"); } } if (-f 'aclocal.m4') { $output_vars .= "ACLOCAL = aclocal.m4\n"; &push_dist_common ('aclocal.m4'); } $output_rules .= &file_contents ('remake'); # Look for some files we need. &require_file ($NORMAL, 'install-sh'); &require_file ($NORMAL, 'mkinstalldirs'); } if (defined $contents{'CONFIG_HEADER'} && $contents{'CONFIG_HEADER'} !~ /\//) { # Header defined and in this directory. if (-f 'acconfig.h') { $output_vars .= "ACCONFIG = acconfig.h\n"; &push_dist_common ('acconfig.h'); } if (-f 'config.h.top') { $output_vars .= "CONFIG_TOP = config.h.top\n"; &push_dist_common ('config.h.top'); } if (-f 'config.h.bot') { $output_vars .= "CONFIG_BOT = config.h.bot\n"; &push_dist_common ('config.h.bot'); } &push_dist_common ('stamp-h.in', $contents{'CONFIG_HEADER'} . '.in'); $output_rules .= &file_contents ('remake-hdr'); } } # Handle C headers. sub handle_headers { &am_install_var ('data', 'HEADERS', 'include', 'oldinclude', 'pkginclude', 'noinst'); } # Handle footer elements. sub handle_footer { if ($contents{'SOURCES'}) { &pretty_print ('SOURCES =', '', split (/\s+/, $contents{'SOURCES'})); } if ($contents{'OBJECTS'}) { &pretty_print ('OBJECTS =', '', split (/\s+/, $contents{'OBJECTS'})); } if ($contents{'SOURCES'} || $contents{'OBJECTS'}) { $output_vars .= "\n"; } if (defined $contents{'SUFFIXES'}) { push (@suffixes, '$(SUFFIXES)'); } $output_trailer .= ".SUFFIXES:\n"; if ($#suffixes >= 0) { $output_trailer .= ".SUFFIXES: " . join (' ', @suffixes) . "\n"; } $output_trailer .= &file_contents ('footer'); } # Deal with installdirs target. sub handle_installdirs { # GNU Makefile standards recommend this. $output_rules .= ("installdirs:" . ($recursive_install ? " installdirs-recursive\n" : "\n")); push (@phony, 'installdirs'); if ($#installdirs >= 0) { &pretty_print_rule ("\t\$(top_srcdir)/mkinstalldirs ", "\t\t", @installdirs); } $output_rules .= "\n"; } # There are several targets which need to be merged. This is because # their complete definition is compiled from many parts. Note that we # avoid double colon rules, otherwise we'd use them instead. sub handle_merge_targets { &do_one_merge_target ('all', @all); &do_one_merge_target ('info', @info); &do_one_merge_target ('dvi', @dvi); push (@check, 'all'); &do_one_merge_target ('check', @check); &do_one_merge_target ('installcheck', @installcheck); # Handle the various install targets specially. We do this so # that (eg) "make install-exec" will run "install-exec-recursive" # if required, but "make install" won't run it twice. Step one is # to see if the user specified local versions of any of the # targets we handle. if (defined $contents{'install-exec-local'}) { push (@install_exec, 'install-exec-local'); } if (defined $contents{'install-data-local'}) { push (@install_data, 'install-data-local'); } if (defined $contents{'uninstall-local'}) { push (@uninstall, 'uninstall-local'); } if (defined $contents{'install-local'}) { &am_error ("use \`install-data' or \`install-exec', not \`install'"); } # Step two: if we are doing recursive makes, write out the # appropriate rules. local (@install); if ($recursive_install) { push (@install, 'install-recursive'); push (@uninstall, 'uninstall-recursive'); if ($#install_exec >= 0) { $output_rules .= ('install-exec-am: ' . join (' ', @install_exec) . "\n\n"); @install_exec = ('install-exec-recursive', 'install-exec-am'); push (@install, 'install-exec-am'); push (@phony, 'install-exec-am'); } if ($#install_data >= 0) { $output_rules .= ('install-data-am: ' . join (' ', @install_data) . "\n\n"); @install_data = ('install-data-recursive', 'install-data-am'); push (@install, 'install-data-am'); push (@phony, 'install-data-am'); } if ($#uninstall >= 0) { $output_rules .= ('uninstall-am: ' . join (' ', @uninstall) . "\n\n"); @uninstall = ('uninstall-recursive', 'uninstall-am'); push (@phony, 'uninstall-am'); } } # Step three: print definitions users can use. if ($#install_exec >= 0) { $output_rules .= ("install-exec: " . join (' ', @install_exec) . "\n\n"); push (@install, 'install-exec') if !$recursive_install; push (@phony, 'install-exec'); } if ($#install_data >= 0) { $output_rules .= ("install-data: " . join (' ', @install_data) . "\n\n"); push (@install, 'install-data') if !$recursive_install; push (@phony, 'install-data'); } $output_rules .= ('install: ' . join (' ', @install) . "\n\t:" . "\n\n" . 'uninstall: ' . join (' ', @uninstall) . "\n\n"); push (@phony, 'install', 'uninstall'); } # Helper for handle_merge_targets. sub do_one_merge_target { local ($name, @values) = @_; if (defined $contents{$name . '-local'}) { # User defined local form of target. So include it. push (@values, $name . '-local'); push (@phony, $name . '-local'); } $output_rules .= $name . ":"; if ($#values >= 0) { $output_rules .= ' ' . join (' ', @values); } $output_rules .= "\n\n"; push (@phony, $name); } # Handle all 'clean' targets. sub handle_clean { push (@clean, 'generic'); $output_rules .= &file_contents ('clean'); &push_phony_cleaners ('generic'); local ($target) = $recursive_install ? 'clean-am' : 'clean'; &do_one_clean_target ($target, 'mostly', '', @clean); &do_one_clean_target ($target, '', 'mostly', @clean); &do_one_clean_target ($target, 'dist', '', @clean); &do_one_clean_target ($target, 'maintainer-', 'dist', @clean); push (@phony, 'clean', 'mostlyclean', 'distclean', 'maintainer-clean'); local (@deps); if ($recursive_install) { @deps = ('am', 'recursive'); &do_one_clean_target ('', 'mostly', '', @deps); &do_one_clean_target ('', '', '', @deps); &do_one_clean_target ('', 'dist', '', @deps); &do_one_clean_target ('', 'maintainer-', '', @deps); } } # Helper for handle_clean. sub do_one_clean_target { local ($target, $name, $last_name, @deps) = @_; # Special case: if target not passed, then don't generate # dependency on next "lower" clean target (eg no # clean<-mostlyclean derivation). In this case the target is # implicitly known to be 'clean'. local ($flag) = $target; $target = 'clean' if ! $flag; grep (($_ = $name . 'clean-' . $_) && 0, @deps); if ($flag) { if ($last_name || $name ne 'mostly') { push (@deps, $last_name . $target . " "); } } &pretty_print_rule ($name . $target . ": ", '', @deps); # FIXME shouldn't we really print these messages before running # the dependencies? if ($name . $target eq 'maintainer-clean') { # Print a special warning. $output_rules .= ("\t\@echo \"This command is intended for maintainers to use;\"\n" . "\t\@echo \"it deletes files that may require special " . "tools to rebuild.\"\n" . "\trm -f config.status\n"); } elsif ($name . $target eq 'distclean') { $output_rules .= "\trm -f config.status\n"; } $output_rules .= "\n"; } # Handle .PHONY target. sub handle_phony { &pretty_print_rule ('.PHONY:', '', @phony); $output_rules .= "\n"; } ################################################################ # Do any extra checking for GNU standards. sub check_gnu_standards { &require_file ($GNU, 'ChangeLog'); if ($relative_dir eq '.') { # In top level (or only) directory. &require_file ($GNU, 'INSTALL', 'NEWS', 'README'); } } # Do any extra checking for GNITS standards. sub check_gnits_standards { } ################################################################ # Pretty-print something. HEAD is what should be printed at the # beginning of the first line, FILL is what should be printed at the # beginning of every subsequent line. sub pretty_print_internal { local ($head, $fill, @values) = @_; local ($column) = length ($head); local ($result) .= $head; local ($bol) = 0; foreach (@values) { # "71" because we also print a space. if ($column + length ($_) > 71) { $result .= " \\\n" . $fill; $column = length ($fill); $bol = 1; } $result .= ' ' unless ($bol); $result .= $_; $column += length ($_) + 1; $bol = 0; } $result .= "\n"; return $result; } # Pretty-print something and append to output_vars. sub pretty_print { $output_vars .= &pretty_print_internal (@_); } # Pretty-print something and append to output_rules. sub pretty_print_rule { $output_rules .= &pretty_print_internal (@_); } ################################################################ # Read Makefile.am and set up %contents. Simultaneously copy lines # from Makefile.am into $output_trailer or $output_vars as # appropriate. NOTE we put rules in the trailer section. We want # user rules to come after our generated stuff. sub read_am_file { local ($amfile) = @_; local ($header_vars) = &file_contents ('header-vars'); open (AM_FILE, $amfile) || die "automake: couldn't open $amfile: $!\n"; $output_vars .= ("# Makefile.in generated automatically by automake " . $VERSION . " from Makefile.am\n"); local ($saw_bk) = 0; local ($was_rule) = 0; local ($spacing) = ''; local ($comment) = ''; local ($last_var_name) = ''; while () { if (/$IGNORE_PATTERN/o) { # Merely delete comments beginning with two hashes. } elsif (/$WHITE_PATTERN/o) { # Stick a single white line before the incoming macro or rule. $spacing = "\n"; } elsif (/$COMMENT_PATTERN/o) { # Stick comments before the incoming macro or rule. $comment .= $spacing . $_; $spacing = ''; } else { last; } } $output_vars .= $comment . "\n" . $header_vars; $comment = ''; $spacing = "\n"; while ($_) { if (/$IGNORE_PATTERN/o) { # Merely delete comments beginning with two hashes. } elsif (/$WHITE_PATTERN/o) { # Stick a single white line before the incoming macro or rule. $spacing = "\n"; } elsif (/$COMMENT_PATTERN/o) { # Stick comments before the incoming macro or rule. $comment .= $spacing . $_; $spacing = ''; } elsif ($saw_bk) { if ($was_rule) { $output_trailer .= $_; $saw_bk = /\\$/; } else { $output_vars .= $_; if (substr ($_, -1) eq "\\") { $contents{$last_var_name} .= substr ($_, 0, length ($_) - 1); } else { $contents{$last_var_name} .= $_; } $saw_bk = /\\$/; } } elsif (/$RULE_PATTERN/o) { # warn "** Saw rule .$1.\n"; # Found a rule. $was_rule = 1; # Value here doesn't matter; for targets we only note # existence. $contents{$1} = 1; $output_trailer .= $comment . $spacing . $_; $comment = $spacing = ''; $saw_bk = /\\$/; } elsif (/$MACRO_PATTERN/o) { # warn "** Saw macro .$1.\n"; # Found a macro definition. $was_rule = 0; $last_var_name = $1; if (substr ($2, -1) eq "\\") { $contents{$1} = substr ($2, 0, length ($2) - 1); } else { $contents{$1} = $2; } $output_vars .= $comment . $spacing . $_; $comment = $spacing = ''; $saw_bk = /\\$/; } elsif ($_ eq "\@kr\@\n") { # Special case: this means we want automatic # de-ANSI-fication. FIXME think of a better way. $contents{'@kr@'} = 1; } else { # This isn't an error; it is probably a continued rule. # In fact, this is what we assume. $was_rule = 1; $output_trailer .= $comment . $spacing . $_; $comment = $spacing = ''; $saw_bk = /\\$/; } $_ = ; } $output_trailer .= $comment; } ################################################################ sub initialize_global_constants { # Associative array of standard directory names. Entry is TRUE if # corresponding directory should be installed during # 'install-exec' phase. %exec_dir_p = ('bin', 1, 'sbin', 1, 'libexec', 1, 'data', 0, 'sysconf', 1, 'localstate', 1, 'lib', 1, 'info', 0, 'man', 0, 'include', 0, 'oldinclude', 0, 'pkgdata', 0, 'pkglib', 1, 'pkginclude', 0 ); # Helper text for dealing with man pages. $install_man_format = ' \@sect=@SECTION@; \\ inst=`echo "@MANBASE@" | sed \'$(transform)\'`.@FULLSECT@; \\ echo installing @MAN@ as $(mandir)/man$$sect/$$inst; \\ $(INSTALL_DATA) $(srcdir)/@MAN@ $(mandir)/man$$sect/$$inst '; $uninstall_man_format = ' inst=`echo "@MANBASE@" | sed \'$(transform)\'`.@FULLSECT@; \\ rm -f $(mandir)/man@SECTION@/$$inst '; # Commonly found files we look for and automatically include in # DISTFILES. @common_files = ( "THANKS", "TODO", "README", "NEWS", "COPYING", "COPYING.LIB", "INSTALL", "ABOUT-NLS", "ChangeLog", "configure", "configure.in", "config.guess", "config.sub" ); # Commonly used files we auto-include, but only sometimes. @common_sometimes = ( "version.texi", "aclocal.m4", "acconfig.h", "config.h.top", "config.h.bot", "stamp-h.in", "mdate-sh", "ansi2knr.c", "ansi2knr.1", 'stamp-vti', "mkinstalldirs", "install-sh" ); $USAGE = "\ --amdir=DIR directory storing config files --help print this help, then exit --include-deps include generated dependencies in Makefile.in --install-missing install missing standard files --output-dir=DIR put generated Makefile.in's into DIR --strictness=LEVEL set strictness level. LEVEL is normal, gnu, gnits --version print version number, then exit\n"; } # (Re)-Initialize per-Makefile.am variables. sub initialize_per_input { # These two variables are used when generating each Makefile.in. # They hold the Makefile.in until it is ready to be printed. $output_rules = ''; $output_vars = ''; $output_trailer = ''; # Suffixes found during a run. @suffixes = (); # This holds the contents of a Makefile.am, as parsed by # read_am_file. %contents = (); # This holds the "relative directory" of the current Makefile.in. # Eg for src/Makefile.in, this is "src". $relative_dir = ''; # Directory where output files go. Actually, output files are # relative to this directory. $output_directory = '.'; # This holds a list of files that are included in the # distribution. %dist_common = (); # List of dependencies for the obvious targets. @install_data = (); @install_exec = (); @uninstall = (); @installdirs = (); @info = (); @dvi = (); @all = (); @check = (); @installcheck = (); @clean = (); @phony = (); # These are pretty obvious, too. They are used to define the # SOURCES and OBJECTS variables. @sources = (); @objects = (); # TRUE if current directory holds any C source files. (Actually # holds object extension, but this information is encapsulated in # the function get_object_extension). $dir_holds_sources = ''; # TRUE if install targets should work recursively. $recursive_install = 0; } ################################################################ # Return contents of a file from $am_dir, automatically skipping # macros or rules which are already known. sub file_contents { local ($basename) = @_; local ($file) = $am_dir . '/' . $basename . '.am'; open (FC_FILE, $file) || die "automake: installation error: cannot open \"$file\"\n"; local ($was_rule) = 0; local ($result_vars) = ''; local ($result_rules) = ''; local ($comment) = ''; local ($spacing) = "\n"; local ($skipping) = 0; while () { if (/$IGNORE_PATTERN/o) { # Merely delete comments beginning with two hashes. } elsif (/$WHITE_PATTERN/o) { # Stick a single white line before the incoming macro or rule. $spacing = "\n"; } elsif (/$COMMENT_PATTERN/o) { # Stick comments before the incoming macro or rule. $comment .= $spacing . $_; $spacing = ''; } elsif ($saw_bk) { if ($was_rule) { $result_rules .= $_ if ! $skipping; } else { $result_vars .= $_ if ! $skipping; } $saw_bk = /\\$/; } elsif (/$RULE_PATTERN/o) { # warn "** Found rule .$1.\n"; # Found a rule. $was_rule = 1; $skipping = defined $contents{$1}; warn "** Skip $skipping\n" if $skipping; $result_rules .= $comment . $spacing . $_ if ! $skipping; $comment = $spacing = ''; $saw_bk = /\\$/; } elsif (/$MACRO_PATTERN/o) { # warn "** Found macro .$1.\n"; # Found a variable reference. $was_rule = 0; $skipping = defined $contents{$1}; warn "** Skip $skipping\n" if $skipping; $result_vars .= $comment . $spacing . $_ if ! $skipping; $comment = $spacing = ''; $saw_bk = /\\$/; } else { # This isn't an error; it is probably a continued rule. # In fact, this is what we assume. $was_rule = 1; $result_rules .= $comment . $spacing . $_ if ! $skipping; $comment = $spacing = ''; $saw_bk = /\\$/; } } close (FC_FILE); return $result_vars . $result_rules . $comment; } # Return contents of some Makefile.am variable. Allow for AM_ style # overrides. sub am_variable { local ($varname) = @_; return (defined $contents{'AM_' . $varname} ? $contents{'AM_' . $varname} : $contents{$varname}); } # Handle `where_HOW' variable magic. Does all lookups, generates # install code,and possibly generates code to define the primary # variable. The first argument is the name of the .am file to munge, # the second argument is the primary variable (eg HEADERS), and all # subsequent arguments are possible installation locations. Returns # list of all values of all _HOW targets. # # FIXME this should be rewritten to be cleaner. It should be broken # up into multiple functions. # # Usage is: am_install_var (OPTION..., file, HOW, where...) sub am_install_var { local (@args) = @_; local ($do_all, $do_clean) = (1, 0); while ($#args >= 0) { if ($args[0] eq '-clean') { $do_clean = 1; } elsif ($args[0] eq '-no-all') { $do_all = 0; } elsif ($args[0] !~ /^-/) { last; } shift (@args); } local ($file, $primary, @prefixes) = @args; local (@used) = (); local (@result) = (); local ($template) = &file_contents ($file); local ($clean_templ) = &file_contents ($file . '-clean'); local ($munge); local ($one_name); foreach (@prefixes) { $one_name = $_ . '_' . $primary; if (defined $contents{$one_name}) { # Append actual contents to result. push (@result, split (/\s+/, $contents{$one_name})); if ($do_clean) { ($munge = $clean_templ) =~ s/\@DIR\@/$_/g; $output_rules .= $munge; push (@clean, $_ . $primary); &push_phony_cleaners ($_ . $primary); } push (@used, '$(' . $one_name . ')'); if ($_ eq 'noinst') { # Objects in noinst_FOO never get installed. next; } ($munge = $template) =~ s/\@DIR\@/$_/g; $output_rules .= $munge; push (@uninstall, 'uninstall-' . $_ . $primary); push (@phony, 'uninstall-' . $_ . $primary); push (@installdirs, '$(' . $_ . 'dir)'); if ($exec_dir_p{$_}) { push (@install_exec, 'install-' . $_ . $primary); } else { push (@install_data, 'install-' . $_ . $primary); } } } if (! defined $contents{$primary} && $#used >= 0) { # Define it. &pretty_print ($primary . '=', '', @used); $output_vars .= "\n"; } # Push here because PRIMARY might be configure time determined. push (@all, '$(' . $primary . ')') if ($do_all && $#used >= 0); # Look for misspellings. It is an error to have a variable ending # in a "reserved" suffix whose prefix is unknown, eg # "bni_PROGRAMS". local (%valid, $varname); grep ($valid{$_} = 0, @prefixes); foreach $varname (keys %contents) { if ($varname =~ /^(.*)_$primary$/ && ! defined $valid{$1}) { &am_error ("invalid variable \"$varname\""); } } return (@result); } ################################################################ # Verify that the file must exist in the current directory. # Usage: require_file (strictness, file) # strictness is the strictness level at which this file becomes # required. sub require_file { local ($mystrict, $file) = @_; local ($fullfile) = $relative_dir . "/" . $file; if (-f $fullfile) { &push_dist_common ($file); } elsif ($install_missing && -f ($am_dir . '/' . $file)) { # Install the missing file. Symlink if we can, copy if we must. if ($symlink_exists) { symlink ($am_dir . '/' . $file, $fullfile); } else { system ('cp', $am_dir . '/' . $file, $fullfile); } &am_error ("required file \"$fullfile\" not found; installing"); } elsif ($strictness >= $mystrict) { # Only an error if strictness constraint violated. &am_error ("required file \"$fullfile\" not found"); } } # Push a list of files onto dist_common. sub push_dist_common { local (@files) = @_; local ($file); foreach $file (@files) { $dist_common{$file} = 1; } } # Push a list of clean targets onto phony. sub push_phony_cleaners { local ($base) = @_; local ($target); foreach $target ('mostly', 'dist', '', 'maintainer-') { push (@phony, $target . 'clean-' . $base); } } # Set strictness. sub set_strictness { local ($name) = @_; if ($name eq 'gnu') { $strictness = $GNU; } elsif ($name eq 'gnits') { $strictness = $GNITS; } elsif ($name eq 'normal') { $strictness = $NORMAL; } else { die "automake: level \`$name' not recognized\n"; } } ################################################################ # Return directory name of file. sub dirname { local ($file) = @_; local ($sub); ($sub = $file) =~ s,/+[^/]+,,g; $sub = '.' if $sub eq $file; return $sub; } # Make a directory. sub mkdir { local ($dirname) = @_; system ("mkdir", $dirname); } ################################################################ # Print an error message and set exit status. sub am_error { warn "automake: ${am_file}.am: ", join (' ', @_), "\n"; $exit_status = 1; } # Print usage information. sub usage { print "Usage: automake [OPTION] ... [Makefile]...\n"; print $USAGE; print "\nFiles which are automatically distributed, if found:\n"; $~ = "USAGE_FORMAT"; local (@lcomm) = sort ((@common_files, @common_sometimes)); local ($one, $two); while ($#lcomm >= 0) { $one = shift (@lcomm); $two = shift (@lcomm); write; } exit 0; } format USAGE_FORMAT = @<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<< $one, $two .