1

我在包含必须从 Perforce 存储库中获取的 Perl 模块时遇到问题。我通过使用 Perforce 读取它们的文本来包含模块P4 print

对于不熟悉 Perforce 的人来说,它是一个代码版本控制工具。我不能直接从该路径读取文件,就好像它是一个映射驱动器一样,所以我需要运行这个命令。

p4 print相当于cat除了路径是特殊的并且只有命令p4可以从 Perforce 工作区访问文件。

BEGIN {
  push @INC, (
    sub {
      open my $fh, "p4 print -q //sw/pvt/shashikanths/perl/mylib/ReadElf.pm |";
      return $fh;
    },
    sub {
      open my $fh1, "p4 print -q //sw/pvt/shashikanths/perl/mylib/SimpleLogger.pm |";
      return $fh1;
    },
  );
}

BEGIN {
  push @INC, sub {
    open my $fh2, "p4 print -q //sw/pvt/shashikanths/perl/mylib/Table.pm |";
    return $fh2;
  }
}

use ReadElf;
use SimpleLogger;
use Table;

始终只ReadElf.pm包含第一个文件。我尝试将所有三个文件连接到一个文件,并BEGIN分别为每个文件使用一个块。它们都不起作用。

因此,当我尝试从 SimpleLogger 访问模块时,我得到未定义的子程序错误。

4

1 回答 1

7

对不起,我只是明白你在做什么。将子例程引用推@INC入是 Perl 功能的一个神秘部分,很少有人知道。

文档是require这样说的:

您还可以通过将 Perl 代码直接放入 @INC 数组来将挂钩插入到导入工具中。钩子有三种形式:子程序引用、数组引用和祝福对象。

子程序引用是最简单的情况。当包含系统遍历@INC 并遇到一个子例程时,这个子例程被调用,带有两个参数,第一个是对自身的引用,第二个是要包含的文件的名称(例如,“Foo/Bar.pm”) . 该子例程应该不返回任何内容,或者按以下顺序返回最多三个值的列表:

1 - 一个文件句柄,将从中读取文件。

2 - 对子程序的引用。如果没有文件句柄(上一项),那么这个子程序每次调用都会生成一行源代码,将该行写入 $_ 并返回 1,最后在文件末尾返回 0。如果有文件句柄,然后将调用子例程以充当简单的源过滤器,并在 $_ 中读取该行。同样,为每个有效行返回 1,在所有行都返回后返回 0。

3 - 子程序的可选状态。状态作为 $_[1] 传入。对子例程本身的引用作为 $_[0] 传入。

问题是您忽略了要推送的子例程的参数@INC。第二个参数将是 perl 试图加载的模块文件的名称,即ReadElf.pmSimpleLogger.pmTable.pm。Perl 找到@INC返回任何内容的第一个条目,并且始终是第一个子例程,它获取ReadElf.pm并返回一个文件句柄以从中读取。

要加载其中任何一个,只要它们都在 Perforce 存储库中的相同位置,您可以编写

BEGIN {
  push @INC, sub {
    my ($self, $module) = @_;
    my $file = "//sw/pvt/shashikanths/perl/mylib/$module";
    open my $fh, "p4 print -q $file |";
    return $fh;
  }
}

这通过构建模块的 Perforce 副本的完整路径并返回允许 Perl 读取它的文件句柄来工作。

您确实应该首先检查由指定的文件是否$file存在,如果不存在则不返回任何内容。否则p4将不必要地运行,并且无论模块是否成功获取,子例程都会返回文件句柄。

于 2013-11-05T23:04:29.903 回答