Perl finds modules by looking through the list of directories in @INC
. There are many ways to add paths to that array, and although I’ve used all of them at some point, I’ve never quite thought about what happens when I use all of them together.
Remember that Perl uses the first matching module name it finds then
stops looking. It does not have a designed way to determine a best match and newest match or anything fancy. Whatever it finds first is the winner. This also means that someone could add paths to @INC
and force your program to run their version of a module, even maliciously. This is something I write about in the “Secure Programming Techniques” chapter of Mastering Perl.
So who gets there first? Start with the default @INC
. Running perl -V
(capital V) shows a bunch of information and the list of the search paths at the end. These paths are set when you (or whoever) compiled that particular perl
binary:
$ perl -V Summary of my perl5 (revision 5 version 30 subversion 1) configuration: ... @INC: /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.1
Here’s a small program to show the paths:
#!perl use v5.10; say "The search paths are:\n\t", join "\n\t", @INC;
You see the same paths:
$ perl order.pl The search paths are: /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.1
Inside a program, you can add to @INC
just as you can with any array. Typically you do this as soon as you can during the compile-phase because use
statements do their work at compile time:
BEGIN { unshift @INC, '/some/path'; }
The lib does this for you, so use that:
#!perl use v5.10; use lib qw(/from/use/lib); say "The search paths are:\n\t", join "\n\t", @INC;
Run the program again and you see that the new path shows up at the front:
$ perl order.pl The search paths are: /from/use/lib /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.1
But there are other ways. The -I
switch adds a path too:
$ perl -I/from/dash-i-outside order.pl The search paths are: /from/use/lib /from/dash-i-outside /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.
But you can put that on the shebang line too:
#!perl -I/from/dash-i-inside use v5.10; use lib qw(/from/use/lib); say "The search paths are:\n\t", join "\n\t", @INC;
The inside -I
from the shebang line shows up earlier:
$ perl -I/from/dash-i-outside order.pl The search paths are: /from/use/lib /from/dash-i-inside /from/dash-i-outside /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.1
Try it with more than one -I
. The first -I
from the command line shows up earlier in @INC
:
$ perl -I/from/dash-i-outside -I/also/from/dash-i-outside order.pl The search paths are: /from/use/lib /from/dash-i-inside /from/dash-i-outside /also/from/dash-i-outside /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.1
The PERL5OPT
allows you to set default options, so put a -I
in there. That one shows up earlier than the path you explicitly set:
$ export PERL5OPT=-I/from/PERL5OPT $ perl -I/from/dash-i-outside order.pl The search paths are: /from/use/lib /from/dash-i-inside /from/PERL5OPT /from/dash-i-outside /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.1
You can set PERL5LIB
with a path, and that shows up right before the default paths:
$ export PERL5LIB=/from/PERL5LIB $ perl -I/from/dash-i-outside order.pl The search paths are: /from/use/lib /from/dash-i-inside /from/PERL5OPT /from/dash-i-outside /from/PERL5LIB /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.1
Remember that taint mode ignores the environment, though. The values from PERL5OPT
and PERL5LIB
disappear:
$ perl -I/from/dash-i-outside -I/also/from/dash-i-outside -T order.pl The search paths are: /from/use/lib /from/dash-i-inside /from/dash-i-outside /also/from/dash-i-outside /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/site_perl/5.30.1 /usr/local/perls/perl-5.30.1/lib/5.30.1/darwin-2level /usr/local/perls/perl-5.30.1/lib/5.30.1