添加了闭包的 Perl newXS()

Perl newXS() with closure added

我想将 Perl 嵌入到 C++ 应用程序中,并且正在寻找一种通过 newXS() 从 Perl 调用 C++ 的方法。除了函数指针之外,我还需要将一个自定义指针关联到由 newXS() 创建的 CV。该指针包含一个 C++ 上下文。我不想为此使用全局变量。有没有一种通用的方法可以做到这一点?

在更广泛的范围内,问题可能是天气有可能 向 newXS() 创建的 CV 添加一个闭包,以及当 c 函数是调用它注册。 CvPADLIST() 似乎是完美的地方,但是对于 XSubs,当设置 PERL_IMPLICIT_CONTEXT 时似乎无效(在 perl 的 pad.c 开头注释)。可以忽略吗?)。有没有其他地方可以放CV本地数据?

最简单(也可能是最好)的方法可能是使上下文显式化——公开面向对象 API 并使用方法而不是函数。当在 Perl 代码中创建 class 的 new 实例时,您将上下文放入该对象中。当您的 XSUB 作为该对象的方法被调用时,它将接收上下文作为第一个参数(即 ST(0))。

从 XS/C++ 的角度来看,这基本上等同于 melpomene 的评论,但不需要额外的包装器闭包。

如果每个进程只存在一个上下文,那么使用全局变量也是合法的——也许是一种必要之恶。也比较 Safely storing static data in XS.

我知道没有任何机制可以直接将额外数据与 xsub 相关联。或许可以通过 CV 发挥一些魔力,但这听起来过于复杂,除非您无法将上下文放入 Perl 对象中。

一种可能性是将 PERL_MAGIC_ext 魔法附加到 SV,如 perlguts 中所述:

int  m_free (pTHX_ SV *sv, MAGIC* mg){ ... }
STATIC MGVTBL my_vtbl = { 0, 0, 0, 0, m_free, 0, 0, 0 };
struct ctx;

XS(XS_some_func)
{
    ...
    MAGIC *mg;
    if ((mg = mg_findext((SV*)cv, PERL_MAGIC_ext, &my_vtbl))) {
        ctx *priv = (ctx *)mg->mg_ptr;
    }
    ...
}

并在通过 newXS() 创建 CV 时分配魔法:

   ctx c;
   ...
   CV *cv = newXS(index, XS_some_func, __FILE__);
   MAGIC *mg = sv_magicext((SV *)cv,
                            0,
                            PERL_MAGIC_ext,
                            &my_vtbl,
                            (const char*)&c,
                            sizeof(c));

有一个 ANY slot in CV 可用于自定义数据并通过 CvXSUBANY(cv) 访问。例如:

CvXSUBANY(cv).any_ptr = my_ptr;

这个插槽通常用于存储 XS ALIASes and the function pointer for XS INTERFACEs 的索引。