7 our $VERSION = "1.006";
9 my @alt_transfer = qw/altname incsuffix libbase/;
12 my ($class, $req) = @_;
14 $req->{verbose} ||= $ENV{IM_VERBOSE};
16 my $name = $req->{name};
19 $result = _probe_code($req);
21 if (!$result && $req->{pkg}) {
22 $result = _probe_pkg($req);
24 if (!$result && $req->{inccheck} && ($req->{libcheck} || $req->{libbase})) {
25 $req->{altname} ||= "main";
26 $result = _probe_check($req);
29 if ($result && $req->{testcode}) {
30 $result = _probe_test($req, $result);
33 if (!$result && $req->{alternatives}) {
36 for my $alt (@{$req->{alternatives}}) {
37 $req->{altname} = $alt->{altname} || "alt $index";
39 and print "$req->{name}: Trying alternative $index\n";
41 for my $key (@alt_transfer) {
42 exists $alt->{$key} and $work{$key} = $alt->{$key};
44 $result = _probe_check(\%work);
46 if ($result && $req->{testcode}) {
47 $result = _probe_test(\%work, $result);
57 if (!$result && $req->{testcode}) {
58 $result = _probe_fake($req);
62 $result = _probe_test($req, $result);
73 my $code = $req->{code};
74 my @probes = ref $code eq "ARRAY" ? @$code : $code;
77 for my $probe (@probes) {
78 $result = $probe->($req)
88 my @exe_suffix = $Config{_exe};
89 if ($^O eq 'MSWin32') {
90 push @exe_suffix, qw/.bat .cmd/;
93 for my $dir (File::Spec->path) {
94 for my $suffix (@exe_suffix) {
95 -x File::Spec->catfile($dir, "$name$suffix")
106 # Setup pkg-config's environment variable to search non-standard paths
107 # which may be provided by --libdirs.
108 my @pkgcfg_paths = map { "$_/pkgconfig" } _lib_paths( $req );
109 push @pkgcfg_paths, $ENV{ 'PKG_CONFIG_PATH' } if $ENV{ 'PKG_CONFIG_PATH' };
111 local $ENV{ 'PKG_CONFIG_PATH' } = join $Config{path_sep}, @pkgcfg_paths;
113 is_exe('pkg-config') or return;
114 my $redir = $^O eq 'MSWin32' ? '' : '2>/dev/null';
116 my @pkgs = @{$req->{pkg}};
117 for my $pkg (@pkgs) {
118 if (!system("pkg-config $pkg --exists $redir")) {
119 # if we find it, but the following fail, then pkg-config is too
120 # broken to be useful
121 my $cflags = `pkg-config $pkg --cflags`
124 my $lflags = `pkg-config $pkg --libs`
128 $cflags =~ s/(-D\S+)/$defines .= " $1"; ''/ge;
132 print "$req->{name}: Found via pkg-config $pkg\n";
133 print <<EOS if $req->{verbose};
139 # if Win32 doesn't provide this information, too bad
140 if (!grep(/^-L/, split " ", $lflags)
141 && $^O ne 'MSWin32') {
142 # pkg-config told us about the library, make sure it's
143 # somewhere EU::MM can find it
144 print "Checking if EU::MM can find $lflags\n" if $req->{verbose};
145 my ($extra, $bs_load, $ld_load, $ld_run_path) =
146 ExtUtils::Liblist->ext($lflags, $req->{verbose});
147 unless ($ld_run_path) {
148 # search our standard places
149 $lflags = _resolve_libs($req, $lflags);
162 print "$req->{name}: Not found via pkg-config\n";
168 return $Config{cc} eq "cl";
186 return $base . $Config{_a};
196 return $opt =~ /\s/ ? qq("$opt") : $opt;
204 if ($req->{libcheck}) {
205 if (ref $req->{libcheck} eq "ARRAY") {
206 push @libcheck, @{$req->{libcheck}};
209 push @libcheck, $req->{libcheck};
212 elsif ($req->{libbase}) {
213 @libbase = ref $req->{libbase} ? @{$req->{libbase}} : $req->{libbase};
215 my $lext=$Config{'so'}; # Get extensions of libraries
216 my $aext=$Config{'_a'};
218 for my $libbase (@libbase) {
219 my $basename = _lib_basename($libbase);
220 push @libcheck, sub {
221 -e File::Spec->catfile($_[0], "$basename$aext")
222 || -e File::Spec->catfile($_[0], "$basename.$lext")
227 print "$req->{name}: No libcheck or libbase, nothing to search for\n"
233 my @lib_search = _lib_paths($req);
234 print "$req->{name}: Searching directories for libraries:\n"
236 for my $libcheck (@libcheck) {
237 for my $path (@lib_search) {
238 print "$req->{name}: $path\n" if $req->{verbose};
239 if ($libcheck->($path)) {
240 print "$req->{name}: Found!\n" if $req->{verbose};
241 push @found_libpath, $path;
248 my $inccheck = $req->{inccheck};
249 my @inc_search = _inc_paths($req);
250 print "$req->{name}: Searching directories for headers:\n"
252 for my $path (@inc_search) {
253 print "$req->{name}: $path\n" if $req->{verbose};
254 if ($inccheck->($path)) {
255 print "$req->{name}: Found!\n" if $req->{verbose};
256 $found_incpath = $path;
262 if ($req->{altname}) {
263 $alt = " $req->{altname}:";
265 print "$req->{name}:$alt includes ", $found_incpath ? "" : "not ",
266 "found - libraries ", @found_libpath == @libcheck ? "" : "not ", "found\n";
268 @found_libpath == @libcheck && $found_incpath
271 my @libs = map "-L$_", @found_libpath;
272 if ($req->{libopts}) {
273 push @libs, $req->{libopts};
276 push @libs, map _lib_option($_), @libbase;
279 die "$req->{altname}: inccheck but no libbase or libopts";
284 INC => _quotearg("-I$found_incpath"),
285 LIBS => join(" ", map _quotearg($_), @libs),
293 # the caller provided test code, and the compiler may look in
294 # places we don't, see Imager-Screenshot ticket 56793,
295 # so fake up a result so the test code can
297 if ($req->{libopts}) {
298 $lopts = $req->{libopts};
300 elsif (defined $req->{libbase}) {
301 # might not need extra libraries, eg. Win32 perl already links
303 my @libs = $req->{libbase}
304 ? ( ref $req->{libbase} ? @{$req->{libbase}} : $req->{libbase} )
306 $lopts = join " ", map _lib_option($_), @libs;
308 if (defined $lopts) {
309 print "$req->{name}: Checking if the compiler can find them on its own\n";
318 print "$req->{name}: Can't fake it - no libbase or libopts\n"
325 my ($req, $result) = @_;
327 require Devel::CheckLib;
328 # setup LD_RUN_PATH to match link time
329 print "Asking liblist for LD_RUN_PATH:\n" if $req->{verbose};
330 my ($extra, $bs_load, $ld_load, $ld_run_path) =
331 ExtUtils::Liblist->ext($result->{LIBS}, $req->{verbose});
332 local $ENV{LD_RUN_PATH};
335 print "Setting LD_RUN_PATH=$ld_run_path for $req->{name} probe\n"
337 $ENV{LD_RUN_PATH} = $ld_run_path;
338 if ($Config{lddlflags} =~ /([^ ]*-(?:rpath|R)[,=]?)([^ ]+)/
341 # LD_RUN_PATH is ignored when there's already an -rpath option
344 $result->{LDDLFLAGS} = $Config{lddlflags} . " " .
345 join " ", map "$prefix$_", split $Config{path_sep}, $ld_run_path;
349 Devel::CheckLib::check_lib
351 debug => $req->{verbose},
352 LIBS => [ $result->{LIBS} ],
353 INC => $result->{INC},
354 header => $req->{testcodeheaders},
355 function => $req->{testcode},
356 prologue => $req->{testcodeprologue},
359 print "$req->{name}: Test code failed: $@";
363 print "$req->{name}: Passed code check\n";
368 my ($req, $lflags) = @_;
370 my @libs = grep /^-l/, split ' ', $lflags;
372 my @paths = _lib_paths($req);
373 my $so = $Config{so};
374 my $libext = $Config{_a};
375 for my $lib (@libs) {
378 for my $path (@paths) {
379 if (-e "$path/$lib.$so" || -e "$path/$lib$libext") {
385 return join(" ", ( map "-L$_", keys %paths ), $lflags );
391 print "$req->{name} IM_LIBPATH: $ENV{IM_LIBPATH}\n"
392 if $req->{verbose} && defined $ENV{IM_LIBPATH};
393 print "$req->{name} LIB: $ENV{IM_LIBPATH}\n"
394 if $req->{verbose} && defined $ENV{LIB} && $^O eq "MSWin32";
395 my $lp = $req->{libpath};
396 print "$req->{name} libpath: ", ref $lp ? join($Config{path_sep}, @$lp) : $lp, "\n"
397 if $req->{verbose} && defined $lp;
406 @Config{qw/loclibpth libpth libspath/}
408 $^O eq "MSWin32" ? $ENV{LIB} : "",
409 $^O eq "cygwin" ? "/usr/lib/w32api" : "",
421 my ($base_version) = $Config{gccversion} =~ /^([0-9]+)/
427 local $ENV{LANG} = "C";
428 local $ENV{LC_ALL} = "C";
429 my ($lib_line) = grep /^libraries:/, `$Config{cc} -print-search-dirs`
431 $lib_line =~ s/^libraries: =//;
434 return grep !/gcc/ && -d, split /:/, $lib_line;
438 return map { defined() ? split /\Q$Config{path_sep}/ : () }
440 qw(LD_RUN_PATH LD_LIBRARY_PATH DYLD_LIBRARY_PATH LIBRARY_PATH);
446 print "$req->{name} IM_INCPATH: $ENV{IM_INCPATH}\n"
447 if $req->{verbose} && defined $ENV{IM_INCPATH};
448 print "$req->{name} INCLUDE: $ENV{INCLUDE}\n"
449 if $req->{verbose} && defined $ENV{INCLUDE} && $^O eq "MSWin32";
450 my $ip = $req->{incpath};
451 print "$req->{name} incpath: ", ref $ip ? join($Config{path_sep}, @$ip) : $ip, "\n"
452 if $req->{verbose} && defined $req->{incpath};
458 $^O eq "MSWin32" ? $ENV{INCLUDE} : "",
459 $^O eq "cygwin" ? "/usr/include/w32api" : "",
463 @Config{qw/locincpth incpath/}
466 "/usr/local/include",
471 if ($req->{incsuffix}) {
472 @paths = map File::Spec->catdir($_, $req->{incsuffix}), @paths;
482 my ($base_version) = $Config{gccversion} =~ /^([0-9]+)/
488 local $ENV{LANG} = "C";
489 local $ENV{LC_ALL} = "C";
490 my $devnull = File::Spec->devnull;
491 my @spam = `$Config{cc} -E -v - <$devnull 2>&1`;
492 # output includes lines like:
494 # ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../x86_64-linux-gnu/include"
495 # #include "..." search starts here:
496 # #include <...> search starts here:
497 # /usr/lib/gcc/x86_64-linux-gnu/4.9/include
499 # /usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed
500 # /usr/include/x86_64-linux-gnu
502 # End of search list.
507 while (@spam && $spam[0] !~ /^#include /) {
511 while (@spam && $spam[0] !~ /^End of search/) {
512 my $line = shift @spam;
514 next if $line =~ /^#include /;
515 next unless $line =~ s/^\s+//;
524 $tmp =~ s/\blib$/include/ ? $tmp : ()
533 # expand any array refs
534 @in = map { ref() ? @$_ : $_ } @in;
538 $path = _tilde_expand($path);
540 push @out, grep -d $_, split /\Q$Config{path_sep}/, $path;
543 @out = map Cwd::realpath($_), @out;
546 @out = grep !$seen{$_}++, @out;
555 if ($path =~ m!^~[/\\]!) {
556 defined $home or $home = $ENV{HOME};
557 if (!defined $home && $^O eq 'MSWin32'
558 && defined $ENV{HOMEDRIVE} && defined $ENV{HOMEPATH}) {
559 $home = $ENV{HOMEDRIVE} . $ENV{HOMEPATH};
561 unless (defined $home) {
562 $home = eval { (getpwuid($<))[7] };
564 defined $home or die "You supplied $path, but I can't find your home directory\n";
566 $path = File::Spec->catdir($home, $path);
578 Imager::Probe - hot needle of inquiry for libraries
582 require Imager::Probe;
586 # short name of what we're looking for (displayed to user)
589 pkg => [ qw/name1 name2 name3/ ],
590 # perl subs that probe for the library
591 code => [ \&foo_probe1, \&foo_probe2 ],
592 # or just: code => \&foo_probe,
593 inccheck => sub { ... },
594 libcheck => sub { ... },
595 # search for this library if libcheck not supplied
597 # library link time options, uses libbase to build options otherwise
599 # C code to check the library is sane
601 # header files needed
602 testcodeheaders => [ "stdio.h", "foo.h" ],
604 my $result = Imager::Probe->probe(\%probe)
605 or print "Foo library not found: ",Imager::Probe->error;
609 Does the probes that were hidden in Imager's F<Makefile.PL>, pulled
610 out so the file format libraries can be externalized.
612 The return value is either nothing if the probe fails, or a hash
619 C<INC> - C<-I> and other C options
623 C<LIBS> - C<-L>, C<-l> and other link-time options
627 C<DEFINE> - C<-D> options, if any.
631 The possible values for the hash supplied to the probe() method are:
637 C<pkg> - an array of F<pkg-config> names to probe for. If the
638 F<pkg-config> checks pass, C<inccheck> and C<libcheck> aren't used.
642 C<inccheck> - a code reference that checks if the supplied include
643 directory contains the required header files.
647 C<libcheck> - a code reference that checks if the supplied library
648 directory contains the required library files. Note: the
649 F<Makefile.PL> version of this was supplied all of the library file
650 names instead. C<libcheck> can also be an arrayref of library check
651 code references, all of which must find a match for the library to be
656 C<libbase> - if C<inccheck> is supplied, but C<libcheck> isn't, then a
657 C<libcheck> that checks for C<lib>I<libbase>I<$Config{_a}> and
658 C<lib>I<libbase>.I<$Config{so}> is created. If C<libopts> isn't
659 supplied then that can be synthesized as C<< -lI<libbase>
660 >>. C<libbase> can also be an arrayref of library base names to search
661 for, in which case all of the libraries mentioned must be found for
662 the probe to succeed.
666 C<libopts> - if the libraries are found via C<inccheck>/C<libcheck>,
667 these are the C<-l> options to supply during the link phase.
671 C<code> - a code reference to perform custom checks. Returns the
672 probe result directly. Can also be an array ref of functions to call.
676 C<testcode> - test C code that is run with Devel::CheckLib. You also
677 need to set C<testcodeheaders>.
681 C<testcodeprologue> - C code to insert between the headers and the
686 C<incpath> - C<$Config{path_sep}> separated list of header file
687 directories to check, or a reference to an array of such.
691 C<libpath> - C<$Config{path_sep}> separated list of library file
692 directories to check, or a reference to an array of such.
696 C<alternatives> - an optional array reference of alternate
697 configurations (as hash references) to test if the primary
698 configuration isn't successful. Each alternative should include an
699 C<altname> key describing the alternative. Any key not mentioned in
700 an alternative defaults to the value from the main configuration.
706 Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson