【问题标题】:Something wrong with @INC in perl?perl 中的@INC 有问题吗?
【发布时间】:2013-11-02 05:21:15
【问题描述】:

假设我们是 perl 的新手并且写了一些很棒的模块 MyModule.pm。我们还写了一些很棒的脚本myscript.pl,需要用到这个模块。

use strict;
use warnings;
use MyModule;
etc...

现在我们将创建目录/home/user/GreatScript 并将我们的文件放入其中。并尝试运行myscript.pl...

cd /home/user/GreatScript
perl myscript.pl

太棒了!现在移动到另一个目录...

cd /
perl /home/user/GreatScript/myscript.pl

得到一些关于@INC 和路径列表的不太有用的错误。这是什么?现在经过一番谷歌搜索,我们知道 @INC 包含搜索我们模块的路径,这个错误意味着 Perl 无法找到 MyModule.pm。

现在我们可以:

  • 添加系统PERL5LIB var的路径,它将我们的路径添加到@INC的开头 将我们的模块安装到来自@INC 的目录之一
  • 在BEGIN 部分手动添加到@INC 的路径 将use lib '/home/user/GreatScript'; 添加到我们的脚本中,但它看起来很糟糕。如果我们将脚本移动到其他目录会怎样?
  • 或者使用FindBin模块找到我们当前的目录,并在use lib "$FindBin::Bin";中使用这个路径,但是并不是100%有效,比如mod_perl或者issues的一些bug...
  • 或使用 __FILE__(或 $0)变量并使用来自 Cwd 模块的 abs_path 方法从中提取路径。看起来像另一辆自行车?
  • 或者有些遗忘或遗漏(我错过了什么吗?)

为什么这个显而易见的常规操作需要大量工作? 如果我有一个脚本,这很容易……但是为什么我需要为我的所有脚本编写这几行额外的代码呢?而且它不会 100% 起作用!为什么 perl 默认不将当前脚本目录添加到 @INC,就像使用 "." 一样?

PS:我正在寻找我的问题的答案,但仅从上面的列表和其他一些列表中找到解决方案列表。我希望这个问题是重复的......

【问题讨论】:

  • “需要大量工作”是什么意思?您已经找到了四种方法来做到这一点。基本上所有语言(python、Java、ruby、任何需要特定 DLL/SO 文件的东西,......)都有同样的问题。哎呀,你甚至需要那种东西来定位 perl 可执行文件本身(PATH 设置)。
  • 所有这些方法都有一些问题,而且不是 100% 保存,我认为在 perl 的核心级别上添加当前脚本目录的路径并不难......
  • 如果这不是您想要的,您会怎么做?如果您确实需要当前路径中的内容来覆盖脚本位置中的内容怎么办?然后你需要别的东西来禁用默认值。在所有语言和平台(直接或通过某种形式的注册表)中,必须为您使用的“模块”设置类似 PATH 的东西。
  • 您缺少sitecustomize.pl 作为可以操纵@INC 的系统级挂钩(可用于实现用户或脚本特定挂钩)。那以及您提到的任何技术都比依赖脚本的 cwd 事故要好。 Neil Slater's answer 更好。

标签: perl


【解决方案1】:

或者有些忘记或丢失(我错过了什么吗?)

另一种选择:不要将模块与脚本一起保存。该模块是独立的,因为它是可重复使用的,所以将它放在一个库文件夹中。这可以是任何东西,从用于个人项目的本地库,包含在 use lib 中(并且可能引用您为项目设置的环境变量),将模块制作成 CPAN 库,并让 cpan 管理它的位置去。你决定做什么取决于你的代码的可重用性,而不是脚本如何使用它。

为什么这种显而易见的常规操作需要大量工作?

在事情的计划中并不是很多工作。您期望在文件系统中组合在一起的文件应该由 Perl 在语言级别自动使用来解析 require 或 use 语句,这是不正确的。不是不可能,也不是你的期望不合理,只是 Perl 不是这样实现的。事后更改它可能会影响现有项目的工作量,并且可能会引起争议 - 因此不太可能更改。

【讨论】:

  • 但即便如此,命令行标志(-R 表示“相对”当前未使用)可用于将 @INC 中的任何相对路径解释为相对于脚本而不是相对于当前工作目录。这个选项甚至可以在 shebang 线上给出,并且不应该有任何负面的向后兼容性后果。
  • @tobyink:可以,但我不能说它是否会被认真地视为perl 的新功能。现状并非不可能——您可以拥有您喜欢的模块文件分组。要获得分配给您对项目结构的偏好的命令行标志(这将为您节省一两行代码),它需要在 Perl 社区中被认为足够流行,并且 Perl 开发人员支持的概念.
【解决方案2】:

如果您的用例是:“我想要一个脚本来访问相同或相对目录中的其他模块或其他资源,并且我不想安装所有东西”,那么 FindBin 是一个完美的解决方案。手册页中提到的限制只发生在像 mod_perl 这样的持久性环境中,但在这里我会提出不同的解决方案(例如,仅在 httpd.conf 中使用 FindBin,而不是在脚本/模块中)。

(/me 是 FindBin 的重度用户,我也是 FindBin 手册页的 KNOWN ISSUES 部分一半的作者)

【讨论】:

    【解决方案3】:

    这是为了知道您想使用哪个模块。当您按照您所说的移动到另一个目录时,perl 会在“。”中查找。目录所以如果运行:

    cd /
    perl /home/user/GreatScript/myscript.pl
    

    如果'/'中的 MyModule.pm,perl 会找到它并将在myscrpit.pl 中使用。现在,当 Perl 在 @INC 中查找模块时,您必须留意 @INC 中的目录。

    总结:明显和常规的操作是为了防止使用错误的同名模块。

    【讨论】:

      猜你喜欢
      • 2019-10-02
      • 2015-07-23
      • 2013-06-07
      • 2019-08-15
      • 2011-10-20
      • 1970-01-01
      • 1970-01-01
      • 2011-09-11
      • 2020-07-15
      相关资源
      最近更新 更多