File Coverage

blib/lib/Devel/CheckLib.pm
Criterion Covered Total %
statement 161 202 79.7
branch 72 136 52.9
condition 20 37 54.0
subroutine 18 19 94.7
pod 3 4 75.0
total 274 398 68.8


line stmt bran cond sub pod time code
1             # $Id: CheckLib.pm,v 1.25 2008/10/27 12:16:23 drhyde Exp $
2              
3             package Devel::CheckLib;
4              
5 11     11   7942 use 5.00405; #postfix foreach
  11         35  
6 11     11   51 use strict;
  11         14  
  11         267  
7 11     11   47 use vars qw($VERSION @ISA @EXPORT);
  11         18  
  11         650  
8             $VERSION = '1.15';
9 11     11   55 use Config qw(%Config);
  11         23  
  11         474  
10 11     11   4298 use Text::ParseWords qw(quotewords shellwords);
  11         12444  
  11         575  
11              
12 11     11   63 use File::Spec;
  11         23  
  11         216  
13 11     11   2593 use File::Temp;
  11         58701  
  11         1816  
14              
15             require Exporter;
16             @ISA = qw(Exporter);
17             @EXPORT = qw(assert_lib check_lib_or_exit check_lib);
18              
19             # localising prevents the warningness leaking out of this module
20             local $^W = 1; # use warnings is a 5.6-ism
21              
22             _findcc(); # bomb out early if there's no compiler
23              
24             =head1 NAME
25              
26             Devel::CheckLib - check that a library is available
27              
28             =head1 DESCRIPTION
29              
30             Devel::CheckLib is a perl module that checks whether a particular C
31             library and its headers are available.
32              
33             =head1 SYNOPSIS
34              
35             use Devel::CheckLib;
36              
37             check_lib_or_exit( lib => 'jpeg', header => 'jpeglib.h' );
38             check_lib_or_exit( lib => [ 'iconv', 'jpeg' ] );
39            
40             # or prompt for path to library and then do this:
41             check_lib_or_exit( lib => 'jpeg', libpath => $additional_path );
42              
43             =head1 USING IT IN Makefile.PL or Build.PL
44              
45             If you want to use this from Makefile.PL or Build.PL, do
46             not simply copy the module into your distribution as this may cause
47             problems when PAUSE and search.cpan.org index the distro. Instead, use
48             the use-devel-checklib script.
49              
50             =head1 HOW IT WORKS
51              
52             You pass named parameters to a function, describing to it how to build
53             and link to the libraries.
54              
55             It works by trying to compile some code - which defaults to this:
56              
57             int main(int argc, char *argv[]) { return 0; }
58              
59             and linking it to the specified libraries. If something pops out the end
60             which looks executable, it gets executed, and if main() returns 0 we know
61             that it worked. That tiny program is
62             built once for each library that you specify, and (without linking) once
63             for each header file.
64              
65             If you want to check for the presence of particular functions in a
66             library, or even that those functions return particular results, then
67             you can pass your own function body for main() thus:
68              
69             check_lib_or_exit(
70             function => 'foo();if(libversion() > 5) return 0; else return 1;'
71             incpath => ...
72             libpath => ...
73             lib => ...
74             header => ...
75             );
76              
77             In that case, it will fail to build if either foo() or libversion() don't
78             exist, and main() will return the wrong value if libversion()'s return
79             value isn't what you want.
80              
81             =head1 FUNCTIONS
82              
83             All of these take the same named parameters and are exported by default.
84             To avoid exporting them, C.
85              
86             =head2 assert_lib
87              
88             This takes several named parameters, all of which are optional, and dies
89             with an error message if any of the libraries listed can
90             not be found. B: dying in a Makefile.PL or Build.PL may provoke
91             a 'FAIL' report from CPAN Testers' automated smoke testers. Use
92             C instead.
93              
94             The named parameters are:
95              
96             =over
97              
98             =item lib
99              
100             Must be either a string with the name of a single
101             library or a reference to an array of strings of library names. Depending
102             on the compiler found, library names will be fed to the compiler either as
103             C<-l> arguments or as C<.lib> file names. (E.g. C<-ljpeg> or C)
104              
105             =item libpath
106              
107             a string or an array of strings
108             representing additional paths to search for libraries.
109              
110             =item LIBS
111              
112             a C-style space-separated list of
113             libraries (each preceded by '-l') and directories (preceded by '-L').
114              
115             This can also be supplied on the command-line.
116              
117             =item debug
118              
119             If true - emit information during processing that can be used for
120             debugging.
121              
122             =back
123              
124             And libraries are no use without header files, so ...
125              
126             =over
127              
128             =item header
129              
130             Must be either a string with the name of a single
131             header file or a reference to an array of strings of header file names.
132              
133             =item incpath
134              
135             a string or an array of strings
136             representing additional paths to search for headers.
137              
138             =item INC
139              
140             a C-style space-separated list of
141             incpaths, each preceded by '-I'.
142              
143             This can also be supplied on the command-line.
144              
145             =item ccflags
146              
147             Extra flags to pass to the compiler.
148              
149             =item ldflags
150              
151             Extra flags to pass to the linker.
152              
153             =item analyze_binary
154              
155             a callback function that will be invoked in order to perform custom
156             analysis of the generated binary. The callback arguments are the
157             library name and the path to the binary just compiled.
158              
159             It is possible to use this callback, for instance, to inspect the
160             binary for further dependencies.
161              
162             =item not_execute
163              
164             Do not try to execute generated binary. Only check that compilation has not failed.
165              
166             =back
167              
168             =head2 check_lib_or_exit
169              
170             This behaves exactly the same as C except that instead of
171             dieing, it warns (with exactly the same error message) and exits.
172             This is intended for use in Makefile.PL / Build.PL
173             when you might want to prompt the user for various paths and
174             things before checking that what they've told you is sane.
175              
176             If any library or header is missing, it exits with an exit value of 0 to avoid
177             causing a CPAN Testers 'FAIL' report. CPAN Testers should ignore this
178             result -- which is what you want if an external library dependency is not
179             available.
180              
181             =head2 check_lib
182              
183             This behaves exactly the same as C except that it is silent,
184             returning false instead of dieing, or true otherwise.
185              
186             =cut
187              
188             sub check_lib_or_exit {
189 0     0 1 0 eval 'assert_lib(@_)';
190 0 0       0 if($@) {
191 0         0 warn $@;
192 0         0 exit;
193             }
194             }
195              
196             sub check_lib {
197 8     8 1 19074 eval 'assert_lib(@_)';
198 8 100       359 return $@ ? 0 : 1;
199             }
200              
201             # borrowed from Text::ParseWords
202             sub _parse_line {
203 31     31   155 my($delimiter, $keep, $line) = @_;
204 31         114 my($word, @pieces);
205              
206 11     11   70 no warnings 'uninitialized'; # we will be testing undef strings
  11         32  
  11         26188  
207              
208 31         137 while (length($line)) {
209             # This pattern is optimised to be stack conservative on older perls.
210             # Do not refactor without being careful and testing it on very long strings.
211             # See Perl bug #42980 for an example of a stack busting input.
212 0 0       0 $line =~ s/^
213             (?:
214             # double quoted string
215             (") # $quote
216             ((?>[^\\"]*(?:\\.[^\\"]*)*))" # $quoted
217             | # --OR--
218             # singe quoted string
219             (') # $quote
220             ((?>[^\\']*(?:\\.[^\\']*)*))' # $quoted
221             | # --OR--
222             # unquoted string
223             ( # $unquoted
224             (?:\\.|[^\\"'])*?
225             )
226             # followed by
227             ( # $delim
228             \Z(?!\n) # EOL
229             | # --OR--
230             (?-x:$delimiter) # delimiter
231             | # --OR--
232             (?!^)(?=["']) # a quote
233             )
234             )//xs or return; # extended layout
235 0 0       0 my ($quote, $quoted, $unquoted, $delim) = (($1 ? ($1,$2) : ($3,$4)), $5, $6);
236              
237 0 0 0     0 return() unless( defined($quote) || length($unquoted) || length($delim));
      0        
238              
239 0 0       0 if ($keep) {
240 0         0 $quoted = "$quote$quoted$quote";
241             }
242             else {
243 0         0 $unquoted =~ s/\\(.)/$1/sg;
244 0 0       0 if (defined $quote) {
245 0 0       0 $quoted =~ s/\\(.)/$1/sg if ($quote eq '"');
246             }
247             }
248 0         0 $word .= substr($line, 0, 0); # leave results tainted
249 0 0       0 $word .= defined $quote ? $quoted : $unquoted;
250              
251 0 0       0 if (length($delim)) {
252 0         0 push(@pieces, $word);
253 0 0       0 push(@pieces, $delim) if ($keep eq 'delimiters');
254 0         0 undef $word;
255             }
256 0 0       0 if (!length($line)) {
257 0         0 push(@pieces, $word);
258             }
259             }
260 31         96 return(@pieces);
261             }
262              
263             sub _parsewords {
264 126 50   126   963 return shellwords @_ if $^O ne 'MSWin32';
265             # for Win32, take off "" but leave \
266 0   0     0 map { my $s=$_; $s =~ s/^"(.*)"$/$1/; $s } grep defined && length, quotewords '\s+', 1, @_;
  0         0  
  0         0  
  0         0  
267             }
268              
269             sub _compile_cmd {
270 48     48   930 my ($Config_cc, $cc, $cfile, $exefile, $incpaths, $ld, $Config_libs, $lib, $libpaths) = @_;
271 48         219 my @sys_cmd = @$cc;
272 48 50       242 if ( $Config_cc eq 'cl' ) { # Microsoft compiler
    50          
273             # this is horribly sensitive to the order of arguments
274 0 0       0 push @sys_cmd,
    0          
275             $cfile,
276             (defined $lib ? "${lib}.lib" : ()),
277             "/Fe$exefile",
278             (map '/I'.$_, @$incpaths),
279             "/link",
280             @$ld,
281             _parsewords($Config_libs),
282             (defined $lib ? map '/libpath:'.$_, @$libpaths : ()),
283             ;
284             } elsif($Config_cc =~ /bcc32(\.exe)?/) { # Borland
285 0 0       0 push @sys_cmd,
286             @$ld,
287             (map "-I$_", @$incpaths),
288             "-o$exefile",
289             (defined $lib ? ((map "-L$_", @$libpaths), "-l$lib") : ()),
290             $cfile,
291             ;
292             } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ...
293             push @sys_cmd,
294             (map "-I$_", @$incpaths),
295             $cfile,
296             (!defined $lib ? () : (
297             (map "-L$_", @$libpaths),
298 48 50       535 ($^O eq 'darwin' ? (map { "-Wl,-rpath,$_" } @$libpaths) : ()),
  0 100       0  
299             "-l$lib",
300             )),
301             @$ld,
302             "-o", $exefile,
303             ;
304             }
305 48         252 @sys_cmd;
306             }
307              
308             sub _make_cfile {
309 43     43   184 my ($use_headers, $function, $debug) = @_;
310 43         158 my $code = '';
311 43         222 $code .= qq{#include <$_>\n} for @$use_headers;
312 43   100     341 $code .= "int main(int argc, char *argv[]) { ".($function || 'return 0;')." }\n";
313 43 50       146 if ($debug) {
314 0         0 (my $c = $code) =~ s:^:# :gm;
315 0         0 warn "# Code:\n$c\n";
316             }
317 43         564 my ($ch, $cfile) = File::Temp::tempfile(
318             'assertlibXXXXXXXX', SUFFIX => '.c'
319             );
320 43         19957 print $ch $code;
321 43         1939 close $ch;
322 43         823 (my $ofile = $cfile) =~ s/\.c$/$Config{_o}/;
323 43         353 ($cfile, $ofile);
324             }
325              
326             sub assert_lib {
327 31     31 1 67749 my %args = @_;
328             $args{$_} = [$args{$_}]
329 31   100     656 for grep $args{$_} && !ref($args{$_}), qw(lib libpath header incpath);
330 31 100       90 my @libs = @{$args{lib} || []};
  31         267  
331 31 100       97 my @libpaths = @{$args{libpath} || []};
  31         200  
332 31 100       78 my @headers = @{$args{header} || []};
  31         158  
333 31 100       79 my @incpaths = @{$args{incpath} || []};
  31         188  
334 31         82 my $analyze_binary = $args{analyze_binary};
335 31         74 my $execute = !$args{not_execute};
336              
337 31         73 my @argv = @ARGV;
338 31   50     383 push @argv, _parse_line('\s+', 0, $ENV{PERL_MM_OPT}||'');
339              
340             # work-a-like for Makefile.PL's LIBS and INC arguments
341             # if given as command-line argument, append to %args
342 31         107 for my $arg (@argv) {
343 0         0 for my $mm_attr_key (qw(LIBS INC)) {
344 0 0       0 if (my ($mm_attr_value) = $arg =~ /\A $mm_attr_key = (.*)/x) {
345             # it is tempting to put some \s* into the expression, but the
346             # MM command-line parser only accepts LIBS etc. followed by =,
347             # so we should not be any more lenient with whitespace than that
348 0         0 $args{$mm_attr_key} .= " $mm_attr_value";
349             }
350             }
351             }
352              
353 31 100       101 if(defined($args{LIBS})) {
354 1         7 foreach my $arg (_parsewords($args{LIBS})) {
355 3 50       195 die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-[lLR]/);
356 3 100       5 push @{$arg =~ /^-l/ ? \@libs : \@libpaths}, substr($arg, 2);
  3         14  
357             }
358             }
359 31 100       91 if(defined($args{INC})) {
360 2         8 foreach my $arg (_parsewords($args{INC})) {
361 3 100       180 die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/);
362 2         12 push @incpaths, substr($arg, 2);
363             }
364             }
365              
366 30         271 my ($cc, $ld) = _findcc($args{debug}, $args{ccflags}, $args{ldflags});
367 30         161 my @missing;
368             my @wrongresult;
369 30         0 my @wronganalysis;
370 30         0 my @use_headers;
371              
372             # first figure out which headers we can't find ...
373 30         72 for my $header (@headers) {
374 13         27 push @use_headers, $header;
375 13         65 my ($cfile, $ofile) = _make_cfile(\@use_headers, '', $args{debug});
376 13         142 my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
377 13         1934 my @sys_cmd = _compile_cmd($Config{cc}, $cc, $cfile, $exefile, \@incpaths, $ld, $Config{libs});
378 13 50       55 warn "# @sys_cmd\n" if $args{debug};
379 13 50       66 my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
380 13 100 66     658 push @missing, $header if $rv != 0 || ! -f $exefile;
381 13         205 _cleanup_exe($exefile);
382 13         656 unlink $cfile;
383             }
384              
385             # now do each library in turn with headers
386 30         313 my ($cfile, $ofile) = _make_cfile(\@use_headers, @args{qw(function debug)});
387 30         127 for my $lib ( @libs ) {
388 35 50       305 last if $Config{cc} eq 'CC/DECC'; # VMS
389 35         481 my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
390 35         7810 my @sys_cmd = _compile_cmd($Config{cc}, $cc, $cfile, $exefile, \@incpaths, $ld, $Config{libs}, $lib, \@libpaths);
391 35 50       222 warn "# @sys_cmd\n" if $args{debug};
392 35 50 33     843 local $ENV{LD_RUN_PATH} = join(":", grep $_, @libpaths, $ENV{LD_RUN_PATH}) unless $^O eq 'MSWin32' or $^O eq 'darwin';
393 35 50       152 local $ENV{PATH} = join(";", @libpaths).";".$ENV{PATH} if $^O eq 'MSWin32';
394 35 50       208 my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
395 35 100 66     1211 if ($rv != 0 || ! -f $exefile) {
396 11         115 push @missing, $lib;
397             }
398             else {
399 24         562 chmod 0755, $exefile;
400 24         3256 my $absexefile = File::Spec->rel2abs($exefile);
401 24 50       445 $absexefile = '"'.$absexefile.'"' if $absexefile =~ m/\s/;
402 24 50       198 warn "# Execute($execute): $absexefile\n" if $args{debug};
403 24 50       123 if ($execute) {
404 24         70208 my $retval = system($absexefile);
405 24 50       536 warn "# return value: $retval\n" if $args{debug};
406 24 100       392 push @wrongresult, $lib if $retval != 0;
407             }
408 24 100 100     354 push @wronganalysis, $lib
409             if $analyze_binary and !$analyze_binary->($lib, $exefile);
410             }
411 35         8677 _cleanup_exe($exefile);
412             }
413 30         1325 unlink $cfile;
414              
415 30         307 my $miss_string = join( q{, }, map qq{'$_'}, @missing );
416 30 100       842 die("Can't link/include C library $miss_string, aborting.\n") if @missing;
417 20         164 my $wrong_string = join( q{, }, map qq{'$_'}, @wrongresult);
418 20 100       283 die("wrong result: $wrong_string\n") if @wrongresult;
419 18         115 my $analysis_string = join(q{, }, map qq{'$_'}, @wronganalysis );
420 18 100       1351 die("wrong analysis: $analysis_string") if @wronganalysis;
421             }
422              
423             sub _cleanup_exe {
424 48     48   428 my ($exefile) = @_;
425 48         365 my $ofile = $exefile;
426 48         5093 $ofile =~ s/$Config{_exe}$/$Config{_o}/;
427             # List of files to remove
428 48         289 my @rmfiles;
429 48         346 push @rmfiles, $exefile, $ofile, "$exefile\.manifest";
430 48 50       660 if ( $Config{cc} eq 'cl' ) {
431             # MSVC also creates foo.ilk and foo.pdb
432 0         0 my $ilkfile = $exefile;
433 0         0 $ilkfile =~ s/$Config{_exe}$/.ilk/;
434 0         0 my $pdbfile = $exefile;
435 0         0 $pdbfile =~ s/$Config{_exe}$/.pdb/;
436 0         0 push @rmfiles, $ilkfile, $pdbfile;
437             }
438 48         2893 foreach (grep -f, @rmfiles) {
439 36 50       2594 unlink $_ or warn "Could not remove $_: $!";
440             }
441             return
442 48         1342 }
443              
444             # return ($cc, $ld)
445             # where $cc is an array ref of compiler name, compiler flags
446             # where $ld is an array ref of linker flags
447             sub _findcc {
448 41     41   236 my ($debug, $user_ccflags, $user_ldflags) = @_;
449             # Need to use $keep=1 to work with MSWin32 backslashes and quotes
450 41         1031 my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile
451 41         258 $Config_ccflags =~ s:-O\S*::; # stop GCC optimising away test code
452 41         111 my @Config_ldflags = ();
453 41         252 for my $config_val ( @Config{qw(ldflags)} ){
454 41 50       982 push @Config_ldflags, $config_val if ( $config_val =~ /\S/ );
455             }
456 41   50     637 my @ccflags = grep { length } _parsewords($Config_ccflags||'', $user_ccflags||'');
  288   100     11527  
457 41 50 50     288 my @ldflags = grep { length && $_ !~ m/^-Wl/ } _parsewords(@Config_ldflags, $user_ldflags||'');
  82         3689  
458 41         761 my @paths = split(/$Config{path_sep}/, $ENV{PATH});
459 41         194 my @cc = _parsewords($Config{cc});
460 41 100       1958 if (check_compiler ($cc[0], $debug)) {
461 1         5 return ( [ @cc, @ccflags ], \@ldflags );
462             }
463             # Find the extension for executables.
464 40         466 my $exe = $Config{_exe};
465 40 50       176 if ($^O eq 'cygwin') {
466 0         0 $exe = '';
467             }
468 40         112 foreach my $path (@paths) {
469             # Look for "$path/$cc[0].exe"
470 243         1872 my $compiler = File::Spec->catfile($path, $cc[0]) . $exe;
471 243 100       536 if (check_compiler ($compiler, $debug)) {
472 39         345 return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags)
473             }
474 204 50       469 next if ! $exe;
475             # Look for "$path/$cc[0]" without the .exe, if necessary.
476 0         0 $compiler = File::Spec->catfile($path, $cc[0]);
477 0 0       0 if (check_compiler ($compiler, $debug)) {
478 0         0 return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags)
479             }
480             }
481 1         24 die("Couldn't find your C compiler.\n");
482             }
483              
484             sub check_compiler
485             {
486 284     284 0 465 my ($compiler, $debug) = @_;
487 284 100 66     3801 if (-f $compiler && -x $compiler) {
488 40 50       129 warn "# Compiler seems to be $compiler\n" if $debug;
489 40         124 return 1;
490             }
491 244 50       531 warn "# Compiler was not $compiler\n" if $debug;
492 244         605 return '';
493             }
494              
495              
496             # code substantially borrowed from IPC::Run3
497             sub _quiet_system {
498 66     66   53748 my (@cmd) = @_;
499              
500             # save handles
501 66         340 local *STDOUT_SAVE;
502 66         237 local *STDERR_SAVE;
503 66 50       1982 open STDOUT_SAVE, ">&STDOUT" or die "CheckLib: $! saving STDOUT";
504 66 50       1466 open STDERR_SAVE, ">&STDERR" or die "CheckLib: $! saving STDERR";
505            
506             # redirect to nowhere
507 66         226 local *DEV_NULL;
508 66 50       3350 open DEV_NULL, ">" . File::Spec->devnull
509             or die "CheckLib: $! opening handle to null device";
510 66 50       1796 open STDOUT, ">&" . fileno DEV_NULL
511             or die "CheckLib: $! redirecting STDOUT to null handle";
512 66 50       1527 open STDERR, ">&" . fileno DEV_NULL
513             or die "CheckLib: $! redirecting STDERR to null handle";
514              
515             # run system command
516 66         2389228 my $rv = system(@cmd);
517              
518             # restore handles
519 66 50       6144 open STDOUT, ">&" . fileno STDOUT_SAVE
520             or die "CheckLib: $! restoring STDOUT handle";
521 66 50       2211 open STDERR, ">&" . fileno STDERR_SAVE
522             or die "CheckLib: $! restoring STDERR handle";
523              
524 66         5617 return $rv;
525             }
526              
527             =head1 PLATFORMS SUPPORTED
528              
529             You must have a C compiler installed. We check for C<$Config{cc}>,
530             both literally as it is in Config.pm and also in the $PATH.
531              
532             It has been tested with varying degrees of rigorousness on:
533              
534             =over
535              
536             =item gcc (on Linux, *BSD, Mac OS X, Solaris, Cygwin)
537              
538             =item Sun's compiler tools on Solaris
539              
540             =item IBM's tools on AIX
541              
542             =item SGI's tools on Irix 6.5
543              
544             =item Microsoft's tools on Windows
545              
546             =item MinGW on Windows (with Strawberry Perl)
547              
548             =item Borland's tools on Windows
549              
550             =item QNX
551              
552             =back
553              
554             =head1 WARNINGS, BUGS and FEEDBACK
555              
556             This is a very early release intended primarily for feedback from
557             people who have discussed it. The interface may change and it has
558             not been adequately tested.
559              
560             Feedback is most welcome, including constructive criticism.
561             Bug reports should be made using L or by email.
562              
563             When submitting a bug report, please include the output from running:
564              
565             perl -V
566             perl -MDevel::CheckLib -e0
567              
568             =head1 SEE ALSO
569              
570             L
571              
572             L
573              
574             =head1 AUTHORS
575              
576             David Cantrell Edavid@cantrell.org.ukE
577              
578             David Golden Edagolden@cpan.orgE
579              
580             Yasuhiro Matsumoto Emattn@cpan.orgE
581              
582             Thanks to the cpan-testers-discuss mailing list for prompting us to write it
583             in the first place;
584              
585             to Chris Williams for help with Borland support;
586              
587             to Tony Cook for help with Microsoft compiler command-line options
588              
589             =head1 COPYRIGHT and LICENCE
590              
591             Copyright 2007 David Cantrell. Portions copyright 2007 David Golden.
592              
593             This module is free-as-in-speech software, and may be used, distributed,
594             and modified under the same conditions as perl itself.
595              
596             =head1 CONSPIRACY
597              
598             This module is also free-as-in-mason software.
599              
600             =cut
601              
602             1;