Perl 程序如何知道在哪里可以找到包含它使用的 Perl 模块的文件?
Posted
技术标签:
【中文标题】Perl 程序如何知道在哪里可以找到包含它使用的 Perl 模块的文件?【英文标题】:How does a Perl program know where to find the file containing Perl module it uses? 【发布时间】:2011-02-01 08:41:00 【问题描述】:如果我的 Perl 程序使用 Perl 模块,它将如何确定在哪里可以找到包含模块代码的文件?
例如,如果程序包含:
use MyModule1; # Example 1
use This::Here::MyModule2; # Example 2
它会在哪里看?
【问题讨论】:
我在 SO 上找不到可以链接到的这个问题的全面答案,所以我决定创建一个。如果下面提供的答案需要补充/更正,请采纳:) 【参考方案1】:Perl 解释器(运行您的 perl 程序)将使用一个名为 @INC
的特殊数组来搜索包含该模块的文件。
@INC
数组中的每个值都是一个目录名称(但请参阅下面的注释); Perl 将使用下面指定的规则在循环中搜索这些目录。 (请参考this SO post for details of how the contents of @INC are determined)。
如果在耗尽@INC
后没有找到模块的文件,程序的编译将被错误中止。如果在@INC
中指定的目录之一中找到模块文件,则搜索结束,无需查看@INC
的其余部分。
Perl 在@INC
中列出的每个目录中搜索模块文件的方式如下:
首先,它将模块名称的分层组件(由::
分隔的单词)分成最后一个组件 - 将用于形成文件名 - 和层次结构路径(最后一个@987654331之前的所有组件@)。
如果模块名称只有一个组件(没有::
,例如上面的MyModule1
),层次结构路径为空,文件名是模块的名称。在这个问题的第二个例子中,最后一个组件是MyModule2
,层次结构路径是This::Here
。
预期的文件名将通过在模块名称的最后一个组成部分附加.pm
扩展名来确定。例如。 MyModule1.pm
和 MyModule2.pm
在我们的示例中。
注意:在 Unix 和其他文件/目录命名区分大小写的操作系统上,模块名称显然区分大小写。
模块的目录将由以下因素决定:
从@INC
获取下一个目录 - 以/usr/lib/perl
为例
通过获取模块名称(如果有)的层次结构路径并将“::”替换为/
或操作系统用作目录分隔符的任何字符来形成该目录的子目录。在我们的两个示例中,将在 /usr/lib/perl
(无子目录)中搜索第一个模块,在 /usr/lib/perl/This/Here
中搜索第二个模块。
注意:上面是一个轻微的简化 - @INC
may also contain subroutine references and object references,它按照自定义代码指定的方式加载模块,而不是在 # 中指定的目录中执行查找2 上面的逻辑。该功能似乎很少使用,本文假设整个 @INC
仅包含目录。
我们来看一个具体的例子,假设你的@INC
包含两个子目录:
("/usr/lib/perl", "/opt/custom/lib")
。
然后 Perl 会搜索如下:
==================================================== ========================= |模块 |试试# |文件尝试 ==================================================== ========================= |我的模块1 |尝试 1 | /usr/lib/perl/MyModule1.pm |我的模块1 |尝试 2 | /opt/custom/lib/MyModule1.pm ==================================================== ========================= | This::Here::MyModule2 |尝试 1 | /usr/lib/perl/This/Here/MyModule2.pm | This::Here::MyModule2 |尝试 2 | /opt/custom/lib/This/Here/MyModule2.pm ==================================================== =========================请记住,一旦 Perl 解释器在其中一个位置找到文件,它将停止尝试搜索,而不会尝试查看文件是否也在后面的位置。例如。如果/usr/lib/perl/This/Here/MyModule2.pm
存在,那么Perl 将不会寻找,也不会关心/opt/custom/lib/This/Here/MyModule2.pm
的存在。
注意:每当 Perl 解释器使用类似 require
的机制来导入 Perl 模块时,都会使用 @INC。这包括:
require
指令本身
use MyModule
语句(相当于require+import)
use base
(相当于require+"push @ISA")
-M
命令行参数
【讨论】:
可能值得注意的是@INC 的内容来自哪里。这甚至可能是 OP 正在寻找的答案。简要总结:主要的默认内容是内置的(路径的确切细节显然取决于您的安装)。在脚本之外修改它的主要方法是设置环境变量 PERL5LIB(以冒号分隔的路径列表)或在运行时为可执行文件提供-I/path/to/dir
选项。 (这些添加到数组中)
任何人都有一份关于@INC 是如何构造的权威列表? perldoc perlvar 中的那个似乎没有提及 PERL5LIB,以及 $Configsitelib/sitecustomize.pl
机制(必须在编译时内置)。
@DVK:太好了!错误地认为你已经完成了,因为对问题的评论以及这已经非常彻底的事实。
您能否标记此 CW,以便低代表用户也可以编辑他们的答案?
@Ether - 完成。我的代表雪崩了:(;)【参考方案2】:
虽然这并不能直接回答问题,但这里有一些简单的技术可以确定您要使用的模块文件的完整路径。
从命令行查看@INC 数组的默认内容以及许多其他信息:
perl -V
如果你想知道Carp模块的位置:
perldoc -l Carp
在脚本中,打印 %INC 哈希的内容对于确定您正在使用的实际模块很有用,特别是如果您修改了 @INC 的默认值:
use Carp;
print $INC'Carp.pm';
这个简单的脚本也可用于Find installed Perl modules matching a regular expression 并识别不同目录中的任何重复模块。
【讨论】:
@toolic - 这个答案与 OP 问题密切相关,但我觉得它与它有些不同(例如“我导入的模块来自哪里”)。您介意在 SO 上将其作为单独的 Q+A 发布(我将链接到它),还是同意我将其作为单独的 Q 提问并发布您的答案(或让我重新发布您的答案)? 完成! ***.com/questions/2527990/… @DVK - 如果我的 Windows 路径环境变量中有两个版本的 perl,那么系统如何知道选择哪个 perl?是第一个吗?对于我的机器上安装的不同软件,我有不同的 perls。它们与软件一起安装。【参考方案3】:根据perlfunc documentation on use
:
使用模块列表
将一些语义从命名模块导入当前包,通常通过将某些子例程或变量名称别名到包中。完全等价于
BEGIN require Module; Module->import( LIST );
除了 Module 必须是一个裸词。
所以require
完成了繁重的工作,而require
documentation 提供了
如果 EXPR 是一个裸字,则 require 假定为
".pm"
扩展名,并将文件名中的"::"
替换为"/"
,以便于加载标准模块。这种形式的模块加载不会改变您的命名空间。换句话说,如果你试试这个:
require Foo::Bar; # a splendid bareword
require 函数实际上会在
@INC
数组中指定的目录中查找"Foo/Bar.pm"
文件。
【讨论】:
以上是关于Perl 程序如何知道在哪里可以找到包含它使用的 Perl 模块的文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何在现代 Linux 上的 Perl 中运行程序(超时)并知道它是如何结束的(信号、退出代码等)?