如何包含位于不同目录中的 Perl 模块?

52

如何引用位于不同目录的 Perl 模块?引用路径需要是相对于包含它的模块的路径。

我已经尝试过:

push ( @INC,"directory_path/more_path");

同样

push ( @INC,"directory_path\\more_path");
6个回答

75

编辑:首先给出正确的解决方案,原始来源于这个问题。它是唯一一个相对于模块目录进行搜索的解决方案:

use FindBin;                 # locate this script
use lib "$FindBin::Bin/..";  # use the parent directory
use yourlib;

除了当前目录,还有许多其他搜索库的方法。您可以使用-I参数调用perl,并传递其他模块的目录:

perl -I.. yourscript.pl

你可以在perl脚本的顶部包含以下一行代码:

use lib '..';

在运行脚本之前,您可以修改环境变量PERL5LIB:

export PERL5LIB=$PERL5LIB:..

使用push(@INC)策略也是可行的,但必须将其包装在BEGIN{}中,以确保在模块搜索之前运行push:

BEGIN {push @INC, '..'}
use yourlib;

经过多次尝试,最终有效的代码来自Andomar链接的问题:use FindBin; # 定位此脚本 use lib "$FindBin::Bin/.."; # 使用父目录 use EPMS;感谢大家的帮助! - ees
谢谢,看起来大家都把“当前目录”理解成了你所写的“模块目录”。 - Andomar
在阅读了https://dev59.com/SHVD5IYBdhLWcg3wHnsX#90721之后,我发现FindBin方法对于某些形式的模块化Perl组织并不健壮(也许有人能够澄清)。 - Louis Maddox

15
很可能你的推送操作未能成功是因为执行顺序的问题。 use 是一个编译时指令。而你的 push 操作是在执行时完成的。
push ( @INC,"directory_path/more_path");
use Foo.pm;  # In directory path/more_path
您可以使用 BEGIN 块来解决这个问题:
BEGIN {
    push ( @INC,"directory_path/more_path");
}
use Foo.pm;  # In directory path/more_path

在我看来,最清晰、因此最好的方法是使用lib

use lib "directory_path/more_path";
use Foo.pm;  # In directory path/more_path

请参考perlmod了解 BEGIN 和其他特殊代码块的信息以及它们执行的时机。

编辑

如果要相对于您的脚本/库加载代码,我强烈推荐使用File::FindLib

您可以使用use File::FindLib 'my/test/libs';来查找位于脚本路径上方任何位置的库目录。

假设您的工作结构如下:

   /home/me/projects/
    |- shared/
    |   |- bin/
    |   `- lib/
    `- ossum-thing/
       `- scripts 
           |- bin/
           `- lib/

ossum-thing/scripts/bin 文件夹内的脚本中:

use File::FindLib 'lib/';
use File::FindLib 'shared/lib/';

将会查找您的库目录并将它们添加到@INC中。

创建一个包含运行工具所需的所有环境设置的模块,然后在项目中的所有可执行文件中加载该模块也非常有用。

use File::FindLib 'lib/MyEnvironment.pm'

10

'use lib' 也可以接受一个字符串作为参数...

#!/usr/bin/perl
use lib '<relative-path>';
use <your lib>;

相对路径是相对于什么而言的? - Flimm

7

来自perlfaq8:


如何将程序所在的目录添加到模块/库搜索路径中?

(由brian d foy提供)

如果您已经知道该目录,您可以像其他目录一样将其添加到@INC中。如果您在编译时知道该目录,可以使用lib:

use lib $directory;

这个任务的关键是找到目录。在你的脚本执行其他操作之前(如chdir),你可以使用Perl附带的Cwd模块获取当前工作目录:

BEGIN {
    use Cwd;
    our $directory = cwd;
    }

use lib $directory;

你可以使用$0的值来完成类似的操作,它保存着脚本名称。这个名称可能是相对路径,但rel2abs可以将其转换为绝对路径。一旦你拥有了这个绝对路径,就可以...
BEGIN {
    use File::Spec::Functions qw(rel2abs);
    use File::Basename qw(dirname);

    my $path   = rel2abs( $0 );
    our $directory = dirname( $path );
    }

use lib $directory;

Perl自带的FindBin模块可能会有所帮助。它可以找到当前正在运行的脚本目录并将其放在$Bin中,然后您可以使用它来构建正确的库路径:

use FindBin qw($Bin);

你的第二个建议(在BEGIN块内使用cwd)似乎不起作用。我得到的只是以下错误:Variable "$directory" is not imported at ./thingy line 16. // Global symbol "$directory" requires explicit package name at ./thingy line 16. // BEGIN not safe after errors--compilation aborted at ./thingy line 16. - zrajm
你需要展示给我看你的代码。听起来你在导入列表中可能引用了$directory。 - brian d foy

2

我很惊讶之前没有人提到过它,但是 FindBin::libs 会在与脚本位置相关的所有合理位置搜索,因此始终能找到您的 libs。

#!/usr/bin/perl
use FindBin::libs;
use <your lib>;

1
我很惊讶,7年过去了,你的回答竟然没有得到任何赞。给你一个赞。 - 0xC0000022L

0

我会告诉你如何在 Eclipse 中完成。我的开发系统是 Windows 64 位、Eclipse Luna、Eclipse 的 Perlipse 插件、以及 Strawberry Pearl 安装程序。我使用 perl.exe 作为解释器。

Eclipse > 创建新的 Perl 项目 > 右键单击项目 > 构建路径 > 配置构建路径 > 库选项卡 > 添加外部源文件夹 > 转到存放所有 Perl 模块的文件夹 > 确定 > 确定。完成!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接