File Coverage

blib/lib/Devel/FindPerl.pm
Criterion Covered Total %
statement 64 81 79.0
branch 8 24 33.3
condition 4 20 20.0
subroutine 15 16 93.7
pod 2 2 100.0
total 93 143 65.0


line stmt bran cond sub pod time code
1             package Devel::FindPerl;
2             $Devel::FindPerl::VERSION = '0.016';
3 2     2   115412 use strict;
  2         10  
  2         48  
4 2     2   10 use warnings;
  2         4  
  2         50  
5              
6 2     2   9 use Exporter 5.57 'import';
  2         32  
  2         95  
7             our @EXPORT_OK = qw/find_perl_interpreter perl_is_same/;
8             our %EXPORT_TAGS = (all => \@EXPORT_OK);
9              
10 2     2   10 use Carp q/carp/;
  2         3  
  2         81  
11 2     2   9 use Config;
  2         3  
  2         68  
12 2     2   9 use Cwd q/realpath/;
  2         4  
  2         99  
13 2     2   10 use File::Basename qw/basename dirname/;
  2         4  
  2         169  
14 2     2   801 use File::Spec::Functions qw/catfile catdir rel2abs file_name_is_absolute updir curdir path splitpath/;
  2         1424  
  2         146  
15 2     2   22 use Scalar::Util 'tainted';
  2         4  
  2         70  
16 2     2   399 use IPC::Open2 qw/open2/;
  2         3892  
  2         1352  
17              
18             my %perl_for;
19             sub find_perl_interpreter {
20 2   50 2 1 134 my $config = shift || 'Devel::FindPerl::Config';
21 2 50       64 my $key = $config->can('serialize') ? $config->serialize : '';
22 2   33     17 $perl_for{$key} ||= _discover_perl_interpreter($config);
23 2 50       74 return wantarray ? @{ $perl_for{$key} } : $perl_for{$key}[0];
  0         0  
24             }
25              
26             sub _discover_perl_interpreter {
27 2     2   5 my $config = shift;
28              
29 2 50       7 return VMS::Filespec::vmsify($^X) if $^O eq 'VMS';
30 2         175 my $perl_basename = basename($^X);
31              
32 2         5 my @potential_perls;
33              
34             # Try 1, Check $^X for absolute and relative path
35 2 0       13 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       77 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         10 push @potential_perls, [ $config->get('perlpath') ];
63 2         21 push @potential_perls, map { [ catfile($_, $perl_basename) ] } path();
  18         110  
64             }
65 2         7 @potential_perls = grep { !tainted($_->[0]) } @potential_perls;
  22         47  
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         5 my $exe = $config->get('exe_ext');
71 2         11 foreach my $thisperl (@potential_perls) {
72 2 50 33     9 $thisperl->[0] .= $exe if length $exe and $thisperl->[0] !~ m/\Q$exe\E$/i;
73 2 50 33     53 return $thisperl if -f $thisperl->[0] && perl_is_same(@{$thisperl});
  2         7  
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 221 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   23 my (@command) = @_;
118              
119 3         33 local @ENV{qw/PATH IFS CDPATH ENV BASH_ENV/};
120 3         24 delete @ENV{qw/PATH IFS CDPATH ENV BASH_ENV/};
121 3         11 my $pid = open2(my($in, $out), @command);
122 3 50       8469 binmode $in, ':crlf' if $^O eq 'MSWin32';
123 3         14 my $ret = do { local $/; <$in> };
  3         32  
  3         29963  
124 3         126 waitpid $pid, 0;
125 3         5161 return $ret;
126             }
127              
128             sub Devel::FindPerl::Config::get {
129 4     4   16 my ($self, $key) = @_;
130 4         112 return $Config{$key};
131             }
132              
133             1;
134              
135             #ABSTRACT: Find the path to your perl
136              
137             __END__