# autoconf -- create `configure' using m4 macros # Copyright (C) 2001, 2002, 2003 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. package Autom4te::General; =head1 NAME Autom4te::General - general support functions for Autoconf and Automake =head1 SYNOPSIS use Autom4te::General =head1 DESCRIPTION This perl module provides various general purpose support functions used in several executables of the Autoconf and Automake packages. =cut use 5.005_03; use Exporter; use File::Basename; use File::Spec; use File::stat; use IO::File; use Carp; use strict; use vars qw (@ISA @EXPORT); @ISA = qw (Exporter); # Variables we define and export. my @export_vars = qw ($debug $force $help $me $tmp $verbose $version); # Functions we define and export. my @export_subs = qw (&catfile &canonpath &contents &debug &error &file_name_is_absolute &find_configure_ac &find_file &getopt &mktmpdir &mtime &uniq &update_file &up_to_date_p &verbose &xsystem &xqx); # Functions we forward (coming from modules we use). my @export_forward_subs = qw (&basename &dirname &fileparse); @EXPORT = (@export_vars, @export_subs, @export_forward_subs); # Variable we share with the main package. Be sure to have a single # copy of them: using `my' together with multiple inclusion of this # package would introduce several copies. =head2 Global Variables =over 4 =item C<$debug> Set this variable to 1 if debug messages should be enabled. Debug messages are meant for developpers only, or when tracking down an incorrect execution. =cut use vars qw ($debug); $debug = 0; =item C<$force> Set this variable to 1 to recreate all the files, or to consider all the output files are obsolete. =cut use vars qw ($force); $force = undef; =item C<$help> Set to the help message associated to the option C<--help>. =cut use vars qw ($help); $help = undef; =item C<$me> The name of this application, as should be used in diagostic messages. =cut use vars qw ($me); $me = basename ($0); =item C<$tmp> The name of the temporary directory created by C. Left C otherwise. =cut # Our tmp dir. use vars qw ($tmp); $tmp = undef; =item C<$verbose> Enable verbosity messages. These messages are meant for ordinary users, and typically make explicit the steps being performed. =cut use vars qw ($verbose); $verbose = 0; =item C<$version> Set to the version message associated to the option C<--version>. =cut use vars qw ($version); $version = undef; =back =cut ## ------------ ## ## Prototypes. ## ## ------------ ## sub verbose (@); ## ----- ## ## END. ## ## ----- ## =head2 Functions =over 4 =item C Filter Perl's exit codes, delete any temporary directory (unless C<$debug>), and exit nonzero whenever closing C fails. =cut # END # --- sub END { # $? contains the exit status we will return. # It was set using one of the following ways: # # 1) normal termination # this sets $? = 0 # 2) calling `exit (n)' # this sets $? = n # 3) calling die or friends (croak, confess...): # a) when $! is non-0 # this set $? = $! # b) when $! is 0 but $? is not # this sets $? = ($? >> 8) (i.e., the exit code of the # last program executed) # c) when both $! and $? are 0 # this sets $? = 255 # # Cases 1), 2), and 3b) are fine, but we prefer $? = 1 for 3a) and 3c). $? = 1 if ($! && $! == $?) || $? == 255; # (Note that we cannot safely distinguish calls to `exit (n)' # from calls to die when `$! = n'. It's not big deal because # we only call `exit (0)' or `exit (1)'.) if (!$debug && defined $tmp && -d $tmp) { if (<$tmp/*>) { if (! unlink <$tmp/*>) { print STDERR "$me: cannot empty $tmp: $!\n"; $? = 1; return; } } if (! rmdir $tmp) { print STDERR "$me: cannot remove $tmp: $!\n"; $? = 1; return; } } # This is required if the code might send any output to stdout # E.g., even --version or --help. So it's best to do it unconditionally. if (! close STDOUT) { print STDERR "$me: closing standard output: $!\n"; $? = 1; return; } } ## ----------- ## ## Functions. ## ## ----------- ## =item C Wrapper around Ccatfile>. Concatenate one or more directory names and a filename to form a complete path ending with a filename. =cut # $FILE # &catfile (@COMPONENT) # --------------------- sub catfile (@) { my (@component) = @_; return File::Spec->catfile (@component); } =item C Wrapper around Ccanonpath>. No physical check on the filesystem, but a logical cleanup of a path. On UNIX eliminates successive slashes and successive "/.". $cpath = canonpath ($path) ; =cut # $FILE # &canonpath ($FILE) # ------------------ sub canonpath ($) { my ($file) = @_; return File::Spec->canonpath ($file); } =item C Return the contents of c<$filename>. Exit with diagnostic on failure. =cut # &contents ($FILENAME) # --------------------- # Swallow the contents of file $FILENAME. sub contents ($) { my ($file) = @_; verbose "reading $file"; local $/; # Turn on slurp-mode. my $f = new Autom4te::XFile "< $file"; my $contents = $f->getline; $f->close; return $contents; } =item C If the debug mode is enabled (C<$debug> and C<$verbose>), report the C<@message> on C, signed with the name of the program. =cut # &debug(@MESSAGE) # ---------------- # Messages displayed only if $DEBUG and $VERBOSE. sub debug (@) { print STDERR "$me: ", @_, "\n" if $verbose && $debug; } =item C Report the C<@message> on C, signed with the name of the program, and exit with failure. If the debug mode is enabled (C<$debug>), then in addition dump the call stack. =cut # &error (@MESSAGE) # ----------------- # Same as die or confess, depending on $debug. sub error (@) { if ($debug) { confess "$me: ", @_, "\n"; } else { die "$me: ", @_, "\n"; } } =item C Wrapper around Cfile_name_is_absolute>. Return true iff C<$filename> is absolute. =cut # $BOOLEAN # &file_name_is_absolute ($FILE) # ------------------------------ sub file_name_is_absolute ($) { my ($file) = @_; return File::Spec->file_name_is_absolute ($file); } =item C])> Look for C or C in the C<$directory> and return the one which should be used. Report ambiguities to the user, but prefer C. =cut # $CONFIGURE_AC # &find_configure_ac ([$DIRECTORY = `.']) # --------------------------------------- sub find_configure_ac (;$) { my ($directory) = @_; $directory ||= '.'; my $configure_ac = canonpath (catfile ($directory, 'configure.ac')); my $configure_in = canonpath (catfile ($directory, 'configure.in')); if (-f $configure_ac) { if (-f $configure_in) { carp "$me: warning: `$configure_ac' and `$configure_in' both present.\n"; carp "$me: warning: proceeding with `$configure_ac'.\n"; } return $configure_ac; } elsif (-f $configure_in) { return $configure_in; } return; } =item C Return the first path for a C<$filename> in the Cs. We match exactly the behavior of GNU M4: first look in the current directory (which includes the case of absolute file names), and, if the file is not absolute, just fail. Otherwise, look in C<@include>. If the file is flagged as optional (ends with C), then return undef if absent, otherwise exit with error. =cut # $FILENAME # find_file ($FILENAME, @INCLUDE) # ------------------------------- sub find_file ($@) { my ($filename, @include) = @_; my $optional = 0; $optional = 1 if $filename =~ s/\?$//; return canonpath ($filename) if -e $filename; if (file_name_is_absolute ($filename)) { error "no such file or directory: $filename" unless $optional; return undef; } foreach my $path (@include) { return canonpath (catfile ($path, $filename)) if -e catfile ($path, $filename); } error "no such file or directory: $filename" unless $optional; return undef; } =item C Wrapper around C. In addition to the user C