File Coverage

blib/lib/Devel/FindPerl.pm
Criterion Covered Total %
statement 63 80 78.7
branch 8 24 33.3
condition 4 20 20.0
subroutine 15 16 93.7
pod 2 2 100.0
total 92 142 64.7


line stmt bran cond sub pod time code
1             package Devel::FindPerl;
2             $Devel::FindPerl::VERSION = '0.015';
3 2     2   134240 use strict;
  2         13  
  2         59  
4 2     2   12 use warnings;
  2         4  
  2         64  
5              
6 2     2   10 use Exporter 5.57 'import';
  2         42  
  2         128  
7             our @EXPORT_OK = qw/find_perl_interpreter perl_is_same/;
8             our %EXPORT_TAGS = (all => \@EXPORT_OK);
9              
10 2     2   14 use Carp q/carp/;
  2         4  
  2         117  
11 2     2   13 use Config;
  2         3  
  2         73  
12 2     2   11 use Cwd q/realpath/;
  2         4  
  2         123  
13 2     2   14 use File::Basename qw/basename dirname/;
  2         3  
  2         185  
14 2     2   888 use File::Spec::Functions qw/catfile catdir rel2abs file_name_is_absolute updir curdir path splitpath/;
  2         1634  
  2         157  
15 2     2   15 use Scalar::Util 'tainted';
  2         5  
  2         83  
16 2     2   465 use IPC::Open2 qw/open2/;
  2         4438  
  2         1570  
17              
18             my %perl_for;
19             sub find_perl_interpreter {
20 2   50 2 1 168 my $config = shift || 'Devel::FindPerl::Config';
21 2 50       80 my $key = $config->can('serialize') ? $config->serialize : '';
22 2   33     31 $perl_for{$key} ||= _discover_perl_interpreter($config);
23 2 50       84 return wantarray ? @{ $perl_for{$key} } : $perl_for{$key}[0];
  0         0  
24             }
25              
26             sub _discover_perl_interpreter {
27 2     2   9 my $config = shift;
28              
29 2 50       11 return VMS::Filespec::vmsify($^X) if $^O eq 'VMS';
30 2         204 my $perl_basename = basename($^X);
31              
32 2         6 my @potential_perls;
33              
34             # Try 1, Check $^X for absolute and relative path
35 2 0       11 push @potential_perls, file_name_is_absolute($^X) ? [ $^X ] : length +(splitpath($^X))[1] ? [ rel2abs($^X) ] : ();
    50          
36              
37             # Try 2, Last ditch effort: These two option use hackery to try to locate
38             # a suitable perl. The hack varies depending on whether we are running
39             # from an installed perl or an uninstalled perl in the perl source dist.
40 2 50       57 if ($ENV{PERL_CORE}) {
41             # Try 3.A, If we are in a perl source tree, running an uninstalled
42             # perl, we can keep moving up the directory tree until we find our
43             # binary. We wouldn't do this under any other circumstances.
44              
45 0         0 my $perl_src = _perl_src();
46 0 0 0     0 if (defined($perl_src) && length($perl_src)) {
47 0         0 my $uninstperl = catfile($perl_src, $perl_basename);
48             # When run from the perl core, @INC will include the directories
49             # where perl is yet to be installed. We need to reference the
50             # absolute path within the source distribution where it can find
51             # it's Config.pm This also prevents us from picking up a Config.pm
52             # from a different configuration that happens to be already
53             # installed in @INC.
54 0         0 push @potential_perls, [ $uninstperl, '-I' . catdir($perl_src, 'lib') ];
55             }
56             }
57             else {
58             # Try 2.B, First look in $Config{perlpath}, then search the user's
59             # PATH. We do not want to do either if we are running from an
60             # uninstalled perl in a perl source tree.
61              
62 2         9 push @potential_perls, [ $config->get('perlpath') ];
63 2         12 push @potential_perls, map { [ catfile($_, $perl_basename) ] } path();
  18         130  
64             }
65 2         8 @potential_perls = grep { !tainted($_->[0]) } @potential_perls;
  22         56  
66              
67             # Now that we've enumerated the potential perls, it's time to test
68             # them to see if any of them match our configuration, returning the
69             # absolute path of the first successful match.
70 2         8 my $exe = $config->get('exe_ext');
71 2         8 foreach my $thisperl (@potential_perls) {
72 2 50 33     10 $thisperl->[0] .= $exe if length $exe and $thisperl->[0] !~ m/\Q$exe\E$/i;
73 2 50 33     75 return $thisperl if -f $thisperl->[0] && perl_is_same(@{$thisperl});
  2         12  
74             }
75              
76             # We've tried all alternatives, and didn't find a perl that matches
77             # our configuration. Throw an exception, and list alternatives we tried.
78 0         0 my @paths = map { dirname($_->[0]) } @potential_perls;
  0         0  
79 0         0 die "Can't locate the perl binary used to run this script in (@paths)\n";
80             }
81              
82             # if building perl, perl's main source directory
83             sub _perl_src {
84             # N.B. makemaker actually searches regardless of PERL_CORE, but
85             # only squawks at not finding it if PERL_CORE is set
86              
87 0 0   0   0 return unless $ENV{PERL_CORE};
88              
89 0         0 my $updir = updir;
90 0         0 my $dir = curdir;
91              
92             # Try up to 10 levels upwards
93 0         0 for (0..10) {
94 0 0 0     0 if (
      0        
95             -f catfile($dir,"config_h.SH")
96             &&
97             -f catfile($dir,"perl.h")
98             &&
99             -f catfile($dir,"lib","Exporter.pm")
100             ) {
101 0         0 return realpath($dir);
102             }
103              
104 0         0 $dir = catdir($dir, $updir);
105             }
106              
107 0         0 carp "PERL_CORE is set but I can't find your perl source!\n";
108 0         0 return;
109             }
110              
111             sub perl_is_same {
112 3     3 1 239 my @perl = @_;
113 3         13 return lc _capture_command(@perl, qw(-MConfig=myconfig -e print -e myconfig)) eq lc Config->myconfig;
114             }
115              
116             sub _capture_command {
117 3     3   29 my (@command) = @_;
118              
119 3         34 local @ENV{qw/PATH IFS CDPATH ENV BASH_ENV/};
120 3         17 my $pid = open2(my($in, $out), @command);
121 3 50       8452 binmode $in, ':crlf' if $^O eq 'MSWin32';
122 3         29 my $ret = do { local $/; <$in> };
  3         53  
  3         27856  
123 3         143 waitpid $pid, 0;
124 3         5191 return $ret;
125             }
126              
127             sub Devel::FindPerl::Config::get {
128 4     4   17 my ($self, $key) = @_;
129 4         124 return $Config{$key};
130             }
131              
132             1;
133              
134             #ABSTRACT: Find the path to your perl
135              
136             __END__