Blame Configure.pm

Packit 910689
#!/usr/bin/perl
Packit 910689
Packit 910689
# Configure.pm. Version 1.00          Copyright (C) 1995, Kenneth Albanowski
Packit 910689
#
Packit 910689
#  You are welcome to use this code in your own perl modules, I just
Packit 910689
#  request that you don't distribute modified copies without making it clear
Packit 910689
#  that you have changed something. If you have a change you think is worth
Packit 910689
#  merging into the original, please contact me at kjahds@kjahds.com or
Packit 910689
#  CIS:70705,126
Packit 910689
#
Packit 910689
#  $Id: Configure.pm,v 2.21 2004/03/02 20:28:11 jonathan Exp $
Packit 910689
# 
Packit 910689
Packit 910689
# Todo: clean up redudant code in CPP, Compile, Link, and Execute
Packit 910689
#
Packit 910689
Packit 910689
# for when no_index is not enough
Packit 910689
package 
Packit 910689
  Configure;
Packit 910689
Packit 910689
use strict;
Packit 910689
use vars qw(@EXPORT @ISA);
Packit 910689
Packit 910689
use Carp;
Packit 910689
require Exporter;
Packit 910689
@ISA = qw(Exporter);
Packit 910689
Packit 910689
@EXPORT = qw( CPP 
Packit 910689
              Compile 
Packit 910689
              Link 
Packit 910689
              Execute
Packit 910689
              FindHeader 
Packit 910689
              FindLib
Packit 910689
              Apply 
Packit 910689
              ApplyHeaders 
Packit 910689
              ApplyLibs 
Packit 910689
              ApplyHeadersAndLibs 
Packit 910689
              ApplyHeadersAndLibsAndExecute
Packit 910689
              CheckHeader 
Packit 910689
              CheckStructure 
Packit 910689
              CheckField
Packit 910689
              CheckHSymbol 
Packit 910689
              CheckSymbol 
Packit 910689
              CheckLSymbol
Packit 910689
              GetSymbol 
Packit 910689
              GetTextSymbol 
Packit 910689
              GetNumericSymbol 
Packit 910689
              GetConstants);
Packit 910689
Packit 910689
use Config;
Packit 910689
Packit 910689
my ($C_usrinc, $C_libpth, $C_cppstdin, $C_cppflags, $C_cppminus,
Packit 910689
$C_ccflags,$C_ldflags,$C_cc,$C_libs) =
Packit 910689
	 @Config{qw( usrinc libpth cppstdin cppflags cppminus
Packit 910689
					 ccflags ldflags cc libs)};
