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