内容

名称

XSLoader - 在 Perl 代码中动态加载 C 库

版本

版本 0.32

概要

package YourPackage;
require XSLoader;

XSLoader::load(__PACKAGE__, $VERSION);

描述

此模块定义了一个标准的简化接口,用于访问许多平台上可用的动态链接机制。它的主要目的是实现 Perl 模块的廉价自动动态加载。

有关更复杂的接口,请参见 DynaLoaderDynaLoader 的许多(大多数)功能在 XSLoader 中未实现,例如 dl_load_flagsXSLoader 不支持。

DynaLoader 迁移

使用 DynaLoader 的典型模块以如下方式开始

package YourPackage;
require DynaLoader;

our @ISA = qw( OnePackage OtherPackage DynaLoader );
our $VERSION = '0.01';
__PACKAGE__->bootstrap($VERSION);

将其更改为

package YourPackage;
use XSLoader;

our @ISA = qw( OnePackage OtherPackage );
our $VERSION = '0.01';
XSLoader::load(__PACKAGE__, $VERSION);

换句话说:用 use XSLoader 替换 require DynaLoader,从 @ISA 中删除 DynaLoader,用 XSLoader::load 替换 bootstrap。不要忘记在 XSLoader::load 行上引用你的包的名称,并在参数(上面的 $VERSION)之前添加逗号 (,)。

当然,如果 @ISA 只包含 DynaLoader,则根本不需要 @ISA 赋值;此外,如果使用更向后兼容的

use vars qw($VERSION @ISA);

可以将此对 @ISA 的引用与 @ISA 赋值一起删除。

如果在 bootstrap 行中没有指定 $VERSION,则最后一行变为

XSLoader::load(__PACKAGE__);

在这种情况下,它可以进一步简化为

XSLoader::load();

因为 load 将使用 caller 来确定包。

向后兼容的样板

如果你想要鱼和熊掌兼得,你需要一个更复杂的样板。

    package YourPackage;

    our @ISA = qw( OnePackage OtherPackage );
    our $VERSION = '0.01';
    eval {
       require XSLoader;
	XSLoader::load(__PACKAGE__, $VERSION);
       1;
    } or do {
       require DynaLoader;
       push @ISA, 'DynaLoader';
       __PACKAGE__->bootstrap($VERSION);
    };

关于 XSLoader::load() 参数的括号是必要的,因为我们用 require 替换了 use XSLoader,所以编译器不知道存在 XSLoader::load() 函数。

这个样板使用低开销的 XSLoader(如果存在);如果与没有 XSLoader 的旧版 Perl 一起使用,它将回退到使用 DynaLoader

初始化顺序:早期加载()

如果 XSUB 函数应该只从其他模块调用,请跳过本节;只有在从模块中的代码调用 XSUB 或在 XS 文件中存在 BOOT: 部分时才阅读它(参见 "perlxs 中的 BOOT: 关键字")。这里描述的内容同样适用于 DynaLoader 接口。

一个足够复杂的模块使用 XS 将同时拥有 Perl 代码(定义在 YourPackage.pm 中)和 XS 代码(定义在 YourPackage.xs 中)。如果此 Perl 代码调用此 XS 代码,或者此 XS 代码调用 Perl 代码,则应注意初始化顺序。

XSLoader::load()(或 bootstrap())的调用会调用模块的引导代码。对于由 xsubpp 构建的模块(几乎所有模块),这有三个副作用

因此,如果.pm文件中的代码调用了这些 XSUB,那么在定义 Perl 代码之前安装 XSUB 会很方便;例如,这使得 XSUB 的原型对该 Perl 代码可见。或者,如果BOOT:部分调用了.pm文件中定义的 Perl 函数(或使用 Perl 变量),则必须在调用XSLoader::load()(或bootstrap())之前定义它们。

第一种情况更为常见,因此有必要将样板代码重写为

package YourPackage;
use XSLoader;
our ($VERSION, @ISA);

BEGIN {
   @ISA = qw( OnePackage OtherPackage );
   $VERSION = '0.01';

   # Put Perl code used in the BOOT: section here

   XSLoader::load(__PACKAGE__, $VERSION);
}

# Put Perl code making calls into XSUBs here

最复杂的情况

如果您的BOOT:部分和 Perl 代码的相互依赖关系比这更复杂(例如,BOOT:部分调用了调用带有原型的 XSUB 的 Perl 函数),则完全删除BOOT:部分。用一个函数onBOOT()替换它,并像这样调用它

package YourPackage;
use XSLoader;
our ($VERSION, @ISA);

BEGIN {
   @ISA = qw( OnePackage OtherPackage );
   $VERSION = '0.01';
   XSLoader::load(__PACKAGE__, $VERSION);
}

# Put Perl code used in onBOOT() function here; calls to XSUBs are
# prototype-checked.

onBOOT;

# Put Perl initialization code assuming that XS is initialized here

诊断信息

找不到 %s 符号在 %s 中

(F) 在扩展模块中找不到引导符号。

无法为模块 %s 加载 '%s':%s

(F) 扩展模块的加载或初始化失败。详细错误如下。

加载 %s 后存在未定义的符号:%s

(W) 正如消息所说,尽管扩展模块已正确加载和初始化,但一些符号仍然未定义。未定义符号列表如下。

限制

为了尽可能减少开销,只检查一个可能的位置来查找扩展 DLL(此位置是make install将 DLL 放置的位置)。如果找不到,则将查找 DLL 的操作透明地委托给DynaLoader,它会在@INC列表中查找 DLL。

特别是,这适用于用于测试尚未安装的扩展的@INC结构。这意味着运行未安装的扩展的开销可能比运行make install后相同的扩展的开销大得多。

已知错误

在 Perl 5.8.4 和 5.8.5 上,使用完全没有参数的 XSLoader::load() 的新简化方法不起作用。

错误

请使用 perlbug(1) 工具报告任何错误或功能请求。

另请参阅

DynaLoader

作者

Ilya Zakharevich 最初从 DynaLoader 中提取了 XSLoader

CPAN 版本目前由 Sébastien Aperghis-Tramoni <[email protected]> 维护。

之前的维护者是 Michael G Schwern <[email protected]>。

版权和许可

版权所有 (C) 1990-2011 Larry Wall 及其他。

本程序是自由软件;您可以在 Perl 本身的相同条款下重新发布和/或修改它。