xref: /netbsd-src/external/gpl3/autoconf/dist/bin/autoscan.in (revision d874e91932377fc40d53f102e48fc3ee6f4fe9de)
1#! @PERL@ -w
2# -*- perl -*-
3# @configure_input@
4
5# autoscan - Create configure.scan (a preliminary configure.ac) for a package.
6# Copyright (C) 1994, 1999-2012 Free Software Foundation, Inc.
7
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.
12
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.
17
18# You should have received a copy of the GNU General Public License
19# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21# Written by David MacKenzie <djm@gnu.ai.mit.edu>.
22
23eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
24    if 0;
25
26BEGIN
27{
28  my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
29  unshift @INC, $pkgdatadir;
30
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');
36}
37
38use Autom4te::ChannelDefs;
39use Autom4te::Configure_ac;
40use Autom4te::General;
41use Autom4te::FileUtils;
42use Autom4te::XFile;
43use File::Basename;
44use File::Find;
45use strict;
46
47use vars qw(@cfiles @makefiles @shfiles @subdirs %printed);
48
49# The kind of the words we are looking for.
50my @kinds = qw (function header identifier program
51		makevar librarie);
52
53# For each kind, the default macro.
54my %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  );
62
63my %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  );
70
71# $USED{KIND}{ITEM} is the list of locations where the ITEM (of KIND) was used
72# in the user package.
73# For instance $USED{function}{alloca} is the list of `file:line' where
74# `alloca (...)' appears.
75my %used = ();
76
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.
80my %macro = ();
81
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 (...)'.
85my %needed_macros =
86  (
87   'AC_PREREQ' => [$me],
88  );
89
90my $configure_scan = 'configure.scan';
91my $log;
92
93# Autoconf and lib files.
94my $autom4te = $ENV{'AUTOM4TE'} || '@bindir@/@autom4te-name@';
95my $autoconf = "$autom4te --language=autoconf";
96my @prepend_include;
97my @include = ('@pkgdatadir@');
98
99# $help
100# -----
101$help = "Usage: $0 [OPTION]... [SRCDIR]
102
103Examine source files in the directory tree rooted at SRCDIR, or the
104current directory if none is given.  Search the source files for
105common portability problems, check for incompleteness of
106`configure.ac', and create a file `$configure_scan' which is a
107preliminary `configure.ac' for that package.
108
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
113
114Library directories:
115  -B, --prepend-include=DIR  prepend directory DIR to search path
116  -I, --include=DIR          append directory DIR to search path
117
118Report bugs to <bug-autoconf\@gnu.org>.
119GNU Autoconf home page: <http://www.gnu.org/software/autoconf/>.
120General help using GNU software: <http://www.gnu.org/gethelp/>.
121";
122
123# $version
124# --------
125$version = "autoscan (@PACKAGE_NAME@) @VERSION@
126Copyright (C) @RELEASE_YEAR@ Free Software Foundation, Inc.
127License GPLv3+/Autoconf: GNU GPL version 3 or later
128<http://gnu.org/licenses/gpl.html>, <http://gnu.org/licenses/exceptions.html>
129This is free software: you are free to change and redistribute it.
130There is NO WARRANTY, to the extent permitted by law.
131
132Written by David J. MacKenzie and Akim Demaille.
133";
134
135
136
137
138## ------------------------ ##
139## Command line interface.  ##
140## ------------------------ ##
141
142# parse_args ()
143# -------------
144# Process any command line arguments.
145sub parse_args ()
146{
147  getopt ('I|include=s' => \@include,
148	  'B|prepend-include=s' => \@prepend_include);
149
150  die "$me: too many arguments
151Try `$me --help' for more information.\n"
152    if @ARGV > 1;
153
154  my $srcdir = $ARGV[0] || ".";
155
156  verb "srcdir = $srcdir";
157  chdir $srcdir || error "cannot cd to $srcdir: $!";
158}
159
160
161# init_tables ()
162# --------------
163# Put values in the tables of what to do with each token.
164sub init_tables ()
165{
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 "< " . open_quote ($file);
173  my $tables_are_consistent = 1;
174
175  while ($_ = $table->getline)
176    {
177      # Ignore blank lines and comments.
178      next
179	if /^\s*$/ || /^\s*\#/;
180
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    }
195
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	}
205
206    }
207}
208
209
210# used ($KIND, $WORD, [$WHERE])
211# -----------------------------
212# $WORD is used as a $KIND.
213sub used ($$;$)
214{
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    }
228}
229
230
231
232## ----------------------- ##
233## Scanning source files.  ##
234## ----------------------- ##
235
236
237# scan_c_file ($FILE-NAME)
238# ------------------------
239sub scan_c_file ($)
240{
241  my ($file_name) = @_;
242  push @cfiles, $File::Find::name;
243
244  # Nonzero if in a multiline comment.
245  my $in_comment = 0;
246
247  my $file = new Autom4te::XFile "< " . open_quote ($file_name);
248
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;
260
261      # Starting on this line.
262      if (s,/\*.*$,,)
263	{
264	  $in_comment = 1;
265	}
266
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	}
285
286      # Remove string and character constants.
287      s,\"[^\"]*\",,g;
288      s,\'[^\']*\',,g;
289
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    }
301
302  $file->close;
303}
304
305
306# scan_makefile($MAKEFILE-NAME)
307# -----------------------------
308sub scan_makefile ($)
309{
310  my ($file_name) = @_;
311  push @makefiles, $File::Find::name;
312
313  my $file = new Autom4te::XFile "< " . open_quote ($file_name);
314
315  while ($_ = $file->getline)
316    {
317      # Strip out comments.
318      s/#.*//;
319
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    }
343
344  $file->close;
345}
346
347
348# scan_sh_file($SHELL-SCRIPT-NAME)
349# --------------------------------
350sub scan_sh_file ($)
351{
352  my ($file_name) = @_;
353  push @shfiles, $File::Find::name;
354
355  my $file = new Autom4te::XFile "< " . open_quote ($file_name);
356
357  while ($_ = $file->getline)
358    {
359      # Strip out comments and variable references.
360      s/#.*//;
361      s/\${[^\}]*}//g;
362      s/@[^@]*@//g;
363
364      # Tokens in the code.
365      while (s/\b([a-zA-Z_]\w*)\b/ /)
366	{
367	  used ('program', $1);
368	}
369    }
370
371  $file->close;
372}
373
374
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.
379sub scan_file ()
380{
381  # Wanted only if there is no corresponding FILE.in.
382  return
383    if -f "$_.in";
384
385  # Save $_ as Find::File requires it to be preserved.
386  local $_ = $_;
387
388  # Strip a useless leading `./'.
389  $File::Find::name =~ s,^\./,,;
390
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    }
419}
420
421
422# scan_files ()
423# -------------
424# Read through the files and collect lists of tokens in them
425# that might create nonportabilities.
426sub scan_files ()
427{
428  find (\&scan_file, '.');
429
430  if ($verbose)
431    {
432      print "cfiles: @cfiles\n";
433      print "makefiles: @makefiles\n";
434      print "shfiles: @shfiles\n";
435
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    }
445}
446
447
448## ----------------------- ##
449## Output configure.scan.  ##
450## ----------------------- ##
451
452
453# output_kind ($FILE, $KIND)
454# --------------------------
455sub output_kind ($$)
456{
457  my ($file, $kind) = @_;
458  # Lists of words to be checked with the generic macro.
459  my @have;
460
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;
498}
499
500
501# output_libraries ($FILE)
502# ------------------------
503sub output_libraries ($)
504{
505  my ($file) = @_;
506
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    }
513}
514
515
516# output ($CONFIGURE_SCAN)
517# ------------------------
518# Print a proto configure.ac.
519sub output ($)
520{
521  my $configure_scan = shift;
522  my %unique_makefiles;
523
524  my $file = new Autom4te::XFile "> " . open_quote ($configure_scan);
525
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    }
537
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');
544
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";
565
566  $file->close;
567}
568
569
570
571## --------------------------------------- ##
572## Checking the accuracy of configure.ac.  ##
573## --------------------------------------- ##
574
575
576# &check_configure_ac ($CONFIGURE_AC)
577# -----------------------------------
578# Use autoconf to check if all the suggested macros are included
579# in CONFIGURE_AC.
580sub check_configure_ac ($)
581{
582  my ($configure_ac) = @_;
583
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)));
590
591  verb "running: $autoconf $trace_option $configure_ac";
592  my $traces =
593    new Autom4te::XFile "$autoconf $trace_option $configure_ac |";
594
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    }
619
620  $traces->close;
621
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    }
634}
635
636
637## -------------- ##
638## Main program.  ##
639## -------------- ##
640
641parse_args;
642$log = new Autom4te::XFile "> " . open_quote ("$me.log");
643
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);
648
649my $configure_ac = find_configure_ac;
650init_tables;
651scan_files;
652output ('configure.scan');
653if (-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;
661exit 0;
662
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:
679