This change prompted by a problem report by Andrey Simonenko in
[autoconf.git] / bin / autoscan.in
blob890108c50eda6950a47b34ff4887e271e2e40b99
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 #  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 $datadir = $ENV{'autom4te_perllibdir'} || '@datadir@';
32   unshift @INC, $datadir;
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 = ('@datadir@');
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>.\n";
123 # $version
124 # --------
125 $version = "autoscan (@PACKAGE_NAME@) @VERSION@
126 Copyright (C) 2006 Free Software Foundation, Inc.
127 This is free software.  You may redistribute copies of it under the terms of
128 the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
129 There is NO WARRANTY, to the extent permitted by law.
131 Written by David J. MacKenzie and Akim Demaille.
137 ## ------------------------ ##
138 ## Command line interface.  ##
139 ## ------------------------ ##
141 # parse_args ()
142 # -------------
143 # Process any command line arguments.
144 sub parse_args ()
146   getopt ('I|include=s' => \@include,
147           'B|prepend-include=s' => \@prepend_include);
149   die "$me: too many arguments
150 Try `$me --help' for more information.\n"
151     if @ARGV > 1;
153   my $srcdir = $ARGV[0] || ".";
155   verb "srcdir = $srcdir";
156   chdir $srcdir || error "cannot cd to $srcdir: $!";
160 # init_tables ()
161 # --------------
162 # Put values in the tables of what to do with each token.
163 sub init_tables ()
165   # The data file format supports only one line of macros per function.
166   # If more than that is required for a common portability problem,
167   # a new Autoconf macro should probably be written for that case,
168   # instead of duplicating the code in lots of configure.ac files.
169   my $file = find_file ("autoscan/autoscan.list",
170                         reverse (@prepend_include), @include);
171   my $table = new Autom4te::XFile $file;
172   my $tables_are_consistent = 1;
174   while ($_ = $table->getline)
175     {
176       # Ignore blank lines and comments.
177       next
178         if /^\s*$/ || /^\s*\#/;
180       # '<kind>: <word> <macro invocation>' or...
181       # '<kind>: <word> warn: <message>'.
182       if (/^(\S+):\s+(\S+)\s+(\S.*)$/)
183         {
184           my ($kind, $word, $macro) = ($1, $2, $3);
185           error "$file:$.: invalid kind: $_"
186             unless grep { $_ eq $kind } @kinds;
187           push @{$macro{$kind}{$word}}, $macro;
188         }
189       else
190         {
191           error "$file:$.: invalid definition: $_";
192         }
193     }
195   if ($debug)
196     {
197       foreach my $kind (@kinds)
198         {
199           foreach my $word (sort keys %{$macro{$kind}})
200             {
201               print "$kind: $word: @{$macro{$kind}{$word}}\n";
202             }
203         }
205     }
209 # used ($KIND, $WORD, [$WHERE])
210 # -----------------------------
211 # $WORD is used as a $KIND.
212 sub used ($$;$)
214   my ($kind, $word, $where) = @_;
215   $where ||= "$File::Find::name:$.";
216   if (
217       # Check for all the libraries.  But `-links' is certainly a
218       # `find' argument, and `-le', a `test' argument.
219       ($kind eq 'library' && $word !~ /^(e|inks)$/)
220       # Other than libraries are to be checked only if listed in
221       # the Autoscan library files.
222       || defined $macro{$kind}{$word}
223      )
224     {
225       push (@{$used{$kind}{$word}}, $where);
226     }
231 ## ----------------------- ##
232 ## Scanning source files.  ##
233 ## ----------------------- ##
236 # scan_c_file ($FILE-NAME)
237 # ------------------------
238 sub scan_c_file ($)
240   my ($file_name) = @_;
241   push @cfiles, $File::Find::name;
243   # Nonzero if in a multiline comment.
244   my $in_comment = 0;
246   my $file = new Autom4te::XFile "<$file_name";
248   while ($_ = $file->getline)
249     {
250       # Strip out comments.
251       if ($in_comment && s,^.*?\*/,,)
252         {
253           $in_comment = 0;
254         }
255       # The whole line is inside a commment.
256       next if $in_comment;
257       # All on one line.
258       s,/\*.*?\*/,,g;
260       # Starting on this line.
261       if (s,/\*.*$,,)
262         {
263           $in_comment = 1;
264         }
266       # Preprocessor directives.
267       if (s/^\s*\#\s*//)
268         {
269           if (/^include\s*<([^>]*)>/)
270             {
271               used ('header', $1);
272             }
273           if (s/^(if|ifdef|ifndef|elif)\s+//)
274             {
275               foreach my $word (split (/\W+/))
276                 {
277                   used ('identifier', $word)
278                     unless $word eq 'defined' || $word !~ /^[a-zA-Z_]/;
279                 }
280             }
281           # Ignore other preprocessor directives.
282           next;
283         }
285       # Remove string and character constants.
286       s,\"[^\"]*\",,g;
287       s,\'[^\']*\',,g;
289       # Tokens in the code.
290       # Maybe we should ignore function definitions (in column 0)?
291       while (s/\b([a-zA-Z_]\w*)\s*\(/ /)
292         {
293           used ('function', $1);
294         }
295       while (s/\b([a-zA-Z_]\w*)\b/ /)
296         {
297           used ('identifier', $1);
298         }
299     }
301   $file->close;
305 # scan_makefile($MAKEFILE-NAME)
306 # -----------------------------
307 sub scan_makefile ($)
309   my ($file_name) = @_;
310   push @makefiles, $File::Find::name;
312   my $file = new Autom4te::XFile "<$file_name";
314   while ($_ = $file->getline)
315     {
316       # Strip out comments.
317       s/#.*//;
319       # Variable assignments.
320       while (s/\b([a-zA-Z_]\w*)\s*=/ /)
321         {
322           used ('makevar', $1);
323         }
324       # Be sure to catch a whole word.  For instance `lex$U.$(OBJEXT)'
325       # is a single token.  Otherwise we might believe `lex' is needed.
326       foreach my $word (split (/\s+/))
327         {
328           # Libraries.
329           if ($word =~ /^-l([a-zA-Z_]\w*)$/)
330             {
331               used ('library', $1);
332             }
333           # Tokens in the code.
334           # We allow some additional characters, e.g., `+', since
335           # autoscan/programs includes `c++'.
336           if ($word =~ /^[a-zA-Z_][\w+]*$/)
337             {
338               used ('program', $word);
339             }
340         }
341     }
343   $file->close;
347 # scan_sh_file($SHELL-SCRIPT-NAME)
348 # --------------------------------
349 sub scan_sh_file ($)
351   my ($file_name) = @_;
352   push @shfiles, $File::Find::name;
354   my $file = new Autom4te::XFile "<$file_name";
356   while ($_ = $file->getline)
357     {
358       # Strip out comments and variable references.
359       s/#.*//;
360       s/\${[^\}]*}//g;
361       s/@[^@]*@//g;
363       # Tokens in the code.
364       while (s/\b([a-zA-Z_]\w*)\b/ /)
365         {
366           used ('program', $1);
367         }
368     }
370   $file->close;
374 # scan_file ()
375 # ------------
376 # Called by &find on each file.  $_ contains the current file name with
377 # the current directory of the walk through.
378 sub scan_file ()
380   # Wanted only if there is no corresponding FILE.in.
381   return
382     if -f "$_.in";
384   # Save $_ as Find::File requires it to be preserved.
385   local $_ = $_;
387   # Strip a useless leading `./'.
388   $File::Find::name =~ s,^\./,,;
390   if ($_ ne '.' and -d $_ and
391       -f "$_/configure.in"  ||
392       -f "$_/configure.ac"  ||
393       -f "$_/configure.gnu" ||
394       -f "$_/configure")
395     {
396       $File::Find::prune = 1;
397       push @subdirs, $File::Find::name;
398     }
399   if (/\.[chlym](\.in)?$/)
400     {
401       used 'program', 'cc', $File::Find::name;
402       scan_c_file ($_);
403     }
404   elsif (/\.(cc|cpp|cxx|CC|C|hh|hpp|hxx|HH|H|yy|ypp|ll|lpp)(\.in)?$/)
405     {
406       used 'program', 'c++', $File::Find::name;
407       scan_c_file ($_);
408     }
409   elsif ((/^((?:GNUm|M|m)akefile)(\.in)?$/ && ! -f "$1.am")
410          || /^(?:GNUm|M|m)akefile(\.am)?$/)
411     {
412       scan_makefile ($_);
413     }
414   elsif (/\.sh(\.in)?$/)
415     {
416       scan_sh_file ($_);
417     }
421 # scan_files ()
422 # -------------
423 # Read through the files and collect lists of tokens in them
424 # that might create nonportabilities.
425 sub scan_files ()
427   find (\&scan_file, '.');
429   if ($verbose)
430     {
431       print "cfiles: @cfiles\n";
432       print "makefiles: @makefiles\n";
433       print "shfiles: @shfiles\n";
435       foreach my $kind (@kinds)
436         {
437           print "\n$kind:\n";
438           foreach my $word (sort keys %{$used{$kind}})
439             {
440               print "$word: @{$used{$kind}{$word}}\n";
441             }
442         }
443     }
447 ## ----------------------- ##
448 ## Output configure.scan.  ##
449 ## ----------------------- ##
452 # output_kind ($FILE, $KIND)
453 # --------------------------
454 sub output_kind ($$)
456   my ($file, $kind) = @_;
457   # Lists of words to be checked with the generic macro.
458   my @have;
460   print $file "\n# $kind_comment{$kind}\n"
461     if exists $kind_comment{$kind};
462   foreach my $word (sort keys %{$used{$kind}})
463     {
464       # Output the needed macro invocations in $configure_scan if not
465       # already printed, and remember these macros are needed.
466       foreach my $macro (@{$macro{$kind}{$word}})
467         {
468           if ($macro =~ /^warn:\s+(.*)/)
469             {
470               my $message = $1;
471               foreach my $location (@{$used{$kind}{$word}})
472                 {
473                   warn "$location: warning: $message\n";
474                 }
475             }
476           elsif (exists $generic_macro{$kind}
477               && $macro eq $generic_macro{$kind})
478             {
479               push (@have, $word);
480               push (@{$needed_macros{"$generic_macro{$kind}([$word])"}},
481                     @{$used{$kind}{$word}});
482             }
483           else
484             {
485               if (! $printed{$macro})
486                 {
487                   print $file "$macro\n";
488                   $printed{$macro} = 1;
489                 }
490               push (@{$needed_macros{$macro}},
491                     @{$used{$kind}{$word}});
492             }
493         }
494     }
495   print $file "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
496     if @have;
500 # output_libraries ($FILE)
501 # ------------------------
502 sub output_libraries ($)
504   my ($file) = @_;
506   print $file "\n# Checks for libraries.\n";
507   foreach my $word (sort keys %{$used{'library'}})
508     {
509       print $file "# FIXME: Replace `main' with a function in `-l$word':\n";
510       print $file "AC_CHECK_LIB([$word], [main])\n";
511     }
515 # output ($CONFIGURE_SCAN)
516 # ------------------------
517 # Print a proto configure.ac.
518 sub output ($)
520   my $configure_scan = shift;
521   my %unique_makefiles;
523   my $file = new Autom4te::XFile ">$configure_scan";
525   print $file
526     ("#                                               -*- Autoconf -*-\n" .
527      "# Process this file with autoconf to produce a configure script.\n" .
528      "\n" .
529      "AC_PREREQ(@VERSION@)\n" .
530      "AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)\n");
531   if (defined $cfiles[0])
532     {
533       print $file "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
534       print $file "AC_CONFIG_HEADER([config.h])\n";
535     }
537   output_kind ($file, 'program');
538   output_kind ($file, 'makevar');
539   output_libraries ($file);
540   output_kind ($file, 'header');
541   output_kind ($file, 'identifier');
542   output_kind ($file, 'function');
544   print $file "\n";
545   if (@makefiles)
546     {
547       # Change DIR/Makefile.in to DIR/Makefile.
548       foreach my $m (@makefiles)
549         {
550           $m =~ s/\.(?:in|am)$//;
551           $unique_makefiles{$m}++;
552         }
553       print $file ("AC_CONFIG_FILES([",
554                    join ("\n                 ",
555                          sort keys %unique_makefiles), "])\n");
556     }
557   if (@subdirs)
558     {
559       print $file ("AC_CONFIG_SUBDIRS([",
560                    join ("\n                   ",
561                          sort @subdirs), "])\n");
562     }
563   print $file "AC_OUTPUT\n";
565   $file->close;
570 ## --------------------------------------- ##
571 ## Checking the accuracy of configure.ac.  ##
572 ## --------------------------------------- ##
575 # &check_configure_ac ($CONFIGURE_AC)
576 # -----------------------------------
577 # Use autoconf to check if all the suggested macros are included
578 # in CONFIGURE_AC.
579 sub check_configure_ac ($)
581   my ($configure_ac) = @_;
583   # Find what needed macros are invoked in CONFIGURE_AC.
584   # I'd be very happy if someone could explain to me why sort (uniq ...)
585   # doesn't work properly: I need `uniq (sort ...)'.  --akim
586   my $trace_option =
587     join (' --trace=', '',
588           uniq (sort (map { s/\(.*//; $_ } keys %needed_macros)));
590   verb "running: $autoconf $trace_option $configure_ac";
591   my $traces =
592     new Autom4te::XFile "$autoconf $trace_option $configure_ac|";
594   while ($_ = $traces->getline)
595     {
596       chomp;
597       my ($file, $line, $macro, @args) = split (/:/, $_);
598       if ($macro =~ /^AC_CHECK_(HEADER|FUNC|TYPE|MEMBER)S$/)
599         {
600           # To be rigorous, we should distinguish between space and comma
601           # separated macros.  But there is no point.
602           foreach my $word (split (/\s|,/, $args[0]))
603             {
604               # AC_CHECK_MEMBERS wants `struct' or `union'.
605               if ($macro eq "AC_CHECK_MEMBERS"
606                   && $word =~ /^stat.st_/)
607                 {
608                   $word = "struct " . $word;
609                 }
610               delete $needed_macros{"$macro([$word])"};
611             }
612         }
613       else
614         {
615           delete $needed_macros{$macro};
616         }
617     }
619   $traces->close;
621   # Report the missing macros.
622   foreach my $macro (sort keys %needed_macros)
623     {
624       warn ("$configure_ac: warning: missing $macro wanted by: "
625             . (${$needed_macros{$macro}}[0])
626             . "\n");
627       print $log "$me: warning: missing $macro wanted by: \n";
628       foreach my $need (@{$needed_macros{$macro}})
629         {
630           print $log "\t$need\n";
631         }
632     }
636 ## -------------- ##
637 ## Main program.  ##
638 ## -------------- ##
640 parse_args;
641 $log = new Autom4te::XFile ">$me.log";
643 $autoconf .= " --debug" if $debug;
644 $autoconf .= " --verbose" if $verbose;
645 $autoconf .= join (' --include=', '', @include);
646 $autoconf .= join (' --prepend-include=', '', @prepend_include);
648 my $configure_ac = find_configure_ac;
649 init_tables;
650 scan_files;
651 output ('configure.scan');
652 if (-f $configure_ac)
653   {
654     check_configure_ac ($configure_ac);
655   }
656 # This close is really needed.  For some reason, probably best named
657 # a bug, it seems that the dtor of $LOG is not called automatically
658 # at END.  It results in a truncated file.
659 $log->close;
660 exit 0;
662 ### Setup "GNU" style for perl-mode and cperl-mode.
663 ## Local Variables:
664 ## perl-indent-level: 2
665 ## perl-continued-statement-offset: 2
666 ## perl-continued-brace-offset: 0
667 ## perl-brace-offset: 0
668 ## perl-brace-imaginary-offset: 0
669 ## perl-label-offset: -2
670 ## cperl-indent-level: 2
671 ## cperl-brace-offset: 0
672 ## cperl-continued-brace-offset: 0
673 ## cperl-label-offset: -2
674 ## cperl-extra-newline-before-brace: t
675 ## cperl-merge-trailing-else: nil
676 ## cperl-continued-statement-offset: 2
677 ## End: