Adjust all the routines to use it.
($log): New file (autoscan.log).
(output): Dump detailed logs into $log, and a shortened version to
stderr.
(&scan_makefile): Refine the regexp catching tokens in the code.
* doc/autoconf.texi (autoscan Invocation): Document `autoscan.log'
and the `configure.ac' checking feature.
+2001-07-14 Akim Demaille <akim@epita.fr>
+
+ * autoscan.in: Use IO::File.
+ Adjust all the routines to use it.
+ ($log): New file (autoscan.log).
+ (output): Dump detailed logs into $log, and a shortened version to
+ stderr.
+ (&scan_makefile): Refine the regexp catching tokens in the code.
+ * doc/autoconf.texi (autoscan Invocation): Document `autoscan.log'
+ and the `configure.ac' checking feature.
+
2001-07-12 Akim Demaille <akim@epita.fr>
For some AWK, such as on HPUX 11, `xfoo' does not match `foo|^bar'.
other hard-to-quote constructs.
- m4_pattern_forbid, m4_pattern_allow
- Tips for upgrading from 2.13.
+- Using autoscan to maintain a configure.ac.
** Default includes
- Now include stdint.h.
use File::Basename;
use File::Find;
use Getopt::Long;
+use IO::File;
use strict;
use vars qw(@cfiles @makefiles @shfiles %c_keywords %printed);
);
my $configure_scan = 'configure.scan';
+my $log = new IO::File ">$me.log"
+ or die "$me: cannot open $me.log: $!\n";
# Autoconf and lib files.
my $autoconf;
Examine source files in the directory tree rooted at SRCDIR, or the
current directory if none is given. Search the source files for
-common portability problems and create a file `$configure_scan' which
-is a preliminary `configure.ac' for that package.
+common portability problems, check for incompleteness of
+`configure.ac', and create a file `$configure_scan' which is a
+preliminary `configure.ac' for that package.
-h, --help print this help, then exit
-V, --version print version number, then exit
foreach my $kind (@kinds)
{
my $file = "$datadir/ac$kind";
- open TABLE, $file or
- die "$me: cannot open $file: $!\n";
- while (<TABLE>)
+ my $table = new IO::File $file
+ or die "$me: cannot open $file: $!\n";
+ while ($_ = $table->getline)
{
# Ignore blank lines and comments.
next
push @{$macro{$kind}{$word}}, $macro;
}
}
- close(TABLE);
+ $table->close
+ or die "$me: cannot close $file: $!\n";
}
die "$me: some tables are inconsistent\n"
## ----------------------- ##
-# scan_c_file(FILE)
-# -----------------
+# scan_c_file(FILENAME)
+# ---------------------
sub scan_c_file ($)
{
- my ($file) = @_;
+ my ($filename) = @_;
push (@cfiles, $File::Find::name);
# Nonzero if in a multiline comment.
my $in_comment = 0;
- open(CFILE, "<$file") || die "$me: cannot open $file: $!\n";
- while (<CFILE>)
+ my $file = new IO::File "<$filename"
+ or die "$me: cannot open $filename: $!\n";
+
+ while ($_ = $file->getline)
{
# Strip out comments, approximately.
# Ending on this line.
if !defined $c_keywords{$1};
}
}
- close(CFILE);
+
+ $file->close
+ or die "$me: cannot close $filename: $!\n";
}
-# scan_makefile(MAKEFILE)
-# -----------------------
+# scan_makefile(MAKEFILE-NAME)
+# ----------------------------
sub scan_makefile ($)
{
- my ($file) = @_;
+ my ($filename) = @_;
push (@makefiles, $File::Find::name);
- open(MFILE, "<$file") || die "$me: cannot open $file: $!\n";
- while (<MFILE>)
+ my $file = new IO::File "<$filename"
+ or die "$me: cannot open $filename: $!\n";
+
+ while ($_ = $file->getline)
{
# Strip out comments and variable references.
s/#.*//;
push (@{$used{'libraries'}{$1}}, "$File::Find::name:$.");
}
# Tokens in the code.
- while (s/\b([a-zA-Z_][\w\+\.-]+)/ /)
+ while (s/(?<![-\w.])([a-zA-Z_][\w+.-]+)/ /)
{
push (@{$used{'programs'}{$1}}, "$File::Find::name:$.");
}
}
- close(MFILE);
+
+ $file->close
+ or die "$me: cannot close $filename: $!\n";
}
-# scan_sh_file(SHELL-SCRIPT)
-# --------------------------
+# scan_sh_file(SHELL-SCRIPT-NAME)
+# -------------------------------
sub scan_sh_file ($)
{
- my ($file) = @_;
+ my ($filename) = @_;
push (@shfiles, $File::Find::name);
- open(MFILE, "<$file") || die "$me: cannot open $file: $!\n";
- while (<MFILE>)
+ my $file = new IO::File "<$filename"
+ or die "$me: cannot open $filename: $!\n";
+
+ while ($_ = $file->getline)
{
# Strip out comments and variable references.
s/#.*//;
+ s/#.*//;
s/\${[^\}]*}//g;
s/@[^@]*@//g;
push (@{$used{'programs'}{$1}}, "$File::Find::name:$.");
}
}
- close(MFILE);
+
+ $file->close
+ or die "$me: cannot close $filename: $!\n";
}
## ----------------------- ##
-# output_kind ($KIND)
-# -------------------
-sub output_kind ($)
+# output_kind ($FILE, $KIND)
+# --------------------------
+sub output_kind ($$)
{
- my ($kind) = @_;
+ my ($file, $kind) = @_;
# Lists of words to be checked with the generic macro.
my @have;
- print CONF "\n# $kind_comment{$kind}\n"
+ print $file "\n# $kind_comment{$kind}\n"
if exists $kind_comment{$kind};
foreach my $word (sort keys %{$used{$kind}})
{
{
if (! $printed{$macro})
{
- print CONF "$macro\n";
+ print $file "$macro\n";
$printed{$macro} = 1;
}
push (@{$needed_macros{$macro}},
}
}
}
- print CONF "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
+ print $file "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
if @have;
}
-# output_libraries ()
-# -------------------
-sub output_libraries ()
+# output_libraries ($FILE)
+# ------------------------
+sub output_libraries ($)
{
- print CONF "\n# Checks for libraries.\n";
+ my ($file) = @_;
+
+ print $file "\n# Checks for libraries.\n";
foreach my $word (sort keys %{$used{'libraries'}})
{
- print CONF "# FIXME: Replace `main' with a function in `-l$word':\n";
- print CONF "AC_CHECK_LIB([$word], [main])\n";
+ print $file "# FIXME: Replace `main' with a function in `-l$word':\n";
+ print $file "AC_CHECK_LIB([$word], [main])\n";
}
}
my $configure_scan = shift;
my %unique_makefiles;
- open (CONF, ">$configure_scan") ||
- die "$me: cannot create $configure_scan: $!\n";
+ my $file = new IO::File ">$configure_scan"
+ or die "$me: cannot create $configure_scan: $!\n";
- print CONF "# Process this file with autoconf to produce a configure script.\n";
- print CONF "AC_INIT\n";
+ print $file "# Process this file with autoconf to produce a configure script.\n";
+ print $file "AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)\n";
if (defined $cfiles[0])
{
- print CONF "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
- print CONF "AC_CONFIG_HEADER([config.h])\n";
+ print $file "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
+ print $file "AC_CONFIG_HEADER([config.h])\n";
}
- output_kind ('programs');
- output_kind ('makevars');
- output_libraries;
- output_kind ('headers');
- output_kind ('identifiers');
- output_kind ('functions');
+ output_kind ($file, 'programs');
+ output_kind ($file, 'makevars');
+ output_libraries ($file);
+ output_kind ($file, 'headers');
+ output_kind ($file, 'identifiers');
+ output_kind ($file, 'functions');
# Change DIR/Makefile.in to DIR/Makefile.
foreach my $m (@makefiles)
$m =~ s/\.in$//;
$unique_makefiles{$m}++;
}
- print CONF "\nAC_CONFIG_FILES([",
+ print $file "\nAC_CONFIG_FILES([",
join ("\n ", sort keys %unique_makefiles), "])\n";
- print CONF "AC_OUTPUT\n";
+ print $file "AC_OUTPUT\n";
- close CONF ||
- die "$me: closing $configure_scan: $!\n";
+ $file->close
+ or die "$me: cannot close $configure_scan: $!\n";
}
# in CONFIGURE_AC.
sub check_configure_ac ($)
{
- my ($configure_ac) = $@;
+ my ($configure_ac) = @_;
my ($trace_option) = '';
+ # Find what needed macros are invoked in CONFIGURE_AC.
foreach my $macro (sort keys %needed_macros)
{
$macro =~ s/\(.*//;
$trace_option .= " -t $macro";
}
- open (TRACES, "$autoconf -A $datadir $trace_option $configure_ac|") ||
- die "$me: cannot create read traces: $!\n";
+ my $traces =
+ new IO::File "$autoconf -A $datadir $trace_option $configure_ac|"
+ or die "$me: cannot create read traces: $!\n";
- while (<TRACES>)
+ while ($_ = $traces->getline)
{
chomp;
my ($file, $line, $macro, @args) = split (/:/, $_);
}
}
- close (TRACES) ||
- die "$me: cannot close traces: $!\n";
+ $traces->close
+ or die "$me: cannot close: $!\n";
+ # Report the missing macros.
foreach my $macro (sort keys %needed_macros)
{
- warn "$me: warning: missing $macro wanted by: \n";
+ warn ("$configure_ac: warning: missing $macro wanted by: "
+ . (${$needed_macros{$macro}}[0])
+ . "\n");
+ print $log "$me: warning: missing $macro wanted by: \n";
foreach my $need (@{$needed_macros{$macro}})
{
- warn "\t$need\n";
+ print $log "\t$need\n";
}
}
}
check_configure_ac ($configure_ac);
}
+$log->close
+ or die "$me: cannot close $me.log: $!\n";
+
exit 0;
use File::Basename;
use File::Find;
use Getopt::Long;
+use IO::File;
use strict;
use vars qw(@cfiles @makefiles @shfiles %c_keywords %printed);
);
my $configure_scan = 'configure.scan';
+my $log = new IO::File ">$me.log"
+ or die "$me: cannot open $me.log: $!\n";
# Autoconf and lib files.
my $autoconf;
Examine source files in the directory tree rooted at SRCDIR, or the
current directory if none is given. Search the source files for
-common portability problems and create a file `$configure_scan' which
-is a preliminary `configure.ac' for that package.
+common portability problems, check for incompleteness of
+`configure.ac', and create a file `$configure_scan' which is a
+preliminary `configure.ac' for that package.
-h, --help print this help, then exit
-V, --version print version number, then exit
foreach my $kind (@kinds)
{
my $file = "$datadir/ac$kind";
- open TABLE, $file or
- die "$me: cannot open $file: $!\n";
- while (<TABLE>)
+ my $table = new IO::File $file
+ or die "$me: cannot open $file: $!\n";
+ while ($_ = $table->getline)
{
# Ignore blank lines and comments.
next
push @{$macro{$kind}{$word}}, $macro;
}
}
- close(TABLE);
+ $table->close
+ or die "$me: cannot close $file: $!\n";
}
die "$me: some tables are inconsistent\n"
## ----------------------- ##
-# scan_c_file(FILE)
-# -----------------
+# scan_c_file(FILENAME)
+# ---------------------
sub scan_c_file ($)
{
- my ($file) = @_;
+ my ($filename) = @_;
push (@cfiles, $File::Find::name);
# Nonzero if in a multiline comment.
my $in_comment = 0;
- open(CFILE, "<$file") || die "$me: cannot open $file: $!\n";
- while (<CFILE>)
+ my $file = new IO::File "<$filename"
+ or die "$me: cannot open $filename: $!\n";
+
+ while ($_ = $file->getline)
{
# Strip out comments, approximately.
# Ending on this line.
if !defined $c_keywords{$1};
}
}
- close(CFILE);
+
+ $file->close
+ or die "$me: cannot close $filename: $!\n";
}
-# scan_makefile(MAKEFILE)
-# -----------------------
+# scan_makefile(MAKEFILE-NAME)
+# ----------------------------
sub scan_makefile ($)
{
- my ($file) = @_;
+ my ($filename) = @_;
push (@makefiles, $File::Find::name);
- open(MFILE, "<$file") || die "$me: cannot open $file: $!\n";
- while (<MFILE>)
+ my $file = new IO::File "<$filename"
+ or die "$me: cannot open $filename: $!\n";
+
+ while ($_ = $file->getline)
{
# Strip out comments and variable references.
s/#.*//;
push (@{$used{'libraries'}{$1}}, "$File::Find::name:$.");
}
# Tokens in the code.
- while (s/\b([a-zA-Z_][\w\+\.-]+)/ /)
+ while (s/(?<![-\w.])([a-zA-Z_][\w+.-]+)/ /)
{
push (@{$used{'programs'}{$1}}, "$File::Find::name:$.");
}
}
- close(MFILE);
+
+ $file->close
+ or die "$me: cannot close $filename: $!\n";
}
-# scan_sh_file(SHELL-SCRIPT)
-# --------------------------
+# scan_sh_file(SHELL-SCRIPT-NAME)
+# -------------------------------
sub scan_sh_file ($)
{
- my ($file) = @_;
+ my ($filename) = @_;
push (@shfiles, $File::Find::name);
- open(MFILE, "<$file") || die "$me: cannot open $file: $!\n";
- while (<MFILE>)
+ my $file = new IO::File "<$filename"
+ or die "$me: cannot open $filename: $!\n";
+
+ while ($_ = $file->getline)
{
# Strip out comments and variable references.
s/#.*//;
+ s/#.*//;
s/\${[^\}]*}//g;
s/@[^@]*@//g;
push (@{$used{'programs'}{$1}}, "$File::Find::name:$.");
}
}
- close(MFILE);
+
+ $file->close
+ or die "$me: cannot close $filename: $!\n";
}
## ----------------------- ##
-# output_kind ($KIND)
-# -------------------
-sub output_kind ($)
+# output_kind ($FILE, $KIND)
+# --------------------------
+sub output_kind ($$)
{
- my ($kind) = @_;
+ my ($file, $kind) = @_;
# Lists of words to be checked with the generic macro.
my @have;
- print CONF "\n# $kind_comment{$kind}\n"
+ print $file "\n# $kind_comment{$kind}\n"
if exists $kind_comment{$kind};
foreach my $word (sort keys %{$used{$kind}})
{
{
if (! $printed{$macro})
{
- print CONF "$macro\n";
+ print $file "$macro\n";
$printed{$macro} = 1;
}
push (@{$needed_macros{$macro}},
}
}
}
- print CONF "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
+ print $file "$generic_macro{$kind}([" . join(' ', sort(@have)) . "])\n"
if @have;
}
-# output_libraries ()
-# -------------------
-sub output_libraries ()
+# output_libraries ($FILE)
+# ------------------------
+sub output_libraries ($)
{
- print CONF "\n# Checks for libraries.\n";
+ my ($file) = @_;
+
+ print $file "\n# Checks for libraries.\n";
foreach my $word (sort keys %{$used{'libraries'}})
{
- print CONF "# FIXME: Replace `main' with a function in `-l$word':\n";
- print CONF "AC_CHECK_LIB([$word], [main])\n";
+ print $file "# FIXME: Replace `main' with a function in `-l$word':\n";
+ print $file "AC_CHECK_LIB([$word], [main])\n";
}
}
my $configure_scan = shift;
my %unique_makefiles;
- open (CONF, ">$configure_scan") ||
- die "$me: cannot create $configure_scan: $!\n";
+ my $file = new IO::File ">$configure_scan"
+ or die "$me: cannot create $configure_scan: $!\n";
- print CONF "# Process this file with autoconf to produce a configure script.\n";
- print CONF "AC_INIT\n";
+ print $file "# Process this file with autoconf to produce a configure script.\n";
+ print $file "AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)\n";
if (defined $cfiles[0])
{
- print CONF "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
- print CONF "AC_CONFIG_HEADER([config.h])\n";
+ print $file "AC_CONFIG_SRCDIR([$cfiles[0]])\n";
+ print $file "AC_CONFIG_HEADER([config.h])\n";
}
- output_kind ('programs');
- output_kind ('makevars');
- output_libraries;
- output_kind ('headers');
- output_kind ('identifiers');
- output_kind ('functions');
+ output_kind ($file, 'programs');
+ output_kind ($file, 'makevars');
+ output_libraries ($file);
+ output_kind ($file, 'headers');
+ output_kind ($file, 'identifiers');
+ output_kind ($file, 'functions');
# Change DIR/Makefile.in to DIR/Makefile.
foreach my $m (@makefiles)
$m =~ s/\.in$//;
$unique_makefiles{$m}++;
}
- print CONF "\nAC_CONFIG_FILES([",
+ print $file "\nAC_CONFIG_FILES([",
join ("\n ", sort keys %unique_makefiles), "])\n";
- print CONF "AC_OUTPUT\n";
+ print $file "AC_OUTPUT\n";
- close CONF ||
- die "$me: closing $configure_scan: $!\n";
+ $file->close
+ or die "$me: cannot close $configure_scan: $!\n";
}
# in CONFIGURE_AC.
sub check_configure_ac ($)
{
- my ($configure_ac) = $@;
+ my ($configure_ac) = @_;
my ($trace_option) = '';
+ # Find what needed macros are invoked in CONFIGURE_AC.
foreach my $macro (sort keys %needed_macros)
{
$macro =~ s/\(.*//;
$trace_option .= " -t $macro";
}
- open (TRACES, "$autoconf -A $datadir $trace_option $configure_ac|") ||
- die "$me: cannot create read traces: $!\n";
+ my $traces =
+ new IO::File "$autoconf -A $datadir $trace_option $configure_ac|"
+ or die "$me: cannot create read traces: $!\n";
- while (<TRACES>)
+ while ($_ = $traces->getline)
{
chomp;
my ($file, $line, $macro, @args) = split (/:/, $_);
}
}
- close (TRACES) ||
- die "$me: cannot close traces: $!\n";
+ $traces->close
+ or die "$me: cannot close: $!\n";
+ # Report the missing macros.
foreach my $macro (sort keys %needed_macros)
{
- warn "$me: warning: missing $macro wanted by: \n";
+ warn ("$configure_ac: warning: missing $macro wanted by: "
+ . (${$needed_macros{$macro}}[0])
+ . "\n");
+ print $log "$me: warning: missing $macro wanted by: \n";
foreach my $need (@{$needed_macros{$macro}})
{
- warn "\t$need\n";
+ print $log "\t$need\n";
}
}
}
check_configure_ac ($configure_ac);
}
+$log->close
+ or die "$me: cannot close $me.log: $!\n";
+
exit 0;
@section Using @code{autoscan} to Create @file{configure.ac}
@cindex @code{autoscan}
-The @code{autoscan} program can help you create a @file{configure.ac}
-file for a software package. @code{autoscan} examines source files in
-the directory tree rooted at a directory given as a command line
-argument, or the current directory if none is given. It searches the
-source files for common portability problems and creates a file
-@file{configure.scan} which is a preliminary @file{configure.ac} for
-that package.
-
-You should manually examine @file{configure.scan} before renaming it to
+The @code{autoscan} program can help you create and/or maintain a
+@file{configure.ac} file for a software package. @code{autoscan}
+examines source files in the directory tree rooted at a directory given
+as a command line argument, or the current directory if none is given.
+It searches the source files for common portability problems and creates
+a file @file{configure.scan} which is a preliminary @file{configure.ac}
+for that package, and checks a possibly existing @file{configure.ac} for
+completeness.
+
+When using @command{autoscan} to create a @file{configure.ac}, you
+should manually examine @file{configure.scan} before renaming it to
@file{configure.ac}; it will probably need some adjustments.
-Occasionally, @code{autoscan} outputs a macro in the wrong order relative
-to another macro, so that @code{autoconf} produces a warning; you need
-to move such macros manually. Also, if you want the package to use a
-configuration header file, you must add a call to
-@code{AC_CONFIG_HEADERS} (@pxref{Configuration Headers}). You might also
-have to change or add some @code{#if} directives to your program in
+Occasionally, @code{autoscan} outputs a macro in the wrong order
+relative to another macro, so that @code{autoconf} produces a warning;
+you need to move such macros manually. Also, if you want the package to
+use a configuration header file, you must add a call to
+@code{AC_CONFIG_HEADERS} (@pxref{Configuration Headers}). You might
+also have to change or add some @code{#if} directives to your program in
order to make it work with Autoconf (@pxref{ifnames Invocation}, for
information about a program that can help with that job).
+When using @command{autoscan} to maintain a @file{configure.ac}, simply
+consider adding its suggestions. The file @file{autoscan.log} will
+contain detailed information on why a macro is requested.
+
@code{autoscan} uses several data files (installed along with Autoconf)
to determine which macros to output when it finds particular symbols in
a package's source files. These data files all have the same format:
.SH DESCRIPTION
Examine source files in the directory tree rooted at SRCDIR, or the
current directory if none is given. Search the source files for
-common portability problems and create a file `configure.scan' which
-is a preliminary `configure.ac' for that package.
+common portability problems, check for incompleteness of
+`configure.ac', and create a file `configure.scan' which is a
+preliminary `configure.ac' for that package.
.TP
\fB\-h\fR, \fB\-\-help\fR
print this help, then exit