Perl的@INC如何构造?(又有什么方法可以影响搜索Perl模块的位置?)


199

有什么方法可以影响在哪里搜索Perl模块?或者,如何构造Perl的@INC

众所周知,Perl使用@INC包含目录名称的数组来确定在何处搜索Perl模块文件

在StackOverflow上似乎没有完整的“ @INC”常见问题解答类型的文章,因此此问题仅供参考。


7
是的,但是在search.cpan.org/perldoc / ...上有一个非常不错的选择?
暴民

3
@mobrule:我认为这没有那么全面-它只是在告诉@INC运行时如何添加,而不是完整的构造。
卡斯卡贝尔

2
@mobrule-@Jefromi猜对了-到目前为止,我发现的ANY和所有引用的主要问题是缺少有关perl二进制文件的已编译默认@INC的全面信息
DVK 2010年

3
有些人可以给我发送补丁来使答案更全面。这很容易,因为perlfaq位于Github中。:)
brian d foy 2010年

1
好吧,“有关perl二进制文件的默认内置@INC的全面信息”是它是由它编译的人。如果您询问进入那里的各种途径,那么我认为您的问题与您回答的问题不同。
brian d foy 2010年

Answers:


254

我们将研究如何构造此数组的内容,以及如何操纵该数组的内容以影响Perl解释器在哪里找到模块文件。

  1. 默认 @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

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

  1. 环境变量PERL5LIB(或PERLLIB

    Perl @INC附带了外壳程序环境变量PERL5LIB(如果未定义,PERLLIB则使用)中包含的目录列表(以冒号分隔)。要查看@INCafter PERL5LIBPERLLIB环境变量生效的内容,请运行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 命令行选项

    Perl预先@INC添加了作为-I命令行选项值传递的目录列表(以冒号分隔)。与Perl选项一样,这可以通过三种方式完成:

    • 通过命令行传递它:

      perl -I /my/moduledir your_script.pl
    • 通过Perl脚本的第一行(shebang)传递它:

      #!/usr/local/bin/perl -w -I /my/moduledir
    • 将其作为PERL5OPT(或PERLOPT)环境变量的一部分传递(请参阅《Perl编程》中的第19.02章)。

  3. 通过编译指示传递lib

    Perl预先@INC添加了通过传递给它的目录列表use lib

    在程序中:

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

    在命令行上:

    perl -Mlib=/dir1,/dir2

    您也可以从除去目录@INC通过no lib

  4. 您可以直接将其@INC作为常规Perl数组进行操作。

    注意:由于@INC是在编译阶段使用的,因此必须BEGIN {}use MyModule语句之前的块内完成。

    • 通过将目录添加到开头unshift @INC, $dir

    • 通过将目录添加到末尾push @INC, $dir

    • 做您可以使用Perl数组做的其他事情。

注:该目录未移动@INC在这个回答中列出的顺序,比如默认@INC是在列表的最后,通过前面PERL5LIB,前面加-I,前面有use lib直接@INC操纵,后两者混在哪个顺序排列在Perl代码。

参考文献:

似乎@INC在Stack Overflow上没有完整的FAQ类型帖子,因此此问题仅供参考。

什么时候使用每种方法?

  • 如果目录中的模块需要由站点上的许多/所有脚本使用,尤其是由多个用户运行,则该目录应包含在默认@INC编译为Perl二进制文件中的目录中。

  • 如果目录中的模块将由特定用户专用于该用户运行的所有脚本(或者如果重新编译Perl不能@INC在以前的用例中更改默认值),则PERL5LIB通常在用户登录期间设置用户的。

    注意:请注意通常的Unix环境变量陷阱-例如,在某些情况下,以特定用户的身份运行脚本并不能保证在该用户的环境设置下运行脚本(例如通过)su

  • 如果目录中的模块仅在特定情况下需要使用(例如,在开发/调试模式下执行脚本时),则可以PERL5LIB手动设置或将-I选项传递给perl。

  • 如果模块仅需要用于特定脚本,则所有使用它们的用户都应在程序本身中使用use lib/ no libpragmas。当需要在运行时动态确定要搜索的目录时,也应使用它(例如,从脚本的命令行参数或脚本的路径来确定)(有关非常好的用例,请参见FindBin模块)。

  • 如果@INC需要根据某些复杂的逻辑来操作目录,或者无法通过use lib/ no libpragma 的组合来实现,那么请@INCBEGIN {}块内部或指定用于@INC操作的专用库中使用直接操作,这些脚本必须由脚本使用(s),然后再使用其他任何模块。

    一个示例是自动在prod / uat / dev目录中的库之间切换,如果在dev和/或UAT中缺少瀑布库拾取,则在prod中使用瀑布库拾取(最后一个条件使标准的“ use lib + FindBin”解决方案相当复杂。如何使用Beta Perl脚本中的beta Perl模块?中对此场景的详细说明。

  • 直接操作的另一个用例@INC是能够添加子例程引用或对象引用(是的,弗吉尼亚州,@INC可以包含自定义Perl代码,而不仅仅是目录名称,如@INC中的子例程引用何时被调用?中所述)。


1
不要忘记PERLOPT,您可以在其中设置-I。另外,诸如base.pm和local :: lib之类的内容将隐式使用您列出的内容。
brian d foy 2010年

1
@brian-use :: base使用它是由于IIRC下面的“ require”。我对local :: lib不熟悉,需要阅读更多内容以了解它的含义
DVK 2010年

3
另外,要使这个问题成为一个很好的答案,您需要告诉人们何时应该使用每个答案。仅给他们10种选择方式的帮助并不大。:)
brian d foy 2010年

PS任何人,请随时编辑答案以通过-I / use lib包含第二个特定于体系结构的目录。我计划自己稍后再做,但现在需要离线。
DVK 2010年

@brian-添加了PERLOPT。我想提到base.pm和其他“何时使用@INC”项目更适合我在此处发布和链接的@ INC / finding模块文件,因此我将其放在此处。
DVK 2010年

18

除了上面列出的位置之外,Perl的OS X版本还具有另外两种方式:

  1. /Library/Perl/x.xx/AppendToPath文件。该文件中列出的路径在运行时会附加到@INC。

  2. /Library/Perl/x.xx/PrependToPath文件。在运行时,此文件中列出的路径在@INC之前。


6

就像已经说过的那样,@ INC是一个数组,您可以随意添加任何所需的内容。

我的CGI REST脚本如下所示:

#!/usr/bin/perl
use strict;
use warnings;
BEGIN {
    push @INC, 'fully_qualified_path_to_module_wiht_our_REST.pm';
}
use Modules::Rest;
gone(@_);

Rest.pm导出了子例程。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.