views:

608

answers:

1

What are all the ways of affecting where Perl modules are searched for? or, How is Perl's @INC constructed?

As we know, Perl uses @INC array containing directory names to determine where to search for Perl module files.

There does not seem to be a comprehensive "@INC" FAQ-type post on StackOverflow, so this question is intended as one.

+12  A: 

We will look at how the contents of this array are constructed and can be manipulated to affect where Perl interpreter will find the module files.

  1. Default @INC

    Perl interpreter is compiled with a specific default value of @INC that it was compiled with. To find out this value, run perl -V command and in the out you will see something like this:

    $ perl -V
    ...
    @INC: 
    /usr/local/lib/perl5/5.8.6/i686-linux
    /usr/local/lib/perl5/5.8.6
    /usr/local/lib/perl5/site_perl/5.8.6/i686-linux
    /usr/local/lib/perl5/site_perl/5.8.6
    /usr/local/lib/perl5/site_perl/5.8.5/i686-linux
    /usr/local/lib/perl5/site_perl/5.8.5
    /usr/local/lib/perl5/site_perl
    

    To change the default path when configuring Perl binary compilation, use otherlibdirs variable:

    Configure -Dotherlibdirs=/usr/lib/perl5/site_perl/5.8.1

  2. Environmental variable PERL5LIB (or PERLLIB)

    Perl pre-pends @INC with a list of directories (colon-separated) contained in PERL5LIB (if it is not defined, PERLLIB is used) environmental variable of your shell.

  3. -I command line parameter

    Perl pre-pends @INC with a list of directories (colon-separated) passed in to it as a value of -I command line parameter. This can be done in one of two ways, as usual with Perl parameters:

    • Pass it on command line: perl -I /my/moduledir your_script.pl

    • Pass it via the first (shebang) line of your Perl script:

    #!/usr/local/bin/perl -w -I /my/moduledir

    • Pass it as part of PERL5OPT (or PERLOPT) environmantal variable (see chapter 19.02 in Programming Perl)
  4. Pass it via the use lib pragma

    Perl pre-pends @INC with a list of directories passed in to it via use lib pragma.

    In a program:

    use lib ("/dir1", "/dir2")

    On the command line:

    perl -Mlib=/dir1,/dir2

    You can also remove the directories from @INC via no lib

  5. You can directly manipulate @INC as a regular Perl array.

    NOTE: Since @INC us used during compilation phase, this must be done inside of a BEGIN {} block, which precedes the use MyModule statement;

    • Add directories to the beginning via unshift @INC, $dir

    • Add directories to the end via push @INC, $dir

    • Do anything else you can do with a Perl array.

NOTE The directories are unshifted onto @INC in the order listed in this answer, e.g. default @INC is last in the list, preceded by PERL5LIB, preceded by -I, preceded by "use lib" and direct @INC manipulation, the latter two mixed in whichever order they are in Perl code.

References:

There does not seem to be a comprehensive "@INC" FAQ-type post on StackOverflow, so this question is intended as one.

When to use each approach?

  • If the modules in a directory need to be used by many/all scripts on your site, especially run by multiple users, that directory should be included in default @INC compiled into Perl binary

  • If the modules in the directory will be used exclusively by a specific user for all the scripts that user runs (or if recompiling Perl is not an option to change default @INC in previous use case), set the users' PERL5LIB, usually during user login.

    NOTE: Please be aware of the usual Unix environment variable pitfalls - e.g. in certain cases running the scripts as a particular user does not guarantee running them with that user's environment set up, e.g. via su.

  • If the modules in the directory need to be used only in specific circumstances (e.g. when the script(s) is executed in development/debug mode, you can either set PERL5LIB manually, or use "-I" perl parameter.

  • If the modules need to be used only for specific scripts, by ALL users using them, use use lib/no lib pragmas in the program itself. It also should be used when the directory to be searched needs to be dynamically determined during runtime - e.g. from script's command line parameters or script's path (see FindBin module for very nice use case)

  • If the directories in @INC need to be manipulated according to some complicated logic, either impossible to too unwieldy to implement by combination of "use lib/no lib" pragmas, then use direct @INC manipulation inside BEGIN {} block or inside a special purpose library designated for @INC manipulation, which must be used by your script(s) before any other modules are used.

    An example of this is automatically switching between libraries in prod/uat/dev directories, with waterfall library pickup in prod if it's missing from dev and/or UAT (the last condition makes the standard "use lib + FindBin" solution fairly complicated. A detailed illustration of this scenario is in this SO post.

  • An additional use case for directly manipulating @INC is to be able to add subroutine references or object references (yes, Virgina, @INC can contain custom Perl code and not just directory names, as explained here)

DVK
don't forget PERLOPT, where you can set -I. Also, things such as base.pm and local::lib use the things you've listed implicitly.
brian d foy
@brian - use::base uses it due to "require" underneath, IIRC. I'm not familiar with local::lib, will need to read more to understand what it is about
DVK
Also, to make this a really good answer, you need to tell people when they should use each one. Just giving them 10 options on how they could isn't very helpful. :)
brian d foy
A little closer to 10K now ;-)
Sinan Ünür
@Sinan - gotta fight the oppression by The Man :)
DVK
@brian - if you don't feel like this will bloat the answer way out of any readable size, I can try
DVK
P.S. Anyone, please feel free to edit the answer to include a second architecture-specific directory inclusion via -I/use lib. I planned to do so myself at a later time but need to get offline for now.
DVK
@brian - added PERLOPT. I feel like mentioning base.pm and other "when does @INC get used" items is more suited to the @INC/finding module files FAQ I posted and linked from here, so I put it there.
DVK
@brian - added the basic :when to use" section. Feel free to comment/edit as I feel it's not 100% up to snuff
DVK
Your answering is looking pretty good. Just keep doing what you are doing. Writing is editing :)
brian d foy
I also added one more use case, the insertion of subroutine references into @INC
DVK