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