使用lib作为相对于模块的路径

时间:2013-03-08 23:46:58

标签: perl perl-module

我在找出use lib的相对路径时遇到了问题。这是我想要做的一个例子:

我有一个目录调用foo,其中包含一个名为myscript.pl的脚本。 myscript.pl使用名为Mod1.pm的模块位于名为bar的子目录中,因此在myscript.pl的顶部我添加了以下行:

    use lib 'bar';
    use Mod1;

这很好,直到我希望Mod1.pm使用另一个模块foo/bar/asdf/Mod2.pm。如果我将use 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 lib s不能有任何绝对路径。对于我的项目,有一个中央模块“Mod1.pm”,use有很多CPAN模块位于存储库的各个目录中。所有use lib语句都是use lib '../../foo/bar/asdf'形式,因此可以找到它们相对于运行脚本的位置,但是这限制了运行使用Mod1.pm的脚本的位置,我想避免。另一个恼人的副作用是我不能只perl -c Mod1.pm来确保我对Mod1.pm所做的任何编辑都是理智的,除非我在正确的位置运行它,这很方便不是Mod1.pm的地方位于。哦加入一个已经有凌乱代码的项目的乐趣...另一个令人讨厌的副作用是我不能使用任何你建议修复我的问题的任何CPAN模块,因为我还需要一种方法找到那些。

2 个答案:

答案 0 :(得分:5)

您应use lib myscript.pl,这是一项惯例。

例如,您的文件组织为:

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

然后use lib中的myscript.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;

答案 1 :(得分: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非常受欢迎。