1 # $Id: CheckLib.pm,v 1.25 2008/10/27 12:16:23 drhyde Exp $
2 # This is a modified version of Devel::CheckLib 0.93 including the patches from
3 # RT issues 60176 and 61645
8 use 5.00405; #postfix foreach
10 use vars qw($VERSION @ISA @EXPORT);
11 $VERSION = '0.93_001';
12 use Config qw(%Config);
13 use Text::ParseWords 'quotewords';
17 use File::Path qw(rmtree);
21 @EXPORT = qw(assert_lib check_lib_or_exit check_lib);
23 # localising prevents the warningness leaking out of this module
24 local $^W = 1; # use warnings is a 5.6-ism
26 _findcc(); # bomb out early if there's no compiler
30 Devel::CheckLib - check that a library is available
34 Devel::CheckLib is a perl module that checks whether a particular C
35 library and its headers are available.
41 check_lib_or_exit( lib => 'jpeg', header => 'jpeglib.h' );
42 check_lib_or_exit( lib => [ 'iconv', 'jpeg' ] );
44 # or prompt for path to library and then do this:
45 check_lib_or_exit( lib => 'jpeg', libpath => $additional_path );
47 =head1 USING IT IN Makefile.PL or Build.PL
49 If you want to use this from Makefile.PL or Build.PL, do
50 not simply copy the module into your distribution as this may cause
51 problems when PAUSE and search.cpan.org index the distro. Instead, use
52 the use-devel-checklib script.
56 You pass named parameters to a function, describing to it how to build
57 and link to the libraries.
59 It works by trying to compile some code - which defaults to this:
61 int main(void) { return 0; }
63 and linking it to the specified libraries. If something pops out the end
64 which looks executable, it gets executed, and if main() returns 0 we know
65 that it worked. That tiny program is
66 built once for each library that you specify, and (without linking) once
69 If you want to check for the presence of particular functions in a
70 library, or even that those functions return particular results, then
71 you can pass your own function body for main() thus:
74 function => 'foo();if(libversion() > 5) return 0; else return 1;'
81 In that case, it will fail to build if either foo() or libversion() don't
82 exist, and main() will return the wrong value if libversion()'s return
83 value isn't what you want.
87 All of these take the same named parameters and are exported by default.
88 To avoid exporting them, C<use Devel::CheckLib ()>.
92 This takes several named parameters, all of which are optional, and dies
93 with an error message if any of the libraries listed can
94 not be found. B<Note>: dying in a Makefile.PL or Build.PL may provoke
95 a 'FAIL' report from CPAN Testers' automated smoke testers. Use
96 C<check_lib_or_exit> instead.
98 The named parameters are:
104 Must be either a string with the name of a single
105 library or a reference to an array of strings of library names. Depending
106 on the compiler found, library names will be fed to the compiler either as
107 C<-l> arguments or as C<.lib> file names. (E.g. C<-ljpeg> or C<jpeg.lib>)
111 a string or an array of strings
112 representing additional paths to search for libraries.
116 a C<ExtUtils::MakeMaker>-style space-seperated list of
117 libraries (each preceded by '-l') and directories (preceded by '-L').
119 This can also be supplied on the command-line.
123 And libraries are no use without header files, so ...
129 Must be either a string with the name of a single
130 header file or a reference to an array of strings of header file names.
134 a string or an array of strings
135 representing additional paths to search for headers.
139 a C<ExtUtils::MakeMaker>-style space-seperated list of
140 incpaths, each preceded by '-I'.
142 This can also be supplied on the command-line.
146 If you need to perform know more than "does it link?" you can provide
147 code to be compiled and run:
153 the body of the <main()> function. If not provided C<return 0;> is
158 code to insert between the C<#include> of the headers and the
163 =head2 check_lib_or_exit
165 This behaves exactly the same as C<assert_lib()> except that instead of
166 dieing, it warns (with exactly the same error message) and exits.
167 This is intended for use in Makefile.PL / Build.PL
168 when you might want to prompt the user for various paths and
169 things before checking that what they've told you is sane.
171 If any library or header is missing, it exits with an exit value of 0 to avoid
172 causing a CPAN Testers 'FAIL' report. CPAN Testers should ignore this
173 result -- which is what you want if an external library dependency is not
178 This behaves exactly the same as C<assert_lib()> except that it is silent,
179 returning false instead of dieing, or true otherwise.
183 sub check_lib_or_exit {
184 eval 'assert_lib(@_)';
192 eval 'assert_lib(@_)';
198 my (@libs, @libpaths, @headers, @incpaths);
200 # FIXME: these four just SCREAM "refactor" at me
201 @libs = (ref($args{lib}) ? @{$args{lib}} : $args{lib})
203 @libpaths = (ref($args{libpath}) ? @{$args{libpath}} : $args{libpath})
205 @headers = (ref($args{header}) ? @{$args{header}} : $args{header})
207 @incpaths = (ref($args{incpath}) ? @{$args{incpath}} : $args{incpath})
210 # each entry is an arrayref containing:
211 # 0: arrayref of library search paths
212 # 1: arrayref of library names
213 my @link_cfgs = map [ \@libpaths, [ $_ ] ], @libs;
215 # work-a-like for Makefile.PL's LIBS and INC arguments
216 # if given as command-line argument, append to %args
217 for my $arg (@ARGV) {
218 for my $mm_attr_key (qw(LIBS INC)) {
219 if (my ($mm_attr_value) = $arg =~ /\A $mm_attr_key = (.*)/x) {
220 # it is tempting to put some \s* into the expression, but the
221 # MM command-line parser only accepts LIBS etc. followed by =,
222 # so we should not be any more lenient with whitespace than that
223 $args{$mm_attr_key} .= " $mm_attr_value";
228 # using special form of split to trim whitespace
229 if(defined($args{LIBS})) {
230 if (ref $args{LIBS}) {
231 foreach my $arg (@{$args{LIBS}}) {
232 my @sep = split ' ', $arg;
233 my @libs = map { /^-l(.+)$/ ? $1 : () } @sep;
234 my @paths = map { /^-L(.+)$/ ? $1 : () } @sep;
235 push @link_cfgs, [ \@paths, \@libs ];
241 foreach my $arg (split(' ', $args{LIBS})) {
242 die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-l/i);
243 push @{$arg =~ /^-l/ ? \@libs : \@paths}, substr($arg, 2);
245 push @link_cfgs, map [ \@paths, [ $_ ] ], @libs;
248 if(defined($args{INC})) {
249 foreach my $arg (_shellwords($args{INC})) {
250 die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/);
251 push @incpaths, substr($arg, 2);
255 my ($cc, $ld) = _findcc();
260 # first figure out which headers we can't find ...
261 for my $header (@headers) {
262 push @use_headers, $header;
263 my($ch, $cfile) = File::Temp::tempfile(
264 'assertlibXXXXXXXX', SUFFIX => '.c'
266 print $ch qq{#include <$_>\n} for @use_headers;
267 print $ch qq{int main(void) { return 0; }\n};
269 my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
271 # FIXME: re-factor - almost identical code later when linking
272 if ( $Config{cc} eq 'cl' ) { # Microsoft compiler
278 (map { '/I'.Win32::GetShortPathName($_) } @incpaths),
282 } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland
285 (map { "-I$_" } @incpaths),
290 } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ...
295 (map { "-I$_" } @incpaths),
299 warn "# @sys_cmd\n" if $args{debug};
300 my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
301 push @missing, $header if $rv != 0 || ! -x $exefile;
302 _cleanup_exe($exefile);
306 # now do each library in turn with headers
307 my($ch, $cfile) = File::Temp::tempfile(
308 'assertlibXXXXXXXX', SUFFIX => '.c'
310 print $ch qq{#include <$_>\n} foreach (@headers);
311 print $ch "\n$args{prologue}\n" if $args{prologue};
312 print $ch "int main(void) { ".($args{function} || 'return 0;')." }\n";
314 for my $link_cfg ( @link_cfgs ) {
315 my ($paths, $libs) = @$link_cfg;
316 my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
318 if ( $Config{cc} eq 'cl' ) { # Microsoft compiler
321 q{/libpath:} . Win32::GetShortPathName($_)
323 # this is horribly sensitive to the order of arguments
327 ( map { "$_.lib" } @$libs ),
329 (map { '/I'.Win32::GetShortPathName($_) } @incpaths),
332 (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths),
334 } elsif($Config{cc} eq 'CC/DECC') { # VMS
335 } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland
340 (map { "-l$_" } @$libs ),
341 (map { "-I$_" } @incpaths),
342 (map { "-L$_" } @$paths),
345 # gcc, Sun, AIX (gcc, cc)
351 (map { "-l$_" } @$libs ),
352 (map { "-I$_" } @incpaths),
353 (map { "-L$_" } @$paths)
356 warn "# @sys_cmd\n" if $args{debug};
357 my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
358 push @missing, @$libs if $rv != 0 || ! -x $exefile;
359 my $absexefile = File::Spec->rel2abs($exefile);
360 $absexefile = '"'.$absexefile.'"' if $absexefile =~ m/\s/;
361 push @wrongresult, @$libs if $rv == 0 && -x $exefile && system($absexefile) != 0;
362 _cleanup_exe($exefile);
366 my $miss_string = join( q{, }, map { qq{'$_'} } @missing );
367 die("Can't link/include $miss_string\n") if @missing;
368 my $wrong_string = join( q{, }, map { qq{'$_'} } @wrongresult);
369 die("wrong result: $wrong_string\n") if @wrongresult;
374 my $ofile = $exefile;
375 $ofile =~ s/$Config{_exe}$/$Config{_o}/;
376 unlink $exefile if -f $exefile;
377 unlink $ofile if -f $ofile;
378 unlink "$exefile\.manifest" if -f "$exefile\.manifest";
379 if ( $Config{cc} eq 'cl' ) {
380 # MSVC also creates foo.ilk and foo.pdb
381 my $ilkfile = $exefile;
382 $ilkfile =~ s/$Config{_exe}$/.ilk/;
383 my $pdbfile = $exefile;
384 $pdbfile =~ s/$Config{_exe}$/.pdb/;
385 unlink $ilkfile if -f $ilkfile;
386 unlink $pdbfile if -f $pdbfile;
388 # created by clang on darwin
389 my $dsym_dir = $exefile;
390 $dsym_dir =~ s/\Q$Config{_exe}\E$/.dSYM/;
391 rmtree $dsym_dir if -d $dsym_dir;
397 # where $cc is an array ref of compiler name, compiler flags
398 # where $ld is an array ref of linker flags
400 # Need to use $keep=1 to work with MSWin32 backslashes and quotes
401 my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile
402 my @Config_ldflags = @Config{qw(ldflags perllibs)};
403 my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags);
404 my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags);
405 my @paths = split(/$Config{path_sep}/, $ENV{PATH});
406 my @cc = split(/\s+/, $Config{cc});
407 return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0];
408 foreach my $path (@paths) {
409 my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe};
410 return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags)
413 die("Couldn't find your C compiler\n");
419 if ($^O eq "MSWin32") {
422 while ($line =~ s/^"([^"]*)"// || $line =~ s/^(\S+)//) {
429 return grep defined && /\S/, quotewords('\s+', 0, $line);
433 # code substantially borrowed from IPC::Run3
440 open STDOUT_SAVE, ">&STDOUT" or die "CheckLib: $! saving STDOUT";
441 open STDERR_SAVE, ">&STDERR" or die "CheckLib: $! saving STDERR";
443 # redirect to nowhere
445 open DEV_NULL, ">" . File::Spec->devnull
446 or die "CheckLib: $! opening handle to null device";
447 open STDOUT, ">&" . fileno DEV_NULL
448 or die "CheckLib: $! redirecting STDOUT to null handle";
449 open STDERR, ">&" . fileno DEV_NULL
450 or die "CheckLib: $! redirecting STDERR to null handle";
453 my $rv = system(@cmd);
456 open STDOUT, ">&" . fileno STDOUT_SAVE
457 or die "CheckLib: $! restoring STDOUT handle";
458 open STDERR, ">&" . fileno STDERR_SAVE
459 or die "CheckLib: $! restoring STDERR handle";
464 =head1 PLATFORMS SUPPORTED
466 You must have a C compiler installed. We check for C<$Config{cc}>,
467 both literally as it is in Config.pm and also in the $PATH.
469 It has been tested with varying degrees on rigourousness on:
473 =item gcc (on Linux, *BSD, Mac OS X, Solaris, Cygwin)
475 =item Sun's compiler tools on Solaris
477 =item IBM's tools on AIX
479 =item SGI's tools on Irix 6.5
481 =item Microsoft's tools on Windows
483 =item MinGW on Windows (with Strawberry Perl)
485 =item Borland's tools on Windows
491 =head1 WARNINGS, BUGS and FEEDBACK
493 This is a very early release intended primarily for feedback from
494 people who have discussed it. The interface may change and it has
495 not been adequately tested.
497 Feedback is most welcome, including constructive criticism.
498 Bug reports should be made using L<http://rt.cpan.org/> or by email.
500 When submitting a bug report, please include the output from running:
503 perl -MDevel::CheckLib -e0
513 David Cantrell E<lt>david@cantrell.org.ukE<gt>
515 David Golden E<lt>dagolden@cpan.orgE<gt>
517 Yasuhiro Matsumoto E<lt>mattn@cpan.orgE<gt>
519 Thanks to the cpan-testers-discuss mailing list for prompting us to write it
522 to Chris Williams for help with Borland support;
524 to Tony Cook for help with Microsoft compiler command-line options
526 =head1 COPYRIGHT and LICENCE
528 Copyright 2007 David Cantrell. Portions copyright 2007 David Golden.
530 This module is free-as-in-speech software, and may be used, distributed,
531 and modified under the same conditions as perl itself.
535 This module is also free-as-in-mason software.