使用闭包的Perl newXS()函数

7
我想在C++应用程序中嵌入Perl,并寻找通过newXS()从Perl调用C++的方法。除了函数指针外,我需要将一个自定义指针关联到由newXS()创建的CV。该指针包含一个C++上下文。我不想使用全局变量来实现这一点。是否有常见的方法来解决这个问题?
在更广泛的范围内,问题可能是是否有可能向通过newXS()创建的CV添加闭包,以及如何在调用已注册的C函数时引用它。 CvPADLIST() 似乎是最完美的地方,但对于设置了 PERL_IMPLICIT_CONTEXT 的 XSubs,使用它似乎是无效的(在perl的pad.c开头的注释中)。它是否可以被忽略?还有其他地方可以放置CV本地数据吗?

我不知道 XS,但你可以让 XS 函数始终采用显式参数,并在纯 Perl 中进行闭包封装:sub make_closure { my $ctx = new_context(); return sub { xs_func($ctx, @_) }; } - melpomene
@melpomene 很有趣,我可以为每个动态注册的xs函数通过eval生成一个包装器...... 这是一种可能性。 正在研究PERL_MAGIC_ext,也许还有其他方法...... - Konrad Eisele
3个回答

5

一种可能的方法是如 perlguts 所描述的,将 PERL_MAGIC_ext 魔法附加到 SV 上:

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));

3

CV中有一个ANY插槽可用于自定义数据,并使用CvXSUBANY(cv)进行访问。例如:

CvXSUBANY(cv).any_ptr = my_ptr;

这个槽通常用于存储XS别名的索引和XS接口的函数指针。


2
最简单(也最好的)方法可能是使上下文显式 - 暴露面向对象的API并使用方法而不是函数。当在Perl代码中创建类的new实例时,将上下文放入该对象中。当作为该对象的方法调用您的XSUB时,它将作为第一个参数(即ST(0))接收上下文。
从XS / C ++角度来看,这基本上相当于melpomene的评论,但不需要额外的包装闭包。
如果每个进程只存在一个上下文,则使用全局变量也是合法的 - 也许是必要的恶。还可以比较在XS中安全地存储静态数据
我不知道直接关联额外数据与xsubs的机制。可能可以通过CV进行一些魔法,但除非您负担不起将上下文放入Perl对象中,否则听起来过于复杂。

如果您编写扩展并从包装主Perl解释器调用C/C++代码,则显式上下文的方法会感觉很自然。但是,当将Perl用作嵌入式解释器,而C++用作包装语言时,从嵌入式Perl调用的C++函数应该驻留在包装C++程序的上下文中。否则,在同一时间内嵌入多个解释器到本地函数中变得繁琐。 - Konrad Eisele
@KonradEisele 嗯,我明白你的意思。在这种情况下,当您初始化解释器时,将单个上下文对象加载到Perl包变量中可能是有意义的? - amon
1
好的,这是可能的。然而,那只能解决一个特定的问题。我正在尝试使用 https://github.com/tomaka/luawrapper 并想要实现类似的机制。我现在发现了 PERL_MAGIC_ext 类型的魔法,我可以进行分配,所以我猜我会尝试一下这个。 - Konrad Eisele
哇,那个luawrapper看起来非常方便 :) 使用魔法是合法的,但我个人仍然更喜欢更明显的基于对象的解决方案。你会把你的解决方案打成答案吗? - amon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接