61

我的脚本的父目录中有一个模块,我想“使用”它。

如果我做

use '../Foo.pm';

我收到语法错误。

我试着做:

push @INC, '..';
use EPMS;

和..显然没有出现在@INC

我要疯了!这里有什么问题?

4

8 回答 8

107

use发生在编译时,所以这会起作用:

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

但更好的解决方案是use lib,这是编写上述内容的更好方式:

use lib '..';
use EPMS;

但是,如果您从不同的目录运行,FindBin建议使用:

use FindBin;                     # locate this script
use lib "$FindBin::RealBin/..";  # use the parent directory
use EPMS;
于 2008-10-08T22:11:29.073 回答
24

您可以通过多种方式修改@INC.

  • set PERL5LIB,如perlrun中所述

  • 使用-I命令行上的开关,也记录在perlrun中。您也可以使用 PERL5OPT 自动应用它,但如果您要这样做,只需使用 PERL5LIB。

  • use lib在你的程序中,虽然这很脆弱,因为不同机器上的另一个人可能将它放在不同的目录中。

  • 手动修改@INC,确保在编译时这样做,如果你想使用一个模块。不过这工作量太大了。

  • require直接文件名。虽然这是可能的,但它不允许该文件名加载同一目录中的文件。这肯定会在代码审查中引起注意。

于 2008-10-08T22:21:38.897 回答
14

就个人而言,我更喜欢将我的模块(我为自己或我可以控制的系统编写的模块)保存在某个目录中,并将它们放在子目录中。如:

/www/modules/MyMods/Foo.pm
/www/modules/MyMods/Bar.pm

然后我在哪里使用它们:

use lib qw(/www/modules);
use MyMods::Foo;
use MyMods::Bar;

顺便说一句..在推动方面,我更喜欢粗箭头逗号:

push @array => $pushee;

但这只是偏好问题。

于 2008-10-08T22:22:43.543 回答
8

正如@ehemient 前面提到的,'use lib' 就是答案。另一种选择是使用 require/import 而不是 use。这意味着模块不会在编译时加载,而是在运行时加载。

这将允许您在尝试时修改@INC,或者您可以传递文件的路径而不是模块名称。从“perldoc -f 要求”:

如果 EXPR 是一个裸字,则 require 假定扩展名为“.pm”,并为您将文件名中的“::”替换为“/”,以便于加载标准模块。这种形式的模块加载不会改变您的命名空间。

于 2008-10-08T22:16:38.690 回答
3

您必须push在 is 之前处理use- 并且use提前处理。所以,我相信你需要BEGIN { push @INC, ".."; }一个机会。

于 2008-10-08T22:11:14.380 回答
2

正如“perldoc -f use”所报告的:

它完全等同于
BEGIN { require Module; import Module LIST; }
除了 Module 必须是一个裸词。

换句话说,“使用”相当于:

  • 在编译时运行,
  • 将包名转换为文件名,
  • require-ing 那个文件名,并且
  • import-ing那个包。

因此,您可以在 BEGIN 块中调用 require 和 import,而不是调用 use:

BEGIN {
  require '../EPMS.pm';
  EPMS->import();
}

当然,如果您的模块在调用 import 时实际上没有进行任何符号导出或其他初始化,则可以省略该行:

BEGIN {
  require '../EPMS.pm';
}
于 2008-12-20T22:57:23.910 回答
0

某些 IDE 无法与首选答案“use lib”一起正常工作。我发现 'use lib::relative' 适用于我的 IDE,JetBrains 的 WebStorm。

参见POD for lib::relative

于 2021-01-01T16:35:30.030 回答
0

它不起作用的原因是因为您要添加的@INC内容与命令行中的当前工作目录相关,而不是脚本的目录。

例如,如果您目前在:

a/b/

您正在运行的脚本具有以下 URL:

a/b/modules/tests/test1.pl

BEGIN {
    unshift(@INC, "..");    
}

以上将意味着..结果是目录a/而不是a/b/modules.

在再次运行脚本之前,您必须在代码中更改..为或在命令行中执行 a。./modulescd modules/tests

于 2022-01-22T20:42:08.413 回答