#! perl

use Config;
use File::Basename qw/basename dirname/;
use File::Spec::Functions qw/catfile catdir path/;

my $perl_path;

sub find_perl {
	$perl_path ||= _discover_perl()
}

sub _discover_perl_interpreter {
	my $perl = $^X;
	my $perl_basename = basename($perl);

	my @potential_perls;

	# Try 1, Check $^X for absolute path
	push @potential_perls, $perl if File::Spec->file_name_is_absolute($perl);

	# Try 2, Check $^X for a valid relative path
	my $abs_perl = File::Spec->rel2abs($perl);
	push @potential_perls, $abs_perl;

	# Try 3, Last ditch effort: These two option use hackery to try to locate
	# a suitable perl. The hack varies depending on whether we are running
	# from an installed perl or an uninstalled perl in the perl source dist.
	if ($ENV{PERL_CORE}) {
		# Try 3.A, If we are in a perl source tree, running an uninstalled
		# perl, we can keep moving up the directory tree until we find our
		# binary. We wouldn't do this under any other circumstances.

		# CBuilder is also in the core, so it should be available here
		require ExtUtils::CBuilder;
		my $perl_src = Cwd::realpath( ExtUtils::CBuilder->perl_src );
		if (defined $perl_src && length $perl_src) {
			my $uninstperl = File::Spec->rel2abs(File::Spec->catfile( $perl_src, $perl_basename ));
			push @potential_perls, $uninstperl;
		}
	}
	else {
		# Try 3.B, First look in $Config{perlpath}, then search the user's
		# PATH. We do not want to do either if we are running from an
		# uninstalled perl in a perl source tree.

		push @potential_perls, $Config{perlpath};

		push @potential_perls, map { catfile($_, $perl_basename) } path();
	}

	# Now that we've enumerated the potential perls, it's time to test
	# them to see if any of them match our configuration, returning the
	# absolute path of the first successful match.
	my $exe = $Config{exe_ext};
	for my $thisperl (@potential_perls) {

		if (defined $exe) {
			$thisperl .= $exe unless $thisperl =~ m/$exe$/i;
		}

		if ( -f $thisperl && _perl_is_same($thisperl) ) {
			return $thisperl;
		}
	}

	# We've tried all alternatives, and didn't find a perl that matches
	# our configuration. Throw an exception, and list alternatives we tried.
	my @paths = map { dirname($_) } @potential_perls;
	die "Can't locate the perl binary used to run this script in (@paths)\n";
}

sub _perl_is_same {
  my $perl = shift;
  my @cmd = $perl;

  # When run from the perl core, @INC will include the directories
  # where perl is yet to be installed. We need to reference the
  # absolute path within the source distribution where it can find
  # it's Config.pm This also prevents us from picking up a Config.pm
  # from a different configuration that happens to be already
  # installed in @INC.
  if ($ENV{PERL_CORE}) {
    push @cmd, '-I' . catdir(File::Basename::dirname($perl), 'lib');
  }

  push @cmd, qw(-MConfig=myconfig -e print -e myconfig);
  return `@cmd` eq Config->myconfig;
}
