7 our $VERSION = "1.005";
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 $lopts = $req->{libbase} ? "-l$req->{libbase}" : "";
305 if (defined $lopts) {
306 print "$req->{name}: Checking if the compiler can find them on its own\n";
315 print "$req->{name}: Can't fake it - no libbase or libopts\n"
322 my ($req, $result) = @_;
324 require Devel::CheckLib;
325 # setup LD_RUN_PATH to match link time
326 print "Asking liblist for LD_RUN_PATH:\n" if $req->{verbose};
327 my ($extra, $bs_load, $ld_load, $ld_run_path) =
328 ExtUtils::Liblist->ext($result->{LIBS}, $req->{verbose});
329 local $ENV{LD_RUN_PATH};
332 print "Setting LD_RUN_PATH=$ld_run_path for $req->{name} probe\n"
334 $ENV{LD_RUN_PATH} = $ld_run_path;
335 if ($Config{lddlflags} =~ /([^ ]*-(?:rpath|R)[,=]?)([^ ]+)/
338 # LD_RUN_PATH is ignored when there's already an -rpath option
341 $result->{LDDLFLAGS} = $Config{lddlflags} . " " .
342 join " ", map "$prefix$_", split $Config{path_sep}, $ld_run_path;
346 Devel::CheckLib::check_lib
348 debug => $req->{verbose},
349 LIBS => [ $result->{LIBS} ],
350 INC => $result->{INC},
351 header => $req->{testcodeheaders},
352 function => $req->{testcode},
353 prologue => $req->{testcodeprologue},
356 print "$req->{name}: Test code failed: $@";
360 print "$req->{name}: Passed code check\n";
365 my ($req, $lflags) = @_;
367 my @libs = grep /^-l/, split ' ', $lflags;
369 my @paths = _lib_paths($req);
370 my $so = $Config{so};
371 my $libext = $Config{_a};
372 for my $lib (@libs) {
375 for my $path (@paths) {
376 if (-e "$path/$lib.$so" || -e "$path/$lib$libext") {
382 return join(" ", ( map "-L$_", keys %paths ), $lflags );
388 print "$req->{name} IM_LIBPATH: $ENV{IM_LIBPATH}\n"
389 if $req->{verbose} && defined $ENV{IM_LIBPATH};
390 print "$req->{name} LIB: $ENV{IM_LIBPATH}\n"
391 if $req->{verbose} && defined $ENV{LIB} && $^O eq "MSWin32";
392 my $lp = $req->{libpath};
393 print "$req->{name} libpath: ", ref $lp ? join($Config{path_sep}, @$lp) : $lp, "\n"
394 if $req->{verbose} && defined $lp;
403 @Config{qw/loclibpth libpth libspath/}
405 $^O eq "MSWin32" ? $ENV{LIB} : "",
406 $^O eq "cygwin" ? "/usr/lib/w32api" : "",
418 my ($base_version) = $Config{gccversion} =~ /^([0-9]+)/
424 local $ENV{LANG} = "C";
425 local $ENV{LC_ALL} = "C";
426 my ($lib_line) = grep /^libraries:/, `$Config{cc} -print-search-dirs`
428 $lib_line =~ s/^libraries: =//;
431 return grep !/gcc/ && -d, split /:/, $lib_line;
435 return map { defined() ? split /\Q$Config{path_sep}/ : () }
437 qw(LD_RUN_PATH LD_LIBRARY_PATH DYLD_LIBRARY_PATH LIBRARY_PATH);
443 print "$req->{name} IM_INCPATH: $ENV{IM_INCPATH}\n"
444 if $req->{verbose} && defined $ENV{IM_INCPATH};
445 print "$req->{name} INCLUDE: $ENV{INCLUDE}\n"
446 if $req->{verbose} && defined $ENV{INCLUDE} && $^O eq "MSWin32";
447 my $ip = $req->{incpath};
448 print "$req->{name} incpath: ", ref $ip ? join($Config{path_sep}, @$ip) : $ip, "\n"
449 if $req->{verbose} && defined $req->{incpath};
455 $^O eq "MSWin32" ? $ENV{INCLUDE} : "",
456 $^O eq "cygwin" ? "/usr/include/w32api" : "",
460 @Config{qw/locincpth incpath/}
463 "/usr/local/include",
468 if ($req->{incsuffix}) {
469 @paths = map File::Spec->catdir($_, $req->{incsuffix}), @paths;
479 my ($base_version) = $Config{gccversion} =~ /^([0-9]+)/
485 local $ENV{LANG} = "C";
486 local $ENV{LC_ALL} = "C";
487 my $devnull = File::Spec->devnull;
488 my @spam = `$Config{cc} -E -v - <$devnull 2>&1`;
489 # output includes lines like:
491 # ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../x86_64-linux-gnu/include"
492 # #include "..." search starts here:
493 # #include <...> search starts here:
494 # /usr/lib/gcc/x86_64-linux-gnu/4.9/include
496 # /usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed
497 # /usr/include/x86_64-linux-gnu
499 # End of search list.
504 while (@spam && $spam[0] !~ /^#include /) {
508 while (@spam && $spam[0] !~ /^End of search/) {
509 my $line = shift @spam;
511 next if $line =~ /^#include /;
512 next unless $line =~ s/^\s+//;
521 $tmp =~ s/\blib$/include/ ? $tmp : ()
530 # expand any array refs
531 @in = map { ref() ? @$_ : $_ } @in;
535 $path = _tilde_expand($path);
537 push @out, grep -d $_, split /\Q$Config{path_sep}/, $path;
540 @out = map Cwd::realpath($_), @out;
543 @out = grep !$seen{$_}++, @out;
552 if ($path =~ m!^~[/\\]!) {
553 defined $home or $home = $ENV{HOME};
554 if (!defined $home && $^O eq 'MSWin32'
555 && defined $ENV{HOMEDRIVE} && defined $ENV{HOMEPATH}) {
556 $home = $ENV{HOMEDRIVE} . $ENV{HOMEPATH};
558 unless (defined $home) {
559 $home = eval { (getpwuid($<))[7] };
561 defined $home or die "You supplied $path, but I can't find your home directory\n";
563 $path = File::Spec->catdir($home, $path);
575 Imager::Probe - hot needle of inquiry for libraries
579 require Imager::Probe;
583 # short name of what we're looking for (displayed to user)
586 pkg => [ qw/name1 name2 name3/ ],
587 # perl subs that probe for the library
588 code => [ \&foo_probe1, \&foo_probe2 ],
589 # or just: code => \&foo_probe,
590 inccheck => sub { ... },
591 libcheck => sub { ... },
592 # search for this library if libcheck not supplied
594 # library link time options, uses libbase to build options otherwise
596 # C code to check the library is sane
598 # header files needed
599 testcodeheaders => [ "stdio.h", "foo.h" ],
601 my $result = Imager::Probe->probe(\%probe)
602 or print "Foo library not found: ",Imager::Probe->error;
606 Does the probes that were hidden in Imager's F<Makefile.PL>, pulled
607 out so the file format libraries can be externalized.
609 The return value is either nothing if the probe fails, or a hash
616 C<INC> - C<-I> and other C options
620 C<LIBS> - C<-L>, C<-l> and other link-time options
624 C<DEFINE> - C<-D> options, if any.
628 The possible values for the hash supplied to the probe() method are:
634 C<pkg> - an array of F<pkg-config> names to probe for. If the
635 F<pkg-config> checks pass, C<inccheck> and C<libcheck> aren't used.
639 C<inccheck> - a code reference that checks if the supplied include
640 directory contains the required header files.
644 C<libcheck> - a code reference that checks if the supplied library
645 directory contains the required library files. Note: the
646 F<Makefile.PL> version of this was supplied all of the library file
647 names instead. C<libcheck> can also be an arrayref of library check
648 code references, all of which must find a match for the library to be
653 C<libbase> - if C<inccheck> is supplied, but C<libcheck> isn't, then a
654 C<libcheck> that checks for C<lib>I<libbase>I<$Config{_a}> and
655 C<lib>I<libbase>.I<$Config{so}> is created. If C<libopts> isn't
656 supplied then that can be synthesized as C<< -lI<libbase>
657 >>. C<libbase> can also be an arrayref of library base names to search
658 for, in which case all of the libraries mentioned must be found for
659 the probe to succeed.
663 C<libopts> - if the libraries are found via C<inccheck>/C<libcheck>,
664 these are the C<-l> options to supply during the link phase.
668 C<code> - a code reference to perform custom checks. Returns the
669 probe result directly. Can also be an array ref of functions to call.
673 C<testcode> - test C code that is run with Devel::CheckLib. You also
674 need to set C<testcodeheaders>.
678 C<testcodeprologue> - C code to insert between the headers and the
683 C<incpath> - C<$Config{path_sep}> separated list of header file
684 directories to check, or a reference to an array of such.
688 C<libpath> - C<$Config{path_sep}> separated list of library file
689 directories to check, or a reference to an array of such.
693 C<alternatives> - an optional array reference of alternate
694 configurations (as hash references) to test if the primary
695 configuration isn't successful. Each alternative should include an
696 C<altname> key describing the alternative. Any key not mentioned in
697 an alternative defaults to the value from the main configuration.
703 Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson