Why installed programs with perl modules hardcode perl version?

Viewed 99

When we install module this module can ship executable which is installed into local/bin directory.

if we spy into installed script we can notice that perl version is hardcoded:

/home/user/t/local/bin/mojo
#!/home/user/perl5/perlbrew/perls/perl-5.35.1/bin/perl5.35.1

Why perl version is hard coded?
I expect it should be /usr/bin/env perl:

$ which cpanm
/home/user/perl5/perlbrew/bin/cpanm

$ cat $(which cpanm) | less
#!/usr/bin/env perl
3 Answers

I expect it should be /usr/bin/env perl:

In this case it would take the Perl installation currently in the path. This might be a different Perl installation compared to what was used to install the application modules. In this case running the application might fail due to missing modules. Or it might show strange behavior since the installed modules have a different version than expected by application and thus can show different behavior.

For example imagine the case when there are two perl installations at your system. And when you install script with first perl you you can not run it with second perl, because second perl lacks modules available from first one.

It should have the path of the Perl with which it was installed.

  • This is the perl for which its dependencies has been installed.
  • This is the perl with which it has been tested.

If the script was made to rely on the environment as you suggest, it could pick up a different perl, and that would very likely cause it to fail.


For example, let's take a tool which has a shebang line of

#!/home/ikegami/usr/perlbrew/perls/5.34.0t/bin/perl -w

Regardless of the environment, it works fine.

$ /home/ikegami/usr/perlbrew/perls/latest/bin/tpage \
   --define USER=World \
   <<<'Hello, [% USER %]!'
Hello, World!

Now let's simulate the following shebang line:

#!/usr/bin/env perl -w

It fails misearbly despite the tool being correctly installed.

$ /usr/bin/env perl -w /home/ikegami/usr/perlbrew/perls/latest/bin/tpage \
   --define USER=World \
   <<<'Hello, [% USER %]!'
Can't locate Template.pm in @INC (you may need to install the Template module) (@INC contains: /home/ikegami/usr/perlbrew/perls/5.28.2t/lib/site_perl/5.28.2/x86_64-linux-thread-multi /home/ikegami/usr/perlbrew/perls/5.28.2t/lib/site_perl/5.28.2 /home/ikegami/usr/perlbrew/perls/5.28.2t/lib/5.28.2/x86_64-linux-thread-multi /home/ikegami/usr/perlbrew/perls/5.28.2t/lib/5.28.2) at /home/ikegami/usr/perlbrew/perls/latest/bin/tpage line 27.
BEGIN failed--compilation aborted at /home/ikegami/usr/perlbrew/perls/latest/bin/tpage line 27.

This is an unreliable solution subject to effects at a distance. For the same reason we scope variables, we should avoid env.


The story is different for self-contained scripts, but a self-contained script wouldn't be installed using ExtUtils::MakeMaker or Module::Build (the modules setting the shebang line), so such scripts aren't relevant here.

Seems correct question to my problem was: How to prevent perl from hard coding its version at shebang?

TLDR;

export PERL_MM_SHEBANG=relocatable

After reading article @Håkon Hægland adviced and reading #38
Now I see that there is two scenario:

  • when script is installed into system
  • when script is installed into application local/bin directory.

My case is second.

So for this case I should simultaneously set environment variable PERL_MM_SHEBANG to relocatable when I set current perl into path

This env variable implemented here

Related