Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated included Devel::CheckLib to resolve issues with v5.17.x perls #1

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 78 additions & 22 deletions inc/Devel/CheckLib.pm
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
package # package #
Devel::CheckLib; Devel::CheckLib;


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


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


require Exporter; require Exporter;
@ISA = qw(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 # localising prevents the warningness leaking out of this module
local $^W = 1; # use warnings is a 5.6-ism local $^W = 1; # use warnings is a 5.6-ism
Expand Down Expand Up @@ -151,6 +153,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 result -- which is what you want if an external library dependency is not
available. 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 =cut


sub check_lib_or_exit { sub check_lib_or_exit {
Expand All @@ -161,6 +168,11 @@ sub check_lib_or_exit {
} }
} }


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

sub assert_lib { sub assert_lib {
my %args = @_; my %args = @_;
my (@libs, @libpaths, @headers, @incpaths); my (@libs, @libpaths, @headers, @incpaths);
Expand All @@ -178,7 +190,7 @@ sub assert_lib {
# work-a-like for Makefile.PL's LIBS and INC arguments # work-a-like for Makefile.PL's LIBS and INC arguments
# if given as command-line argument, append to %args # if given as command-line argument, append to %args
for my $arg (@ARGV) { 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) { if (my ($mm_attr_value) = $arg =~ /\A $mm_attr_key = (.*)/x) {
# it is tempting to put some \s* into the expression, but the # it is tempting to put some \s* into the expression, but the
# MM command-line parser only accepts LIBS etc. followed by =, # MM command-line parser only accepts LIBS etc. followed by =,
Expand All @@ -202,54 +214,66 @@ sub assert_lib {
} }
} }


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


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


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


my $miss_string = join( q{, }, map { qq{'$_'} } @missing ); 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); my $wrong_string = join( q{, }, map { qq{'$_'} } @wrongresult);
die("wrong result: $wrong_string\n") if @wrongresult; die("wrong result: $wrong_string\n") if @wrongresult;
} }
Expand All @@ -311,16 +342,37 @@ sub _cleanup_exe {
unlink $exefile if -f $exefile; unlink $exefile if -f $exefile;
unlink $ofile if -f $ofile; unlink $ofile if -f $ofile;
unlink "$exefile\.manifest" if -f "$exefile\.manifest"; 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
} }


# 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 { 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 @paths = split(/$Config{path_sep}/, $ENV{PATH});
my @cc = split(/\s+/, $Config{cc}); my @cc = split(/\s+/, $Config{cc});
return @cc if -x $cc[0]; return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0];
foreach my $path (@paths) { foreach my $path (@paths) {
my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; 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"); die("Couldn't find your C compiler\n");
} }
Expand Down Expand Up @@ -409,10 +461,14 @@ David Cantrell E<lt>david@cantrell.org.ukE<gt>


David Golden E<lt>dagolden@cpan.orgE<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 Thanks to the cpan-testers-discuss mailing list for prompting us to write it
in the first place; 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 =head1 COPYRIGHT and LICENCE


Expand Down