make update-copyright
[autoconf.git] / bin / autoscan.in
bloba33c4a871a5a3b4066743c826dd4962d81c7416c
1 #! @PERL@
2 # -*- perl -*-
3 # @configure_input@
5 # autoscan - Create configure.scan (a preliminary configure.ac) for a package.
6 # Copyright (C) 1994, 1999-2017, 2020-2022 Free Software Foundation,
7 # 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 <https://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 use 5.006;
28 use strict;
29 use warnings FATAL => 'all';
31 BEGIN
33   my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
34   unshift @INC, $pkgdatadir;
36   # Override SHELL.  On DJGPP SHELL may not be set to a shell
37   # that can handle redirection and quote arguments correctly,
38   # e.g.: COMMAND.COM.  For DJGPP always use the shell that configure
39   # has detected.
40   $ENV{'SHELL'} = '@SHELL@' if ($^O eq 'dos');
43 use File::Basename;
44 use File::Find;
46 use Autom4te::ChannelDefs;
47 use Autom4te::Configure_ac;
48 use Autom4te::FileUtils;
49 use Autom4te::General;
50 use Autom4te::XFile;
52 my (@cfiles, @makefiles, @shfiles, @subdirs, %printed);
54 # The kind of the words we are looking for.
55 my @kinds = qw (function header identifier program
56                 makevar librarie);
58 # For each kind, the default macro.
59 my %generic_macro =
60   (
61    'function'   => 'AC_CHECK_FUNCS',
62    'header'     => 'AC_CHECK_HEADERS',
63    'identifier' => 'AC_CHECK_TYPES',
64    'program'    => 'AC_CHECK_PROGS',
65    'library'    => 'AC_CHECK_LIB'
66   );
68 my %kind_comment =
69   (
70    'function'   => 'Checks for library functions.',
71    'header'     => 'Checks for header files.',
72    'identifier' => 'Checks for typedefs, structures, and compiler characteristics.',
73    'program'    => 'Checks for programs.',
74   );
76 # $USED{KIND}{ITEM} is the list of locations where the ITEM (of KIND) was
77 # used in the user package.
78 # For instance $USED{function}{alloca} is the list of 'file:line' where
79 # 'alloca (...)' appears.
80 my %used = ();
82 # $MACRO{KIND}{ITEM} is the list of macros to use to test ITEM.
83 # Initialized from lib/autoscan/*.  E.g., $MACRO{function}{alloca} contains
84 # the singleton AC_FUNC_ALLOCA.  Some require several checks.
85 my %macro = ();
87 # $NEEDED_MACROS{MACRO} is an array of locations requiring MACRO.
88 # E.g., $NEEDED_MACROS{AC_FUNC_ALLOC} the list of 'file:line' containing
89 # 'alloca (...)'.
90 my %needed_macros =
91   (
92    'AC_PREREQ' => [$me],
93   );
95 my $log;
97 # Autoconf and lib files.
98 my $autom4te = $ENV{'AUTOM4TE'} || '@bindir@/@autom4te-name@';
99 my $autoconf = "$autom4te --language=autoconf";
100 my @prepend_include;
101 my @include = ('@pkgdatadir@');
103 # $help
104 # -----
105 $help = "Usage: $0 [OPTION]... [SRCDIR]
107 Examine source files in the directory tree rooted at SRCDIR, or the
108 current directory if none is given.  Search the source files for
109 common portability problems, check for incompleteness of
110 'configure.ac', and create a file 'configure.scan' which is a
111 preliminary 'configure.ac' for that package.
113   -h, --help          print this help, then exit
114   -V, --version       print version number, then exit
115   -v, --verbose       verbosely report processing
116   -d, --debug         don't remove temporary files
118 Library directories:
119   -B, --prepend-include=DIR  prepend directory DIR to search path
120   -I, --include=DIR          append directory DIR to search path
122 Report bugs to <bug-autoconf\@gnu.org>.
123 GNU Autoconf home page: <https://www.gnu.org/software/autoconf/>.
124 General help using GNU software: <https://www.gnu.org/gethelp/>.
127 # $version
128 # --------
129 $version = "autoscan (@PACKAGE_NAME@) @VERSION@
130 Copyright (C) @RELEASE_YEAR@ Free Software Foundation, Inc.
131 License GPLv3+/Autoconf: GNU GPL version 3 or later
132 <https://gnu.org/licenses/gpl.html>, <https://gnu.org/licenses/exceptions.html>
133 This is free software: you are free to change and redistribute it.
134 There is NO WARRANTY, to the extent permitted by law.
136 Written by David J. MacKenzie and Akim Demaille.
142 ## ------------------------ ##
143 ## Command line interface.  ##
144 ## ------------------------ ##
146 # parse_args ()
147 # -------------
148 # Process any command line arguments.
149 sub parse_args ()
151   getopt ('I|include=s' => \@include,
152           'B|prepend-include=s' => \@prepend_include);
154   die "$me: too many arguments
155 Try '$me --help' for more information.\n"
156     if @ARGV > 1;
158   my $srcdir = $ARGV[0] || ".";
160   verb "srcdir = $srcdir";
161   chdir $srcdir || error "cannot cd to $srcdir: $!";
165 # init_tables ()
166 # --------------
167 # Put values in the tables of what to do with each token.
168 sub init_tables ()
170   # The data file format supports only one line of macros per function.
171   # If more than that is required for a common portability problem,
172   # a new Autoconf macro should probably be written for that case,
173   # instead of duplicating the code in lots of configure.ac files.
174   my $file = find_file ("autoscan/autoscan.list",
175                         reverse (@prepend_include), @include);
176   my $table = new Autom4te::XFile ($file, "<");
177   my $tables_are_consistent = 1;
179   while ($_ = $table->getline)
180     {
181       # Ignore blank lines and comments.
182       next
183         if /^\s*$/ || /^\s*\#/;
185       # '<kind>: <word> <macro invocation>' or...
186       # '<kind>: <word> warn: <message>'.
187       if (/^(\S+):\s+(\S+)\s+(\S.*)$/)
188         {
189           my ($kind, $word, $macro) = ($1, $2, $3);
190           error "$file:$.: invalid kind: $_"
191             unless grep { $_ eq $kind } @kinds;
192           push @{$macro{$kind}{$word}}, $macro;
193         }
194       else
195         {
196           error "$file:$.: invalid definition: $_";
197         }
198     }
200   if ($debug)
201     {
202       foreach my $kind (@kinds)
203         {
204           foreach my $word (sort keys %{$macro{$kind}})
205             {
206               print "$kind: $word: @{$macro{$kind}{$word}}\n";
207             }
208         }
210     }
214 # used ($KIND, $WORD, [$WHERE])
215 # -----------------------------
216 # $WORD is used as a $KIND.
217 sub used ($$;$)
219   my ($kind, $word, $where) = @_;
220   $where ||= "$File::Find::name:$.";
221   if (
222       # Check for all the libraries.  But '-links' is certainly a
223       # 'find' argument, and '-le', a 'test' argument.
224       ($kind eq 'library' && $word !~ /^(e|inks)$/)
225       # Other than libraries are to be checked only if listed in
226       # the Autoscan library files.
227       || defined $macro{$kind}{$word}
228      )
229     {
230       push (@{$used{$kind}{$word}}, $where);
231     }
236 ## ----------------------- ##
237 ## Scanning source files.  ##
238 ## ----------------------- ##
241 # scan_c_file ($FILE-NAME)
242 # ------------------------
243 sub scan_c_file ($)
245   my ($file_name) = @_;
246   push @cfiles, $File::Find::name;
248   # Nonzero if in a multiline comment.
249   my $in_comment = 0;
251   my $file = new Autom4te::XFile ($file_name, "<");
253   while ($_ = $file->getline)
254     {
255       # Strip out comments.
256       if ($in_comment && s,^.*?\*/,,)
257         {
258           $in_comment = 0;
259         }
260       # The whole line is inside a comment.
261       next if $in_comment;
262       # All on one line.
263       s,/\*.*?\*/,,g;
265       # Starting on this line.
266       if (s,/\*.*$,,)
267         {
268           $in_comment = 1;
269         }
271       # Preprocessor directives.
272       if (s/^\s*\#\s*//)
273         {
274           if (/^include\s*<([^>]*)>/)
275             {
276               used ('header', $1);
277             }
278           if (s/^(if|ifdef|ifndef|elif)\s+//)
279             {
280               foreach my $word (split (/\W+/))
281                 {
282                   used ('identifier', $word)
283                     unless $word eq 'defined' || $word !~ /^[a-zA-Z_]/;
284                 }
285             }
286           # Ignore other preprocessor directives.
287           next;
288         }
290       # Remove string and character constants.
291       s,\"[^\"]*\",,g;
292       s,\'[^\']*\',,g;
294       # Tokens in the code.
295       # Maybe we should ignore function definitions (in column 0)?
296       while (s/\b([a-zA-Z_]\w*)\s*\(/ /)
297         {
298           used ('function', $1);
299         }
300       while (s/\b([a-zA-Z_]\w*)\b/ /)
301         {
302           used ('identifier', $1);
303         }
304     }
306   $file->close;
310 # scan_makefile($MAKEFILE-NAME)
311 # -----------------------------
312 sub scan_makefile ($)
314   my ($file_name) = @_;
315   push @makefiles, $File::Find::name;
317   my $file = new Autom4te::XFile ($file_name, "<");
319   while ($_ = $file->getline)
320     {
321       # Strip out comments.
322       s/#.*//;
324       # Variable assignments.
325       while (s/\b([a-zA-Z_]\w*)\s*=/ /)
326         {
327           used ('makevar', $1);
328         }
329       # Be sure to catch a whole word.  For instance 'lex$U.$(OBJEXT)'
330       # is a single token.  Otherwise we might believe 'lex' is needed.
331       foreach my $word (split (/\s+/))
332         {
333           # Libraries.
334           if ($word =~ /^-l([a-zA-Z_]\w*)$/)
335             {
336               used ('library', $1);
337             }
338           # Tokens in the code.
339           # We allow some additional characters, e.g., '+', since
340           # autoscan/programs includes 'c++'.
341           if ($word =~ /^[a-zA-Z_][\w+]*$/)
342             {
343               used ('program', $word);
344             }
345         }
346     }
348   $file->close;
352 # scan_sh_file($SHELL-SCRIPT-NAME)
353 # --------------------------------
354 sub scan_sh_file ($)
356   my ($file_name) = @_;
357   push @shfiles, $File::Find::name;
359   my $file = new Autom4te::XFile ($file_name, "<");
361   while ($_ = $file->getline)
362     {
363       # Strip out comments and variable references.
364       s/#.*//;
365       s/\$\{[^\}]*}//g;
366       s/@[^@]*@//g;
368       # Tokens in the code.
369       while (s/\b([a-zA-Z_]\w*)\b/ /)
370         {
371           used ('program', $1);
372         }
373     }
375   $file->close;
379 # scan_file ()
380 # ------------
381 # Called by &find on each file.  $_ contains the current file name with
382 # the current directory of the walk through.
383 sub scan_file ()
385   # Wanted only if there is no corresponding FILE.in.
386   return
387     if -f "$_.in";
389   # Save $_ as Find::File requires it to be preserved.
390   local $_ = $_;
392   # Strip a useless leading './'.
393   $File::Find::name =~ s,^\./,,;
395   if ($_ ne '.' and -d $_ and
396       -f "$_/configure.in"  ||
397       -f "$_/configure.ac"  ||
398       -f "$_/configure.gnu" ||
399       -f "$_/configure")
400     {
401       $File::Find::prune = 1;
402       push @subdirs, $File::Find::name;
403     }
404   if (/\.[chlym](\.in)?$/)
405     {
406       used 'program', 'cc', $File::Find::name;
407       scan_c_file ($_);
408     }
409   elsif (/\.(cc|cpp|cxx|CC|C|hh|hpp|hxx|HH|H|yy|ypp|ll|lpp)(\.in)?$/)
410     {
411       used 'program', 'c++', $File::Find::name;
412       scan_c_file ($_);
413     }
414   elsif ((/^((?:GNUm|M|m)akefile)(\.in)?$/ && ! -f "$1.am")
415          || /^(?:GNUm|M|m)akefile(\.am)?$/)
416     {
417       scan_makefile ($_);
418     }
419   elsif (/\.sh(\.in)?$/)
420     {
421       scan_sh_file ($_);
422     }
426 # scan_files ()
427 # -------------
428 # Read through the files and collect lists of tokens in them
429 # that might create nonportabilities.
430 sub scan_files ()
432   find (\&scan_file, '.');
434   if ($verbose)
435     {
436       print "cfiles: @cfiles\n";
437       print "makefiles: @makefiles\n";
438       print "shfiles: @shfiles\n";
440       foreach my $kind (@kinds)
441         {
442           print "\n$kind:\n";
443           foreach my $word (sort keys %{$used{$kind}})
444             {
445               print "$word: @{$used{$kind}{$word}}\n";
446             }
447         }
448     }
452 ## ----------------------- ##
453 ## Output configure.scan.  ##
454 ## ----------------------- ##
457 # output_kind ($FILE, $KIND)
458 # --------------------------
459 sub output_kind ($$)
461   my ($file, $kind) = @_;
462   # Lists of words to be checked with the generic macro.
463   my @have;
465   print $file "\n# $kind_comment{$kind}\n"
466     if exists $kind_comment{$kind};
467   foreach my $word (sort keys %{$used{$kind}})
468     {
469       # Output the needed macro invocations in configure.scan if not
470       # already printed, and remember these macros are needed.
471       foreach my $macro (@{$macro{$kind}{$word}})
472         {
473           if ($macro =~ /^warn:\s+(.*)/)
474             {
475               my $message = $1;
476               foreach my $location (@{$used{$kind}{$word}})
477                 {
478                   warn "$location: warning: $message\n";
479                 }
480             }
481           elsif (exists $generic_macro{$kind}
482               && $macro eq $generic_macro{$kind})
483             {
484               push (@have, $word);
485               push (@{$needed_macros{"$generic_macro{$kind}([$word])"}},
486                     @{$used{$kind}{$word}});
487             }
488           else
489             {
490               if (! $printed{$macro})
491                 {
492                   print $file "$macro\n";
493                   $printed{$macro} = 1;
494                 }
495               push (@{$needed_macros{$macro}},
496                     @{$used{$kind}{$word}});
497             }
498         }
499     }
500   print $file "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
501     if @have;
505 # output_libraries ($FILE)
506 # ------------------------
507 sub output_libraries ($)
509   my ($file) = @_;
511   print $file "\n# Checks for libraries.\n";
512   foreach my $word (sort keys %{$used{'library'}})
513     {
514       print $file "# FIXME: Replace 'main' with a function in '-l$word':\n";
515       print $file "AC_CHECK_LIB([$word], [main])\n";
516     }
520 # output ($CONFIGURE_SCAN)
521 # ------------------------
522 # Print a proto configure.ac.
523 sub output ($)
525   my $configure_scan = shift;
526   my %unique_makefiles;
528   my $file = new Autom4te::XFile ($configure_scan, ">");
530   print $file
531     ("#                                               -*- Autoconf -*-\n" .
532      "# Process this file with autoconf to produce a configure script.\n" .
533      "\n" .
534      "AC_PREREQ([@VERSION@])\n" .
535      "AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])\n");
536   if (defined $cfiles[0])
537     {
538       print $file "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
539       print $file "AC_CONFIG_HEADERS([config.h])\n";
540     }
542   output_kind ($file, 'program');
543   output_kind ($file, 'makevar');
544   output_libraries ($file);
545   output_kind ($file, 'header');
546   output_kind ($file, 'identifier');
547   output_kind ($file, 'function');
549   print $file "\n";
550   if (@makefiles)
551     {
552       # Change DIR/Makefile.in to DIR/Makefile.
553       foreach my $m (@makefiles)
554         {
555           $m =~ s/\.(?:in|am)$//;
556           $unique_makefiles{$m}++;
557         }
558       print $file ("AC_CONFIG_FILES([",
559                    join ("\n                 ",
560                          sort keys %unique_makefiles), "])\n");
561     }
562   if (@subdirs)
563     {
564       print $file ("AC_CONFIG_SUBDIRS([",
565                    join ("\n                   ",
566                          sort @subdirs), "])\n");
567     }
568   print $file "AC_OUTPUT\n";
570   $file->close;
575 ## --------------------------------------- ##
576 ## Checking the accuracy of configure.ac.  ##
577 ## --------------------------------------- ##
580 # &check_configure_ac ($CONFIGURE_AC)
581 # -----------------------------------
582 # Use autoconf to check if all the suggested macros are included
583 # in CONFIGURE_AC.
584 sub check_configure_ac ($)
586   my ($configure_ac) = @_;
588   # Find what needed macros are invoked in CONFIGURE_AC.
589   # I'd be very happy if someone could explain to me why sort (uniq ...)
590   # doesn't work properly: I need 'uniq (sort ...)'.  --akim
591   my $trace_option =
592     join (' --trace=', '',
593           uniq (sort (map { s/\(.*//; $_ } keys %needed_macros)));
595   # Suppress all warnings from the subsidiary autoconf invocation.
596   local $ENV{WARNINGS} = 'none';
598   verb "running: WARNINGS=none $autoconf $trace_option $configure_ac";
599   my $traces =
600     new Autom4te::XFile "$autoconf $trace_option $configure_ac |";
602   while ($_ = $traces->getline)
603     {
604       chomp;
605       my ($file, $line, $macro, @args) = split (/:/, $_);
606       if ($macro =~ /^AC_CHECK_(HEADER|FUNC|TYPE|MEMBER)S$/)
607         {
608           # To be rigorous, we should distinguish between space and comma
609           # separated macros.  But there is no point.
610           foreach my $word (split (/\s|,/, $args[0]))
611             {
612               # AC_CHECK_MEMBERS wants 'struct' or 'union'.
613               if ($macro eq "AC_CHECK_MEMBERS"
614                   && $word =~ /^stat.st_/)
615                 {
616                   $word = "struct " . $word;
617                 }
618               delete $needed_macros{"$macro([$word])"};
619             }
620         }
621       else
622         {
623           delete $needed_macros{$macro};
624         }
625     }
627   $traces->close;
629   # Report the missing macros.
630   foreach my $macro (sort keys %needed_macros)
631     {
632       warn ("$configure_ac: warning: missing $macro wanted by: "
633             . (${$needed_macros{$macro}}[0])
634             . "\n");
635       print $log "$me: warning: missing $macro wanted by: \n";
636       foreach my $need (@{$needed_macros{$macro}})
637         {
638           print $log "\t$need\n";
639         }
640     }
644 ## -------------- ##
645 ## Main program.  ##
646 ## -------------- ##
648 parse_args;
649 $log = new Autom4te::XFile ("$me.log", ">");
651 $autoconf .= " --debug" if $debug;
652 $autoconf .= " --verbose" if $verbose;
653 $autoconf .= join (' --include=', '', map { shell_quote ($_) } @include);
654 $autoconf .= join (' --prepend-include=', '', map { shell_quote ($_) } @prepend_include);
656 my $configure_ac = find_configure_ac;
657 init_tables;
658 scan_files;
659 output ('configure.scan');
660 if (-f $configure_ac)
661   {
662     check_configure_ac ($configure_ac);
663   }
664 # This close is really needed.  For some reason, probably best named
665 # a bug, it seems that the dtor of $LOG is not called automatically
666 # at END.  It results in a truncated file.
667 $log->close;
668 exit 0;
670 ### Setup "GNU" style for perl-mode and cperl-mode.
671 ## Local Variables:
672 ## perl-indent-level: 2
673 ## perl-continued-statement-offset: 2
674 ## perl-continued-brace-offset: 0
675 ## perl-brace-offset: 0
676 ## perl-brace-imaginary-offset: 0
677 ## perl-label-offset: -2
678 ## cperl-indent-level: 2
679 ## cperl-brace-offset: 0
680 ## cperl-continued-brace-offset: 0
681 ## cperl-label-offset: -2
682 ## cperl-extra-newline-before-brace: t
683 ## cperl-merge-trailing-else: nil
684 ## cperl-continued-statement-offset: 2
685 ## End: