How to change @INC to find Perl modules in non-standard locations
When using modules that are not installed in the standard directories of Perl, we need to change @INC so perl will be able to find them. There are several ways to do that solving different use-cases.
We are going to see a use-case and a solution, but if you have arrived to this page, I wonder, do you really have a special case, or do you just need to install the Perl module?
Loading your private Perl module
You have a script and have just started to move some parts of it, out to a new module called My::Module. You saved the module to /home/foobar/code/My/Module.pm.
Your perl script now starts like this:
use strict; use warnings; use My::Module;
When you run the script you get a friendly error message like this:
Can't locate My/Module.pm in @INC (@INC contains: /home/foobar/perl5/lib/perl5/x86_64-linux-gnu-thread-multi /home/foobar/perl5/lib/perl5 /etc/perl /usr/local/lib/perl/5.12.4 /usr/local/share/perl/5.12.4 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.12 /usr/share/perl/5.12 /usr/local/lib/site_perl .). BEGIN failed--compilation aborted.
Perl cannot find your module.
Upgrading a Perl module
On a system you are thinking to upgrade a module that came from CPAN. You don't want to install it in the standard location yet. First you'd like to put it in some private directory, try it, and install to the system only once you are sure it works well.
In this case too you "install" the module in a private directory, e.g. in /home/foobar/code and somehow you'd like to convince perl to find that version of the module, and not the one that was installed in the system.
The use statement
When perl encounters use My::Module; it goes over the elements of the built-in @INC array that contains directory names. In each directory it checks if there is a subdirectory called "My" and if in that subdirectory there is a file called "Module.pm".
The first such file it encounters will be loaded into memory.
If it does not find the file you get the above error messages.
@INC is defined when perl is compiled and it is embedded in the binary code. You cannot change that, unless you recompile perl. Not something we would do every day.
Luckily the @INC array can be changed in several ways when we execute a script. We'll see these solutions and discuss when each one of them is appropriate to use.
PERLLIB and PERL5LIB
You can define the PERL5LIB environment variable (though PERLLIB works the same way, I'd recommend using PERL5LIB over PERLLIB as that makes it clear it is related to Perl 5) the same way you can define the PATH environment variable. Every directory listed in this variable will be added to the beginning of @INC.
On Linux/Unix when using Bash, you would write
export PERL5LIB=/home/foobar/code
You can add this to the ~/.bashrc to make it always available when you log-in.
On Windows you can set the same in the cmd command window by typing
set PERL5LIB=c:\path\to\dir
For a more long term solution follow these steps:
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.
In taint mode, that will be explained in a separate post, the PERLLIB and PERL5LIB environment variables are ignored.
use lib
Adding a use lib statement to the script will add the directory to @INC for that specific script. Regardless who and in what environment runs it.
You just have to make sure to have the use lib statement before trying to load the module:
use lib '/home/foobar/code'; use My::Module;
One note here. I saw several companies where use lib statements were added to the modules so they will be able to load their dependencies. I don't think this is good. I think the right place to change @INC is the main script or even better, outside the script such as in the two other solutions.
-I on the command line
(That's a capital i)
The last solution is the most temporary solution. Add a -I /home/foobar/code flag to perl when running the script.
perl -I /home/foobar/code script.pl
This will add /home/foobar/code to the beginning of @INC for this specific execution of the script.
So which one to use?
If you would like to just test a newer version of a module, I'd recommend the command line flag: perl -I /path/to/lib.
If you are installing lots of modules in a private directory then I'd probably use PERL5LIB though we'll also see local::lib that does this for you.
use lib is used in two cases:
- When you have a fixed, but not standard company-wide environment in which you put modules in a common standard location.
- When you are developing an application and you'd like to make sure the script always picks up the modules relative to their own location. We'll discuss this in another post.
Comments
What if the perl module is in the same path as the script? I tried running the script without any changes to @INC and I'm still getting the same error. Why is that? --- Unlike in Python, Perl does not automatically include the path of the script in @INC. You need to do that yourself. --- I MIGHT have a work around; a variable called $^0. Detects if Windows or Linux.
$OS=$^0; use lib "path_to_perl5" if $OS == 'MSWin32';
In theory, it will load the new path if on Windows, but when online on a Unix server, the IF will be false, and so library will not load. --- I think based on this link you might not get the result that you expect, https://perlmaven.com/use-require-import this "if" is not work as you expected, during "use" statement execute on compile time not run time.
--- So which language do you already know. Perl or Python? --- Boths of them. But I dont know @INC from perl to python. --- Do you know what @INC is ? ---
This is the first times i work with file on perl and try to research but i dont know what @INC is ---
I am a bit confused now. You said you know perl but this is the first time you work with a file in perl? ---
Yes, I just know basic about array, hash, regex and I just know pert about several week --- OK, so which part do you understand from the Perl code and which part not? What does this code do? (Search this site for answers if something you don't know.)
--- As I know, the Perl code below will find the file in directory where install Perl. Is it right? ---
You can say so. Yes. Now where do you need to search for a file with the python code and how far have you got or what are you still missing? --- I got it, but I still not know the equivalent in Perl and Python (@INC) or library to support for this case in Python --- sys.path --- Thank you so much.
Hi Gabor, Thank you for your article.
I added "use lib" to my script and my problem, which was about @INC, was solved. But I got another the following error: Can't load '/home/MyAccount/perl5/lib/perl5/x86_64-linux/auto/XML/LibXML/LibXML.so' for module XML::LibXML: /home/MyAccount/perl5/lib/perl5/x86_64-linux/auto/XML/LibXML/LibXML.so: undefined symbol: PL_unitcheckav at /usr/lib64/perl5/DynaLoader.pm line 200. at /usr/lib64/perl5/DynaLoader.pm line 156 BEGIN failed--compilation aborted at /home/MyAccount/perl5/lib/perl5/x86_64-linux/XML/LibXML.pm line 156. Compilation failed in require at ./MyScript line 18. BEGIN failed--compilation aborted at ./MyScript line 18.
Where is my problem? What is your idea?
Thank you!
---- That looks like XML::LibXML was not properly installed or that the "use lib" does not include all the necessary directories, or maybe that you have two versions of perl installed and the "use lib" includes the directory of the other perl. --- Thank you so much for your reply.
You think how I can check what the problem is? For example, There is a command I can check that all the necessary directories or libraries are included or not. Also, I installed XML::LibXML locally.
Generally, you would suggest where? I you were me, what would you do?
I am working to install a model on a server and I don't have admin privilege. PERL was installed on the server by admin and I installed XML::LibXML locally. When I installed XML::LibXML locally, PREL5 directory was created in my account
I added custom directory in @INC by appending `export PERL5LIB=some_dir`. I'm able to execute the script using cli `perl -e 'use some_module_in_dir'` but when I m using it in a separate file then it showing me error
Very Helpful. Thanks
Putting use statements in the code works for me but the PERL5LIB command line method does not. I am using Strawberry Perl could that be the reason ? --- No. Does your script really see the changes you made to PERL5LIB ? You can try it with a simple print $ENV{PERL5LIB} in your code (without any use-statements) How did you make the changes to PERL5LIB and how do you run your script?
--- Grateful if you could help. With my old version of Perl I could have require statements that where relative to the scripts folder (windows) when including a module of my own. I understand having updated perl that the @INC var no longer had an auto . included to access current directory and I have had to change any relative paths to absolute ones. However on my machine I have created an extra user and it is within this user that I want to run most of my scripts but I am finding that within this second user not even absolute paths work in the require statement. Any idea how I can get round this. Oh for the days when installing Perl meant everything just worked
---- I appear to have solved this via your other page by using
use FindBin; use lib $FindBin::Bin;
Now all relative pathnames used by Required work OK
Is there a good reason why the developers of Perl inflicted this upon us ?. With earlier versions you just installed Perl and off you went with all your require statements working fine.
---- It also seems to work without the FindBin magic if you are requiring a file other than in the same directory as the script, but in the same direc' it falls over and the FindBin code is needed ??
I am curious I am trying to query the database as sysdba, I am using "use lib" with the specific path to the Oracle.pm but i am still receiving the following error?
Can't locate DBD/Oracle.pm in @INC (@INC contains: /usr/app/oracle/product/agentE5/agent_13.3.0.0.0/perl/lib/site_perl/5.14.4/x86_64-linux-thread-multi/DBD/ /usr/app/oracle/product/agentE5/agent_13.3.0.0.0/perl/lib/site_perl/5.14.4/x86_64-linux-thread-multi/Bundle/ /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at db_upgrade.pl line 16. BEGIN failed--compilation aborted at db_upgrade.pl line 16 (#1)
I have the following in my script:
use lib ("/usr/app/oracle/product/agentE5/agent_13.3.0.0.0/perl/lib/site_perl/5.14.4/x86_64-linux-thread-multi/DBD/", "/usr/app/oracle/product/agentE5/agent_13.3.0.0.0/perl/lib/site_perl/5.14.4/x86_64-linux-thread-multi/Bundle/"); use DBD::Oracle qw(:ora_session_modes); # imports SYSDBA or SYSOPER
When checking PERL5LIB in enviroment variables, it lists that the path is "C:/users/My_name/perl5/lib/perl5" which is indeed where Strawberry CPAN is installing the modules. But ... when I run perl, it cannot find the module as @INC only contains "strawberry/perl/site", "strawberry/perl/vendor/lib" and "strawberry/perl/lib" How do I add the perl5 path to @INC without resorting to adding a line to every script? (This is Win7)
I don't really want to change the PERL5LIB path as I understand that DMAKE and similar rely on a default path
When I installed miRDeep2, the following error occurred in make_html.pl: Cannot find PDF/API2.pm in @INC (@INC contains: /usr/local/lib64/perl5/usr/local/share/perl5/usr/lib64/perl5/vendor_perl/usr/share/perl5/vendor_perl/ usr / lib64 / perl5 / usr / share / perl5.) Located at line 9 of /home/students/anaconda3/bin/make_html.pl. BEGIN failed-compilation was aborted in line 9 of /home/students/anaconda3/bin/make_html.pl. I added the path to “./bashrc”, and the source “./bashrc” ,script make_html.pl still showed the same error. I tried to modify make_html.pl and add the use lib ‘/home/foobar/code' Use My::Module; but it cannot be modified. I don’t quite understand how to use lib and how to modify @INC. Can you help me? Many thanks!
i installed activeperl when running cmd cli everthing works OK when running perl cgi on iis I get error 502.2 - bad gateway cant ;locate CGI.pm i definedly installed GCI.pm using state command
show installed packages : =========================== [yehudaeshelgmail/Perl-5.32] C:\Users\User\yehudaeshelgmail\Perl-5.32>state packages ╔══════════════════╗ ║ Listing Packages ║ ╚══════════════════╝ Name Version ──────────────────────────────── CGI Auto DateTime Auto Win32 Auto Win32-NetResource Auto strict Auto
its crazy any ideas ?? thanks in advance
Why do I get the error "Can't locate Win32/ http://LongPath.pm in @INC" after following the ppm profile save/restore instructions in "How to Migrate Perl Server-to-Server" to migrate Perl 5.20 to a new system? Doesn't ppm set @INC when it restores the configuration?
Published on 2012-07-24