1

我在确定use lib. 这是我正在尝试做的一个例子:

我有一个目录调用foo,其中包含一个名为myscript.pl. myscript.pl使用一个名为的模块,该模块Mod1.pm位于名为 的子目录中bar,所以在顶部myscript.pl我放了以下几行:

    use lib 'bar';
    use Mod1;

这工作正常,直到我想Mod1.pm使用另一个模块,foo/bar/asdf/Mod2.pm. 如果我将 ause lib 'asdf'放在它的顶部Mod1.pm将不起作用,因为它相对于我正在运行的目录进行搜索myscript.pl。所以我做了一些搜索并找到了FindBin,并尝试将这些行添加到 Mod1.pm:

    use FindBin;
    use lib "$FindBin::Bin/asdf";

这也不起作用,因为FindBin找到了我正在运行的脚本 ( myscript.pl) 所在的目录,而不是使用的文件FindBin(在这种情况下Mod1.pm)。所以我的问题是,有没有一种方法可以相对于所在位置进行搜索Mod1.pm,以便Mod2.pm无论使用的脚本在哪里都可以找到Mod1.pm

编辑:进一步解释我的情况以解决您的一些评论:

我正在处理存储库中的代码,所有 CPAN 库都需要安装在存储库的目录中。这意味着use libs 不能有任何绝对路径。对于我的项目,有一个中央模块“Mod1.pm”,其中包含use很多 CPAN 模块,它们位于存储库的各个目录中。所有use lib语句的格式都是use lib '../../foo/bar/asdf'这样的,因此可以相对于您运行脚本的位置找到它们,但这限制了您可以运行使用 Mod1.pm 的脚本的位置,我试图避免这种情况。另一个恼人的副作用是我不能perl -c Mod1.pm确保我对 Mod1.pm 所做的任何编辑都是合理的,除非我在正确的位置运行它,而这不是 Mod1.pm 所在的位置。哦,加入一个已经有混乱代码的项目的乐趣......另一个令人讨厌的副作用是我不能使用你们中的任何人建议的任何 CPAN 模块来解决我的问题,因为我仍然需要一种方法找到那些。

4

2 回答 2

5

你应该use libmyscript.pl,这是一个约定。

例如,您的文件组织为:

.
├── bar
│   ├── Mod1.pm
│   └── asdf
│       └── Mod2.pm
└── myscript.pl

然后use libmyscript.pl

use File::Spec;
use FindBin qw($Bin);
use lib File::Spec->catdir($Bin, 'bar');
use Mod1;

然后使用Mod1.pmMod2.pm就像使用其他 CPAN 模块一样。使用时记得在模块名前加上目录名Mod2.pm

Mod1.pm

package Mod1;

use asdf::Mod2;

1;

Mod2.pm

package asdf::Mod2;

1;
于 2013-03-09T04:44:07.587 回答
5

通常您希望您的主程序自行查找其所有库,在这种情况下,您应该按照 Alec Chen 的回答进行操作。

在某些情况下,例如查找插件,您希望一个库能够找到与其位置相关的其他库。

您可以使用__FILE__包含源代码当前文件的位置来执行此操作。

package Mod1;

use strict;
use warnings;

use File::Basename;

# Must put this in a BEGIN block so it happens at "compile time" while the
# "use"s are being executed.  But the "my" declaration must happen outside
# the BEGIN block else it can't be seen.
my $module_dir;
BEGIN { $module_dir = dirname(__FILE__); }

use lib $module_dir;

use Mod2;

上面写的有趣的方式是因为每个 Perl 文件都有两个(或更多)执行阶段。“编译时间”和“运行时间”。 use语句发生在编译时。为了做到use lib $module_dir这一点,我们必须$module_dir在编译时设置一个BEGIN块。使困惑?有更简单的方法...

@INC模块全局更改是不好的形式。加载模块不应更改程序的全局状态(除非这是其功能的一部分)。相反,您将对其进行本地化。

package Mod1;

use strict;
use warnings;

use File::Basename;
my $module_dir = dirname(__FILE__);

{
    local @INC;
    push @INC, $module_dir;
    require Mod2;
}

但是直接将其作为文件需要它可能更简单。

package Mod1;

use strict;
use warnings;

use File::Basename;
use File::Spec;
my $module_dir = dirname(__FILE__);
require File::Spec->catfile($module_dir, "Mod2.pm");

而且,这是 Perl,有一些模块可以处理插件,Module::Pluggable非常流行。

于 2013-03-09T05:17:49.297 回答