gpt4 book ai didi

Perl 5 : namespace issues when `use` ing SWIG-generated module in declared package

转载 作者:行者123 更新时间:2023-12-04 16:52:13 25 4
gpt4 key购买 nike

我遇到了 Perl 模块的命名空间问题。当我use它在一个常规脚本文件中,所有公共(public)符号都被导入(隐式)main::按预期打包。但是当我尝试 use它在带有自己的包声明的源文件中(即通常是另一个模块),奇怪的事情开始发生。

有问题的模块可以在 CPAN 上找到,名称为 Ufal::MorphoDiTa .它是一组 C++ 库的绑定(bind),使用 SWIG 自动生成.无需安装 lib 本身即可重现下面的测试用例。

首先是一个没有包声明的常规脚本文件:

# script.pl
use Ufal::MorphoDiTa qw(:all);
use Data::Dumper;

# a closer look at symbols inside the main:: package
my %morph_in_main = %main::{ grep { /morph/i } keys %main:: };
print "main:: namespace:\n", Dumper \%morph_in_main;

# Morpho:: is exported by Ufal::MorphoDiTa
Morpho::load('foo');

正如预期的那样,来自 Ufal::MorphoDiTa 的符号导入到 main::Morpho::load子程序被调用(没有可见的输出,但这很好):
$ perl script.pl
main:: namespace:
$VAR1 = {
'Morpho::' => *{'Ufal::MorphoDiTa::Morpho::'},
'_<morphodita/morphodita_perl.cpp' => *{'::_<morphodita/morphodita_perl.cpp'},
'_</usr/local/Cellar/perl/5.22.0/lib/site_perl/5.22.0/darwin-thread-multi-2level/auto/Ufal/MorphoDiTa/MorphoDiTa.bundle' => *{'::_</usr/local/Cellar/perl/5.22.0/lib/site_perl/5.22.0/darwin-thread-multi-2level/auto/Ufal/MorphoDiTa/MorphoDiTa.bundle'}
};

现在让我们添加一个包声明:
# Qux.pm
package Qux;
use Ufal::MorphoDiTa qw(:all);
use Data::Dumper;

# a closer look at symbols inside the main:: package
my %morph_in_main = %main::{ grep { /morph/i } keys %main:: };
print "main:: namespace:\n", Dumper \%morph_in_main;

# a closer look at symbols inside the Qux:: package
my %morph_in_qux = %Qux::{ grep { /morph/i } keys %Qux:: };
print "Qux:: namespace:\n", Dumper \%morph_in_qux;

# Morpho:: is exported by Ufal::MorphoDiTa
Morpho::load('foo');

正如您在下面看到的,在这种情况下,一些导入的符号会出现在 main:: 中。包裹和一些在声明的 Qux::包(也许这是预期的行为?):
$ perl Qux.pm
main:: namespace:
$VAR1 = {
'_<morphodita/morphodita_perl.cpp' => *{'::_<morphodita/morphodita_perl.cpp'},
'Morpho::' => *{'::Morpho::'},
'_</usr/local/Cellar/perl/5.22.0/lib/site_perl/5.22.0/darwin-thread-multi-2level/auto/Ufal/MorphoDiTa/MorphoDiTa.bundle' => *{'::_</usr/local/Cellar/perl/5.22.0/lib/site_perl/5.22.0/darwin-thread-multi-2level/auto/Ufal/MorphoDiTa/MorphoDiTa.bundle'}
};
Qux:: namespace:
$VAR1 = {
'Morpho::' => *{'Ufal::MorphoDiTa::Morpho::'}
};
Undefined subroutine &Morpho::load called at Qux.pm line 11.

无论如何,如输出的最后一行所示, Perl 突然找不到子程序了 .注意我们真正做的只是在所有 use 之前添加包声明声明。

现在樱桃在上面——如果我们 use Ufal::MorphoDiTa 之前 申报 package Qux ,一切又开始工作:
# Qux.pm
use Ufal::MorphoDiTa qw(:all);
package Qux;
use Data::Dumper;
# etc.

使用 perl Qux.pm 运行模块的输出与第一种情况相同,即子 Morpho::load找到了, 尽管 没有前缀 main::它被加载到的命名空间。将此与标准模块的行为进行对比,例如 Data::Dumper -- 在包声明之前加载时,子 Dumper必须被称为 main::Dumper包装时 Qux:: .

我很感激任何关于这里发生的事情的指示......并不是我无法解决它,而是问题困扰着我——我不确定这是否是 Perl 的一个怪癖,是 SWIG 上的一个错误事情的另一面(我没有足够的 Perl-Fu 来理解自动生成的绑定(bind)模块,该模块到处都有包声明),或者(另一个可能的替代方案)我自己的无知是否有问题。感谢您提供任何意见! :)

最佳答案

所以,原来这是预期行为 ,正如 perldoc perlmod 中非常简洁的解释(强调我的):

Packages may themselves contain package separators, as in $OUTER::INNER::var . This implies nothing about the order of name lookups, however. There are no relative packages: all symbols are either local to the current package, or must be fully qualified from the outer package name down. For instance, there is nowhere within package OUTER that $INNER::var refers to $OUTER::INNER::var. INNER refers to a totally separate global package.



现在, Ufal::MorphoDiTa 导出的符号模块都位于不同的子命名空间中(例如 load 命名空间中的 Morpho:: 子例程),因此它们必须始终是完全限定的(它们不是导入它们的包的本地)。可能令人困惑的是 main::前缀对于符号查找是隐含的,因此没有包声明(即在常规脚本中),一切正常,因为调用 Morpho::loadmain::Morpho::load 的快捷方式(并且该模块确实已加载到 main:: 内)。

但是当模块被导入包 Qux:: , Morpho::load必须被称为 Qux::Morpho::load因为,用 perldoc 的话说,“包 Qux 中没有任何地方 Morpho::load 指的是 Qux::Morpho::loadMorpho 指的是一个完全独立的全局包 [ main::Morpho]”——因为它不存在 Morpho::load被加载在里面 Qux:: ,不在 main:: .

这解释了上面引用的所有明显的怪癖。向 MorphoDiTa project 上的好人致敬为 their help and responsiveness在解决这个难题!

关于Perl 5 : namespace issues when `use` ing SWIG-generated module in declared package,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33703533/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com