Why installed programs with perl modules hardcode perl version? - perl

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

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

perl DBI module installation erroring out

perl DBI module installation is erroring out.
Installed perl 5.32.1 in non standard location, using -Dinstallprefix option
./Configure -Dinstallprefix=/test/user/home/perl -des
make
make test
make install
/test/user/home/perl/bin/perl -version
This is perl 5, version 32, subversion 1 (v5.32.1) built for x86_64-linux
Set PERL5LIB env variable
export PERL5LIB="/test/user/home/perl/lib/5.32.1:/test/user/home/perl/lib/site_perl/5.32.1:/test/user/home/perl/lib/5.32.1/x86_64-linux"
which perl
/test/user/home/perl/bin/perl
Downloaded DBI-1.643 archive, after extraction execution of Makefile.PL is failing
perl Makefile.PL
Warning: PERL_LIB (/perl/lib/5.32.1) seems not to be a perl library directory
(strict.pm not found) at /test/user/home/perl/lib/5.32.1/ExtUtils/MM_Unix.pm line 1934.
Have /test/user/home/perl/lib/5.32.1/x86_64-linux
Want /perl/lib/5.32.1/x86_64-linux
Your perl and your Config.pm seem to have different ideas about the
architecture they are running on.
Perl thinks: [x86_64-linux]
Config says: [x86_64-linux]
This may or may not cause problems. Please check your installation of perl
if you have problems building this extension.
Can't stat /perl/lib/5.32.1: No such file or directory
at Makefile.PL line 280.
Can't stat /perl/lib/5.32.1/x86_64-linux: No such file or directory
at Makefile.PL line 280.
Failed to opendir '/perl/lib/5.32.1/x86_64-linux/CORE' to find header files: No such file or directory at /test/user/home/perl/lib/5.32.1/ExtUtils/MM_Any.pm line 3048.
Found non existing paths are referred from #INC
perl -e "print \"#INC\""
/test/user/home/perl/lib/5.32.1 /test/user/home/perl/lib/site_perl/5.32.1 /test/user/home/perl/lib/5.32.1/x86_64-linux
/perl/lib/site_perl/5.32.1/x86_64-linux /perl/lib/site_perl/5.32.1 /perl/lib/5.32.1/x86_64-linux /perl/lib/5.32.1
Can someone guide me where from #INC getting these non existing paths
/perl/lib/site_perl/5.32.1/x86_64-linux /perl/lib/site_perl/5.32.1 /perl/lib/5.32.1/x86_64-linux /perl/lib/5.32.1
are there any way to restrict #INC to append non existing paths?
I think you want just -Dprefix=/.... There are other things that need to end up in the right place too. You shouldn't need to set PERL5LIB though because perl should be using your prefix as its default #INC. What does your perl -V show?
There is an installprefix, but it's aimed at compiling on one machine and installing on another. However, the INSTALL docs also recommend against using that. Is that what you are trying to do?
As for the other directories, the INSTALL docs describe the various directories that show up in #INC.
Thank you #brian for pointing me in right direction.
Following was the root cause behind #INC contains non existing directories.
Last time during perl installation at least one time I ran following command
./Configure -des -Dprefix=/perl
Use relocatable #INC? [n]
Pathname where the private library files will reside? (~name ok)
[/perl/lib/5.32.1]
Where do you want to put the public architecture-dependent libraries? (~name ok)
[/perl/lib/5.32.1/x86_64-linux]
Pathname for the site-specific library files? (~name ok)
[/perl/lib/site_perl/5.32.1]
Pathname for the site-specific architecture-dependent library files? (~name ok)
[/perl/lib/site_perl/5.32.1/x86_64-linux]
then executed make command. Later on make test failed for other error.
Then without running make distclean command, I re ran Configure with
-Dinstallprefix option
./Configure -Dinstallprefix=/test/user/home/perl -des
This populate #INC as follows
/test/user/home/perl/lib/5.32.1 /test/user/home/perl/lib/site_perl/5.32.1 /test/user/home/perl/lib/5.32.1/x86_64-linux
/perl/lib/site_perl/5.32.1/x86_64-linux /perl/lib/site_perl/5.32.1 /perl/lib/5.32.1/x86_64-linux /perl/lib/5.32.1
To fix this issue executed following steps,
make distclean
./Configure -des -Dprefix=/test/user/home/perl -Dusethreads
now #INC is populated correct
#INC:
/test/user/home/perl/lib/site_perl/5.32.1/x86_64-linux-thread-multi
/test/user/home/perl/lib/site_perl/5.32.1
/test/user/home/perl/lib/5.32.1/x86_64-linux-thread-multi
/test/user/home/perl/lib/5.32.1
Now DBI installation ran successfully.

Installing cURL modules for Perl on Windows

