Describe a Solaris /bin/sh bug w.r.t. for loops.
[autoconf.git] / bin / autoscan.in
blob7623a99ea96b7d7c117689bac09c2a0400d40cf6
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, 2010 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 3 of the License, or
12 # (at your option) 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, see <http://www.gnu.org/licenses/>.
22 # Written by David MacKenzie <djm@gnu.ai.mit.edu>.
24 eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
25     if 0;
27 BEGIN
29   my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
30   unshift @INC, $pkgdatadir;
32   # Override SHELL.  On DJGPP SHELL may not be set to a shell
33   # that can handle redirection and quote arguments correctly,
34   # e.g.: COMMAND.COM.  For DJGPP always use the shell that configure
35   # has detected.
36   $ENV{'SHELL'} = '@SHELL@' if ($^O eq 'dos');
39 use Autom4te::ChannelDefs;
40 use Autom4te::Configure_ac;
41 use Autom4te::General;
42 use Autom4te::FileUtils;
43 use Autom4te::XFile;
44 use File::Basename;
45 use File::Find;
46 use strict;
48 use vars qw(@cfiles @makefiles @shfiles @subdirs %printed);
50 # The kind of the words we are looking for.
51 my @kinds = qw (function header identifier program
52                 makevar librarie);
54 # For each kind, the default macro.
55 my %generic_macro =
56   (
57    'function'   => 'AC_CHECK_FUNCS',
58    'header'     => 'AC_CHECK_HEADERS',
59    'identifier' => 'AC_CHECK_TYPES',
60    'program'    => 'AC_CHECK_PROGS',
61    'library'    => 'AC_CHECK_LIB'
62   );
64 my %kind_comment =
65   (
66    'function'   => 'Checks for library functions.',
67    'header'     => 'Checks for header files.',
68    'identifier' => 'Checks for typedefs, structures, and compiler characteristics.',
69    'program'    => 'Checks for programs.',
70   );
72 # $USED{KIND}{ITEM} is the list of locations where the ITEM (of KIND) was used
73 # in the user package.
74 # For instance $USED{function}{alloca} is the list of `file:line' where
75 # `alloca (...)' appears.
76 my %used = ();
78 # $MACRO{KIND}{ITEM} is the list of macros to use to test ITEM.
79 # Initialized from lib/autoscan/*.  E.g., $MACRO{function}{alloca} contains
80 # the singleton AC_FUNC_ALLOCA.  Some require several checks.
81 my %macro = ();
83 # $NEEDED_MACROS{MACRO} is an array of locations requiring MACRO.
84 # E.g., $NEEDED_MACROS{AC_FUNC_ALLOC} the list of `file:line' containing
85 # `alloca (...)'.
86 my %needed_macros =
87   (
88    'AC_PREREQ' => [$me],
89   );
91 my $configure_scan = 'configure.scan';
92 my $log;
94 # Autoconf and lib files.
95 my $autom4te = $ENV{'AUTOM4TE'} || '@bindir@/@autom4te-name@';
96 my $autoconf = "$autom4te --language=autoconf";
97 my @prepend_include;
98 my @include = ('@pkgdatadir@');
100 # $help
101 # -----
102 $help = "Usage: $0 [OPTION]... [SRCDIR]
104 Examine source files in the directory tree rooted at SRCDIR, or the
105 current directory if none is given.  Search the source files for
106 common portability problems, check for incompleteness of
107 `configure.ac', and create a file `$configure_scan' which is a
108 preliminary `configure.ac' for that package.
110   -h, --help          print this help, then exit
111   -V, --version       print version number, then exit
112   -v, --verbose       verbosely report processing
113   -d, --debug         don't remove temporary files
115 Library directories:
116   -B, --prepend-include=DIR  prepend directory DIR to search path
117   -I, --include=DIR          append directory DIR to search path
119 Report bugs to <bug-autoconf\@gnu.org>.
120 GNU Autoconf home page: <http://www.gnu.org/software/autoconf/>.
121 General help using GNU software: <http://www.gnu.org/gethelp/>.
124 # $version
125 # --------
126 $version = "autoscan (@PACKAGE_NAME@) @VERSION@
127 Copyright (C) @RELEASE_YEAR@ Free Software Foundation, Inc.
128 License GPLv3+/Autoconf: GNU GPL version 3 or later
129 <http://gnu.org/licenses/gpl.html>, <http://gnu.org/licenses/exceptions.html>
130 This is free software: you are free to change and redistribute it.
131 There is NO WARRANTY, to the extent permitted by law.
133 Written by David J. MacKenzie and Akim Demaille.
139 ## ------------------------ ##
140 ## Command line interface.  ##
141 ## ------------------------ ##
143 # parse_args ()
144 # -------------
145 # Process any command line arguments.
146 sub parse_args ()
148   getopt ('I|include=s' => \@include,
149           'B|prepend-include=s' => \@prepend_include);
151   die "$me: too many arguments
152 Try `$me --help' for more information.\n"
153     if @ARGV > 1;
155   my $srcdir = $ARGV[0] || ".";
157   verb "srcdir = $srcdir";
158   chdir $srcdir || error "cannot cd to $srcdir: $!";
162 # init_tables ()
163 # --------------
164 # Put values in the tables of what to do with each token.
165 sub init_tables ()
167   # The data file format supports only one line of macros per function.
168   # If more than that is required for a common portability problem,
169   # a new Autoconf macro should probably be written for that case,
170   # instead of duplicating the code in lots of configure.ac files.
171   my $file = find_file ("autoscan/autoscan.list",
172                         reverse (@prepend_include), @include);
173   my $table = new Autom4te::XFile "< " . open_quote ($file);
174   my $tables_are_consistent = 1;
176   while ($_ = $table->getline)
177     {
178       # Ignore blank lines and comments.
179       next
180         if /^\s*$/ || /^\s*\#/;
182       # '<kind>: <word> <macro invocation>' or...
183       # '<kind>: <word> warn: <message>'.
184       if (/^(\S+):\s+(\S+)\s+(\S.*)$/)
185         {
186           my ($kind, $word, $macro) = ($1, $2, $3);
187           error "$file:$.: invalid kind: $_"
188             unless grep { $_ eq $kind } @kinds;
189           push @{$macro{$kind}{$word}}, $macro;
190         }
191       else
192         {
193           error "$file:$.: invalid definition: $_";
194         }
195     }
197   if ($debug)
198     {
199       foreach my $kind (@kinds)
200         {
201           foreach my $word (sort keys %{$macro{$kind}})
202             {
203               print "$kind: $word: @{$macro{$kind}{$word}}\n";
204             }
205         }
207     }
211 # used ($KIND, $WORD, [$WHERE])
212 # -----------------------------
213 # $WORD is used as a $KIND.
214 sub used ($$;$)
216   my ($kind, $word, $where) = @_;
217   $where ||= "$File::Find::name:$.";
218   if (
219       # Check for all the libraries.  But `-links' is certainly a
220       # `find' argument, and `-le', a `test' argument.
221       ($kind eq 'library' && $word !~ /^(e|inks)$/)
222       # Other than libraries are to be checked only if listed in
223       # the Autoscan library files.
224       || defined $macro{$kind}{$word}
225      )
226     {
227       push (@{$used{$kind}{$word}}, $where);
228     }
233 ## ----------------------- ##
234 ## Scanning source files.  ##
235 ## ----------------------- ##
238 # scan_c_file ($FILE-NAME)
239 # ------------------------
240 sub scan_c_file ($)
242   my ($file_name) = @_;
243   push @cfiles, $File::Find::name;
245   # Nonzero if in a multiline comment.
246   my $in_comment = 0;
248   my $file = new Autom4te::XFile "< " . open_quote ($file_name);
250   while ($_ = $file->getline)
251     {
252       # Strip out comments.
253       if ($in_comment && s,^.*?\*/,,)
254         {
255           $in_comment = 0;
256         }
257       # The whole line is inside a commment.
258       next if $in_comment;
259       # All on one line.
260       s,/\*.*?\*/,,g;
262       # Starting on this line.
263       if (s,/\*.*$,,)
264         {
265           $in_comment = 1;
266         }
268       # Preprocessor directives.
269       if (s/^\s*\#\s*//)
270         {
271           if (/^include\s*<([^>]*)>/)
272             {
273               used ('header', $1);
274             }
275           if (s/^(if|ifdef|ifndef|elif)\s+//)
276             {
277               foreach my $word (split (/\W+/))
278                 {
279                   used ('identifier', $word)
280                     unless $word eq 'defined' || $word !~ /^[a-zA-Z_]/;
281                 }
282             }
283           # Ignore other preprocessor directives.
284           next;
285         }
287       # Remove string and character constants.
288       s,\"[^\"]*\",,g;
289       s,\'[^\']*\',,g;
291       # Tokens in the code.
292       # Maybe we should ignore function definitions (in column 0)?
293       while (s/\b([a-zA-Z_]\w*)\s*\(/ /)
294         {
295           used ('function', $1);
296         }
297       while (s/\b([a-zA-Z_]\w*)\b/ /)
298         {
299           used ('identifier', $1);
300         }
301     }
303   $file->close;
307 # scan_makefile($MAKEFILE-NAME)
308 # -----------------------------
309 sub scan_makefile ($)
311   my ($file_name) = @_;
312   push @makefiles, $File::Find::name;
314   my $file = new Autom4te::XFile "< " . open_quote ($file_name);
316   while ($_ = $file->getline)
317     {
318       # Strip out comments.
319       s/#.*//;
321       # Variable assignments.
322       while (s/\b([a-zA-Z_]\w*)\s*=/ /)
323         {
324           used ('makevar', $1);
325         }
326       # Be sure to catch a whole word.  For instance `lex$U.$(OBJEXT)'
327       # is a single token.  Otherwise we might believe `lex' is needed.
328       foreach my $word (split (/\s+/))
329         {
330           # Libraries.
331           if ($word =~ /^-l([a-zA-Z_]\w*)$/)
332             {
333               used ('library', $1);
334             }
335           # Tokens in the code.
336           # We allow some additional characters, e.g., `+', since
337           # autoscan/programs includes `c++'.
338           if ($word =~ /^[a-zA-Z_][\w+]*$/)
339             {
340               used ('program', $word);
341             }
342         }
343     }
345   $file->close;
349 # scan_sh_file($SHELL-SCRIPT-NAME)
350 # --------------------------------
351 sub scan_sh_file ($)
353   my ($file_name) = @_;
354   push @shfiles, $File::Find::name;
356   my $file = new Autom4te::XFile "< " . open_quote ($file_name);
358   while ($_ = $file->getline)
359     {
360       # Strip out comments and variable references.
361       s/#.*//;
362       s/\${[^\}]*}//g;
363       s/@[^@]*@//g;
365       # Tokens in the code.
366       while (s/\b([a-zA-Z_]\w*)\b/ /)
367         {
368           used ('program', $1);
369         }
370     }
372   $file->close;
376 # scan_file ()
377 # ------------
378 # Called by &find on each file.  $_ contains the current file name with
379 # the current directory of the walk through.
380 sub scan_file ()
382   # Wanted only if there is no corresponding FILE.in.
383   return
384     if -f "$_.in";
386   # Save $_ as Find::File requires it to be preserved.
387   local $_ = $_;
389   # Strip a useless leading `./'.
390   $File::Find::name =~ s,^\./,,;
392   if ($_ ne '.' and -d $_ and
393       -f "$_/configure.in"  ||
394       -f "$_/configure.ac"  ||
395       -f "$_/configure.gnu" ||
396       -f "$_/configure")
397     {
398       $File::Find::prune = 1;
399       push @subdirs, $File::Find::name;
400     }
401   if (/\.[chlym](\.in)?$/)
402     {
403       used 'program', 'cc', $File::Find::name;
404       scan_c_file ($_);
405     }
406   elsif (/\.(cc|cpp|cxx|CC|C|hh|hpp|hxx|HH|H|yy|ypp|ll|lpp)(\.in)?$/)
407     {
408       used 'program', 'c++', $File::Find::name;
409       scan_c_file ($_);
410     }
411   elsif ((/^((?:GNUm|M|m)akefile)(\.in)?$/ && ! -f "$1.am")
412          || /^(?:GNUm|M|m)akefile(\.am)?$/)
413     {
414       scan_makefile ($_);
415     }
416   elsif (/\.sh(\.in)?$/)
417     {
418       scan_sh_file ($_);
419     }
423 # scan_files ()
424 # -------------
425 # Read through the files and collect lists of tokens in them
426 # that might create nonportabilities.
427 sub scan_files ()
429   find (\&scan_file, '.');
431   if ($verbose)
432     {
433       print "cfiles: @cfiles\n";
434       print "makefiles: @makefiles\n";
435       print "shfiles: @shfiles\n";
437       foreach my $kind (@kinds)
438         {
439           print "\n$kind:\n";
440           foreach my $word (sort keys %{$used{$kind}})
441             {
442               print "$word: @{$used{$kind}{$word}}\n";
443             }
444         }
445     }
449 ## ----------------------- ##
450 ## Output configure.scan.  ##
451 ## ----------------------- ##
454 # output_kind ($FILE, $KIND)
455 # --------------------------
456 sub output_kind ($$)
458   my ($file, $kind) = @_;
459   # Lists of words to be checked with the generic macro.
460   my @have;
462   print $file "\n# $kind_comment{$kind}\n"
463     if exists $kind_comment{$kind};
464   foreach my $word (sort keys %{$used{$kind}})
465     {
466       # Output the needed macro invocations in $configure_scan if not
467       # already printed, and remember these macros are needed.
468       foreach my $macro (@{$macro{$kind}{$word}})
469         {
470           if ($macro =~ /^warn:\s+(.*)/)
471             {
472               my $message = $1;
473               foreach my $location (@{$used{$kind}{$word}})
474                 {
475                   warn "$location: warning: $message\n";
476                 }
477             }
478           elsif (exists $generic_macro{$kind}
479               && $macro eq $generic_macro{$kind})
480             {
481               push (@have, $word);
482               push (@{$needed_macros{"$generic_macro{$kind}([$word])"}},
483                     @{$used{$kind}{$word}});
484             }
485           else
486             {
487               if (! $printed{$macro})
488                 {
489                   print $file "$macro\n";
490                   $printed{$macro} = 1;
491                 }
492               push (@{$needed_macros{$macro}},
493                     @{$used{$kind}{$word}});
494             }
495         }
496     }
497   print $file "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
498     if @have;
502 # output_libraries ($FILE)
503 # ------------------------
504 sub output_libraries ($)
506   my ($file) = @_;
508   print $file "\n# Checks for libraries.\n";
509   foreach my $word (sort keys %{$used{'library'}})
510     {
511       print $file "# FIXME: Replace `main' with a function in `-l$word':\n";
512       print $file "AC_CHECK_LIB([$word], [main])\n";
513     }
517 # output ($CONFIGURE_SCAN)
518 # ------------------------
519 # Print a proto configure.ac.
520 sub output ($)
522   my $configure_scan = shift;
523   my %unique_makefiles;
525   my $file = new Autom4te::XFile "> " . open_quote ($configure_scan);
527   print $file
528     ("#                                               -*- Autoconf -*-\n" .
529      "# Process this file with autoconf to produce a configure script.\n" .
530      "\n" .
531      "AC_PREREQ([@VERSION@])\n" .
532      "AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])\n");
533   if (defined $cfiles[0])
534     {
535       print $file "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
536       print $file "AC_CONFIG_HEADERS([config.h])\n";
537     }
539   output_kind ($file, 'program');
540   output_kind ($file, 'makevar');
541   output_libraries ($file);
542   output_kind ($file, 'header');
543   output_kind ($file, 'identifier');
544   output_kind ($file, 'function');
546   print $file "\n";
547   if (@makefiles)
548     {
549       # Change DIR/Makefile.in to DIR/Makefile.
550       foreach my $m (@makefiles)
551         {
552           $m =~ s/\.(?:in|am)$//;
553           $unique_makefiles{$m}++;
554         }
555       print $file ("AC_CONFIG_FILES([",
556                    join ("\n                 ",
557                          sort keys %unique_makefiles), "])\n");
558     }
559   if (@subdirs)
560     {
561       print $file ("AC_CONFIG_SUBDIRS([",
562                    join ("\n                   ",
563                          sort @subdirs), "])\n");
564     }
565   print $file "AC_OUTPUT\n";
567   $file->close;
572 ## --------------------------------------- ##
573 ## Checking the accuracy of configure.ac.  ##
574 ## --------------------------------------- ##
577 # &check_configure_ac ($CONFIGURE_AC)
578 # -----------------------------------
579 # Use autoconf to check if all the suggested macros are included
580 # in CONFIGURE_AC.
581 sub check_configure_ac ($)
583   my ($configure_ac) = @_;
585   # Find what needed macros are invoked in CONFIGURE_AC.
586   # I'd be very happy if someone could explain to me why sort (uniq ...)
587   # doesn't work properly: I need `uniq (sort ...)'.  --akim
588   my $trace_option =
589     join (' --trace=', '',
590           uniq (sort (map { s/\(.*//; $_ } keys %needed_macros)));
592   verb "running: $autoconf $trace_option $configure_ac";
593   my $traces =
594     new Autom4te::XFile "$autoconf $trace_option $configure_ac |";
596   while ($_ = $traces->getline)
597     {
598       chomp;
599       my ($file, $line, $macro, @args) = split (/:/, $_);
600       if ($macro =~ /^AC_CHECK_(HEADER|FUNC|TYPE|MEMBER)S$/)
601         {
602           # To be rigorous, we should distinguish between space and comma
603           # separated macros.  But there is no point.
604           foreach my $word (split (/\s|,/, $args[0]))
605             {
606               # AC_CHECK_MEMBERS wants `struct' or `union'.
607               if ($macro eq "AC_CHECK_MEMBERS"
608                   && $word =~ /^stat.st_/)
609                 {
610                   $word = "struct " . $word;
611                 }
612               delete $needed_macros{"$macro([$word])"};
613             }
614         }
615       else
616         {
617           delete $needed_macros{$macro};
618         }
619     }
621   $traces->close;
623   # Report the missing macros.
624   foreach my $macro (sort keys %needed_macros)
625     {
626       warn ("$configure_ac: warning: missing $macro wanted by: "
627             . (${$needed_macros{$macro}}[0])
628             . "\n");
629       print $log "$me: warning: missing $macro wanted by: \n";
630       foreach my $need (@{$needed_macros{$macro}})
631         {
632           print $log "\t$need\n";
633         }
634     }
638 ## -------------- ##
639 ## Main program.  ##
640 ## -------------- ##
642 parse_args;
643 $log = new Autom4te::XFile "> " . open_quote ("$me.log");
645 $autoconf .= " --debug" if $debug;
646 $autoconf .= " --verbose" if $verbose;
647 $autoconf .= join (' --include=', '', map { shell_quote ($_) } @include);
648 $autoconf .= join (' --prepend-include=', '', map { shell_quote ($_) } @prepend_include);
650 my $configure_ac = find_configure_ac;
651 init_tables;
652 scan_files;
653 output ('configure.scan');
654 if (-f $configure_ac)
655   {
656     check_configure_ac ($configure_ac);
657   }
658 # This close is really needed.  For some reason, probably best named
659 # a bug, it seems that the dtor of $LOG is not called automatically
660 # at END.  It results in a truncated file.
661 $log->close;
662 exit 0;
664 ### Setup "GNU" style for perl-mode and cperl-mode.
665 ## Local Variables:
666 ## perl-indent-level: 2
667 ## perl-continued-statement-offset: 2
668 ## perl-continued-brace-offset: 0
669 ## perl-brace-offset: 0
670 ## perl-brace-imaginary-offset: 0
671 ## perl-label-offset: -2
672 ## cperl-indent-level: 2
673 ## cperl-brace-offset: 0
674 ## cperl-continued-brace-offset: 0
675 ## cperl-label-offset: -2
676 ## cperl-extra-newline-before-brace: t
677 ## cperl-merge-trailing-else: nil
678 ## cperl-continued-statement-offset: 2
679 ## End: