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