Packit 910689
Packit 910689
my $Verbose = 0;
Packit 910689
Packit 910689
=head1 NAME
Packit 910689
Packit 910689
Configure.pm - provide auto-configuration utilities
Packit 910689
Packit 910689
=head1 SUMMARY
Packit 910689
Packit 910689
This perl module provides tools to figure out what is present in the C
Packit 910689
compilation environment. This is intended mostly for perl extensions to use
Packit 910689
to configure themselves. There are a number of functions, with widely varying
Packit 910689
levels of specificity, so here is a summary of what the functions can do:
Packit 910689
Packit 910689
Packit 910689
CheckHeader:		Look for headers.
Packit 910689
Packit 910689
CheckStructure:		Look for a structure.
Packit 910689
Packit 910689
CheckField:		Look for a field in a structure.
Packit 910689
Packit 910689
CheckHSymbol:		Look for a symbol in a header.
Packit 910689
Packit 910689
CheckLSymbol:		Look for a symbol in a library.
Packit 910689
Packit 910689
CheckSymbol:		Look for a symbol in a header and library.
Packit 910689
Packit 910689
GetTextSymbol:		Get the contents of a symbol as text.
Packit 910689
Packit 910689
GetNumericSymbol:	Get the contents of a symbol as a number.	
Packit 910689
Packit 910689
Apply:			Try compiling code with a set of headers and libs.
Packit 910689
Packit 910689
ApplyHeaders:		Try compiling code with a set of headers.
Packit 910689
Packit 910689
ApplyLibraries:		Try linking code with a set of libraries.
Packit 910689
Packit 910689
ApplyHeadersAndLibaries:	You get the idea.
Packit 910689
Packit 910689
ApplyHeadersAndLibariesAnExecute:	You get the idea.
Packit 910689
Packit 910689
CPP:		Feed some code through the C preproccessor.
Packit 910689
Packit 910689
Compile:	Try to compile some C code.
Packit 910689
Packit 910689
Link:		Try to compile & link some C code.
Packit 910689
Packit 910689
Execute:	Try to compile, link, & execute some C code.
Packit 910689
Packit 910689
=head1 FUNCTIONS
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
# Here we go into the actual functions
Packit 910689
Packit 910689
=head2 CPP
Packit 910689
Packit 910689
Takes one or more arguments. The first is a string containing a C program.
Packit 910689
Embedded newlines are legal, the text simply being stuffed into a temporary
Packit 910689
file. The result is then fed to the C preproccessor (that preproccessor being
Packit 910689
previously determined by perl's Configure script.) Any additional arguments
Packit 910689
provided are passed to the preprocessing command.
Packit 910689
Packit 910689
In a scalar context, the return value is either undef, if something went wrong,
Packit 910689
or the text returned by the preprocessor. In an array context, two values are 
Packit 910689
returned: the numeric exit status and the output of the preproccessor.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub CPP { # Feed code to preproccessor, returning error value and output
Packit 910689
Packit 910689
	my($code,@options) = @_;
Packit 910689
	my($options) = join(" ",@options);
Packit 910689
	my($file) = "tmp$$";
Packit 910689
	my($in,$out) = ($file.".c",$file.".o");
Packit 910689
Packit 910689
	open(F,">$in");
Packit 910689
	print F $code;
Packit 910689
	close(F);
Packit 910689
Packit 910689
	print "Preprocessing |$code|\n" if $Verbose;
Packit 910689
	my($result) = scalar(`$C_cppstdin $C_cppflags $C_cppminus $options < $in 2>/dev/null`);
Packit 910689
	print "Executing '$C_cppstdin $C_cppflags $C_cppminus $options < $in 2>/dev/null'\n"  if $Verbose;
Packit 910689
Packit 910689
Packit 910689
	my($error) = $?;
Packit 910689
	print "Returned |$result|\n" if $Verbose;
Packit 910689
	unlink($in,$out);
Packit 910689
	return ($error ? undef : $result) unless wantarray;
Packit 910689
	($error,$result);
Packit 910689
}
Packit 910689
Packit 910689
=head2 Compile
Packit 910689
Packit 910689
Takes one or more arguments. The first is a string containing a C program.
Packit 910689
Embedded newlines are legal, the text simply being stuffed into a temporary
Packit 910689
file. The result is then fed to the C compiler (that compiler being
Packit 910689
previously determined by perl's Configure script.) Any additional arguments
Packit 910689
provided are passed to the compiler command.
Packit 910689
Packit 910689
In a scalar context, either 0 or 1 will be returned, with 1 indicating a
Packit 910689
successful compilation. In an array context, three values are returned: the
Packit 910689
numeric exit status of the compiler, a string consisting of the output
Packit 910689
generated by the compiler, and a numeric value that is false if a ".o" file
Packit 910689
wasn't produced by the compiler, error status or no.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub Compile { # Feed code to compiler. On error, return status and text
Packit 910689
	my($code,@options) = @_;
Packit 910689
	my($options)=join(" ",@options);
Packit 910689
	my($file) = "tmp$$";
Packit 910689
	my($in,$out) = ($file.".c",$file.".o");
Packit 910689
Packit 910689
	open(F,">$in");
Packit 910689
	print F $code;
Packit 910689
	close(F);
Packit 910689
	print "Compiling |$code|\n"  if $Verbose;
Packit 910689
	my($result) = scalar(`$C_cc $C_ccflags -c $in $C_ldflags $C_libs $options 2>&1`);
Packit 910689
	print "Executing '$C_cc $C_ccflags -c $in $C_ldflags $C_libs $options 2>&1'\n"  if $Verbose;
Packit 910689
	my($error) = $?;
Packit 910689
        my($error2) = ! -e $out;
Packit 910689
	unlink($in,$out);
Packit 910689
	return (($error || $error2) ? 0 : 1) unless wantarray;
Packit 910689
	($error,$result,$error2);
Packit 910689
}
Packit 910689
Packit 910689
=head2 Link
Packit 910689
Packit 910689
Takes one or more arguments. The first is a string containing a C program.
Packit 910689
Embedded newlines are legal, the text simply being stuffed into a temporary
Packit 910689
file. The result is then fed to the C compiler and linker (that compiler and
Packit 910689
linker being previously determined by perl's Configure script.) Any
Packit 910689
additional arguments provided are passed to the compilation/link command.
Packit 910689
Packit 910689
In a scalar context, either 0 or 1 is returned, with 1 indicating a
Packit 910689
successful compilation. In an array context, two values are returned: the
Packit 910689
numeric exit status of the compiler/linker, and a string consisting of the
Packit 910689
output generated by the compiler/linker.
Packit 910689
Packit 910689
Note that this command I<only> compiles and links the C code. It does not
Packit 910689
attempt to execute it.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub Link { # Feed code to compiler and linker. On error, return status and text
Packit 910689
	my($code,@options) = @_;
Packit 910689
	my($options) = join(" ",@options);
Packit 910689
	my($file) = "tmp$$";
Packit 910689
	my($in,$out) = $file.".c",$file.".o";
Packit 910689
Packit 910689
	open(F,">$in");
Packit 910689
	print F $code;
Packit 910689
	close(F);
Packit 910689
	print "Linking |$code|\n" if $Verbose;
Packit 910689
	my($result) = scalar(`$C_cc $C_ccflags -o $file $in $C_ldflags $C_libs $options 2>&1`);
Packit 910689
	print "Executing '$C_cc $C_ccflags -o $file $in $C_ldflags $C_libs $options 2>&1'\n" if $Verbose;
Packit 910689
	my($error)=$?;
Packit 910689
	print "Error linking: $error, |$result|\n" if $Verbose;
Packit 910689
	unlink($in,$out,$file);
Packit 910689
	return (($error || $result ne "")?0:1) unless wantarray;
Packit 910689
	($error,$result);
Packit 910689
}
Packit 910689
Packit 910689
=head2 Execute
Packit 910689
Packit 910689
Takes one or more arguments. The first is a string containing a C program.
Packit 910689
Embedded newlines are legal, the text simply being stuffed into a temporary
Packit 910689
file. The result is then fed to the C compiler and linker (that compiler and
Packit 910689
linker being previously determined by perl's metaconfig script.) and then
Packit 910689
executed. Any additional arguments provided are passed to the
Packit 910689
compilation/link command. (There is no way to feed arguments to the program
Packit 910689
being executed.)
Packit 910689
Packit 910689
In a scalar context, the return value is either undef, indicating the 
Packit 910689
compilation or link failed, or that the executed program returned a nonzero
Packit 910689
status. Otherwise, the return value is the text output by the program.
Packit 910689
Packit 910689
In an array context, an array consisting of three values is returned: the
Packit 910689
first value is 0 or 1, 1 if the compile/link succeeded. The second value either
Packit 910689
the exist status of the compiler or program, and the third is the output text.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub Execute { #Compile, link, and execute.
Packit 910689
Packit 910689
	my($code,@options) = @_;
Packit 910689
	my($options)=join(" ",@options);
Packit 910689
	my($file) = "tmp$$";
Packit 910689
	my($in,$out) = $file.".c",$file.".o";
Packit 910689
Packit 910689
	open(F,">$in");
Packit 910689
	print F $code;
Packit 910689
	close(F);
Packit 910689
	print "Executing |$code|\n" if $Verbose;
Packit 910689
	my($result) = scalar(`$C_cc $C_ccflags -o $file $in $C_ldflags $C_libs $options 2>&1`);
Packit 910689
	print "Executing '$C_cc $C_ccflags -o $file $in $C_ldflags $C_libs $options 2>&1'\n" if $Verbose;
Packit 910689
	my($error) = $?;
Packit 910689
	unlink($in,$out);
Packit 910689
	if(!$error) {
Packit 910689
		my($result2) = scalar(`./$file`);
Packit 910689
		$error = $?;
Packit 910689
		unlink($file);
Packit 910689
		return ($error?undef:$result2) unless wantarray;
Packit 910689
		print "Executed successfully, status $error, link $result, exec |$result2|\n" if $Verbose;
Packit 910689
		(1,$error,$result2);
Packit 910689
	} else {
Packit 910689
		print "Link failed, status $error, message |$result|\n" if $Verbose;
Packit 910689
		return undef unless wantarray;
Packit 910689
		(0,$error,$result);
Packit 910689
	}
Packit 910689
}
Packit 910689
Packit 910689
=head2 FindHeader
Packit 910689
Packit 910689
Takes an unlimited number of arguments, consisting of both header names in
Packit 910689
the form "header.h", or directory specifications such as "-I/usr/include/bsd".
Packit 910689
For each supplied header, FindHeader will attempt to find the complete path.
Packit 910689
The return value is an array consisting of all the headers that were located.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub FindHeader { #For each supplied header name, find full path
Packit 910689
	my(@headers) = grep(!/^-I/,@_);
Packit 910689
	my(@I) = grep(/^-I/,@_);
Packit 910689
	my($h);
Packit 910689
	for $h (@headers) {
Packit 910689
		print "Searching for $h... " if $Verbose;
Packit 910689
		if($h eq "") {$h=undef; next}
Packit 910689
		if( -f $h) {next}
Packit 910689
		if( -f $Config{"usrinc"}."/".$h) {
Packit 910689
			$h = $Config{"usrinc"}."/".$h;
Packit 910689
			print "Found as $h.\n" if $Verbose;
Packit 910689
		} else {
Packit 910689
                        my $text;
Packit 910689
			if($text = CPP("#include <$h>",join(" ",@I))) {
Packit 910689
				grepcpp:
Packit 910689
				for (split(/\s+/,(grep(/^\s*#.*$h/,split(/\n/,$text)))[0])) {
Packit 910689
					if(/$h/) {
Packit 910689
						s/^\"(.*)\"$/$1/;
Packit 910689
						s/^\'(.*)\'$/$1/;					
Packit 910689
						$h = $_;
Packit 910689
						print "Found as $h.\n" if $Verbose;
Packit 910689
						last grepcpp; 
Packit 910689
					}
Packit 910689
				}
Packit 910689
			} else {
Packit 910689
				$h = undef; # remove header from resulting list
Packit 910689
				print "Not found.\n" if $Verbose;
Packit 910689
			}
Packit 910689
		}
Packit 910689
	}
Packit 910689
	grep($_,@headers);
Packit 910689
}
Packit 910689
Packit 910689
=head2 FindLib
Packit 910689
Packit 910689
Takes an unlimited number of arguments, consisting of both library names in
Packit 910689
the form "-llibname", "/usr/lib/libxyz.a" or "dld", or directory
Packit 910689
specifications such as "-L/usr/lib/foo". For each supplied library, FindLib
Packit 910689
will attempt to find the complete path. The return value is an array
Packit 910689
consisting of the full paths to all of the libraries that were located.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub FindLib { #For each supplied library name, find full path
Packit 910689
	my(@libs) = grep(!/^-L/,@_);
Packit 910689
	my(@L) = (grep(/^-L/,@_),split(" ",$Config{"libpth"}));
Packit 910689
	grep(s/^-L//,@L);
Packit 910689
	my($l);
Packit 910689
	my($so) = $Config{"so"};
Packit 910689
	my($found);
Packit 910689
	#print "Libaries I am searching for: ",join(",",@libs),"\n";
Packit 910689
	#print "Directories: ",join(",",@L),"\n";
Packit 910689
        my $lib;
Packit 910689
	for $lib (@libs) {
Packit 910689
		print "Searching for $lib... " if $Verbose;
Packit 910689
		$found=0;		
Packit 910689
		$lib =~ s/^-l//;
Packit 910689
		if($lib eq "") {$lib=undef; next}
Packit 910689
		next if -f $lib;
Packit 910689
                my $path;
Packit 910689
		for $path (@L) {
Packit 910689
                        my ( $fullname, @fullname );
Packit 910689
			print "Searching $path for $lib...\n" if $Verbose;
Packit 910689
			if (@fullname=<${path}/lib${lib}.${so}.[0-9]*>){
Packit 910689
				$fullname=$fullname[-1]; #ATTN: 10 looses against 9!
Packit 910689
			} elsif (-f ($fullname="$path/lib$lib.$so")){
Packit 910689
			} elsif (-f ($fullname="$path/lib${lib}_s.a")
Packit 910689
			&& ($lib .= "_s") ){ # we must explicitly ask for _s version
Packit 910689
			} elsif (-f ($fullname="$path/lib$lib.a")){
Packit 910689
			} elsif (-f ($fullname="$path/Slib$lib.a")){
Packit 910689
			} else { 
Packit 910689
				warn "$lib not found in $path\n" if $Verbose;
Packit 910689
				next;
Packit 910689
			}
Packit 910689
			warn "'-l$lib' found at $fullname\n" if $Verbose;
Packit 910689
			$lib = $fullname;
Packit 910689
			$found=1;
Packit 910689
		}
Packit 910689
		if(!$found) { 
Packit 910689
			$lib = undef; # Remove lib if not found
Packit 910689
			print "Not found.\n" if $Verbose;
Packit 910689
		}
Packit 910689
	}
Packit 910689
	grep($_,@libs);
Packit 910689
}
Packit 910689
Packit 910689
Packit 910689
=head2
Packit 910689
Packit 910689
Apply takes a chunk of code, a series of libraries and headers, and attempts
Packit 910689
to apply them, in series, to a given perl command. In a scalar context, the
Packit 910689
return value of the first set of headers and libraries that produces a 
Packit 910689
non-zero return value from the command is returned. In an array context, the
Packit 910689
header and library set it returned.
Packit 910689
Packit 910689
This is best explained by some examples:
Packit 910689
Packit 910689
	Apply(\&Compile,"main(){}","sgtty.h",""); 
Packit 910689
Packit 910689
In a scalar context either C<undef> or C<1>. In an array context,
Packit 910689
this returns C<()> or C<("sgtty.h","")>.
Packit 910689
Packit 910689
	Apply(\&Link,"main(){int i=COLOR_PAIRS;}","curses.h","-lcurses",
Packit 910689
	"ncurses.h","-lncurses","ncurses/ncurses.h","-lncurses");
Packit 910689
Packit 910689
In a scalar context, this returns either C<undef>, C<1>. In an array context,
Packit 910689
this returns C<("curses.h","-lcurses")>, C<("ncurses.h","-lncurses")>, 
Packit 910689
C<("ncurses/ncurses.h","-lncurses")>, or C<()>.
Packit 910689
Packit 910689
If we had instead said 
Packit 910689
C<Apply(\&Execute,'main(){printf("%d",(int)COLOR_PAIRS)',...)> then in a scalar
Packit 910689
context either C<undef> or the value of COLOR_PAIRS would be returned.
Packit 910689
Packit 910689
Note that you can also supply multiple headers and/or libraries at one time,
Packit 910689
like this:
Packit 910689
Packit 910689
	Apply(\&Compile,"main(){fcntl(0,F_GETFD);}","fcntl.h","",
Packit 910689
	"ioctl.h fcntl.h","","sys/ioctl.h fcntl.h"","");
Packit 910689
Packit 910689
So if fcntl needs ioctl or sys/ioctl loaded first, this will catch it. In an 
Packit 910689
array context, C<()>, C<("fcntl.h","")>, C<("ioctl.h fcntl.h","")>, or 
Packit 910689
C<("sys/ioctl.h fcntl.h","")> could be returned.
Packit 910689
Packit 910689
You can also use nested arrays to get exactly the same effect. The returned
Packit 910689
array will always consist of a string, though, with elements separated by
Packit 910689
spaces.
Packit 910689
Packit 910689
	Apply(\&Compile,"main(){fcntl(0,F_GETFD);}",["fcntl.h"],"",
Packit 910689
	["ioctl.h","fcntl.h"],"",["sys/ioctl.h","fcntl.h"],"");
Packit 910689
Packit 910689
Note that there are many functions that provide simpler ways of doing these
Packit 910689
things, from GetNumericSymbol to get the value of a symbol, to ApplyHeaders
Packit 910689
which doesn't ask for libraries.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub Apply { #
Packit 910689
	my($cmd,$code,@lookup) = @_;
Packit 910689
	my(@l,@h,$i,$ret);
Packit 910689
	for ($i=0;$i<@lookup;$i+=2) {
Packit 910689
		if( ref($lookup[$i]) eq "ARRAY" ) {
Packit 910689
			@h = @{$lookup[$i]};
Packit 910689
		} else {
Packit 910689
			@h = split(/\s+/,$lookup[$i]);
Packit 910689
		}
Packit 910689
		if( ref($lookup[$i+1]) eq "ARRAY" ) {
Packit 910689
			@l = @{$lookup[$i+1]};
Packit 910689
		} else {
Packit 910689
			@l = split(/\s+/,$lookup[$i+1]);
Packit 910689
		}
Packit 910689
Packit 910689
		if ($ret=&{$cmd == \&Link && !@l?\&Compile:$cmd}(
Packit 910689
                        join("",map($_?"#include <$_>\n":"",grep(!/^-I/,@h))).
Packit 910689
				$code,grep(/^-I/,@h),@l)) {
Packit 910689
			print "Ret=|$ret|\n" if $Verbose;
Packit 910689
			return $ret unless wantarray;
Packit 910689
                        return (join(" ",@h),join(" ",@l));
Packit 910689
		}
Packit 910689
	}
Packit 910689
	return 0 unless wantarray;
Packit 910689
	();
Packit 910689
}
Packit 910689
Packit 910689
=head2 ApplyHeadersAndLibs
Packit 910689
Packit 910689
This function takes the same sort of arguments as Apply, it just sends them
Packit 910689
directly to Link.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub ApplyHeadersAndLibs { #
Packit 910689
	my($code,@lookup) = @_;
Packit 910689
	Apply \&Link,$code,@lookup;
Packit 910689
}
Packit 910689
Packit 910689
=head2 ApplyHeadersAndLibsAndExecute
Packit 910689
Packit 910689
This function is similar to Apply and ApplyHeadersAndLibs, but it always
Packit 910689
uses Execute.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub ApplyHeadersAndLibsAndExecute { #
Packit 910689
	my($code,@lookup) = @_;
Packit 910689
	Apply \&Execute,$code,@lookup;
Packit 910689
}
Packit 910689
Packit 910689
=head2 ApplyHeaders
Packit 910689
Packit 910689
If you are only checking headers, and don't need to look at libs, then
Packit 910689
you will probably want to use ApplyHeaders. The return value is the same
Packit 910689
in a scalar context, but in an array context the returned array will only 
Packit 910689
consists of the headers, spread out.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub ApplyHeaders {
Packit 910689
	my($code,@headers) = @_;
Packit 910689
	return scalar(ApplyHeadersAndLibs $code, map(($_,""),@headers))
Packit 910689
		unless wantarray;	
Packit 910689
	split(/\s+/,(ApplyHeadersAndLibs $code, map(($_,""),@headers))[0]);
Packit 910689
}
Packit 910689
Packit 910689
=head2 ApplyLibs
Packit 910689
Packit 910689
If you are only checking libraries, and don't need to look at headers, then
Packit 910689
you will probably want to use ApplyLibs. The return value is the same
Packit 910689
in a scalar context, but in an array context the returned array will only 
Packit 910689
consists of the libraries, spread out.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub ApplyLibs {
Packit 910689
	my($code,@libs) = @_;
Packit 910689
	return scalar(ApplyHeadersAndLibs $code, map(("",$_),@libs))
Packit 910689
		unless wantarray;	
Packit 910689
	split(/\s+/,(ApplyHeadersAndLibs $code, map(("",$_),@libs))[0]);
Packit 910689
}
Packit 910689
Packit 910689
=head2 CheckHeader
Packit 910689
Packit 910689
Takes an unlimited number of arguments, consiting of headers in the
Packit 910689
Apply style. The first set that is fully accepted
Packit 910689
by the compiler is returned. 
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub CheckHeader { #Find a header (or set of headers) that exists
Packit 910689
	ApplyHeaders("main(){}",@_);
Packit 910689
}
Packit 910689
Packit 910689
=head2 CheckStructure
Packit 910689
Packit 910689
Takes the name of a structure, and an unlimited number of further arguments
Packit 910689
consisting of header groups. The first group that defines that structure 
Packit 910689
properly will be returned. B<undef> will be returned if nothing succeeds.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub CheckStructure { # Check existance of a structure.
Packit 910689
	my($structname,@headers) = @_;
Packit 910689
	ApplyHeaders("main(){ struct $structname s;}",@headers);
Packit 910689
}
Packit 910689
Packit 910689
=head2 CheckField
Packit 910689
Packit 910689
Takes the name of a structure, the name of a field, and an unlimited number
Packit 910689
of further arguments consisting of header groups. The first group that
Packit 910689
defines a structure that contains the field will be returned. B<undef> will
Packit 910689
be returned if nothing succeeds.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub CheckField { # Check for the existance of specified field in structure
Packit 910689
	my($structname,$fieldname,@headers) = @_;
Packit 910689
	ApplyHeaders("main(){ struct $structname s1; struct $structname s2;
Packit 910689
		     s1.$fieldname = s2.$fieldname; }",@headers);
Packit 910689
}
Packit 910689
Packit 910689
=head2 CheckLSymbol
Packit 910689
Packit 910689
Takes the name of a symbol, and an unlimited number of further arguments
Packit 910689
consisting of library groups. The first group of libraries that defines
Packit 910689
that symbol will be returned. B<undef> will be returned if nothing succeeds.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub CheckLSymbol { # Check for linkable symbol
Packit 910689
	my($symbol,@libs) = @_;
Packit 910689
	ApplyLibs("main() { void * f = (void *)($symbol); }",@libs);
Packit 910689
}
Packit 910689
Packit 910689
=head2 CheckSymbol
Packit 910689
Packit 910689
Takes the name of a symbol, and an unlimited number of further arguments
Packit 910689
consisting of header and library groups, in the Apply format. The first
Packit 910689
group of headers and libraries that defines that symbol will be returned.
Packit 910689
B<undef> will be returned if nothing succeeds.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub CheckSymbol { # Check for linkable/header symbol
Packit 910689
	my($symbol,@lookup) = @_;
Packit 910689
	ApplyHeadersAndLibs("main() { void * f = (void *)($symbol); }",@lookup);
Packit 910689
}
Packit 910689
Packit 910689
=head2 CheckHSymbol
Packit 910689
Packit 910689
Takes the name of a symbol, and an unlimited number of further arguments
Packit 910689
consisting of header groups. The first group of headers that defines
Packit 910689
that symbol will be returned. B<undef> will be returned if nothing succeeds.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub CheckHSymbol { # Check for header symbol
Packit 910689
	my($symbol,@headers) = @_;
Packit 910689
	ApplyHeaders("main() { void * f = (void *)($symbol); }",@headers);
Packit 910689
}
Packit 910689
Packit 910689
=head2 CheckHPrototype (unexported)
Packit 910689
Packit 910689
An experimental routine that takes a name of a function, a nested array
Packit 910689
consisting of the prototype, and then the normal header groups. It attempts
Packit 910689
to deduce whether the given prototype matches what the header supplies.
Packit 910689
Basically, it doesn't work. Or maybe it does. I wouldn't reccomend it,
Packit 910689
though.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub CheckHPrototype { # Check for header prototype.
Packit 910689
	# Note: This function is extremely picky about "const int" versus "int",
Packit 910689
   # and depends on having an extremely snotty compiler. Anything but GCC
Packit 910689
   # may fail, and even GCC may not work properly. In any case, if the
Packit 910689
   # names function doesn't exist, this call will _succeed_. Caveat Utilitor.
Packit 910689
	my($function,$proto,@headers) = @_;
Packit 910689
	my(@proto) = @{$proto};
Packit 910689
	ApplyHeaders("main() { extern ".$proto[0]." $function(".
Packit 910689
                     join(",",@proto[1..$#proto])."); }",@headers);
Packit 910689
}
Packit 910689
Packit 910689
=head2 GetSymbol
Packit 910689
Packit 910689
Takes the name of a symbol, a printf command, a cast, and an unlimited
Packit 910689
number of further arguments consisting of header and library groups, in the
Packit 910689
Apply. The first group of headers and libraries that defines that symbol
Packit 910689
will be used to get the contents of the symbol in the format, and return it.
Packit 910689
B<undef> will be returned if nothing defines that symbol.
Packit 910689
Packit 910689
Example:
Packit 910689
Packit 910689
	GetSymbol("__LINE__","ld","long","","");
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub GetSymbol { # Check for linkable/header symbol
Packit 910689
	my($symbol,$printf,$cast,@lookup) = @_,"","";
Packit 910689
	scalar(ApplyHeadersAndLibsAndExecute(
Packit 910689
		"main(){ printf(\"\%$printf\",($cast)($symbol));exit(0);}",@lookup));
Packit 910689
}
Packit 910689
Packit 910689
=head2 GetTextSymbol
Packit 910689
Packit 910689
Takes the name of a symbol, and an unlimited number of further arguments
Packit 910689
consisting of header and library groups, in the ApplyHeadersAndLibs format.
Packit 910689
The first group of headers and libraries that defines that symbol will be
Packit 910689
used to get the contents of the symbol in text format, and return it.
Packit 910689
B<undef> will be returned if nothing defines that symbol.
Packit 910689
Packit 910689
Note that the symbol I<must> actually be text, either a char* or a constant
Packit 910689
string. Otherwise, the results are undefined.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub GetTextSymbol { # Check for linkable/header symbol
Packit 910689
	my($symbol,@lookup) = @_,"","";
Packit 910689
	my($result) = GetSymbol($symbol,"s","char*",@lookup);
Packit 910689
	$result .= "" if defined($result);
Packit 910689
	$result;
Packit 910689
}
Packit 910689
Packit 910689
=head2 GetNumericSymbol
Packit 910689
Packit 910689
Takes the name of a symbol, and an unlimited number of further arguments
Packit 910689
consisting of header and library groups, in the ApplyHeadersAndLibs format.
Packit 910689
The first group of headers and libraries that defines that symbol will be
Packit 910689
used to get the contents of the symbol in numeric format, and return it.
Packit 910689
B<undef> will be returned if nothing defines that symbol.
Packit 910689
Packit 910689
Note that the symbol I<must> actually be numeric, in a format compatible
Packit 910689
with a float. Otherwise, the results are undefined.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub GetNumericSymbol { # Check for linkable/header symbol
Packit 910689
	my($symbol,@lookup) = @_,"","";
Packit 910689
	my($result) = GetSymbol($symbol,"f","float",@lookup);
Packit 910689
	$result += 0 if defined($result);
Packit 910689
	$result;
Packit 910689
}
Packit 910689
Packit 910689
=head2 GetConstants
Packit 910689
Packit 910689
Takes a list of header names (possibly including -I directives) and attempts
Packit 910689
to grep the specified files for constants, a constant being something #defined
Packit 910689
with a name that matches /[A-Z0-9_]+/. Returns the list of names.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
sub GetConstants { # Try to grep constants out of a header
Packit 910689
	my(@headers) = @_;
Packit 910689
	@headers = FindHeader(@headers);
Packit 910689
	my %seen;
Packit 910689
	my(%results);
Packit 910689
	map($seen{$_}=1,@headers);
Packit 910689
	while(@headers) {
Packit 910689
		$_=shift(@headers); 
Packit 910689
		next if !defined($_);
Packit 910689
		open(SEARCHHEADER,"<$_");
Packit 910689
		while(<SEARCHHEADER>) {
Packit 910689
			if(/^\s*#\s*define\s+([A-Z_][A-Za-z0-9_]+)\s+/) {
Packit 910689
				$results{$1} = 1;
Packit 910689
			} elsif(/^\s*#\s*include\s+[<"]?([^">]+)[>"]?/) {
Packit 910689
				my(@include) = FindHeader($1);
Packit 910689
				@include = grep(!$seen{$_},map(defined($_)?$_:(),@include));
Packit 910689
				push(@headers,@include);
Packit 910689
				map($seen{$_}=1,@include);
Packit 910689
			}
Packit 910689
		}
Packit 910689
		close(SEARCHHEADER);
Packit 910689
	}
Packit 910689
	keys %results;
Packit 910689
}
Packit 910689
Packit 910689
Packit 910689
=head2 DeducePrototype (unexported)
Packit 910689
Packit 910689
This one is B<really> experimental. The idea is to figure out some basic
Packit 910689
characteristics of the compiler, and then attempt to "feel out" the prototype
Packit 910689
of a function. Eventually, it may work. It is guaranteed to be very slow,
Packit 910689
and it may simply not be capable of working on some systems.
Packit 910689
Packit 910689
=cut
Packit 910689
Packit 910689
my $firstdeduce = 1;
Packit 910689
sub DeducePrototype {
Packit 910689
Packit 910689
        my (@types, $checkreturn, $checknilargs, $checkniletcargs, $checkreturnnil);
Packit 910689
        
Packit 910689
	if($firstdeduce) {
Packit 910689
		$firstdeduce=0;
Packit 910689
		my $checknumber=!Compile("
Packit 910689
extern int func(int a,int b); 
Packit 910689
extern int func(int a,int b,int c); 
Packit 910689
main(){}");
Packit 910689
		$checkreturn=!Compile("
Packit 910689
extern int func(int a,int b); 
Packit 910689
extern long func(int a,int b); 
Packit 910689
main(){}");
Packit 910689
		my $checketc=   !Compile("
Packit 910689
extern int func(int a,int b); 
Packit 910689
extern long func(int a,...); 
Packit 910689
main(){}");
Packit 910689
		my $checknumberetc=!Compile("
Packit 910689
extern int func(int a,int b); 
Packit 910689
extern int func(int a,int b,...); 
Packit 910689
main(){}");
Packit 910689
		my $checketcnumber=!Compile("
Packit 910689
extern int func(int a,int b,int c,...); 
Packit 910689
extern int func(int a,int b,...); 
Packit 910689
main(){}");
Packit 910689
		my $checkargtypes=!Compile("
Packit 910689
extern int func(int a); 
Packit 910689
extern int func(long a); 
Packit 910689
main(){}");
Packit 910689
		my $checkargsnil=!Compile("
Packit 910689
extern int func(); 
Packit 910689
extern int func(int a,int b,int c); 
Packit 910689
main(){}");
Packit 910689
		$checknilargs=!Compile("
Packit 910689
extern int func(int a,int b,int c);
Packit 910689
extern int func(); 
Packit 910689
main(){}");
Packit 910689
		my $checkargsniletc=!Compile("
Packit 910689
extern int func(...); 
Packit 910689
extern int func(int a,int b,int c); 
Packit 910689
main(){}");
Packit 910689
		$checkniletcargs=!Compile("
Packit 910689
extern int func(int a,int b,int c); 
Packit 910689
extern int func(...); 
Packit 910689
main(){}");
Packit 910689
Packit 910689
		my $checkconst=!Compile("
Packit 910689
extern int func(const int * a);
Packit 910689
extern int func(int * a);
Packit 910689
main(){ }");
Packit 910689
Packit 910689
		my $checksign=!Compile("
Packit 910689
extern int func(int a);
Packit 910689
extern int func(unsigned int a);
Packit 910689
main(){ }");
Packit 910689
Packit 910689
		$checkreturnnil=!Compile("
Packit 910689
extern func(int a);
Packit 910689
extern void func(int a);
Packit 910689
main(){ }");
Packit 910689
Packit 910689
		@types = sort grep(Compile("main(){$_ a;}"),
Packit 910689
			"void","int","long int","unsigned int","unsigned long int","long long int",
Packit 910689
			"long long","unsigned long long",
Packit 910689
			"unsigned long long int","float","long float",
Packit 910689
			"double","long double",
Packit 910689
			"char","unsigned char","short int","unsigned short int");
Packit 910689
Packit 910689
		if(Compile("main(){flurfie a;}")) { @types = (); }
Packit 910689
Packit 910689
		$Verbose=0;
Packit 910689
Packit 910689
		# Attempt to remove duplicate types (if any) from type list
Packit 910689
                my ( $i, $j );
Packit 910689
		if($checkargtypes) {
Packit 910689
			for ($i=0;$i<=$#types;$i++) {
Packit 910689
				for ($j=$i+1;$j<=$#types;$j++) {
Packit 910689
					next if $j==$i;
Packit 910689
					if(Compile("
Packit 910689
extern void func($types[$i]);
Packit 910689
extern void func($types[$j]);
Packit 910689
main(){}")) {
Packit 910689
                                            print "Removing type $types[$j] because it equals $types[$i]\n";
Packit 910689
                                            splice(@types,$j,1);
Packit 910689
                                            $j--;
Packit 910689
					}
Packit 910689
				}
Packit 910689
			}
Packit 910689
		} elsif($checkreturn) {
Packit 910689
			for ($i=0;$i<=$#types;$i++) {
Packit 910689
				for ($j=$i+1;$j<=$#types;$j++) {
Packit 910689
					next if $j==$i;
Packit 910689
					if(Compile("
Packit 910689
$types[$i] func(void);
Packit 910689
extern $types[$j] func(void);
Packit 910689
main(){}")) {
Packit 910689
						print "Removing type $types[$j] because it equals $types[$i]\n";
Packit 910689
						splice(@types,$j,1);
Packit 910689
						$j--;
Packit 910689
					}
Packit 910689
				}
Packit 910689
			}
Packit 910689
		}
Packit 910689
		$Verbose=1;
Packit 910689
Packit 910689
		print "Detect differing numbers of arguments: $checknumber\n";
Packit 910689
		print "Detect differing return types: $checkreturn\n";
Packit 910689
		print "Detect differing argument types if one is ...: $checketc\n";
Packit 910689
		print "Detect differing numbers of arguments if ... is involved: $checknumberetc\n";
Packit 910689
		print "Detect differing numbers of arguments if ... is involved #2: $checketcnumber\n";
Packit 910689
		print "Detect differing argument types: $checkargtypes\n";
Packit 910689
		print "Detect differing argument types if first has no defined args: $checkargsnil\n";
Packit 910689
		print "Detect differing argument types if second has no defined args: $checknilargs\n";
Packit 910689
		print "Detect differing argument types if first has only ...: $checkargsniletc\n";
Packit 910689
		print "Detect differing argument types if second has only ...: $checkniletcargs\n";
Packit 910689
		print "Detect differing argument types by constness: $checkconst\n";
Packit 910689
		print "Detect differing argument types by signedness: $checksign\n";
Packit 910689
		print "Detect differing return types if one is not defined: $checkreturnnil\n";
Packit 910689
		print "Types known: ",join(",",@types),"\n";
Packit 910689
Packit 910689
	}
Packit 910689
Packit 910689
	my($function,@headers) = @_;
Packit 910689
	@headers = CheckHSymbol($function,@headers);
Packit 910689
	return undef if !@headers;
Packit 910689
Packit 910689
	my $rettype = undef;
Packit 910689
	my @args = ();
Packit 910689
	my @validcount = ();
Packit 910689
Packit 910689
	# Can we check the return type without worry about arguements?
Packit 910689
	if($checkreturn and (!$checknilargs or !$checkniletcargs)) {
Packit 910689
		for (@types) {
Packit 910689
			if(ApplyHeaders("extern $_ $function(". ($checknilargs?"...":"").");main(){}",[@headers])) {
Packit 910689
				$rettype = $_; # Great, we found the return type.
Packit 910689
				last;
Packit 910689
			}
Packit 910689
		}
Packit 910689
	}
Packit 910689
Packit 910689
	if(!defined($rettype) and $checkreturnnil) {
Packit 910689
		die "No way to deduce function prototype in a rational amount of time";
Packit 910689
	}
Packit 910689
Packit 910689
	my $numargs=-1;
Packit 910689
	my $varargs=0;
Packit 910689
	for (0..32) {
Packit 910689
			if(ApplyHeaders("main(){ $function(".join(",",("0") x $_).");}",@headers)) {
Packit 910689
				$numargs=$_;
Packit 910689
				if(ApplyHeaders("main(){ $function(".join(",",("0") x ($_+1)).");}",@headers)) {
Packit 910689
					$varargs=1;
Packit 910689
				}
Packit 910689
				last
Packit 910689
			} 
Packit 910689
	}
Packit 910689
Packit 910689
	die "Unable to deduce number of arguments" if $numargs==-1;
Packit 910689
Packit 910689
	if($varargs) { $args[$numargs]="..."; }
Packit 910689
	
Packit 910689
	# OK, now we know how many arguments the thing takes.
Packit 910689
Packit 910689
Packit 910689
	if(@args>0 and !defined($rettype)) {
Packit 910689
		for (@types) {
Packit 910689
			if(defined(ApplyHeaders("extern $_ $function(".join(",",@args).");main(){}",[@headers]))) {
Packit 910689
				$rettype = $_; # Great, we found the return type.
Packit 910689
				last;
Packit 910689
			}
Packit 910689
		}
Packit 910689
	}
Packit 910689
	
Packit 910689
	print "Return type: $rettype\nArguments: ",join(",",@args),"\n";
Packit 910689
	print "Valid number of arguments: $numargs\n";
Packit 910689
	print "Accepts variable number of args: $varargs\n";
Packit 910689
}
Packit 910689
Packit 910689
Packit 910689
#$Verbose=1;
Packit 910689
Packit 910689
#print scalar(join("|",CheckHeader("sgtty.h"))),"\n";
Packit 910689
#print scalar(join("|",FindHeader(CheckHeader("sgtty.h")))),"\n";
Packit 910689
#print scalar(join("|",CheckSymbol("COLOR_PAIRS","curses.h","-lcurses","ncurses.h","-lncurses","ncurses/ncurses.h","ncurses/libncurses.a"))),"\n";
Packit 910689
#print scalar(join("|",GetNumericSymbol("PRIO_USER","sys/resource.h",""))),"\n";
Packit 910689