Can't update #INC with export PERL5LIB - perl

I'm trying to add the HTML::Entities module path to #INC. I did export PERL5LIB=/mypath/HTML/ followed by source ~/.bashrc. That path is reflected in PERL5LIB, but not in #INC. Is there an additional step that I'm missing?
I'm using perl 5.26.2 on CentOS6.5
Edit:
I (wrongly) assumed that my path wasn't being added to #INC because when I run my perl script I get
Can't locate HTML/Entities.pm in #INC (you may need to install the HTML::Entities module)
(#INC contains:
/home/hek/anaconda3/bin/aux/lib/perl5
/home/hek/anaconda3/lib/site_perl/5.26.2/x86_64-linux-thread-multi
/home/hek/anaconda3/lib/site_perl/5.26.2
/home/hek/anaconda3/lib/5.26.2/x86_64-linux-thread-multi
/home/hek/anaconda3/lib/5.26.2
)
(Line breaks added for readability)
But it does appear below
echo $PERL5LIB
/opt/rh/devtoolset-2/root//usr/lib64/perl5/vendor_perl:/opt/rh/devtoolset-2/root/usr/lib/perl5:/opt/rh/devtoolset-2/root//usr/share/perl5/vendor_perl:/opt/perl/lib/site_perl/5.14.2/x86_64-linux-thread-multi/HTML/
perl -e 'use Data::Dumper; print Dumper(\#INC), "\n"'
$VAR1 = [
'/opt/rh/devtoolset-2/root//usr/lib64/perl5/vendor_perl',
'/opt/rh/devtoolset-2/root/usr/lib/perl5',
'/opt/rh/devtoolset-2/root//usr/share/perl5/vendor_perl',
'/opt/perl/lib/site_perl/5.14.2/x86_64-linux-thread-multi/HTML/',
'/home/hek/anaconda3/lib/site_perl/5.26.2/x86_64-linux-thread-multi',
'/home/hek/anaconda3/lib/site_perl/5.26.2',
'/home/hek/anaconda3/lib/5.26.2/x86_64-linux-thread-multi',
'/home/hek/anaconda3/lib/5.26.2',
'.'
];
Why would there be this discrepency?
I do have multiple versions of perl installed, but which perl returns the version that I need to use, ~/anaconda3/bin/perl.
I tried changing the shebang in my script from #!/usr/bin/env perl to #!/~/anaconda3/bin/perl, but that didn't help.

Two possibilities:
Either the PERL5LIB env var wasn't set in the parent of the perl process giving the error (e.g. you launched it from a web server), or
The -T command line switch was provided to perl process giving the error (since this causes PERL5LIB to be ignored).
In either case, you can use use lib in the source instead of PERL5LIB.

use HTML::Entities looks for a file HTML/Entities.pm in the directories in #INC. No such path is found because it's looking for ones like /opt/perl/lib/site_perl/5.14.2/x86_64-linux-thread-multi/HTML/HTML/Entities.pm.
Leave off the HTML/ part in the directory you're trying to add to the search path and you might have better luck.
Edit: There's still the version mismatch, but as long as the module is pure Perl without any XS components I don't think that will be a big problem. Still better to get it in the right path for the version of perl you're actually using. Do that and you shouldn't have to manipulate the search path at all.

This is to summarize the problems and state what seems to be the simplest solution.
From the output of your test one-liner it is clear that a module installed under v5.14.2 is used in a program meant to run under v5.26.2. That is not good, even if it happens to work.
So install HTML::Entities under the perl build that needs it, v5.26.2.
That also solves the problem you are asking about, since then you won't have to muck about with PERL5LIB or anything else.
Further, the #INC in your one-liner test clearly isn't loaded in your real run, just as you suspected. Possible reasons are given in ikegami's answer, as well as the solution, to use lib "...";. But then you need to use the module version installed for v5.26.2, and once you installed it with that perl there'll actually be no need to specify extra library paths.
Finally, if you end up needing to add that path for some reason, leave off the HTML (last) directory, as Shawn's answer indicates. With use HTML::Entities the directory HTML will be searched (for Entities.pm file) and you only need to provide the directory that contains it.

