1 # $Id: CheckLib.pm,v 1.25 2008/10/27 12:16:23 drhyde Exp $
7 use vars qw($VERSION @ISA @EXPORT);
8 $VERSION = '0.699_002';
16 @EXPORT = qw(assert_lib check_lib_or_exit check_lib);
18 # localising prevents the warningness leaking out of this module
19 local $^W = 1; # use warnings is a 5.6-ism
21 _findcc(); # bomb out early if there's no compiler
25 Devel::CheckLib - check that a library is available
29 Devel::CheckLib is a perl module that checks whether a particular C
30 library and its headers are available.
36 check_lib_or_exit( lib => 'jpeg', header => 'jpeglib.h' );
37 check_lib_or_exit( lib => [ 'iconv', 'jpeg' ] );
39 # or prompt for path to library and then do this:
40 check_lib_or_exit( lib => 'jpeg', libpath => $additional_path );
42 =head1 USING IT IN Makefile.PL or Build.PL
44 If you want to use this from Makefile.PL or Build.PL, do
45 not simply copy the module into your distribution as this may cause
46 problems when PAUSE and search.cpan.org index the distro. Instead, use
47 the use-devel-checklib script.
51 You pass named parameters to a function, describing to it how to build
52 and link to the libraries.
54 It works by trying to compile some code - which defaults to this:
56 int main(void) { return 0; }
58 and linking it to the specified libraries. If something pops out the end
59 which looks executable, it gets executed, and if main() returns 0 we know
60 that it worked. That tiny program is
61 built once for each library that you specify, and (without linking) once
64 If you want to check for the presence of particular functions in a
65 library, or even that those functions return particular results, then
66 you can pass your own function body for main() thus:
69 function => 'foo();if(libversion() > 5) return 0; else return 1;'
76 In that case, it will fail to build if either foo() or libversion() don't
77 exist, and main() will return the wrong value if libversion()'s return
78 value isn't what you want.
82 All of these take the same named parameters and are exported by default.
83 To avoid exporting them, C<use Devel::CheckLib ()>.
87 This takes several named parameters, all of which are optional, and dies
88 with an error message if any of the libraries listed can
89 not be found. B<Note>: dying in a Makefile.PL or Build.PL may provoke
90 a 'FAIL' report from CPAN Testers' automated smoke testers. Use
91 C<check_lib_or_exit> instead.
93 The named parameters are:
99 Must be either a string with the name of a single
100 library or a reference to an array of strings of library names. Depending
101 on the compiler found, library names will be fed to the compiler either as
102 C<-l> arguments or as C<.lib> file names. (E.g. C<-ljpeg> or C<jpeg.lib>)
106 a string or an array of strings
107 representing additional paths to search for libraries.
111 a C<ExtUtils::MakeMaker>-style space-seperated list of
112 libraries (each preceded by '-l') and directories (preceded by '-L').
114 This can also be supplied on the command-line.
118 And libraries are no use without header files, so ...
124 Must be either a string with the name of a single
125 header file or a reference to an array of strings of header file names.
129 a string or an array of strings
130 representing additional paths to search for headers.
134 a C<ExtUtils::MakeMaker>-style space-seperated list of
135 incpaths, each preceded by '-I'.
137 This can also be supplied on the command-line.
141 If you need to perform know more than "does it link?" you can provide
142 code to be compiled and run:
148 the body of the <main()> function. If not provided C<return 0;> is
153 code to insert between the C<#include> of the headers and the
158 =head2 check_lib_or_exit
160 This behaves exactly the same as C<assert_lib()> except that instead of
161 dieing, it warns (with exactly the same error message) and exits.
162 This is intended for use in Makefile.PL / Build.PL
163 when you might want to prompt the user for various paths and
164 things before checking that what they've told you is sane.
166 If any library or header is missing, it exits with an exit value of 0 to avoid
167 causing a CPAN Testers 'FAIL' report. CPAN Testers should ignore this
168 result -- which is what you want if an external library dependency is not
173 This behaves exactly the same as C<assert_lib()> except that it is silent,
174 returning false instead of dieing, or true otherwise.
178 sub check_lib_or_exit {
179 eval 'assert_lib(@_)';
187 eval 'assert_lib(@_)';
193 my (@libs, @libpaths, @headers, @incpaths);
195 # FIXME: these four just SCREAM "refactor" at me
196 @libs = (ref($args{lib}) ? @{$args{lib}} : $args{lib})
198 @libpaths = (ref($args{libpath}) ? @{$args{libpath}} : $args{libpath})
200 @headers = (ref($args{header}) ? @{$args{header}} : $args{header})
202 @incpaths = (ref($args{incpath}) ? @{$args{incpath}} : $args{incpath})
205 # each entry is an arrayref containing:
206 # 0: arrayref of library search paths
207 # 1: arrayref of library names
208 my @link_cfgs = map [ \@libpaths, [ $_ ] ], @libs;
210 # work-a-like for Makefile.PL's LIBS and INC arguments
211 # if given as command-line argument, append to %args
212 for my $arg (@ARGV) {
213 for my $mm_attr_key qw(LIBS INC) {
214 if (my ($mm_attr_value) = $arg =~ /\A $mm_attr_key = (.*)/x) {
215 # it is tempting to put some \s* into the expression, but the
216 # MM command-line parser only accepts LIBS etc. followed by =,
217 # so we should not be any more lenient with whitespace than that
218 $args{$mm_attr_key} .= " $mm_attr_value";
222 # using special form of split to trim whitespace
223 if(defined($args{LIBS})) {
224 if (ref $args{LIBS}) {
225 foreach my $arg (@{$args{LIBS}}) {
226 my @sep = split ' ', $arg;
227 my @libs = map { /^-l(.+)$/ ? $1 : () } @sep;
228 my @paths = map { /^-L(.+)$/ ? $1 : () } @sep;
229 push @link_cfgs, [ \@paths, \@libs ];
235 foreach my $arg (split(' ', $args{LIBS})) {
236 die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-l/i);
237 push @{$arg =~ /^-l/ ? \@libs : \@paths}, substr($arg, 2);
239 push @link_cfgs, map [ \@paths, [ $_ ] ], @libs;
242 if(defined($args{INC})) {
243 foreach my $arg (split(' ', $args{INC})) {
244 die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/);
245 push @incpaths, substr($arg, 2);
253 # first figure out which headers we can't find ...
255 for my $header (@headers) {
256 push @use_headers, $header;
257 my($ch, $cfile) = File::Temp::tempfile(
258 'assertlibXXXXXXXX', SUFFIX => '.c'
260 print $ch qq{#include <$_>\n} for @use_headers;
261 print $ch qq{int main(void) { return 0; }\n};
263 my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
265 # FIXME: re-factor - almost identical code later when linking
266 if ( $Config{cc} eq 'cl' ) { # Microsoft compiler
272 (map { '/I'.Win32::GetShortPathName($_) } @incpaths)
274 } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland
277 (map { "-I$_" } @incpaths),
281 } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ...
285 (map { "-I$_" } @incpaths),
289 warn "# @sys_cmd\n" if $args{debug};
290 my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
291 push @missing, $header if $rv != 0 || ! -x $exefile;
292 _cleanup_exe($exefile);
296 # now do each library in turn with headers
297 my($ch, $cfile) = File::Temp::tempfile(
298 'assertlibXXXXXXXX', SUFFIX => '.c'
300 print $ch qq{#include <$_>\n} foreach (@headers);
301 print $ch "\n$args{prologue}\n" if $args{prologue};
302 print $ch "int main(void) { ".($args{function} || 'return 0;')." }\n";
304 for my $link_cfg ( @link_cfgs ) {
305 my ($paths, $libs) = @$link_cfg;
306 my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe};
308 if ( $Config{cc} eq 'cl' ) { # Microsoft compiler
311 q{/libpath:} . Win32::GetShortPathName($_)
313 # this is horribly sensitive to the order of arguments
317 ( map { "$_.lib" } @$libs ),
319 (map { '/I'.Win32::GetShortPathName($_) } @incpaths),
321 (map {'/libpath:'.Win32::GetShortPathName($_)} @$paths),
323 } elsif($Config{cc} eq 'CC/DECC') { # VMS
324 } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland
328 (map { "-l$_" } @$libs ),
329 (map { "-I$_" } @incpaths),
330 (map { "-L$_" } @$paths),
333 # gcc, Sun, AIX (gcc, cc)
338 (map { "-l$_" } @$libs ),
339 (map { "-I$_" } @incpaths),
340 (map { "-L$_" } @$paths)
343 warn "# @sys_cmd\n" if $args{debug};
344 my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd);
345 push @missing, @$libs if $rv != 0 || ! -x $exefile;
346 push @wrongresult, @$libs if $rv == 0 && -x $exefile && system(File::Spec->rel2abs($exefile)) != 0;
347 _cleanup_exe($exefile);
351 my $miss_string = join( q{, }, map { qq{'$_'} } @missing );
352 die("Can't link/include $miss_string\n") if @missing;
353 my $wrong_string = join( q{, }, map { qq{'$_'} } @wrongresult);
354 die("wrong result: $wrong_string\n") if @wrongresult;
359 my $ofile = $exefile;
360 $ofile =~ s/$Config{_exe}$/$Config{_o}/;
361 unlink $exefile if -f $exefile;
362 unlink $ofile if -f $ofile;
363 unlink "$exefile\.manifest" if -f "$exefile\.manifest";
368 my @paths = split(/$Config{path_sep}/, $ENV{PATH});
369 my @cc = split(/\s+/, $Config{cc});
370 return @cc if -x $cc[0];
371 foreach my $path (@paths) {
372 my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe};
373 return ($compiler, @cc[1 .. $#cc]) if -x $compiler;
375 die("Couldn't find your C compiler\n");
378 # code substantially borrowed from IPC::Run3
385 open STDOUT_SAVE, ">&STDOUT" or die "CheckLib: $! saving STDOUT";
386 open STDERR_SAVE, ">&STDERR" or die "CheckLib: $! saving STDERR";
388 # redirect to nowhere
390 open DEV_NULL, ">" . File::Spec->devnull
391 or die "CheckLib: $! opening handle to null device";
392 open STDOUT, ">&" . fileno DEV_NULL
393 or die "CheckLib: $! redirecting STDOUT to null handle";
394 open STDERR, ">&" . fileno DEV_NULL
395 or die "CheckLib: $! redirecting STDERR to null handle";
398 my $rv = system(@cmd);
401 open STDOUT, ">&" . fileno STDOUT_SAVE
402 or die "CheckLib: $! restoring STDOUT handle";
403 open STDERR, ">&" . fileno STDERR_SAVE
404 or die "CheckLib: $! restoring STDERR handle";
409 =head1 PLATFORMS SUPPORTED
411 You must have a C compiler installed. We check for C<$Config{cc}>,
412 both literally as it is in Config.pm and also in the $PATH.
414 It has been tested with varying degrees on rigourousness on:
418 =item gcc (on Linux, *BSD, Mac OS X, Solaris, Cygwin)
420 =item Sun's compiler tools on Solaris
422 =item IBM's tools on AIX
424 =item SGI's tools on Irix 6.5
426 =item Microsoft's tools on Windows
428 =item MinGW on Windows (with Strawberry Perl)
430 =item Borland's tools on Windows
436 =head1 WARNINGS, BUGS and FEEDBACK
438 This is a very early release intended primarily for feedback from
439 people who have discussed it. The interface may change and it has
440 not been adequately tested.
442 Feedback is most welcome, including constructive criticism.
443 Bug reports should be made using L<http://rt.cpan.org/> or by email.
445 When submitting a bug report, please include the output from running:
448 perl -MDevel::CheckLib -e0
458 David Cantrell E<lt>david@cantrell.org.ukE<gt>
460 David Golden E<lt>dagolden@cpan.orgE<gt>
462 Thanks to the cpan-testers-discuss mailing list for prompting us to write it
465 to Chris Williams for help with Borland support.
467 =head1 COPYRIGHT and LICENCE
469 Copyright 2007 David Cantrell. Portions copyright 2007 David Golden.
471 This module is free-as-in-speech software, and may be used, distributed,
472 and modified under the same conditions as perl itself.
476 This module is also free-as-in-mason software.