123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- #! @PERL@ -w
- # -*- perl -*-
- # @configure_input@
- # autoscan - Create configure.scan (a preliminary configure.ac) for a package.
- # Copyright (C) 1994, 1999-2012 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 3 of the License, or
- # (at your option) any later version.
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- # Written by David MacKenzie <djm@gnu.ai.mit.edu>.
- eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
- if 0;
- BEGIN
- {
- my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
- unshift @INC, $pkgdatadir;
- # Override SHELL. On DJGPP SHELL may not be set to a shell
- # that can handle redirection and quote arguments correctly,
- # e.g.: COMMAND.COM. For DJGPP always use the shell that configure
- # has detected.
- $ENV{'SHELL'} = '@SHELL@' if ($^O eq 'dos');
- }
- use Autom4te::ChannelDefs;
- use Autom4te::Configure_ac;
- use Autom4te::General;
- use Autom4te::FileUtils;
- use Autom4te::XFile;
- use File::Basename;
- use File::Find;
- use strict;
- use vars qw(@cfiles @makefiles @shfiles @subdirs %printed);
- # The kind of the words we are looking for.
- my @kinds = qw (function header identifier program
- makevar librarie);
- # For each kind, the default macro.
- my %generic_macro =
- (
- 'function' => 'AC_CHECK_FUNCS',
- 'header' => 'AC_CHECK_HEADERS',
- 'identifier' => 'AC_CHECK_TYPES',
- 'program' => 'AC_CHECK_PROGS',
- 'library' => 'AC_CHECK_LIB'
- );
- my %kind_comment =
- (
- 'function' => 'Checks for library functions.',
- 'header' => 'Checks for header files.',
- 'identifier' => 'Checks for typedefs, structures, and compiler characteristics.',
- 'program' => 'Checks for programs.',
- );
- # $USED{KIND}{ITEM} is the list of locations where the ITEM (of KIND) was used
- # in the user package.
- # For instance $USED{function}{alloca} is the list of `file:line' where
- # `alloca (...)' appears.
- my %used = ();
- # $MACRO{KIND}{ITEM} is the list of macros to use to test ITEM.
- # Initialized from lib/autoscan/*. E.g., $MACRO{function}{alloca} contains
- # the singleton AC_FUNC_ALLOCA. Some require several checks.
- my %macro = ();
- # $NEEDED_MACROS{MACRO} is an array of locations requiring MACRO.
- # E.g., $NEEDED_MACROS{AC_FUNC_ALLOC} the list of `file:line' containing
- # `alloca (...)'.
- my %needed_macros =
- (
- 'AC_PREREQ' => [$me],
- );
- my $configure_scan = 'configure.scan';
- my $log;
- # Autoconf and lib files.
- my $autom4te = $ENV{'AUTOM4TE'} || '@bindir@/@autom4te-name@';
- my $autoconf = "$autom4te --language=autoconf";
- my @prepend_include;
- my @include = ('@pkgdatadir@');
- # $help
- # -----
- $help = "Usage: $0 [OPTION]... [SRCDIR]
- Examine source files in the directory tree rooted at SRCDIR, or the
- current directory if none is given. Search the source files for
- common portability problems, check for incompleteness of
- `configure.ac', and create a file `$configure_scan' which is a
- preliminary `configure.ac' for that package.
- -h, --help print this help, then exit
- -V, --version print version number, then exit
- -v, --verbose verbosely report processing
- -d, --debug don't remove temporary files
- Library directories:
- -B, --prepend-include=DIR prepend directory DIR to search path
- -I, --include=DIR append directory DIR to search path
- Report bugs to <bug-autoconf\@gnu.org>.
- GNU Autoconf home page: <http://www.gnu.org/software/autoconf/>.
- General help using GNU software: <http://www.gnu.org/gethelp/>.
- ";
- # $version
- # --------
- $version = "autoscan (@PACKAGE_NAME@) @VERSION@
- Copyright (C) @RELEASE_YEAR@ Free Software Foundation, Inc.
- License GPLv3+/Autoconf: GNU GPL version 3 or later
- <http://gnu.org/licenses/gpl.html>, <http://gnu.org/licenses/exceptions.html>
- This is free software: you are free to change and redistribute it.
- There is NO WARRANTY, to the extent permitted by law.
- Written by David J. MacKenzie and Akim Demaille.
- ";
- ## ------------------------ ##
- ## Command line interface. ##
- ## ------------------------ ##
- # parse_args ()
- # -------------
- # Process any command line arguments.
- sub parse_args ()
- {
- getopt ('I|include=s' => \@include,
- 'B|prepend-include=s' => \@prepend_include);
- die "$me: too many arguments
- Try `$me --help' for more information.\n"
- if @ARGV > 1;
- my $srcdir = $ARGV[0] || ".";
- verb "srcdir = $srcdir";
- chdir $srcdir || error "cannot cd to $srcdir: $!";
- }
- # init_tables ()
- # --------------
- # Put values in the tables of what to do with each token.
- sub init_tables ()
- {
- # The data file format supports only one line of macros per function.
- # If more than that is required for a common portability problem,
- # a new Autoconf macro should probably be written for that case,
- # instead of duplicating the code in lots of configure.ac files.
- my $file = find_file ("autoscan/autoscan.list",
- reverse (@prepend_include), @include);
- my $table = new Autom4te::XFile "< " . open_quote ($file);
- my $tables_are_consistent = 1;
- while ($_ = $table->getline)
- {
- # Ignore blank lines and comments.
- next
- if /^\s*$/ || /^\s*\#/;
- # '<kind>: <word> <macro invocation>' or...
- # '<kind>: <word> warn: <message>'.
- if (/^(\S+):\s+(\S+)\s+(\S.*)$/)
- {
- my ($kind, $word, $macro) = ($1, $2, $3);
- error "$file:$.: invalid kind: $_"
- unless grep { $_ eq $kind } @kinds;
- push @{$macro{$kind}{$word}}, $macro;
- }
- else
- {
- error "$file:$.: invalid definition: $_";
- }
- }
- if ($debug)
- {
- foreach my $kind (@kinds)
- {
- foreach my $word (sort keys %{$macro{$kind}})
- {
- print "$kind: $word: @{$macro{$kind}{$word}}\n";
- }
- }
- }
- }
- # used ($KIND, $WORD, [$WHERE])
- # -----------------------------
- # $WORD is used as a $KIND.
- sub used ($$;$)
- {
- my ($kind, $word, $where) = @_;
- $where ||= "$File::Find::name:$.";
- if (
- # Check for all the libraries. But `-links' is certainly a
- # `find' argument, and `-le', a `test' argument.
- ($kind eq 'library' && $word !~ /^(e|inks)$/)
- # Other than libraries are to be checked only if listed in
- # the Autoscan library files.
- || defined $macro{$kind}{$word}
- )
- {
- push (@{$used{$kind}{$word}}, $where);
- }
- }
- ## ----------------------- ##
- ## Scanning source files. ##
- ## ----------------------- ##
- # scan_c_file ($FILE-NAME)
- # ------------------------
- sub scan_c_file ($)
- {
- my ($file_name) = @_;
- push @cfiles, $File::Find::name;
- # Nonzero if in a multiline comment.
- my $in_comment = 0;
- my $file = new Autom4te::XFile "< " . open_quote ($file_name);
- while ($_ = $file->getline)
- {
- # Strip out comments.
- if ($in_comment && s,^.*?\*/,,)
- {
- $in_comment = 0;
- }
- # The whole line is inside a comment.
- next if $in_comment;
- # All on one line.
- s,/\*.*?\*/,,g;
- # Starting on this line.
- if (s,/\*.*$,,)
- {
- $in_comment = 1;
- }
- # Preprocessor directives.
- if (s/^\s*\#\s*//)
- {
- if (/^include\s*<([^>]*)>/)
- {
- used ('header', $1);
- }
- if (s/^(if|ifdef|ifndef|elif)\s+//)
- {
- foreach my $word (split (/\W+/))
- {
- used ('identifier', $word)
- unless $word eq 'defined' || $word !~ /^[a-zA-Z_]/;
- }
- }
- # Ignore other preprocessor directives.
- next;
- }
- # Remove string and character constants.
- s,\"[^\"]*\",,g;
- s,\'[^\']*\',,g;
- # Tokens in the code.
- # Maybe we should ignore function definitions (in column 0)?
- while (s/\b([a-zA-Z_]\w*)\s*\(/ /)
- {
- used ('function', $1);
- }
- while (s/\b([a-zA-Z_]\w*)\b/ /)
- {
- used ('identifier', $1);
- }
- }
- $file->close;
- }
- # scan_makefile($MAKEFILE-NAME)
- # -----------------------------
- sub scan_makefile ($)
- {
- my ($file_name) = @_;
- push @makefiles, $File::Find::name;
- my $file = new Autom4te::XFile "< " . open_quote ($file_name);
- while ($_ = $file->getline)
- {
- # Strip out comments.
- s/#.*//;
- # Variable assignments.
- while (s/\b([a-zA-Z_]\w*)\s*=/ /)
- {
- used ('makevar', $1);
- }
- # Be sure to catch a whole word. For instance `lex$U.$(OBJEXT)'
- # is a single token. Otherwise we might believe `lex' is needed.
- foreach my $word (split (/\s+/))
- {
- # Libraries.
- if ($word =~ /^-l([a-zA-Z_]\w*)$/)
- {
- used ('library', $1);
- }
- # Tokens in the code.
- # We allow some additional characters, e.g., `+', since
- # autoscan/programs includes `c++'.
- if ($word =~ /^[a-zA-Z_][\w+]*$/)
- {
- used ('program', $word);
- }
- }
- }
- $file->close;
- }
- # scan_sh_file($SHELL-SCRIPT-NAME)
- # --------------------------------
- sub scan_sh_file ($)
- {
- my ($file_name) = @_;
- push @shfiles, $File::Find::name;
- my $file = new Autom4te::XFile "< " . open_quote ($file_name);
- while ($_ = $file->getline)
- {
- # Strip out comments and variable references.
- s/#.*//;
- s/\${[^\}]*}//g;
- s/@[^@]*@//g;
- # Tokens in the code.
- while (s/\b([a-zA-Z_]\w*)\b/ /)
- {
- used ('program', $1);
- }
- }
- $file->close;
- }
- # scan_file ()
- # ------------
- # Called by &find on each file. $_ contains the current file name with
- # the current directory of the walk through.
- sub scan_file ()
- {
- # Wanted only if there is no corresponding FILE.in.
- return
- if -f "$_.in";
- # Save $_ as Find::File requires it to be preserved.
- local $_ = $_;
- # Strip a useless leading `./'.
- $File::Find::name =~ s,^\./,,;
- if ($_ ne '.' and -d $_ and
- -f "$_/configure.in" ||
- -f "$_/configure.ac" ||
- -f "$_/configure.gnu" ||
- -f "$_/configure")
- {
- $File::Find::prune = 1;
- push @subdirs, $File::Find::name;
- }
- if (/\.[chlym](\.in)?$/)
- {
- used 'program', 'cc', $File::Find::name;
- scan_c_file ($_);
- }
- elsif (/\.(cc|cpp|cxx|CC|C|hh|hpp|hxx|HH|H|yy|ypp|ll|lpp)(\.in)?$/)
- {
- used 'program', 'c++', $File::Find::name;
- scan_c_file ($_);
- }
- elsif ((/^((?:GNUm|M|m)akefile)(\.in)?$/ && ! -f "$1.am")
- || /^(?:GNUm|M|m)akefile(\.am)?$/)
- {
- scan_makefile ($_);
- }
- elsif (/\.sh(\.in)?$/)
- {
- scan_sh_file ($_);
- }
- }
- # scan_files ()
- # -------------
- # Read through the files and collect lists of tokens in them
- # that might create nonportabilities.
- sub scan_files ()
- {
- find (\&scan_file, '.');
- if ($verbose)
- {
- print "cfiles: @cfiles\n";
- print "makefiles: @makefiles\n";
- print "shfiles: @shfiles\n";
- foreach my $kind (@kinds)
- {
- print "\n$kind:\n";
- foreach my $word (sort keys %{$used{$kind}})
- {
- print "$word: @{$used{$kind}{$word}}\n";
- }
- }
- }
- }
- ## ----------------------- ##
- ## Output configure.scan. ##
- ## ----------------------- ##
- # output_kind ($FILE, $KIND)
- # --------------------------
- sub output_kind ($$)
- {
- my ($file, $kind) = @_;
- # Lists of words to be checked with the generic macro.
- my @have;
- print $file "\n# $kind_comment{$kind}\n"
- if exists $kind_comment{$kind};
- foreach my $word (sort keys %{$used{$kind}})
- {
- # Output the needed macro invocations in $configure_scan if not
- # already printed, and remember these macros are needed.
- foreach my $macro (@{$macro{$kind}{$word}})
- {
- if ($macro =~ /^warn:\s+(.*)/)
- {
- my $message = $1;
- foreach my $location (@{$used{$kind}{$word}})
- {
- warn "$location: warning: $message\n";
- }
- }
- elsif (exists $generic_macro{$kind}
- && $macro eq $generic_macro{$kind})
- {
- push (@have, $word);
- push (@{$needed_macros{"$generic_macro{$kind}([$word])"}},
- @{$used{$kind}{$word}});
- }
- else
- {
- if (! $printed{$macro})
- {
- print $file "$macro\n";
- $printed{$macro} = 1;
- }
- push (@{$needed_macros{$macro}},
- @{$used{$kind}{$word}});
- }
- }
- }
- print $file "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
- if @have;
- }
- # output_libraries ($FILE)
- # ------------------------
- sub output_libraries ($)
- {
- my ($file) = @_;
- print $file "\n# Checks for libraries.\n";
- foreach my $word (sort keys %{$used{'library'}})
- {
- print $file "# FIXME: Replace `main' with a function in `-l$word':\n";
- print $file "AC_CHECK_LIB([$word], [main])\n";
- }
- }
- # output ($CONFIGURE_SCAN)
- # ------------------------
- # Print a proto configure.ac.
- sub output ($)
- {
- my $configure_scan = shift;
- my %unique_makefiles;
- my $file = new Autom4te::XFile "> " . open_quote ($configure_scan);
- print $file
- ("# -*- Autoconf -*-\n" .
- "# Process this file with autoconf to produce a configure script.\n" .
- "\n" .
- "AC_PREREQ([@VERSION@])\n" .
- "AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])\n");
- if (defined $cfiles[0])
- {
- print $file "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
- print $file "AC_CONFIG_HEADERS([config.h])\n";
- }
- output_kind ($file, 'program');
- output_kind ($file, 'makevar');
- output_libraries ($file);
- output_kind ($file, 'header');
- output_kind ($file, 'identifier');
- output_kind ($file, 'function');
- print $file "\n";
- if (@makefiles)
- {
- # Change DIR/Makefile.in to DIR/Makefile.
- foreach my $m (@makefiles)
- {
- $m =~ s/\.(?:in|am)$//;
- $unique_makefiles{$m}++;
- }
- print $file ("AC_CONFIG_FILES([",
- join ("\n ",
- sort keys %unique_makefiles), "])\n");
- }
- if (@subdirs)
- {
- print $file ("AC_CONFIG_SUBDIRS([",
- join ("\n ",
- sort @subdirs), "])\n");
- }
- print $file "AC_OUTPUT\n";
- $file->close;
- }
- ## --------------------------------------- ##
- ## Checking the accuracy of configure.ac. ##
- ## --------------------------------------- ##
- # &check_configure_ac ($CONFIGURE_AC)
- # -----------------------------------
- # Use autoconf to check if all the suggested macros are included
- # in CONFIGURE_AC.
- sub check_configure_ac ($)
- {
- my ($configure_ac) = @_;
- # Find what needed macros are invoked in CONFIGURE_AC.
- # I'd be very happy if someone could explain to me why sort (uniq ...)
- # doesn't work properly: I need `uniq (sort ...)'. --akim
- my $trace_option =
- join (' --trace=', '',
- uniq (sort (map { s/\(.*//; $_ } keys %needed_macros)));
- verb "running: $autoconf $trace_option $configure_ac";
- my $traces =
- new Autom4te::XFile "$autoconf $trace_option $configure_ac |";
- while ($_ = $traces->getline)
- {
- chomp;
- my ($file, $line, $macro, @args) = split (/:/, $_);
- if ($macro =~ /^AC_CHECK_(HEADER|FUNC|TYPE|MEMBER)S$/)
- {
- # To be rigorous, we should distinguish between space and comma
- # separated macros. But there is no point.
- foreach my $word (split (/\s|,/, $args[0]))
- {
- # AC_CHECK_MEMBERS wants `struct' or `union'.
- if ($macro eq "AC_CHECK_MEMBERS"
- && $word =~ /^stat.st_/)
- {
- $word = "struct " . $word;
- }
- delete $needed_macros{"$macro([$word])"};
- }
- }
- else
- {
- delete $needed_macros{$macro};
- }
- }
- $traces->close;
- # Report the missing macros.
- foreach my $macro (sort keys %needed_macros)
- {
- warn ("$configure_ac: warning: missing $macro wanted by: "
- . (${$needed_macros{$macro}}[0])
- . "\n");
- print $log "$me: warning: missing $macro wanted by: \n";
- foreach my $need (@{$needed_macros{$macro}})
- {
- print $log "\t$need\n";
- }
- }
- }
- ## -------------- ##
- ## Main program. ##
- ## -------------- ##
- parse_args;
- $log = new Autom4te::XFile "> " . open_quote ("$me.log");
- $autoconf .= " --debug" if $debug;
- $autoconf .= " --verbose" if $verbose;
- $autoconf .= join (' --include=', '', map { shell_quote ($_) } @include);
- $autoconf .= join (' --prepend-include=', '', map { shell_quote ($_) } @prepend_include);
- my $configure_ac = find_configure_ac;
- init_tables;
- scan_files;
- output ('configure.scan');
- if (-f $configure_ac)
- {
- check_configure_ac ($configure_ac);
- }
- # This close is really needed. For some reason, probably best named
- # a bug, it seems that the dtor of $LOG is not called automatically
- # at END. It results in a truncated file.
- $log->close;
- exit 0;
- ### Setup "GNU" style for perl-mode and cperl-mode.
- ## Local Variables:
- ## perl-indent-level: 2
- ## perl-continued-statement-offset: 2
- ## perl-continued-brace-offset: 0
- ## perl-brace-offset: 0
- ## perl-brace-imaginary-offset: 0
- ## perl-label-offset: -2
- ## cperl-indent-level: 2
- ## cperl-brace-offset: 0
- ## cperl-continued-brace-offset: 0
- ## cperl-label-offset: -2
- ## cperl-extra-newline-before-brace: t
- ## cperl-merge-trailing-else: nil
- ## cperl-continued-statement-offset: 2
- ## End:
|