Skip to content

Commit

Permalink
update Devel::CheckLib
Browse files Browse the repository at this point in the history
  • Loading branch information
trinitum committed May 25, 2013
1 parent 4387974 commit de2f03c
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 25 deletions.
11 changes: 11 additions & 0 deletions Makefile.PL
@@ -1,3 +1,14 @@
use lib qw(inc);
use Devel::CheckLib;

# Prompt the user here for any paths and other configuration

check_lib_or_exit(
# fill in what you prompted the user for here
lib => [qw()]
);


use lib qw(inc);
use Devel::CheckLib;
use ExtUtils::MakeMaker;
Expand Down
112 changes: 87 additions & 25 deletions inc/Devel/CheckLib.pm
@@ -1,18 +1,21 @@
# $Id: CheckLib.pm,v 1.25 2008/10/27 12:16:23 drhyde Exp $

package Devel::CheckLib;
package #
Devel::CheckLib;

use 5.00405; #postfix foreach
use strict;
use vars qw($VERSION @ISA @EXPORT);
$VERSION = '0.699_001';
use Config;
$VERSION = '0.99';
use Config qw(%Config);
use Text::ParseWords 'quotewords';

use File::Spec;
use File::Temp;

require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(assert_lib check_lib_or_exit);
@EXPORT = qw(assert_lib check_lib_or_exit check_lib);

# localising prevents the warningness leaking out of this module
local $^W = 1; # use warnings is a 5.6-ism
Expand Down Expand Up @@ -112,6 +115,11 @@ libraries (each preceded by '-l') and directories (preceded by '-L').
This can also be supplied on the command-line.
=item debug
If true - emit information during processing that can be used for
debugging.
=back
And libraries are no use without header files, so ...
Expand Down Expand Up @@ -150,6 +158,11 @@ causing a CPAN Testers 'FAIL' report. CPAN Testers should ignore this
result -- which is what you want if an external library dependency is not
available.
=head2 check_lib
This behaves exactly the same as C<assert_lib()> except that it is silent,
returning false instead of dieing, or true otherwise.
=cut

sub check_lib_or_exit {
Expand All @@ -160,6 +173,11 @@ sub check_lib_or_exit {
}
}

sub check_lib {
eval 'assert_lib(@_)';
return $@ ? 0 : 1;
}

