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

前端 未结 3 1267
说谎
说谎 2020-11-22 13:06

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 conta

3条回答
  •  囚心锁ツ
    2020-11-22 13:11

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

    1. Default @INC

      Perl interpreter is compiled with a specific @INC default value. To find out this value, run env -i perl -V command (env -i ignores the PERL5LIB environmental 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 . 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 Perl binary compilation, set the configuration option otherlibdirs:

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

    1. 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) environment variable of your shell. To see the contents of @INC after 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
       .
      
    2. -I command-line option

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

      • Pass it on command line:

        perl -I /my/moduledir your_script.pl
        
      • Pass it via the first line (shebang) of your Perl script:

        #!/usr/local/bin/perl -w -I /my/moduledir
        
      • Pass it as part of PERL5OPT (or PERLOPT) environment variable (see chapter 19.02 in Programming Perl)

    3. Pass it via the lib pragma

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

      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.

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

      Note: Since @INC is used during the 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:

    • perldoc perlmod
    • perldoc lib
    • Perl Module Mechanics - a great guide containing practical HOW-TOs
    • How do I 'use' a Perl module in a directory not in @INC?
    • Programming Perl - chapter 31 part 13, ch 7.2.41
    • How does a Perl program know where to find the file containing Perl module it uses?

    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?

    • 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 the default @INC compiled into the 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 pass the -I option to perl.

    • 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 the script's command line parameters or script's path (see the 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 How do I use beta Perl modules from beta Perl scripts?.

    • An additional use case for directly manipulating @INC is to be able to add subroutine references or object references (yes, Virginia, @INC can contain custom Perl code and not just directory names, as explained in When is a subroutine reference in @INC called?).

提交回复
热议问题