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   7882 use 5.00405; #postfix foreach
  11         33  
6 11     11   47 use strict;
  11         16  
  11         226  
7 11     11   43 use vars qw($VERSION @ISA @EXPORT);
  11         23  
  11         646  
8             $VERSION = '1.16';
9 11     11   52 use Config qw(%Config);
  11         18  
  11         498  
10 11     11   4250 use Text::ParseWords qw(quotewords shellwords);
  11         12420  
  11         565  
11              
12 11     11   63 use File::Spec;
  11         20  
  11         203  
13 11     11   2516 use File::Temp;
  11         57958  
  11         1766  
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 19008 eval 'assert_lib(@_)';
198 8 100       339 return $@ ? 0 : 1;
199             }
200              
201             # borrowed from Text::ParseWords
202             sub _parse_line {
203 31     31   132 my($delimiter, $keep, $line) = @_;
204 31         95 my($word, @pieces);
205              
206 11     11   70 no warnings 'uninitialized'; # we will be testing undef strings
  11         17  
  11         25626  
207              
208 31         116 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         86 return(@pieces);
261             }
262              
263             sub _parsewords {
264 126 50   126   853 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   952 my ($Config_cc, $cc, $cfile, $exefile, $incpaths, $ld, $Config_libs, $lib, $libpaths) = @_;
271 48         240 my @sys_cmd = @$cc;
272 48 50       255 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       506 ($^O eq 'darwin' ? (map { "-Wl,-rpath,$_" } @$libpaths) : ()),
  0 100       0  
299             "-l$lib",
300             )),
301             @$ld,
302             "-o", $exefile,
303             ;
304             }
305 48         245 @sys_cmd;
306             }
307              
308             sub _make_cfile {
309 43     43   198 my ($use_headers, $function, $debug) = @_;
310 43         108 my $code = '';
311 43         201 $code .= qq{#include <$_>\n} for @$use_headers;
312 43   100     383 $code .= "int main(int argc, char *argv[]) { ".($function || 'return 0;')." }\n";
313 43 50       149 if ($debug) {
314 0         0 (my $c = $code) =~ s:^:# :gm;
315 0         0 warn "# Code:\n$c\n";
316             }
317 43         486 my ($ch, $cfile) = File::Temp::tempfile(
318             'assertlibXXXXXXXX', SUFFIX => '.c'
319             );
320 43         18401 print $ch $code;
321 43         1553 close $ch;
322 43         816 (my $ofile = $cfile) =~ s/\.c$/$Config{_o}/;
323 43         296 ($cfile, $ofile);
324             }
325              
326             sub assert_lib {
327 31     31 1 64458 my %args = @_;
328             $args{$_} = [$args{$_}]
329 31   100     590 for grep $args{$_} && !ref($args{$_}), qw(lib libpath header incpath);
330 31 100       95 my @libs = @{$args{lib} || []};
  31         252  
331 31 100       68 my @libpaths = @{$args{libpath} || []};
  31         172  
332 31 100       77 my @headers = @{$args{header} || []};
  31         149  
333 31 100       60 my @incpaths = @{$args{incpath} || []};
  31         176  
334 31         77 my $analyze_binary = $args{analyze_binary};
335 31         67 my $execute = !$args{not_execute};
336              
337 31         71 my @argv = @ARGV;
338 31   50     352 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       107 if(defined($args{LIBS})) {
354 1         11 foreach my $arg (_parsewords($args{LIBS})) {
355 3 50       177 die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-[lLR]/);
356 3 100       6 push @{$arg =~ /^-l/ ? \@libs : \@libpaths}, substr($arg, 2);
  3         13  
357             }
358             }
359 31 100       99 if(defined($args{INC})) {
360 2         31 foreach my $arg (_parsewords($args{INC})) {
361 3 100       271 die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/);
362 2         27 push @incpaths, substr($arg, 2);
363             }
364             }
365              
366 30         263 my ($cc, $ld) = _findcc($args{debug}, $args{ccflags}, $args{ldflags});
367 30         184 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         81 for my $header (@headers) {
374 13         48 push @use_headers, $header;
375 13         77 my ($cfile, $ofile) = _make_cfile(\@use_headers, '', $args{debug});
376 13         139 my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
377 13         1803 my @sys_cmd = _compile_cmd($Config{cc}, $cc, $cfile, $exefile, \@incpaths, $ld, $Config{libs});
378 13 50       45 warn "# @sys_cmd\n" if $args{debug};
379 13 50       57 my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
380 13 100 66     548 push @missing, $header if $rv != 0 || ! -f $exefile;
381 13         204 _cleanup_exe($exefile);
382 13         613 unlink $cfile;
383             }
384              
385             # now do each library in turn with headers
386 30         343 my ($cfile, $ofile) = _make_cfile(\@use_headers, @args{qw(function debug)});
387 30         110 for my $lib ( @libs ) {
388 35 50       270 last if $Config{cc} eq 'CC/DECC'; # VMS
389 35         444 my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
390 35         7490 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     737 local $ENV{LD_RUN_PATH} = join(":", grep $_, @libpaths, $ENV{LD_RUN_PATH}) unless $^O eq 'MSWin32' or $^O eq 'darwin';
393 35 50       137 local $ENV{PATH} = join(";", @libpaths).";".$ENV{PATH} if $^O eq 'MSWin32';
394 35 50       178 my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
395 35 100 66     1113 if ($rv != 0 || ! -f $exefile) {
396 11         105 push @missing, $lib;
397             }
398             else {
399 24         475 chmod 0755, $exefile;
400 24         2946 my $absexefile = File::Spec->rel2abs($exefile);
401 24 50       382 $absexefile = '"'.$absexefile.'"' if $absexefile =~ m/\s/;
402 24 50       196 warn "# Execute($execute): $absexefile\n" if $args{debug};
403 24 50       121 if ($execute) {
404 24         64603 my $retval = system($absexefile);
405 24 50       376 warn "# return value: $retval\n" if $args{debug};
406 24 100       345 push @wrongresult, $lib if $retval != 0;
407             }
408 24 100 100     289 push @wronganalysis, $lib
409             if $analyze_binary and !$analyze_binary->($lib, $exefile);
410             }
411 35         6162 _cleanup_exe($exefile);
412             }
413 30         1193 unlink $cfile;
414              
415 30         266 my $miss_string = join( q{, }, map qq{'$_'}, @missing );
416 30 100       781 die("Can't link/include C library $miss_string, aborting.\n") if @missing;
417 20         127 my $wrong_string = join( q{, }, map qq{'$_'}, @wrongresult);
418 20 100       222 die("wrong result: $wrong_string\n") if @wrongresult;
419 18         102 my $analysis_string = join(q{, }, map qq{'$_'}, @wronganalysis );
420 18 100       1323 die("wrong analysis: $analysis_string") if @wronganalysis;
421             }
422              
423             sub _cleanup_exe {
424 48     48   368 my ($exefile) = @_;
425 48         270 my $ofile = $exefile;
426 48         4367 $ofile =~ s/$Config{_exe}$/$Config{_o}/;
427             # List of files to remove
428 48         261 my @rmfiles;
429 48         328 push @rmfiles, $exefile, $ofile, "$exefile\.manifest";
430 48 50       577 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         2482 foreach (grep -f, @rmfiles) {
439 36 50       2220 unlink $_ or warn "Could not remove $_: $!";
440             }
441             return
442 48         1121 }
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   237 my ($debug, $user_ccflags, $user_ldflags) = @_;
449             # Need to use $keep=1 to work with MSWin32 backslashes and quotes
450 41         929 my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile
451 41         232 $Config_ccflags =~ s:-O\S*::; # stop GCC optimising away test code
452 41         95 my @Config_ldflags = ();
453 41         228 for my $config_val ( @Config{qw(ldflags)} ){
454 41 50       954 push @Config_ldflags, $config_val if ( $config_val =~ /\S/ );
455             }
456 41   50     592 my @ccflags = grep { length } _parsewords($Config_ccflags||'', $user_ccflags||'');
  288   100     11274  
