perlperl-module

How is Perl's @INC constructed?


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.


Solution

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

    1. Default @INC

    The Perl interpreter is compiled with a specific default value for @INC. To find this value, run the command env -i perl -V (env -i ignores the PERL5LIB environment variable - see #2) and in the output you will see something like this:

    $ env -i perl -V
    ...
    @INC:
     /usr/lib/perl5/site_perl/5.18.0/x86_64-linux-thread-multi-ld
     /usr/lib/perl5/site_perl/5.18.0
     /usr/lib/perl5/5.18.0/x86_64-linux-thread-multi-ld
     /usr/lib/perl5/5.18.0
     .
    

    Note the . at the end; this is the current directory (which is not necessarily the same as the script's directory). It is missing in Perl 5.26+, and when Perl runs with -T (taint checks enabled).

    To change the default path when configuring compilation of the Perl binary, set the configuration option otherlibdirs:

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

    1. Environment variable PERL5LIB (or PERLLIB)

    Perl prepends a list of directories (colon-separated) contained in the PERL5LIB environment variable of your shell to @INC (if PERL5LIB is not defined, PERLLIB is used). To see the contents of @INC after the PERL5LIB and PERLLIB environment variables have taken effect, run perl -V:

    $ perl -V
    ...
    %ENV:
      PERL5LIB="/home/myuser/test"
    @INC:
     /home/myuser/test
     /usr/lib/perl5/site_perl/5.18.0/x86_64-linux-thread-multi-ld
     /usr/lib/perl5/site_perl/5.18.0
     /usr/lib/perl5/5.18.0/x86_64-linux-thread-multi-ld
     /usr/lib/perl5/5.18.0
     .
    
    1. -I command-line option

    Perl prepends a list of directories (colon-separated) passed as the parameter of the -I command-line option to @INC. This can be done in three ways, as usual with Perl options:

    1. Pass it via the lib pragma

    Perl prepends a list of directories passed in to it via use lib to @INC.

    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.

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

    Note: Since @INC is used during the compilation phase, this must be done inside a BEGIN {} block, which precedes the use MyModule statement.

    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 Stack Overflow, so this question is intended as one.

    When to use each approach?

    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.

    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 How do I use beta Perl modules from beta Perl scripts?.