Related

Does Perl look in the current directory (.) for modules?

Does Perl look in . (the current directory) for modules?
I can't directly install a module and I think I could copy it into the local directory. Is this true?
perl -V will print out various properties about your Perl installation, including the default #INC. You should notice a . in there: yes, the current working directory is searched for modules by default.
(If not, you can use environment variables PERL5LIB or PERLLIB, or -I on the command line, or add a sitecustomize.pl to perl -V:sitelib.)
In response to Cameron and tchrist's discussion in the comments to ephemient's answer.
You may use this snippet to use modules in the same directory as the script, even if the script is executed while in another directory.
use Cwd 'abs_path';
use File::Basename;
use lib dirname( abs_path $0 );
It should work in all cases and on all OSes. (Source: http://use.perl.org/~Aristotle/journal/33995)
Lately there has been some reason to not rely on . being in #INC more than usual, namely that this default behavior is scheduled to be removed in Perl 5.26. See the development release notes here: https://metacpan.org/pod/release/EXODIST/perl-5.25.7/pod/perldelta.pod#and-INC
It is generally known that this is being done to address vulnerabilities that were noticed in some applications as a result of this behavior. The CVE(s) have not been released publicly (yet).
Perl searches directories in the #INC array when searching for modules.
Please refer to the following Stack Overflow question on how that array is constructed (this would tell you how your current or home directory can be added):
How is Perl's #INC constructed? (aka What are all the ways of affecting where Perl modules are searched for?)
Please refer to the following Stack Overflow question on how Perl finds the actual file for the module:
How does a Perl program know where to find the file containing Perl module it uses?
I think it most likely will by default, as indicated in this post. If your implementation does not do so, the syntax referenced in the initial question on that post will allow you to reference the module you need.
When you unpack the module’s tarball directory, build its Makefile with an optional library argument with the name of whatever personal directory you want the module contents placed in:
$ perl Makefile.PL LIB=~/perllibs
Then make sure you have your ~/perllibs directory included in your $PERL5LIB envariable.

How can I include Perl modules with paths relative to the program?

I have a Perl script which uses installed packages. One is a Perl package another one is Perl XS package.
Now I want to call this script but use not installed packages, but packages with the same name by path.
I used perl -I /home/.../lib script.pl but it doesn't work
How can I do it?
For various ways of affecting where your modules are loaded, please review this SO posting:
How is Perl's #INC constructed? (aka What are all the ways of affecting where Perl modules are searched for?)
You can use the lib pragma to prepend directories to the path perl uses to find modules.
So, if there is a module named Foo installed in the default directories and a different version installed in /home/cowens/perl5 you can say
use lib "/home/cowens/perl5";
use Foo;
and perl will find the version in /home/cowens/perl5.
Can you show us a recursive listing of the directory where you're storing the modules you want to use? An ls -R could help us figure out if you have the right paths.
When you use the -I switch, you have to ensure you get the right path in there. If you use a module:
use Some::Module;
Perl actually looks for:
$lib/Some/Module.pm
The $lib is one of the directories in #INC. Another way to say that though, is that if the particular directory is not in #INC, Perl isn't going to look in it. This means that Perl won't automatically look in subdirectories for you
If your module is not at that location, Perl is not going to rummage around in that $lib to look for it. Your XS module is probably not stored like that. It might have a Perl version and archtype in the path, so you might find it in:
$lib/5.10.1/darwin-2level/Some/Module.pm
You need to add those paths yourself if you are using -I.
However, you can load modules on the command line. It's much easier to use lib, which adds the extra directories for you:
perl -Mlib=/path/to/lib ...

DynaLoader seeing wrong values in #INC

I have multiple versions of Perl installed; each under a different directory. e.g. C:\Perl\5.x.y. I switch between them in a shell by setting PERL5LIB and altering my PATH so that only one version is visible at a time. Normally, this works fine, but when trying to run the version of pp (PAR::Packer) installed under 5.10.1 I have problems loading XS components. parll2nc.exe complains:
This application has failed to start because perl512.dll was not found...
I set PERL_DL_DEBUG and see the following when DynaLoader initializes:
DynaLoader.pm loaded (C:/Perl/5.10.1/site/lib C:/Perl/5.12.1/lib ., \lib)
The stuff before the comma is #INC. The first entry is correct, the second is not. I can't figure out how DynaLoader is getting a 5.12 lib path as running perl directly shows what I would expect:
C:\>perl -e "print join ' ', #INC"
C:/Perl/5.10.1/site/lib C:/Perl/5.10.1/lib .
How is DynaLoader picking up the wrong path and how do I prevent it from doing so?
Similar to the approach I suggested for this question, put a trace on #INC and see when it gets updated.
At the very top of your script, before any other use statements, put:
use Tie::Trace;
BEGIN { Tie::Trace::watch #INC };
Then you will get a warning message when another module edits your #INC array.
I figured it out. The problem is caused by an interaction of several things:
I have *.pl files associated with perl.exe (for the most recent version of Perl installed -- 5.12.1).
I have ".PL" in my PATHEXT environment variable so that I can run Perl scripts without typing the extension. e.g. C:\>foo instead of C:\>foo.pl
My installation of the pp utility does not have a batch file wrapper created with pl2bat. (I'm not sure why.)
The net result is that when I ran pp #myconfig it effectively did this:
C:\Perl\5.12.1\bin\perl.exe C:\Perl\5.10.1\site\bin\pp.pl #myconfig
i.e. it ran the version of pp.pl in my path using the version of perl associated with *.pl files, not the version of perl in my PATH. Thus the mix of libs in #INC between what came from the executable (C:\Perl\5.12.1\lib) and what came from the PERL5LIB environment variable (C:\Perl\5.10.1\site\lib).
The solution is to either run pp as perl pp.pl or (better, because you don't have to remember anything) to create a batch wrapper. Assuming that .BAT is in PATHEXT before .PL, when you type pp Windows will run pp.bat instead of pp.pl, and pp.bat invokes perl (using the version in your path).
sigh

Is there a way to avoid putting the Perl version number into the "use lib" line for Perl modules in non-standard locations?

I am trying to install some Perl modules into a non-standard location, let's call it /non/standard/location. I used
perl Makefile.PL PREFIX=/non/standard/location
make;make install
to install them.
In the script which uses the module, it seems to be necessary to specify a long directory path including the version of Perl, like so:
#!/usr/local/bin/perl
use lib '/non/standard/location/lib/perl5/site_perl/5.8.9/';
use A::B;
Is there any use lib or other statement which I can use which is not so long and verbose, and which does not include the actual version of Perl, in order that I don't have to go back and edit this out of the program if the version of Perl is upgraded?
Probably not addressing all your questions, but do you know local::lib? When it’s available in the system perl, you can just use local::lib. If not:
use lib glob '~/perl5/lib/perl5';
use local::lib;
That’s probably a bit constraining – not sure how it works on Windows –, but it’s good enough for my purposes. Of course, if you can set up the environment before the script runs (.bashrc, SetEnv etc.), you can forget about the use lib glob, as the right path will be already set in PERL5LIB.
Currently I have installed via the following prescription, which seems to fix things.
perl Makefile.PL --no-manpages --skipdeps PREFIX=/non/system/location INSTALLSITELIB=/non/system/location/lib INSTALLSITEBIN=/non/system/location/bin INSTALLMAN1DIR=/non/system/location/man/man1 INSTALLMAN3DIR=/non/system/location/man/man3
I welcome any constructive criticism of this. I want to use --no-manpages but the INSTALLMAN1DIR seems to be necessary anyway.

How can my Perl script find its module in the same directory?

I recently wrote a new Perl script to kill processes based on either process name / user name and extended it using Classes so that I could reuse the process code in other programs. My current layout is -
/home/mutew/src/prod/pskill <-- Perl script
/home/mutew/src/prod/Process.pm <-- Package to handle process descriptions
I added ~/src/prod in my $PATH variable to access the script from anywhere. On running the script from any directory other than its resident directory leads to a "Can't locate Process.pm in #INC" (which is understandable given that other than the shared directories in /usr, #INC includes only the current directory - '.'). One workaround that I have been using is the use lib directive as so -
use lib '/home/mutew/src/prod';
but this is a major portability issue. Any solutions which will also allow me to export the script to other systems without and changes?
EDIT
I chose 'depesz' answer as the correct one because of its simplicity and core module usage.
brian d foy's answer though suggests other methods to accomplish the same (TMTOWTDI), his contribution in perlfaq8 renders this question absolutely redundant.
I am curious why the simplistic solution
use File::Basename;
use lib dirname (__FILE__);
use SomeModuleLocatedInTheSameDirectoryAsThisPerlScriptOrModule;
did not come up. The FindBin module seems to have some issues if the file is not the main executable perl script, but simply a non-executable Perl module. At least that's how I interpret the comment in the documentation. Did not really test it.
To have any other path relative to the location of this Perl file, do something like
use File::Basename;
use lib dirname (__FILE__) . "/MyModules";
The simplest approach I found it to use FindBin module. Like this:
use FindBin;
use lib $FindBin::Bin;
Generally I prefer to have my scripts provided in such a way that programs are in whatever/bin, and libraries are in whatever/lib
In these situations I use a slightly more complicated approach:
use Cwd qw(abs_path);
use FindBin;
use lib abs_path("$FindBin::Bin/../lib");
The abs_path call is to make the #INC contain whatever/lib, and not whatever/bin/../lib - it's just a slight change, but makes reading error messages easier.
From perlfaq8, which answers "How do I add a directory to my include path (#INC) at runtime?". There are several other answers for questions around this issue too.
How do I add a directory to my include path (#INC) at runtime?
Here are the suggested ways of modifying your include path, including environment variables, run-time switches, and in-code statements:
the PERLLIB environment variable
$ export PERLLIB=/path/to/my/dir
$ perl program.pl
the PERL5LIB environment variable
$ export PERL5LIB=/path/to/my/dir
$ perl program.pl
the perl -Idir command line flag
$ perl -I/path/to/my/dir program.pl
the use lib pragma:
use lib "$ENV{HOME}/myown_perllib";
The last is particularly useful because it knows about machine dependent architectures. The lib.pm pragmatic module was first included with the 5.002 release of Perl.
Besides the already stated solutions:
use FindBin / lib
Perl Faq 8 How do I add a directory to my include path (#INC) at runtime?
'The simplest approach' (™) that I use while dev/testing a module prior
to deploying it (in /usr/local/lib/site_perl/ or elsewhere in #INC) is
to modify #INC before loading the module as follows:
#!/usr/bin/perl
use strict;
use warnings;
# Modify #INC prior to module loading.
BEGIN { unshift #INC, '.'; }
use YourModuleInCWD;
(Add current working directory to #INC? - PerlMonks)
You can make perl look in any directory by using the -I flag. Here, -I stands for #INC which is the array of paths in which perl looks for modules. Using -I adds the given path to the #INC array for this execution.
eg:
perl -I lib bin/script.pl
where lib contains the modules I want to use.
I know that this works for perl 5. I am not at sure about other versions.
Take a look at Par::Packer. It creates an executable with all of the script's dependencies included. It makes distribution easy. You also could also provide your users a version of your module that can be installed on their systems. See Module::Starter for an easy way to build all of the files required to make a standard CPAN-style distribution.
The path can be included in perl script in first line, marked with #!
#!/usr/bin/perl -I.
use anymodule;
To convert relative links to absolute and add to #INC, I normally use ex::lib. Of course, this is useful only if you plan to keep the relative locations of the script and the module identical on all machines where you plan to run your script.
Just keep it simple. There is no need to import any libraries; just find out your current working directory:
use lib "$ENV{PWD}/relativ_path_own_perllib";
For similar problems, you can read out the environment variable which gives your information about where you are, your home directory, operating system stuff, and so on, with just one row of programming code in the shell-terminal, like:
perl -e 'map { print; print " : ". $ENV{$_}." \n\r"; } sort keys %ENV '
There is no need to bind some libraries; just use the %ENV-Hash.
FindBin::libs will find all your libs placed at reasonable places relative to the path from where your script is running.