457 41 50 50     303 my @ldflags = grep { length && $_ !~ m/^-Wl/ } _parsewords(@Config_ldflags, $user_ldflags||'');
  82         3530  
458 41         695 my @paths = split(/$Config{path_sep}/, $ENV{PATH});
459 41         200 my @cc = _parsewords($Config{cc});
460 41 100       1874 if (check_compiler ($cc[0], $debug)) {
461 1         6 return ( [ @cc, @ccflags ], \@ldflags );
462             }
463             # Find the extension for executables.
464 40         432 my $exe = $Config{_exe};
465 40 50       204 if ($^O eq 'cygwin') {
466 0         0 $exe = '';
467             }
468 40         109 foreach my $path (@paths) {
469             # Look for "$path/$cc[0].exe"
470 243         1757 my $compiler = File::Spec->catfile($path, $cc[0]) . $exe;
471 243 100       530 if (check_compiler ($compiler, $debug)) {
472 39         384 return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags)
473             }
474 204 50       455 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         27 die("Couldn't find your C compiler.\n");
482             }
483              
484             sub check_compiler
485             {
486 284     284 0 461 my ($compiler, $debug) = @_;
487 284 100 66     3596 if (-f $compiler && -x $compiler) {
488 40 50       140 warn "# Compiler seems to be $compiler\n" if $debug;
489 40         126 return 1;
490             }
491 244 50       532 warn "# Compiler was not $compiler\n" if $debug;
492 244         584 return '';
493             }
494              
495              
496             # code substantially borrowed from IPC::Run3
497             sub _quiet_system {
498 66     66   52461 my (@cmd) = @_;
499              
500             # save handles
501 66         280 local *STDOUT_SAVE;
502 66         146 local *STDERR_SAVE;
503 66 50       1714 open STDOUT_SAVE, ">&STDOUT" or die "CheckLib: $! saving STDOUT";
504 66 50       1405 open STDERR_SAVE, ">&STDERR" or die "CheckLib: $! saving STDERR";
505            
506             # redirect to nowhere
507 66         226 local *DEV_NULL;
508 66 50       3303 open DEV_NULL, ">" . File::Spec->devnull
509             or die "CheckLib: $! opening handle to null device";
510 66 50       1672 open STDOUT, ">&" . fileno DEV_NULL
511             or die "CheckLib: $! redirecting STDOUT to null handle";
512 66 50       1420 open STDERR, ">&" . fileno DEV_NULL
513             or die "CheckLib: $! redirecting STDERR to null handle";
514              
515             # run system command
516 66         2276341 my $rv = system(@cmd);
517              
518             # restore handles
519 66 50       5194 open STDOUT, ">&" . fileno STDOUT_SAVE
520             or die "CheckLib: $! restoring STDOUT handle";
521 66 50       1522 open STDERR, ">&" . fileno STDERR_SAVE
522             or die "CheckLib: $! restoring STDERR handle";
523              
524 66         4793 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;