Perl的@INC是如何构建的?(又名影响Perl模块搜索的所有方法是什么?)

DVK*_*DVK 198 perl perl-module

影响Perl模块搜索位置的所有方法是什么?或者,Perl的@INC是如何构建的

我们知道,Perl使用@INC包含目录名的数组来确定搜索Perl模块文件的位置.

在StackOverflow上似乎没有全面的"@INC"FAQ类型的帖子,所以这个问题是一个问题.

DVK*_*DVK 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
     .
    
    Run Code Online (Sandbox Code Playgroud)

注意.最后; 这是当前目录(不一定与脚本的目录相同).它在Perl 5.26+中缺失,当Perl运行时-T(启用了污点检查).

要在配置Perl二进制编译时更改默认路径,请设置配置选项otherlibdirs:

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

  1. 环境变量PERL5LIB(或PERLLIB)

    Perl预先@INC添加了一个目录列表(冒号分隔),其中包含PERL5LIB(如果未定义,PERLLIB使用)shell的环境变量.要查看@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
     .
    
    Run Code Online (Sandbox Code Playgroud)
  2. -I 命令行选项

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

  3. 通过pragma传递它lib

    Perl预先挂起@INC了一个通过它传递给它的目录列表use lib.

    在一个程序中:

    use lib ("/dir1", "/dir2");
    
    Run Code Online (Sandbox Code Playgroud)

    在命令行上:

    perl -Mlib=/dir1,/dir2
    
    Run Code Online (Sandbox Code Playgroud)

    您也可以@INCvia中删除目录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 libpragma.当需要在运行时期间动态确定要搜索的目录时,也应该使用它 - 例如,从脚本的命令行参数或脚本的路径(请参阅FindBin模块以获得非常好的用例).

  • 如果@INC需要根据某些复杂的逻辑操作目录,或者通过组合use lib/ no libpragma 实现不太笨重,那么@INCBEGIN {}块内或指定用于@INC操作的专用库内部使用直接操作,这必须由脚本使用(s)在使用任何其他模块之前.

    这方面的一个例子是在prod/uat/dev目录中的库之间自动切换,如果dev和/或UAT中缺少了瀑布库,那么它就会被丢弃(最后一个条件使标准的"使用lib + FindBin"解决方案相当复杂.此方案的详细说明是如何使用从公测Perl脚本测试Perl模块?.

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

  • 另外,为了使这个成为一个非常好的答案,你需要告诉人们何时应该使用每一个.给他们提供10种可能的选择并不是很有帮助.:) (3认同)

dga*_*ood 17

除了上面列出的位置,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(@_);
Run Code Online (Sandbox Code Playgroud)

子程序消失由Rest.pm导出.