无法在运行时加载“Cwd”(以及其他非核心模块)

Posted

技术标签:

【中文标题】无法在运行时加载“Cwd”(以及其他非核心模块)【英文标题】:Cannot load `Cwd` (and other, non-core, modules) at runtime 【发布时间】:2017-04-26 23:02:35 【问题描述】:

假设我想在运行时加载一个模块。我希望这可以工作

use warnings;
use strict;

eval 
    require Cwd; 
    Cwd->import;
;
if ($@)  die "Can't load Cwd: $@" 

say "Dir: ", getcwd;

但不是,根据Bareword "getcwd" not allowed ...

Cwd 默认导出getcwd。我尝试将函数名称赋予import,并尝试使用它的其他函数。 它使用全名say Cwd::getcwd,所以我认为它没有导入。

这与我尝试过的其他几个核心模块的尝试一样,例如

use warnings;
use strict;

eval  
    require List::Util; 
    List::Util->import('max');
;
if ($@)  die "Can't load List::Util: $@" 

my $max = max (1, 14, 3, 26, 2); 
print "Max is $max\n";

添加了注意事项 显然,带括号的函数调用为编译器提供了线索。但是,在我看来,问题仍然存在,请参阅最后的 EDIT。此外,上面模块中的first BLOCK LIST 之类的函数也不起作用。


但是,它适用于我尝试过的一些(成熟的)非核心模块。更糟糕,更令人困惑的是,即使使用完全限定的名称,它也不起作用。

如果在运行时使用require,我可以想象在编译时使用的符号(函数)是未知的,但它适用于(其他)核心模块。我认为这是在运行时加载的标准方式。

如果我需要在动态加载时使用全名,那很好,但是不一致是怎么回事?以及我如何在运行时加载(和使用)非核心模块?

我也尝试了Module::Load::Conditional,但没有成功。

我缺少什么,如何在运行时加载模块? (尝试使用5.165.10.1。)


编辑

如Matt Jacob 所述,带括号的调用有效,getcwd()。但是,鉴于perlsub

NAME LIST; # 如果预先声明/导入,括号是可选的。

这意味着导入不起作用,为什么仍然存在问题。

此外,必须根据模块的加载方式使用不同的语法是不好的。此外,我无法让非核心模块以这种方式工作,尤其是那些语法像 List::MoreUtils 的模块。

【问题讨论】:

Perl 不知道它是一个子程序。你需要:&getcwd(不太好)、use subs qw(getcwd);(更好),或者只是getcwd()(最好)。 @MattJacob 谢谢,确实有效。但是,问题仍然存在,正如我在最后添加的注释中所解释的那样。 在编译 getcwd 调用时导入还没有工作,所以你得到了严格的错误(或者没有严格,把它解释为字符串"getcwd")。添加括号告诉 perl 这是一个子调用,而不是一个简单的单词。 @ysth 好的,谢谢,我想到了(我可以想象...)——但它确实适用于其他核心模块,即使涉及语法.比如说,在List::Util 我可以使用max BLOCK LIST。可以说这可能是因为的语法(给编译器或类似的提示)......但它不应该依赖于此。那么如何动态加载呢?我认为这是常态。 重点是在编译过程之后导入模块。更改后 eval 需要 Cwd; cwd->导入; ;进入 Beginn-Block BEGIN 需要 Cwd; cwd->导入; ;一切正常。 【参考方案1】:

首先,这与核心与非核心模块无关。当解析器必须猜测特定标记是否是函数调用时,就会发生这种情况。


eval 
    require Cwd; 
    Cwd->import;
;
if ($@)  die "Can't load Cwd: $@" 

say "Dir: ", getcwd;

在编译时,main:: 符号表中没有 getcwd。没有任何提示表明它是一个函数(getcwd()&getcwd),解析器无法知道,strict 抱怨。


eval  
    require List::Util; 
    List::Util->import('max');
;
if ($@)  die "Can't load List::Util: $@" 

my $max = max (1, 14, 3, 26, 2);

在编译时,main:: 符号表中没有 max。但是,由于您使用括号调用max,因此解析器可以猜测它是稍后定义的函数,因此strict 不会抱怨。

在这两种情况下,strict 检查都发生在 import 被调用之前。


List::MoreUtils 很特别,因为函数使用原型。如果函数定义在编译时不可见,则忽略原型。因此,您不仅需要向解析器提示您正在调用一个函数,而且还必须以不同的方式调用它,因为原型将被忽略:

use strict;
use warnings 'all';
use 5.010;

eval 
    require List::MoreUtils;
    List::MoreUtils->import('any')
;
die "Can't load List::MoreUtils: $@" if $@;

say 'found' if any( sub  $_ > 5 , 1..9 );

【讨论】:

非常感谢。因此,在运行时加载时,必须考虑编译器并使用不同的语法。很高兴知道。 (我已经看过很多次了,但从来没有看到过这种暗示。) 我认为符号不为人所知,如问题中所述,但后来我认为它对其他模块“有效”让我相信正在做一些魔法(对于核心模块,我想)。 即使在其他情况下,您也必须考虑解析器,例如sub foo ... foo; 可以,但foo; sub foo ... 不行。所以有些人总是用括号;太容易被咬了。这只是您应该避免使用原型的另一个例子。 是的,原型让我对整个事情感到厌烦。我从不靠近他们(也不认识他们),所以我没有意识到这个模块使用了它。 (显然,我需要更仔细地重新阅读 Perl 文档,并确保始终查看我使用的模块的源代码。)谢谢。

以上是关于无法在运行时加载“Cwd”(以及其他非核心模块)的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:无法读取未定义的属性“cwd”

无法为“XCTest”加载底层模块

amd模块化——typeScript下载于安装以及运行 ——yarn下载——TS的运行——Ts数据类型描述

自动化运维ansible用法

自动化运维ansible用法

开机加载模块失败是怎么回事?