I have ActivePerl 5.14.2 on my Windows machine. I have been trying to install the LWP cURL module. I have already installed the libcurl-dev library and GCC on my machine.
I also understand that LWP cURL has a dependency on the WWW-Curl-Easy module. So I installed that too. I installed all these through the command lines using the steps given in the Readme files. I ran the perl makefile.pl command followed by a make and a make install. No errors were given out during the installation.
I am trying to execute this sample code to test my LWP cURL installation:
use LWP::Curl;
use strict;
use warnings;
my $lwpcurl = LWP::Curl->new();
my $content = $lwpcurl->get('http://search.cpan.org','http://www.cpan.org');
I am receiving the below error:
Can't locate loadable object for module WWW::Curl in #INC (#INC
contains: C:/Perl64/site/lib C:/Perl64/lib .) at
C:/Perl64/site/lib/WWW/Curl.pm line 11. BEGIN failed--compilation
aborted at C:/Perl64/site/lib/WWW/Curl.pm line 11. Compilation failed
in require at C:/Perl64/site/lib/WWW/Curl/Easy.pm line 9. Compilation
failed in require at C:/Perl64/site/lib/LWP/Curl.pm line 5. BEGIN
failed--compilation aborted at C:/Perl64/site/lib/LWP/Curl.pm line 5.
Compilation failed in require at D:\Varsha\Curl.pl line 1. BEGIN
failed--compilation aborted at D:\Varsha\Curl.pl line 1.
Where am I going wrong?
This is probably not the direction you want to go, but I'd advise you to consider upgrading your perl and changing distributions:
Install Strawberry Perl - 5.18.2.2 is the currently recommended version.
Install cpanm: perl -MCPAN -e "install App::cpanminus"
Install LWP::Curl: cpanm LWP::Curl
I won't bother trying convince you of the change, but Strawberry Perl and cpanm in combination make installing modules a lot easier than having to dealing with the proprietary ppm's of ActivePerl in my opinion.
Just something to consider if you ever get tired of the occasional headaches.
The error means that WWW::Curl is either not installed or its path is not searchable (it's not in #INC). So the solutions are
Make sure that the module is installed.
Add the path where the module is installed to the #INC. Since you are on Windows, you can use set PERL5LIB = c:\path\to\dir
For a permanent solution follow the below:
Right-click My Computer and click Properties.
In the System Properties window, click on the Advanced tab.
In the Advanced section, click the Environment Variables button.
In the Environment Variables window in the "User variables for Foo Bar" section click on New and type in the following:
Variable name: PERL5LIB
Variable value: c:\path\to\dir
Then click OK 3 times. Windows that you open after this will already know about the new variable. Type this in the command window, to see the newly set value:
echo %PERL5LIB%
This will add the private /home/foobar/code directory (or c:\path\to\dir directory) to the beginning of #INC for every script that is executed in the same environment.
Also see: Installing perl dependency automatically in perl

Can't locate LWP/Simple.pm in #INC [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What's the easiest way to install a missing Perl module?
I'm attempting to run a Perl script to convert SCXML to Graphviz DOT. I modified the first line of the script to:
#!/usr/bin/env perl
and chmod +x the file. When I run it via ./scmxl2dot.pl I see the following error output:
Can't locate LWP/Simple.pm in #INC (#INC contains: /opt/local/lib/perl5/site_perl/5.12.3/darwin-multi-2level /opt/local/lib/perl5/site_perl/5.12.3 /opt/local/lib/perl5/vendor_perl/5.12.3/darwin-multi-2level /opt/local/lib/perl5/vendor_perl/5.12.3 /opt/local/lib/perl5/5.12.3/darwin-multi-2level /opt/local/lib/perl5/5.12.3 /opt/local/lib/perl5/site_perl /opt/local/lib/perl5/vendor_perl .) at ./scmxml2dot.pl line 14.
BEGIN failed--compilation aborted at ./scmxml2dot.pl line 14.
Line 14 of the file is use LWP::Simple;
How do I:
Find out if I have this thing (module?) installed, and/or
Get LWP::Simple and make it available to the script?
This is running under OS X 10.7.3 and Perl 5.12.3 (as seen in the error).
You're already determined that you don't have it (somewhere it can be found).
perl -MCPAN -e'install "LWP::Simple"'
Execute the following from the command line:
perl -MLWP::Simple -e 1
If you don't get any output from the above command then the module is installed; if you get an error, it's not installed
to install use
perl -MCPAN -e'install "LWP::Simple"'
When perl encounters use My::Module it goes over the elements of the built-in #INC module that contains directory names. In each directory it check if there is a subdirectory called "My" and if in that subdirectory there is a file called "Module.pm".
check where LWP::Simple module is installed on your system and type below line just above the use LWP::Simple statement of your code.
use lib '/usr/local/module';
use LWP::Simple;
Take a look at the Perldoc webpage. This will tell you which modules are standard Perl modules and which ones aren't.
You can also use the perldoc command to find out if a Perl module is installed, and if it is, its documentation.
$ perldoc LWP::Simple
(If Perldoc doesn't execute as a command do ls -l /usr/bin/perl*. On Macs, some of the Perl commands don't have the execute bit turned on. To turn it on, do sudo chmod a+x /usr/bin/perl).
It just happens the LWP::Simple isn't a standard Perl module, and if you don't have it, you'll have to install it. Most people have already told you about cpan. Unfortunately, by default, the Mac doesn't have the needed command line development tools installed. You'll have to install them.
Once they're installed, you can use the cpan command to install LWP::Simple:
$ sudo cpan #Run cpan and configure it. It takes about 3 minutes
cpan> install LWP::Simple
cpan> exit

Manual installation of a Perl Module

I have downloaded the module Digest::SHA1 and extracted it to a directory (../Digest-SHA1-2.13/) , then copied all the SHA1.* files into (../Digest-SHA1-2.13/Digest)
and in the perl script, I did : use Digest::SHA1;
launching the script like this:
perl -I ../Digest-SHA1-2.13/Digest perlscriptname.pl
I get this error:
Can't locate loadable object for module Digest::SHA1 in #INC
I assume it has something to do with a shared library (*.so)?, I have no idea how to continue from here.
I can install it directly using CPAN (-MCPAN) module, as I dont have permissions on that server to do that, and can install only locally (where the application is running).
My final goal is to use Algorithm::CouponCode which is dependent on Digest::SHA1
The weird part is, that I have Digest::SHA1 installed (perl -MDigest::SHA1 -e 'print $Digest::SHA1::VERSION' shows version 2.11), still Algorithm::CouponCode (which is installed the same way I did with Digest::SHA1) complains it can find it in #INC
thanks!
Use this recipe for manually installing perl modules:
tar zxf Digest-SHA1-2.13.tar.gz
cd Digest-SHA1-2.13
perl Makefile.PL
make
make test
make install
Note that some distributions will have a Build.PL file instead of Makefile.PL. In that case use this recipe:
tar zxf ...
cd ...
perl Build.PL
./Build
./Build test
./Build install
(You may be able to get by with just running make install and ./Build install.)
If you need to alter the installation dir then use:
perl Makefile.PL INSTALL_BASE=...
or
perl Build.PL --install_base ...
depending on the kind of module.
For more info see the perldoc for ExtUtils::MakeMaker::FAQ and Module::Build
There are two kinds of Perl module: pure-Perl and XS. Pure-Perl modules are written entirely in Perl, and can usually be installed just by copying the .pm files to an appropriate directory. XS modules are written in both Perl and C (XS is processed into C code by the ExtUtils::ParseXS module) and require a C compiler to install them.
As dsolimano said, the easiest way to install Perl modules for the system Perl when you don't have root access is to use local::lib. (You could do the same things that local::lib does yourself, but why bother?)
The reason why Digest::SHA1 works by itself but not when you're using Algorithm::CouponCode is that the system Perl already has version 2.11 of Digest::SHA1 installed. When you use -I ../Digest-SHA1-2.13/Digest, then use Digest::SHA1 picks up the Perl code from ../Digest-SHA1-2.13/Digest, but the shared library that would be built from the XS code is not in the corresponding location.
Any reason why you can't use local::lib?
create and use a local lib/ for perl modules with PERL5LIB
It is basically a tool to help you use a private (non-systemwide) directory as your Perl library directory.
After setting it up, you could run a command like
perl -MCPAN -Mlocal::lib -e 'CPAN::install(Algorithm::CouponCode)'
and then your script would use your locally installed copy of Algorithm::CouponCode).

