How is Perl's @INC constructed? (aka What are all the ways of affecting where Perl modules are searched for?)
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.
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.
- Default - @INC- Perl interpreter is compiled with a specific - @INCdefault value. To find out this value, run- env -i perl -Vcommand (- env -iignores the- PERL5LIBenvironmental 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
- Environmental variable - PERL5LIB(or- PERLLIB)- Perl pre-pends - @INCwith a list of directories (colon-separated) contained in- PERL5LIB(if it is not defined,- PERLLIBis used) environment variable of your shell. To see the contents of- @INCafter- PERL5LIBand- PERLLIBenvironment 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 .
- -Icommand-line option- Perl pre-pends - @INCwith a list of directories (colon-separated) passed as value of the- -Icommand-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)
 
- Pass it via the - libpragma- Perl pre-pends - @INCwith 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 - @INCvia- no lib.
- You can directly manipulate - @INCas a regular Perl array.- Note: Since - @INCis used during the compilation phase, this must be done inside of a- BEGIN {}block, which precedes the- use MyModulestatement.- 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 - @INCcompiled 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 - @INCin 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 - PERL5LIBmanually, or pass the- -Ioption to perl.
- If the modules need to be used only for specific scripts, by all users using them, use - use lib/- no libpragmas 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 - @INCneed to be manipulated according to some complicated logic, either impossible to too unwieldy to implement by combination of- use lib/- no libpragmas, then use direct- @INCmanipulation inside- BEGIN {}block or inside a special purpose library designated for- @INCmanipulation, 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 - @INCis to be able to add subroutine references or object references (yes, Virginia,- @INCcan contain custom Perl code and not just directory names, as explained in When is a subroutine reference in @INC called?).
In addition to the locations listed above, the OS X version of Perl also has two more ways:
- The /Library/Perl/x.xx/AppendToPath file. Paths listed in this file are appended to @INC at runtime. 
- The /Library/Perl/x.xx/PrependToPath file. Paths listed in this file are prepended to @INC at runtime. 
As it was said already @INC is an array and you're free to add anything you want.
My CGI REST script looks like:
#!/usr/bin/perl
use strict;
use warnings;
BEGIN {
    push @INC, 'fully_qualified_path_to_module_wiht_our_REST.pm';
}
use Modules::Rest;
gone(@_);
Subroutine gone is exported by Rest.pm.
 
         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论