Perl 的@INC 是如何构造的?(又名影响 Perl 模块搜索位置的所有方式是什么?) [英] How is Perl's @INC constructed? (aka What are all the ways of affecting where Perl modules are searched for?)
问题描述
影响 Perl 模块搜索位置的所有方式是什么?或者,Perl 的@INC 是如何构建的?
众所周知,Perl 使用包含目录名称的 @INC
数组来确定在哪里搜索 Perl 模块文件.
StackOverflow 上似乎没有一个全面的@INC"FAQ 类型的帖子,所以这个问题是一个.
我们将看看这个数组的内容是如何构造的,并且可以通过操作来影响 Perl 解释器将在哪里找到模块文件.
默认
@INC
Perl 解释器是 使用特定的
<块引用>@INC
默认值编译.要找出此值,请运行env -i perl -V
命令(env -i
忽略PERL5LIB
环境变量 - 参见 #2)和在输出中,您将看到如下内容:$ 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.
注意.
在最后;这是当前目录(不一定与脚本的目录相同).它在 Perl 5.26+ 中缺失,并且当 Perl 使用 -T代码>(启用污点检查)
.
要在配置Perl二进制编译时更改默认路径,设置配置选项otherlibdirs
:
配置-Dotherlibdirs=/usr/lib/perl5/site_perl/5.16.3
环境变量
PERL5LIB
(或PERLLIB
)Perl 在
<块引用>@INC
前面加上PERL5LIB
中包含的目录列表(以冒号分隔)(如果没有定义,PERLLIB
> 被使用)你的 shell 的环境变量.要查看PERL5LIB
和PERLLIB
环境变量生效后@INC
的内容,运行perl -V
.$ perl -V...%环境:PERL5LIB="/home/myuser/test"@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.
-I
命令行选项Perl 在
@INC
前面加上一个目录列表(以冒号分隔),作为-I
命令行选项的值传递.这可以通过三种方式完成,像往常一样使用 Perl 选项:在命令行上传递:
perl -I/my/moduledir your_script.pl
通过 Perl 脚本的第一行 (shebang) 传递它:
#!/usr/local/bin/perl -w -I/my/moduledir
将其作为
PERL5OPT
(或PERLOPT
)环境变量的一部分传递(请参阅 Perl 编程)
通过
lib
pragma>Perl 在
@INC
前面加上通过use lib
传入的目录列表.在程序中:
使用lib("/dir1", "/dir2");
在命令行上:
perl -Mlib=/dir1,/dir2
您也可以从
@INC
通过no lib
.您可以直接操作
@INC
作为常规 Perl 数组.注意:由于在编译阶段使用了
@INC
,这必须在BEGIN {}
块内完成,该块位于use MyModule<之前/code> 语句.
通过
unshift @INC, $dir
将目录添加到开头.通过
push @INC, $dir
添加目录到最后.做任何你可以用 Perl 数组做的事情.
注意:目录按此答案中列出的顺序未移动到 @INC
上,例如默认@INC
在列表的最后,前面是PERL5LIB
,前面是-I
,前面是use lib
和直接 @INC
操作,后两者以它们在 Perl 代码中的顺序混合.
参考:
- perldoc perlmod
- perldoc 库
- Perl 模块机制 - 包含实用 HOW-TO 的出色指南
- 我该怎么做使用"不在
@INC
中的目录中的 Perl 模块? - Perl 编程 - 第 31 章第 13 部分,第 7.2.41 节
- Perl 程序如何知道在哪里可以找到包含它使用的 Perl 模块的文件?
在 Stack Overflow 上似乎没有一个全面的 @INC
FAQ 类型的帖子,所以这个问题是一个.
何时使用每种方法?
如果一个目录中的模块需要被您站点上的许多/所有脚本使用,尤其是由多个用户运行,则该目录应包含在编译成的默认
@INC
中Perl 二进制文件.如果目录中的模块将由特定用户专门用于该用户运行的所有脚本(或者如果重新编译 Perl 不是更改前面的默认
@INC
的选项)用例),设置用户的PERL5LIB
,通常在用户登录时.注意:请注意常见的 Unix 环境变量陷阱 - 例如在某些情况下,以特定用户身份运行脚本并不能保证在该用户的环境设置下运行它们,例如通过
su
.如果目录中的模块只需要在特定情况下使用(例如在开发/调试模式下执行脚本时,您可以手动设置
PERL5LIB
,或将-I
选项传递给 perl.如果模块只需要用于特定的脚本,所有用户使用它们,使用
use lib
/no lib
程序本身的编译指示.当需要在运行时动态确定要搜索的目录时,也应该使用它 - 例如从脚本的命令行参数或脚本路径(请参阅 FindBin 模块以获得非常好的用例).如果
@INC
中的目录需要按照一些复杂的逻辑进行操作,要么结合use lib
/no lib
编译指示,然后在BEGIN {}
块内或在为@INC指定的专用库内使用直接
@INC
操作code> 操作,在使用任何其他模块之前必须由您的脚本使用.一个例子是在 prod/uat/dev 目录中的库之间自动切换,如果开发和/或 UAT 中缺少瀑布库,则在 prod 中提取瀑布库(最后一个条件使标准的使用 lib + FindBin"解决方案相当复杂的.这种情况的详细说明在 如何使用 beta Perl 脚本中的 beta Perl 模块?.
直接操作
@INC
的另一个用例是能够添加子程序引用或对象引用(是的,弗吉尼亚,@INC
可以包含自定义Perl 代码而不仅仅是目录名称,如何时调用@INC 中的子程序引用?).
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
@INC
default value. To find out this value, runenv -i perl -V
command (env -i
ignores thePERL5LIB
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
Environmental variable
PERL5LIB
(orPERLLIB
)Perl pre-pends
@INC
with a list of directories (colon-separated) contained inPERL5LIB
(if it is not defined,PERLLIB
is used) environment variable of your shell. To see the contents of@INC
afterPERL5LIB
andPERLLIB
environment variables have taken effect, runperl -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 .
-I
command-line optionPerl 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
(orPERLOPT
) environment variable (see chapter 19.02 in Programming Perl)
Pass it via the
lib
pragmaPerl pre-pends
@INC
with a list of directories passed in to it viause lib
.In a program:
use lib ("/dir1", "/dir2");
On the command line:
perl -Mlib=/dir1,/dir2
You can also remove the directories from
@INC
viano lib
.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 aBEGIN {}
block, which precedes theuse 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 ofuse lib
/no lib
pragmas, then use direct@INC
manipulation insideBEGIN {}
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?).
这篇关于Perl 的@INC 是如何构造的?(又名影响 Perl 模块搜索位置的所有方式是什么?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!