sub assert_lib {
my %args = @_;
my (@libs, @libpaths, @headers, @incpaths);
Expand All @@ -177,7 +195,7 @@ sub assert_lib {
# work-a-like for Makefile.PL's LIBS and INC arguments
# if given as command-line argument, append to %args
for my $arg (@ARGV) {
for my $mm_attr_key qw(LIBS INC) {
for my $mm_attr_key (qw(LIBS INC)) {
if (my ($mm_attr_value) = $arg =~ /\A $mm_attr_key = (.*)/x) {
# it is tempting to put some \s* into the expression, but the
# MM command-line parser only accepts LIBS etc. followed by =,
Expand All @@ -190,7 +208,7 @@ sub assert_lib {
# using special form of split to trim whitespace
if(defined($args{LIBS})) {
foreach my $arg (split(' ', $args{LIBS})) {
die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-l/i);
die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-[lLR]/);
push @{$arg =~ /^-l/ ? \@libs : \@libpaths}, substr($arg, 2);
}
}
Expand All @@ -201,54 +219,66 @@ sub assert_lib {
}
}

my @cc = _findcc();
my ($cc, $ld) = _findcc();
my @missing;
my @wrongresult;
my @use_headers;

# first figure out which headers we can't find ...
for my $header (@headers) {
push @use_headers, $header;
my($ch, $cfile) = File::Temp::tempfile(
'assertlibXXXXXXXX', SUFFIX => '.c'
);
print $ch qq{#include <$header>\nint main(void) { return 0; }\n};
my $ofile = $cfile;
$ofile =~ s/\.c$/$Config{_o}/;
print $ch qq{#include <$_>\n} for @use_headers;
print $ch qq{int main(void) { return 0; }\n};
close($ch);
my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
my @sys_cmd;
# FIXME: re-factor - almost identical code later when linking
if ( $Config{cc} eq 'cl' ) { # Microsoft compiler
require Win32;
@sys_cmd = (
@cc,
@$cc,
$cfile,
"/Fe$exefile",
(map { '/I'.Win32::GetShortPathName($_) } @incpaths)
(map { '/I'.Win32::GetShortPathName($_) } @incpaths),
"/link",
@$ld
);
} elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland
@sys_cmd = (
@cc,
@$cc,
@$ld,
(map { "-I$_" } @incpaths),
"-o$exefile",
$cfile
);
} else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ...
@sys_cmd = (
@cc,
@$cc,
@$ld,
$cfile,
(map { "-I$_" } @incpaths),
"-o", "$exefile"
);
}
warn "# @sys_cmd\n" if $args{debug};
my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
push @missing, $header if $rv != 0 || ! -x $exefile;
push @missing, $header if $rv != 0 || ! -x $exefile;
_cleanup_exe($exefile);
unlink $ofile if -e $ofile;
unlink $cfile;
}

# now do each library in turn with headers
my($ch, $cfile) = File::Temp::tempfile(
'assertlibXXXXXXXX', SUFFIX => '.c'
);
my $ofile = $cfile;
$ofile =~ s/\.c$/$Config{_o}/;
print $ch qq{#include <$_>\n} foreach (@headers);
print $ch "int main(void) { ".($args{function} || 'return 0;')." }\n";
close($ch);
Expand All @@ -260,45 +290,52 @@ sub assert_lib {
my @libpath = map {
q{/libpath:} . Win32::GetShortPathName($_)
} @libpaths;
# this is horribly sensitive to the order of arguments
@sys_cmd = (
@cc,
@$cc,
$cfile,
"${lib}.lib",
"/Fe$exefile",
(map { '/I'.Win32::GetShortPathName($_) } @incpaths),
"/link",
@$ld,
(map {'/libpath:'.Win32::GetShortPathName($_)} @libpaths),
(map { '/I'.Win32::GetShortPathName($_) } @incpaths)
);
} elsif($Config{cc} eq 'CC/DECC') { # VMS
} elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland
@sys_cmd = (
@cc,
@$cc,
@$ld,
"-o$exefile",
"-l$lib",
(map { "-I$_" } @incpaths),
(map { "-L$_" } @libpaths),
"-l$lib",
$cfile);
} else { # Unix-ish
# gcc, Sun, AIX (gcc, cc)
@sys_cmd = (
@cc,
@$cc,
@$ld,
$cfile,
"-o", "$exefile",
"-l$lib",
(map { "-I$_" } @incpaths),
(map { "-L$_" } @libpaths)
(map { "-L$_" } @libpaths),
"-l$lib",
);
}
warn "# @sys_cmd\n" if $args{debug};
my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
push @missing, $lib if $rv != 0 || ! -x $exefile;
push @wrongresult, $lib if $rv == 0 && -x $exefile && system(File::Spec->rel2abs($exefile)) != 0;
my $absexefile = File::Spec->rel2abs($exefile);
$absexefile = '"'.$absexefile.'"' if $absexefile =~ m/\s/;
push @wrongresult, $lib if $rv == 0 && -x $exefile && system($absexefile) != 0;
unlink $ofile if -e $ofile;
_cleanup_exe($exefile);
}
unlink $cfile;

my $miss_string = join( q{, }, map { qq{'$_'} } @missing );
die("Can't link/include $miss_string\n") if @missing;
die("Can't link/include C library $miss_string, aborting.\n") if @missing;
my $wrong_string = join( q{, }, map { qq{'$_'} } @wrongresult);
die("wrong result: $wrong_string\n") if @wrongresult;
}
Expand All @@ -310,16 +347,37 @@ sub _cleanup_exe {
unlink $exefile if -f $exefile;
unlink $ofile if -f $ofile;
unlink "$exefile\.manifest" if -f "$exefile\.manifest";
if ( $Config{cc} eq 'cl' ) {
# MSVC also creates foo.ilk and foo.pdb
my $ilkfile = $exefile;
$ilkfile =~ s/$Config{_exe}$/.ilk/;
my $pdbfile = $exefile;
$pdbfile =~ s/$Config{_exe}$/.pdb/;
unlink $ilkfile if -f $ilkfile;
unlink $pdbfile if -f $pdbfile;
}
return
}

# return ($cc, $ld)
# where $cc is an array ref of compiler name, compiler flags
# where $ld is an array ref of linker flags
sub _findcc {
# Need to use $keep=1 to work with MSWin32 backslashes and quotes
my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile
my @Config_ldflags = ();
for my $config_val ( @Config{qw(ldflags perllibs)} ){
push @Config_ldflags, $config_val if ( $config_val =~ /\S/ );
}
my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags||'');
my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags);
my @paths = split(/$Config{path_sep}/, $ENV{PATH});
my @cc = split(/\s+/, $Config{cc});
return @cc if -x $cc[0];
return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0];
foreach my $path (@paths) {
my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe};
return ($compiler, @cc[1 .. $#cc]) if -x $compiler;
return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags)
if -x $compiler;
}
die("Couldn't find your C compiler\n");
}
Expand Down Expand Up @@ -408,10 +466,14 @@ David Cantrell E<lt>david@cantrell.org.ukE<gt>
David Golden E<lt>dagolden@cpan.orgE<gt>
Yasuhiro Matsumoto E<lt>mattn@cpan.orgE<gt>
Thanks to the cpan-testers-discuss mailing list for prompting us to write it
in the first place;
to Chris Williams for help with Borland support.
to Chris Williams for help with Borland support;
to Tony Cook for help with Microsoft compiler command-line options
=head1 COPYRIGHT and LICENCE
Expand Down

0 comments on commit de2f03c

Please sign in to comment.