revert previous push
[autoconf.git] / bin / autoscan.in
blob75abd1cd2dc7d3109cf69e396a44382f9575109b
1 #! @PERL@ -w
2 # -*- perl -*-
3 # @configure_input@
5 # autoscan - Create configure.scan (a preliminary configure.ac) for a package.
6 # Copyright (C) 1994, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
7 # 2007, 2008, 2009 Free Software Foundation, Inc.
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2, or (at your option)
12 # any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 # 02110-1301, USA.
24 # Written by David MacKenzie <djm@gnu.ai.mit.edu>.
26 eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
27     if 0;
29 BEGIN
31   my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
32   unshift @INC, $pkgdatadir;
34   # Override SHELL.  On DJGPP SHELL may not be set to a shell
35   # that can handle redirection and quote arguments correctly,
36   # e.g.: COMMAND.COM.  For DJGPP always use the shell that configure
37   # has detected.
38   $ENV{'SHELL'} = '@SHELL@' if ($^O eq 'dos');
41 use Autom4te::ChannelDefs;
42 use Autom4te::Configure_ac;
43 use Autom4te::General;
44 use Autom4te::FileUtils;
45 use Autom4te::XFile;
46 use File::Basename;
47 use File::Find;
48 use strict;
50 use vars qw(@cfiles @makefiles @shfiles @subdirs %printed);
52 # The kind of the words we are looking for.
53 my @kinds = qw (function header identifier program
54                 makevar librarie);
56 # For each kind, the default macro.
57 my %generic_macro =
58   (
59    'function'   => 'AC_CHECK_FUNCS',
60    'header'     => 'AC_CHECK_HEADERS',
61    'identifier' => 'AC_CHECK_TYPES',
62    'program'    => 'AC_CHECK_PROGS',
63    'library'    => 'AC_CHECK_LIB'
64   );
66 my %kind_comment =
67   (
68    'function'   => 'Checks for library functions.',
69    'header'     => 'Checks for header files.',
70    'identifier' => 'Checks for typedefs, structures, and compiler characteristics.',
71    'program'    => 'Checks for programs.',
72   );
74 # $USED{KIND}{ITEM} is the list of locations where the ITEM (of KIND) was used
75 # in the user package.
76 # For instance $USED{function}{alloca} is the list of `file:line' where
77 # `alloca (...)' appears.
78 my %used = ();
80 # $MACRO{KIND}{ITEM} is the list of macros to use to test ITEM.
81 # Initialized from lib/autoscan/*.  E.g., $MACRO{function}{alloca} contains
82 # the singleton AC_FUNC_ALLOCA.  Some require several checks.
83 my %macro = ();
85 # $NEEDED_MACROS{MACRO} is an array of locations requiring MACRO.
86 # E.g., $NEEDED_MACROS{AC_FUNC_ALLOC} the list of `file:line' containing
87 # `alloca (...)'.
88 my %needed_macros =
89   (
90    'AC_PREREQ' => [$me],
91   );
93 my $configure_scan = 'configure.scan';
94 my $log;
96 # Autoconf and lib files.
97 my $autom4te = $ENV{'AUTOM4TE'} || '@bindir@/@autom4te-name@';
98 my $autoconf = "$autom4te --language=autoconf";
99 my @prepend_include;
100 my @include = ('@pkgdatadir@');
102 # $help
103 # -----
104 $help = "Usage: $0 [OPTION]... [SRCDIR]
106 Examine source files in the directory tree rooted at SRCDIR, or the
107 current directory if none is given.  Search the source files for
108 common portability problems, check for incompleteness of
109 `configure.ac', and create a file `$configure_scan' which is a
110 preliminary `configure.ac' for that package.
112   -h, --help          print this help, then exit
113   -V, --version       print version number, then exit
114   -v, --verbose       verbosely report processing
115   -d, --debug         don't remove temporary files
117 Library directories:
118   -B, --prepend-include=DIR  prepend directory DIR to search path
119   -I, --include=DIR          append directory DIR to search path
121 Report bugs to <bug-autoconf\@gnu.org>.
122 GNU Autoconf home page: <http://www.gnu.org/software/autoconf/>.
123 General help using GNU software: <http://www.gnu.org/gethelp/>.
126 # $version
127 # --------
128 $version = "autoscan (@PACKAGE_NAME@) @VERSION@
129 Copyright (C) @RELEASE_YEAR@ Free Software Foundation, Inc.
130 License GPLv2+: GNU GPL version 2 or later
131 <http://gnu.org/licenses/old-licenses/gpl-2.0.html>
132 This is free software: you are free to change and redistribute it.
133 There is NO WARRANTY, to the extent permitted by law.
135 Written by David J. MacKenzie and Akim Demaille.
141 ## ------------------------ ##
142 ## Command line interface.  ##
143 ## ------------------------ ##
145 # parse_args ()
146 # -------------
147 # Process any command line arguments.
148 sub parse_args ()
150   getopt ('I|include=s' => \@include,
151           'B|prepend-include=s' => \@prepend_include);
153   die "$me: too many arguments
154 Try `$me --help' for more information.\n"
155     if @ARGV > 1;
157   my $srcdir = $ARGV[0] || ".";
159   verb "srcdir = $srcdir";
160   chdir $srcdir || error "cannot cd to $srcdir: $!";
164 # init_tables ()
165 # --------------
166 # Put values in the tables of what to do with each token.
167 sub init_tables ()
169   # The data file format supports only one line of macros per function.
170   # If more than that is required for a common portability problem,
171   # a new Autoconf macro should probably be written for that case,
172   # instead of duplicating the code in lots of configure.ac files.
173   my $file = find_file ("autoscan/autoscan.list",
174                         reverse (@prepend_include), @include);
175   my $table = new Autom4te::XFile "< " . open_quote ($file);
176   my $tables_are_consistent = 1;
178   while ($_ = $table->getline)
179     {
180       # Ignore blank lines and comments.
181       next
182         if /^\s*$/ || /^\s*\#/;
184       # '<kind>: <word> <macro invocation>' or...
185       # '<kind>: <word> warn: <message>'.
186       if (/^(\S+):\s+(\S+)\s+(\S.*)$/)
187         {
188           my ($kind, $word, $macro) = ($1, $2, $3);
189           error "$file:$.: invalid kind: $_"
190             unless grep { $_ eq $kind } @kinds;
191           push @{$macro{$kind}{$word}}, $macro;
192         }
193       else
194         {
195           error "$file:$.: invalid definition: $_";
196         }
197     }
199   if ($debug)
200     {
201       foreach my $kind (@kinds)
202         {
203           foreach my $word (sort keys %{$macro{$kind}})
204             {
205               print "$kind: $word: @{$macro{$kind}{$word}}\n";
206             }
207         }
209     }
213 # used ($KIND, $WORD, [$WHERE])
214 # -----------------------------
215 # $WORD is used as a $KIND.
216 sub used ($$;$)
218   my ($kind, $word, $where) = @_;
219   $where ||= "$File::Find::name:$.";
220   if (
221       # Check for all the libraries.  But `-links' is certainly a
222       # `find' argument, and `-le', a `test' argument.
223       ($kind eq 'library' && $word !~ /^(e|inks)$/)
224       # Other than libraries are to be checked only if listed in
225       # the Autoscan library files.
226       || defined $macro{$kind}{$word}
227      )
228     {
229       push (@{$used{$kind}{$word}}, $where);
230     }
235 ## ----------------------- ##
236 ## Scanning source files.  ##
237 ## ----------------------- ##
240 # scan_c_file ($FILE-NAME)
241 # ------------------------
242 sub scan_c_file ($)
244   my ($file_name) = @_;
245   push @cfiles, $File::Find::name;
247   # Nonzero if in a multiline comment.
248   my $in_comment = 0;
250   my $file = new Autom4te::XFile "< " . open_quote ($file_name);
252   while ($_ = $file->getline)
253     {
254       # Strip out comments.
255       if ($in_comment && s,^.*?\*/,,)
256         {
257           $in_comment = 0;
258         }
259       # The whole line is inside a commment.
260       next if $in_comment;
261       # All on one line.
262       s,/\*.*?\*/,,g;
264       # Starting on this line.
265       if (s,/\*.*$,,)
266         {
267           $in_comment = 1;
268         }
270       # Preprocessor directives.
271       if (s/^\s*\#\s*//)
272         {
273           if (/^include\s*<([^>]*)>/)
274             {
275               used ('header', $1);
276             }
277           if (s/^(if|ifdef|ifndef|elif)\s+//)
278             {
279               foreach my $word (split (/\W+/))
280                 {
281                   used ('identifier', $word)
282                     unless $word eq 'defined' || $word !~ /^[a-zA-Z_]/;
283                 }
284             }
285           # Ignore other preprocessor directives.
286           next;
287         }
289       # Remove string and character constants.
290       s,\"[^\"]*\",,g;
291       s,\'[^\']*\',,g;
293       # Tokens in the code.
294       # Maybe we should ignore function definitions (in column 0)?
295       while (s/\b([a-zA-Z_]\w*)\s*\(/ /)
296         {
297           used ('function', $1);
298         }
299       while (s/\b([a-zA-Z_]\w*)\b/ /)
300         {
301           used ('identifier', $1);
302         }
303     }
305   $file->close;
309 # scan_makefile($MAKEFILE-NAME)
310 # -----------------------------
311 sub scan_makefile ($)
313   my ($file_name) = @_;
314   push @makefiles, $File::Find::name;
316   my $file = new Autom4te::XFile "< " . open_quote ($file_name);
318   while ($_ = $file->getline)
319     {
320       # Strip out comments.
321       s/#.*//;
323       # Variable assignments.
324       while (s/\b([a-zA-Z_]\w*)\s*=/ /)
325         {
326           used ('makevar', $1);
327         }
328       # Be sure to catch a whole word.  For instance `lex$U.$(OBJEXT)'
329       # is a single token.  Otherwise we might believe `lex' is needed.
330       foreach my $word (split (/\s+/))
331         {
332           # Libraries.
333           if ($word =~ /^-l([a-zA-Z_]\w*)$/)
334             {
335               used ('library', $1);
336             }
337           # Tokens in the code.
338           # We allow some additional characters, e.g., `+', since
339           # autoscan/programs includes `c++'.
340           if ($word =~ /^[a-zA-Z_][\w+]*$/)
341             {
342               used ('program', $word);
343             }
344         }
345     }
347   $file->close;
351 # scan_sh_file($SHELL-SCRIPT-NAME)
352 # --------------------------------
353 sub scan_sh_file ($)
355   my ($file_name) = @_;
356   push @shfiles, $File::Find::name;
358   my $file = new Autom4te::XFile "< " . open_quote ($file_name);
360   while ($_ = $file->getline)
361     {
362       # Strip out comments and variable references.
363       s/#.*//;
364       s/\${[^\}]*}//g;
365       s/@[^@]*@//g;
367       # Tokens in the code.
368       while (s/\b([a-zA-Z_]\w*)\b/ /)
369         {
370           used ('program', $1);
371         }
372     }
374   $file->close;
378 # scan_file ()
379 # ------------
380 # Called by &find on each file.  $_ contains the current file name with
381 # the current directory of the walk through.
382 sub scan_file ()
384   # Wanted only if there is no corresponding FILE.in.
385   return
386     if -f "$_.in";
388   # Save $_ as Find::File requires it to be preserved.
389   local $_ = $_;
391   # Strip a useless leading `./'.
392   $File::Find::name =~ s,^\./,,;
394   if ($_ ne '.' and -d $_ and
395       -f "$_/configure.in"  ||
396       -f "$_/configure.ac"  ||
397       -f "$_/configure.gnu" ||
398       -f "$_/configure")
399     {
400       $File::Find::prune = 1;
401       push @subdirs, $File::Find::name;
402     }
403   if (/\.[chlym](\.in)?$/)
404     {
405       used 'program', 'cc', $File::Find::name;
406       scan_c_file ($_);
407     }
408   elsif (/\.(cc|cpp|cxx|CC|C|hh|hpp|hxx|HH|H|yy|ypp|ll|lpp)(\.in)?$/)
409     {
410       used 'program', 'c++', $File::Find::name;
411       scan_c_file ($_);
412     }
413   elsif ((/^((?:GNUm|M|m)akefile)(\.in)?$/ && ! -f "$1.am")
414          || /^(?:GNUm|M|m)akefile(\.am)?$/)
415     {
416       scan_makefile ($_);
417     }
418   elsif (/\.sh(\.in)?$/)
419     {
420       scan_sh_file ($_);
421     }
425 # scan_files ()
426 # -------------
427 # Read through the files and collect lists of tokens in them
428 # that might create nonportabilities.
429 sub scan_files ()
431   find (\&scan_file, '.');
433   if ($verbose)
434     {
435       print "cfiles: @cfiles\n";
436       print "makefiles: @makefiles\n";
437       print "shfiles: @shfiles\n";
439       foreach my $kind (@kinds)
440         {
441           print "\n$kind:\n";
442           foreach my $word (sort keys %{$used{$kind}})
443             {
444               print "$word: @{$used{$kind}{$word}}\n";
445             }
446         }
447     }
451 ## ----------------------- ##
452 ## Output configure.scan.  ##
453 ## ----------------------- ##
456 # output_kind ($FILE, $KIND)
457 # --------------------------
458 sub output_kind ($$)
460   my ($file, $kind) = @_;
461   # Lists of words to be checked with the generic macro.
462   my @have;
464   print $file "\n# $kind_comment{$kind}\n"
465     if exists $kind_comment{$kind};
466   foreach my $word (sort keys %{$used{$kind}})
467     {
468       # Output the needed macro invocations in $configure_scan if not
469       # already printed, and remember these macros are needed.
470       foreach my $macro (@{$macro{$kind}{$word}})
471         {
472           if ($macro =~ /^warn:\s+(.*)/)
473             {
474               my $message = $1;
475               foreach my $location (@{$used{$kind}{$word}})
476                 {
477                   warn "$location: warning: $message\n";
478                 }
479             }
480           elsif (exists $generic_macro{$kind}
481               && $macro eq $generic_macro{$kind})
482             {
483               push (@have, $word);
484               push (@{$needed_macros{"$generic_macro{$kind}([$word])"}},
485                     @{$used{$kind}{$word}});
486             }
487           else
488             {
489               if (! $printed{$macro})
490                 {
491                   print $file "$macro\n";
492                   $printed{$macro} = 1;
493                 }
494               push (@{$needed_macros{$macro}},
495                     @{$used{$kind}{$word}});
496             }
497         }
498     }
499   print $file "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
500     if @have;
504 # output_libraries ($FILE)
505 # ------------------------
506 sub output_libraries ($)
508   my ($file) = @_;
510   print $file "\n# Checks for libraries.\n";
511   foreach my $word (sort keys %{$used{'library'}})
512     {
513       print $file "# FIXME: Replace `main' with a function in `-l$word':\n";
514       print $file "AC_CHECK_LIB([$word], [main])\n";
515     }
519 # output ($CONFIGURE_SCAN)
520 # ------------------------
521 # Print a proto configure.ac.
522 sub output ($)
524   my $configure_scan = shift;
525   my %unique_makefiles;
527   my $file = new Autom4te::XFile "> " . open_quote ($configure_scan);
529   print $file
530     ("#                                               -*- Autoconf -*-\n" .
531      "# Process this file with autoconf to produce a configure script.\n" .
532      "\n" .
533      "AC_PREREQ([@VERSION@])\n" .
534      "AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])\n");
535   if (defined $cfiles[0])
536     {
537       print $file "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
538       print $file "AC_CONFIG_HEADERS([config.h])\n";
539     }
541   output_kind ($file, 'program');
542   output_kind ($file, 'makevar');
543   output_libraries ($file);
544   output_kind ($file, 'header');
545   output_kind ($file, 'identifier');
546   output_kind ($file, 'function');
548   print $file "\n";
549   if (@makefiles)
550     {
551       # Change DIR/Makefile.in to DIR/Makefile.
552       foreach my $m (@makefiles)
553         {
554           $m =~ s/\.(?:in|am)$//;
555           $unique_makefiles{$m}++;
556         }
557       print $file ("AC_CONFIG_FILES([",
558                    join ("\n                 ",
559                          sort keys %unique_makefiles), "])\n");
560     }
561   if (@subdirs)
562     {
563       print $file ("AC_CONFIG_SUBDIRS([",
564                    join ("\n                   ",
565                          sort @subdirs), "])\n");
566     }
567   print $file "AC_OUTPUT\n";
569   $file->close;
574 ## --------------------------------------- ##
575 ## Checking the accuracy of configure.ac.  ##
576 ## --------------------------------------- ##
579 # &check_configure_ac ($CONFIGURE_AC)
580 # -----------------------------------
581 # Use autoconf to check if all the suggested macros are included
582 # in CONFIGURE_AC.
583 sub check_configure_ac ($)
585   my ($configure_ac) = @_;
587   # Find what needed macros are invoked in CONFIGURE_AC.
588   # I'd be very happy if someone could explain to me why sort (uniq ...)
589   # doesn't work properly: I need `uniq (sort ...)'.  --akim
590   my $trace_option =
591     join (' --trace=', '',
592           uniq (sort (map { s/\(.*//; $_ } keys %needed_macros)));
594   verb "running: $autoconf $trace_option $configure_ac";
595   my $traces =
596     new Autom4te::XFile "$autoconf $trace_option $configure_ac |";
598   while ($_ = $traces->getline)
599     {
600       chomp;
601       my ($file, $line, $macro, @args) = split (/:/, $_);
602       if ($macro =~ /^AC_CHECK_(HEADER|FUNC|TYPE|MEMBER)S$/)
603         {
604           # To be rigorous, we should distinguish between space and comma
605           # separated macros.  But there is no point.
606           foreach my $word (split (/\s|,/, $args[0]))
607             {
608               # AC_CHECK_MEMBERS wants `struct' or `union'.
609               if ($macro eq "AC_CHECK_MEMBERS"
610                   && $word =~ /^stat.st_/)
611                 {
612                   $word = "struct " . $word;
613                 }
614               delete $needed_macros{"$macro([$word])"};
615             }
616         }
617       else
618         {
619           delete $needed_macros{$macro};
620         }
621     }
623   $traces->close;
625   # Report the missing macros.
626   foreach my $macro (sort keys %needed_macros)
627     {
628       warn ("$configure_ac: warning: missing $macro wanted by: "
629             . (${$needed_macros{$macro}}[0])
630             . "\n");
631       print $log "$me: warning: missing $macro wanted by: \n";
632       foreach my $need (@{$needed_macros{$macro}})
633         {
634           print $log "\t$need\n";
635         }
636     }
640 ## -------------- ##
641 ## Main program.  ##
642 ## -------------- ##
644 parse_args;
645 $log = new Autom4te::XFile "> " . open_quote ("$me.log");
647 $autoconf .= " --debug" if $debug;
648 $autoconf .= " --verbose" if $verbose;
649 $autoconf .= join (' --include=', '', map { shell_quote ($_) } @include);
650 $autoconf .= join (' --prepend-include=', '', map { shell_quote ($_) } @prepend_include);
652 my $configure_ac = find_configure_ac;
653 init_tables;
654 scan_files;
655 output ('configure.scan');
656 if (-f $configure_ac)
657   {
658     check_configure_ac ($configure_ac);
659   }
660 # This close is really needed.  For some reason, probably best named
661 # a bug, it seems that the dtor of $LOG is not called automatically
662 # at END.  It results in a truncated file.
663 $log->close;
664 exit 0;
666 ### Setup "GNU" style for perl-mode and cperl-mode.
667 ## Local Variables:
668 ## perl-indent-level: 2
669 ## perl-continued-statement-offset: 2
670 ## perl-continued-brace-offset: 0
671 ## perl-brace-offset: 0
672 ## perl-brace-imaginary-offset: 0
673 ## perl-label-offset: -2
674 ## cperl-indent-level: 2
675 ## cperl-brace-offset: 0
676 ## cperl-continued-brace-offset: 0
677 ## cperl-label-offset: -2
678 ## cperl-extra-newline-before-brace: t
679 ## cperl-merge-trailing-else: nil
680 ## cperl-continued-statement-offset: 2
681 ## End: