Perl 的@INC 是如何构造的?又名影响 Perl 模块搜索位置的所有方法是什么?

问题描述

我们将看看这个数组的内容是如何构造的,并且可以被操纵来影响 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会在您的 shell 环境变量中包含(如果未定义,则使用)环境变量中@INC包含的目录列表(以冒号分隔) 。要查看after和环境变量的内容是否已生效,请运行.PERL5LIB``PERLLIB``@INC``PERL5LIB``PERLLIB``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
 .
  1. -I命令行选项

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

* 在命令行上传递它:

            perl -I /my/moduledir your_script.pl


* 通过 Perl 脚本的第一行 (shebang) 传递它:

            #!/usr/local/bin/perl -w -I /my/moduledir


* 将它作为`PERL5OPT`(或`PERLOPT`)环境变量的一部分传递(参见[Programming Perl](http://oreilly.com/catalog/9780596004927)中的第 19.02 章)
  1. 通过libpragma传递它

Perl 在前面@INC加上一个通过use lib.

一个程序中:

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

在命令行上:

    perl -Mlib=/dir1,/dir2

您还可以从via中删除目录@INC``no lib

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

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

* 通过 . 将目录添加到开头`unshift @INC, $dir`。

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

* 做任何你可以用 Perl 数组做的事情。

注意:目录未按此答案中列出的顺序移动到,例如,认值 列表中的最后一个,前面是,前面是,前面是直接操作,后两者按照它们在 Perl 代码中的顺序混合。@INC``@INC``PERL5LIB``-I``use lib``@INC

似乎没有全面的@INC常见问题解答类型的帖子,所以这个问题旨在作为一个问题。

何时使用每种方法

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

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

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

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

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

  • 如果@INC需要根据一些复杂的逻辑对目录进行操作,或者通过use lib/ no libpragma 的组合无法实现太笨重,则在块内或指定用于操作的专用库内使用直接@INC操作,必须由您的脚本使用(s) 在使用任何其他模块之前。BEGIN {}``@INC

这方面的一个示例是在 prod/uat/dev 目录中的库之间自动切换,如果 dev 和/或 UAT 中缺少瀑布库,则在 prod 中拾取瀑布库(最后一个条件使标准的“使用 lib + FindBin”解决方案相当复杂。

解决方法

影响 Perl 模块搜索位置的所有方式有哪些?或者, Perl 的 @INC 是如何构造的

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

似乎没有全面的“@INC”常见问题解答类型的帖子,因此这个问题旨在作为一个问题。