Can't locate in #INC during CPAN dependency install performed not as root

While trying to do:
perl -I'/v1/data/site_perl' -MCPAN -e 'install Log::Dispatch';
I continue to get "Can't locate Params/Validate.pm in #INC." When looking at the output, /v1/data/site_perl is NOT in the #INC displayed, even though I used -I.
I am not root so I have changed my CPAN config so that:
'makepl_arg' => q[LIB=/v1/data/site_perl INSTALLSITEMAN1DIR=/v1/data/site_perl/man/man1 INSTALLSITEMAN3DIR=/v1/data/site_perl/man/man3 INSTALLMAN1DIR=/v1/data/site_perl/man/man1 INSTALLMAN3DIR=/v1/data/site_perl/man/man3]
So even LIB is set.
In a basic script I have:
use lib '/v1/data/site_perl';
use Params::Validate;
With no problems.
How do I make the Log::Dispatch use lib /v1/data/site_perl without a force install? What am I missing?
I believe CPAN.pm likes to call a lot of sub-processes for various tasks, and these end up starting new perls, which will not inherit your -I flag. Instead, try setting a PERL5LIB environment variable, e.g.
PERL5LIB='/v1/data/site_perl' perl -MCPAN -e 'install Log::Dispatch'
Another strategy to consider is to simply build a complete Perl installation in your local directory -- then use that perl's CPAN utilities. They will already have all your own paths built-in. This is the way I tend to do it.
You cannot install into a different CPAN directory using a simple -I flag. You can use the local::lib package to install a local set of libraries, or see this question and this question.