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