Skip Menu |

This queue is for tickets about the Devel-CheckLib CPAN distribution.

Report information
The Basics
Id: 60176
Status: open
Priority: 0/
Queue: Devel-CheckLib

People
Owner: Nobody in particular
Requestors: TONYC [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.699_002
Fixed in: (no value)



Subject: no way to test with dependent libraries
Some libraries, on some platforms, require other libraries to perform their function. For example, on OpenBSD 4.7 the standard libpng package requires libz and libm to be linked in, otherwise some symbols are unresolved: # sample code from probes I do for Imager 0.75_02 bash-4.0$ cat pngtest.c #include <png.h> #include <stdio.h> int main() { fprintf(stderr, "PNG: library version %ld, header version %ld\n", (long)png_access_version_number(), (long)PNG_LIBPNG_VER); return 0; } bash-4.0$ pkg-config --libs libpng -L/usr/local/lib -lpng -lz -lm bash-4.0$ pkg-config --cflags libpng -I/usr/local/include/libpng bash-4.0$ cc -opngtest pngtest.c -I/usr/local/include/libpng -L/usr/local/lib -lpng -lz -lm bash-4.0$ ./pngtest PNG: library version 10241, header version 10241 And yes, the extra libraries specified by pkg-config are required: bash-4.0$ cc -opngtest pngtest.c -I/usr/local/include/libpng -L/usr/local/lib -lpng /usr/local/lib/libpng.so.9.0: undefined reference to `deflate' /usr/local/lib/libpng.so.9.0: undefined reference to `inflate' /usr/local/lib/libpng.so.9.0: undefined reference to `inflateInit_' /usr/local/lib/libpng.so.9.0: undefined reference to `crc32' /usr/local/lib/libpng.so.9.0: undefined reference to `pow' /usr/local/lib/libpng.so.9.0: undefined reference to `deflateInit2_' /usr/local/lib/libpng.so.9.0: undefined reference to `inflateReset' /usr/local/lib/libpng.so.9.0: undefined reference to `deflateReset' /usr/local/lib/libpng.so.9.0: undefined reference to `inflateEnd' /usr/local/lib/libpng.so.9.0: undefined reference to `deflateEnd' collect2: ld returned 1 exit status Now, if I supply LIBS with "-L/usr/local/lib -lpng -lz -lm" to EU::MM it will use all of those options at once to build the library: # extract from building Imager with the Devel::CheckLib check disabled LD_RUN_PATH="/usr/local/lib:/usr/lib" cc -shared -fPIC -fstack-protector PNG.o impng.o -o ../blib/arch/auto/Imager/File/PNG/PNG.so -L/usr/local/lib -lpng -lz -lm unfortunately Devel::CheckLib will apply the library options one at a time, and so failing every time: bash-4.0$ cat checklib.pl #!perl -w use Devel::CheckLib; assert_lib ( debug => 1, function => <<'CODE', fprintf(stderr, "PNG: library version %ld, header version %ld\n", (long)png_access_version_number(), (long)PNG_LIBPNG_VER); return 0; CODE LIBS => "-L/usr/local/lib -lpng -lz -lm", INC => "-I/usr/local/include/libpng", header => [ "png.h", "stdio.h" ], ); bash-4.0$ perl -I/home/tony/dev/imager/svn/Imager/inc checklib.pl # /usr/bin/cc assertlib7SvTIKT4.c -I/usr/local/include/libpng -o assertlib9L8Q6Za_ # /usr/bin/cc assertlibIa6SBYbZ.c -I/usr/local/include/libpng -o assertlibYpJcXz1F # /usr/bin/cc assertlib_xG5BLU_.c -o assertlibDFkVO8hE -lpng -I/usr/local/include/libpng -L/usr/local/lib /usr/local/lib/libpng.so.9.0: undefined reference to `deflate' /usr/local/lib/libpng.so.9.0: undefined reference to `inflate' /usr/local/lib/libpng.so.9.0: undefined reference to `inflateInit_' /usr/local/lib/libpng.so.9.0: undefined reference to `crc32' /usr/local/lib/libpng.so.9.0: undefined reference to `pow' /usr/local/lib/libpng.so.9.0: undefined reference to `deflateInit2_' /usr/local/lib/libpng.so.9.0: undefined reference to `inflateReset' /usr/local/lib/libpng.so.9.0: undefined reference to `deflateReset' /usr/local/lib/libpng.so.9.0: undefined reference to `inflateEnd' /usr/local/lib/libpng.so.9.0: undefined reference to `deflateEnd' collect2: ld returned 1 exit status # /usr/bin/cc assertlib_xG5BLU_.c -o assertlib1DI8N7tq -lz -I/usr/local/include/libpng -L/usr/local/lib /tmp//ccfQ8IgC.o(.text+0x21): In function `main': : undefined reference to `png_access_version_number' collect2: ld returned 1 exit status # /usr/bin/cc assertlib_xG5BLU_.c -o assertlibstnQw0RH -lm -I/usr/local/include/libpng -L/usr/local/lib /tmp//ccxlAPpV.o(.text+0x21): In function `main': : undefined reference to `png_access_version_number' collect2: ld returned 1 exit status Can't link/include 'png', 'z', 'm' I'm willing to produce a patch for this, but making the behaviour match EU::MM behaviour would break backwards compatibility, since the current split-the-scalar-on-whitespace behaviour would need to be changed. Also, unfortunately, I don't see a way to make the LIBS behaviour exactly match the separate lib and libpaths parameters, since each values in the LIBS array is independent, while D::CL applies all values in libpath to each separate library name in libs. I expect I'd need to build a set of libtests, each with libpaths and libraries, which would be built in different ways depending on whether LIBS was supplied or lib/libpath. Tony
Subject: [patch] no way to test with dependent libraries
Patch: make LIBS act like EU::MM whether supplied as a scalar or array ref. This may break backward compatibility. This is the patch within the Imager dev tree, so the base directory is a bit off.
Subject: dc-like-eu-mm.diff
Index: Devel/CheckLib.pm =================================================================== --- Devel/CheckLib.pm (revision 1785) +++ Devel/CheckLib.pm (revision 1786) @@ -185,6 +185,11 @@ @incpaths = (ref($args{incpath}) ? @{$args{incpath}} : $args{incpath}) if $args{incpath}; + # each entry is an arrayref containing: + # 0: arrayref of library search paths + # 1: arrayref of library names + my @link_cfgs = map [ \@libpaths, [ $_ ] ], @libs; + # work-a-like for Makefile.PL's LIBS and INC arguments # if given as command-line argument, append to %args for my $arg (@ARGV) { @@ -197,12 +202,14 @@ } } } - # 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); - push @{$arg =~ /^-l/ ? \@libs : \@libpaths}, substr($arg, 2); + my @LIBS = ref $args{LIBS} ? @{$args{LIBS}} : split ' ', $args{LIBS}; + foreach my $arg (@LIBS) { + my @sep = split ' ', $arg; + my @libs = map { /^-l(.+)$/ ? $1 : () } @sep; + my @paths = map { /^-L(.+)$/ ? $1 : () } @sep; + push @link_cfgs, [ \@paths, \@libs ]; } } if(defined($args{INC})) { @@ -263,7 +270,8 @@ print $ch qq{#include <$_>\n} foreach (@headers); print $ch "int main(void) { ".($args{function} || 'return 0;')." }\n"; close($ch); - for my $lib ( @libs ) { + for my $link_cfg ( @link_cfgs ) { + my ($paths, $libs) = @$link_cfg; my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe}; my @sys_cmd; if ( $Config{cc} eq 'cl' ) { # Microsoft compiler @@ -275,20 +283,20 @@ @sys_cmd = ( @cc, $cfile, - "${lib}.lib", + ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", - (map {'/libpath:'.Win32::GetShortPathName($_)} @libpaths), + (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( @cc, "-o$exefile", - "-l$lib", + (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), - (map { "-L$_" } @libpaths), + (map { "-L$_" } @$paths), $cfile); } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @@ -296,15 +304,15 @@ @cc, $cfile, "-o", "$exefile", - "-l$lib", + (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), - (map { "-L$_" } @libpaths) + (map { "-L$_" } @$paths) ); } 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; + push @missing, @$libs if $rv != 0 || ! -x $exefile; + push @wrongresult, @$libs if $rv == 0 && -x $exefile && system(File::Spec->rel2abs($exefile)) != 0; _cleanup_exe($exefile); } unlink $cfile;
Subject: [PATCH] no way to test with dependent libraries
Patch: make LIBS act like EU::MM when supplied as an array ref, but backward compatibly when supplied as a scalar. This should retain backward compability. This is the patch within the Imager dev tree, so the base directory is a bit off.
Subject: dc-compat.diff
Index: Devel/CheckLib.pm =================================================================== --- Devel/CheckLib.pm (revision 1785) +++ Devel/CheckLib.pm (revision 1788) @@ -185,6 +185,11 @@ @incpaths = (ref($args{incpath}) ? @{$args{incpath}} : $args{incpath}) if $args{incpath}; + # each entry is an arrayref containing: + # 0: arrayref of library search paths + # 1: arrayref of library names + my @link_cfgs = map [ \@libpaths, [ $_ ] ], @libs; + # work-a-like for Makefile.PL's LIBS and INC arguments # if given as command-line argument, append to %args for my $arg (@ARGV) { @@ -197,13 +202,25 @@ } } } - # 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); - push @{$arg =~ /^-l/ ? \@libs : \@libpaths}, substr($arg, 2); - } + if (ref $args{LIBS}) { + foreach my $arg (@{$args{LIBS}}) { + my @sep = split ' ', $arg; + my @libs = map { /^-l(.+)$/ ? $1 : () } @sep; + my @paths = map { /^-L(.+)$/ ? $1 : () } @sep; + push @link_cfgs, [ \@paths, \@libs ]; + } + } + else { + my @libs; + my @paths; + foreach my $arg (split(' ', $args{LIBS})) { + die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-l/i); + push @{$arg =~ /^-l/ ? \@libs : \@paths}, substr($arg, 2); + } + push @link_cfgs, map [ \@paths, [ $_ ] ], @libs; + } } if(defined($args{INC})) { foreach my $arg (split(' ', $args{INC})) { @@ -263,7 +280,8 @@ print $ch qq{#include <$_>\n} foreach (@headers); print $ch "int main(void) { ".($args{function} || 'return 0;')." }\n"; close($ch); - for my $lib ( @libs ) { + for my $link_cfg ( @link_cfgs ) { + my ($paths, $libs) = @$link_cfg; my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe}; my @sys_cmd; if ( $Config{cc} eq 'cl' ) { # Microsoft compiler @@ -275,20 +293,20 @@ @sys_cmd = ( @cc, $cfile, - "${lib}.lib", + ( map { "$_.lib" } @$libs ), "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", - (map {'/libpath:'.Win32::GetShortPathName($_)} @libpaths), + (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( @cc, "-o$exefile", - "-l$lib", + (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), - (map { "-L$_" } @libpaths), + (map { "-L$_" } @$paths), $cfile); } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @@ -296,15 +314,15 @@ @cc, $cfile, "-o", "$exefile", - "-l$lib", + (map { "-l$_" } @$libs ), (map { "-I$_" } @incpaths), - (map { "-L$_" } @libpaths) + (map { "-L$_" } @$paths) ); } 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; + push @missing, @$libs if $rv != 0 || ! -x $exefile; + push @wrongresult, @$libs if $rv == 0 && -x $exefile && system(File::Spec->rel2abs($exefile)) != 0; _cleanup_exe($exefile); } unlink $cfile;
Thanks. I'll apply this. However, I can't promise when I'll release it, as I also have some Windows bugs to fix.