背景:我有一个perl模块 - 让我们称之为Foo::Common
已经安装在我们的一个文件服务器上(为了简单起见,我将称之为'全局'版本)。该模块包含在大约1000 perl脚本的某个地方,每15分钟启动一次。该模块有几个旧版本,但更新它将需要在几个月的时间内进行大量测试。
我正在编写一个新的perl脚本,它将在同一个处理服务器上运行,但我需要的功能只包含在最新版本的Foo::Common
中。如果我只想使用较新版本的Foo::Common
,我可以将Foo/Common.pm
放在运行脚本的./lib
目录中,然后使用以下代码:
my $lib = '';
BEGIN {
$lib = $ENV{FOO_ENV_HOME} || '';
}
use lib "$lib/core/bin/";
use lib './lib';
use Foo::Common;
由于use lib
将目录添加到@INC
的开头,因此将首先找到并使用较新版本的Foo::Common
。
这一切都很好,但我不希望我的脚本依赖于Foo::Common
的本地版本。 Foo::Common
的全局版本为our $VERSION = '1.1.2'
,我想在本地安装的版本位于1.1.7
。如果我部署上面的代码,然后我们将全局版本升级到尚未编写的1.2.0
,我的脚本将停止运行1.1.7
。
根据perldoc -f require
:
`require $filename` Has semantics similar to the following subroutine:
sub require {
my ($filename) = @_;
if (exists $INC{$filename}) {
return 1 if $INC{$filename};
die "Compilation failed in require";
}
my ($realfilename,$result);
ITER: {
foreach $prefix (@INC) {
$realfilename = "$prefix/$filename";
if (-f $realfilename) {
$INC{$filename} = $realfilename;
$result = do $realfilename;
last ITER;
}
}
die "Can't find $filename in \@INC";
}
if ($@) {
$INC{$filename} = undef;
die $@;
} elsif (!$result) {
delete $INC{$filename};
die "$filename did not return true value";
} else {
return $result;
}
}
我不清楚这与use MODULE VERSION
语法的交互方式,尽管What does Perl do when two versions of a module are installed?的答案中的讨论表明use Module Version
还不够。
我认为我将操纵@INC,但我不确定如何根据每个模块$VERSION
执行此操作,尤其是因为use
具有隐式BEGIN
言。
我该如何处理?
答案 0 :(得分:4)
在阳光下没有什么新东西。
use only::latest 'Foo::Common'
答案 1 :(得分:2)
您无法根据版本进行检查,因为$VERSION
不存在,直到加载后才会执行。
所以你想要"全球"如果存在则使用的版本,否则使用本地版本?将本地路径附加到@INC而不是预先添加它。
BEGIN {
push @INC, "$ENV{FOO_ENV_HOME}/core/bin";
if $ENV{FOO_ENV_HOME};
}
use Foo::Common;
如果您无法重新排列@INC
,因为它会影响其他内容,请在更改@INC
之前尝试加载Foo :: Common。
BEGIN { eval { require Foo::Common; }; }
use lib ...;
use Foo::Common;
use ...;
use Foo::Common;
如果先前已加载模块,则不会加载该模块,并且它将从加载的任何版本(无论加载到何处)导入。