Perl 的@INC 是如何构造的?(又名影响 Perl 模块搜索位置的所有方式是什么?) [英] How is Perl's @INC constructed? (aka What are all the ways of affecting where Perl modules are searched for?)

查看:24
本文介绍了Perl 的@INC 是如何构造的?(又名影响 Perl 模块搜索位置的所有方式是什么?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

解决方案

我们将看看这个数组的内容是如何构造的,并且可以通过操作来影响 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:

<块引用>

配置-Dotherlibdirs=/usr/lib/perl5/site_perl/5.16.3

  1. 环境变量PERL5LIB(或PERLLIB)

    Perl 在 @INC 前面加上 PERL5LIB 中包含的目录列表(以冒号分隔)(如果没有定义,PERLLIB> 被使用)你的 shell 的环境变量.要查看PERL5LIBPERLLIB环境变量生效后@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.

  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 编程)

  3. 通过lib pragma

    Perl 在 @INC 前面加上通过 use lib 传入的目录列表.

    在程序中:

    使用lib("/dir1", "/dir2");

    在命令行上:

    perl -Mlib=/dir1,/dir2

    您也可以@INC 通过 no lib.

  4. 您可以直接操作 @INC 作为常规 Perl 数组.

    注意:由于在编译阶段使用了 @INC,这必须在 BEGIN {} 块内完成,该块位于 use MyModule<之前/code> 语句.

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

    • 通过push @INC, $dir 添加目录到最后.

    • 做任何你可以用 Perl 数组做的事情.

注意:目录按此答案中列出的顺序未移动@INC 上,例如默认@INC在列表的最后,前面是PERL5LIB,前面是-I,前面是use lib和直接 @INC 操作,后两者以它们在 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.

  1. Default @INC

    Perl interpreter is compiled with a specific @INC default value. To find out this value, run env -i perl -V command (env -i ignores the PERL5LIB 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

  1. Environmental variable PERL5LIB (or PERLLIB)

    Perl pre-pends @INC with a list of directories (colon-separated) contained in PERL5LIB (if it is not defined, PERLLIB is used) environment variable of your shell. To see the contents of @INC after PERL5LIB and PERLLIB environment 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
     .
    

  2. -I command-line option

    Perl 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 (or PERLOPT) environment variable (see chapter 19.02 in Programming Perl)

  3. Pass it via the lib pragma

    Perl pre-pends @INC with 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 @INC via no lib.

  4. 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 a BEGIN {} block, which precedes the use 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:

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 of use lib/no lib pragmas, then use direct @INC manipulation inside BEGIN {} 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