简体   繁体   English

寻找一种从辅助函数调用 Perl XS C API 函数/宏的方法

[英]Looking for a way to call Perl XS C API functions/macros from helper functions

I've been experimenting with the Perl XS C API and have hit a roadblock.我一直在试验 Perl XS C API 并遇到了障碍。

I have simplified my example below.我在下面简化了我的示例。 Assuming an existing struct MyObject then to access property “a” or “b” and create a hash for either one I could use the following code:假设现有的 struct MyObject 然后访问属性“a”或“b”并为其中一个创建 hash,我可以使用以下代码:

typedef struct {
   const char *prop_a;
   const char *prop_b;
   struct {
    const char **items;
    int num;
   } names;
}   MyObjectInfo;

typedef MyObjectInfo *MyObject;

MODULE = my_obj            PACKAGE = MyObject    PREFIX = my_obj_

SV *
my_obj_a(o)
   MyObject o

   CODE:
   SV *info = newHV();
   hv_store(info, “a”, 1, newSVpvn(o->prop_a, strlen(o->prop_a)), 0);
   int i;
   for(i = 0; i < o->names.num; i++) {
        const char *n = o->names.items[i];
        hv_store(info, n, strlen(n), newSViv(i), 0);
   }
   RETVAL = sv_2mortal(newrv_noinc(val));
 
   OUTPUT:
   RETVAL

SV *
my_obj_b(o)
   MyObject o

   CODE:
   SV *info = newHV();
   hv_store(info, “b”, 1, newSVpvn(o->prop_b, strlen(o->prop_b)), 0);
   int i;
   for(i = 0; i < o->names.num; i++) {
        const char *n = o->names.items[i];
        hv_store(info, n, strlen(n), newSViv(i), 0);
   }
   RETVAL = sv_2mortal(newrv_noinc(val));
 
   OUTPUT:
   RETVAL

What I want to do is share some of the functionality in a utility function like this我想做的是像这样分享实用程序 function 中的一些功能

SV *create_obj_hash(MyObjectInfo *o, const char *k, const char *p) {
    SV *val = newHV();
    hv_store(val, k, strlen(k), newSVpvn(p, strlen(p)), 0);
    int i;
    for(i = 0; i < o->names.num; i++) {
        const char *n = o->names.items[i];
        hv_store(info, n, strlen(n), newSViv(i), 0);
    }
    return val;
}

MODULE = my_obj            PACKAGE = MyObject    PREFIX = my_obj_

SV *
my_obj_a(o)
   MyObject o

   CODE:
   SV *info = create_obj_hash(o, “a”, o->prop_a);
   RETVAL = sv_2mortal(newrv_noinc(val));
 
   OUTPUT:
   RETVAL

SV *
my_obj_b(o)
   MyObject o

   CODE:
   SV *info = create_obj_hash(o, “b”, o->prop_b);;
   RETVAL = sv_2mortal(newrv_noinc(val));
 
   OUTPUT:
   RETVAL

But, when I do the macro expansion within create_obj_hash() fails with the following messages.但是,当我在 create_obj_hash() 中进行宏扩展时,会出现以下消息。

myobj.xs: In function 'create_obj_hash':
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/perl.h:175:16: error: 'my_perl' undeclared (first use in this function); did you mean 'my_fork'?
 #  define aTHX my_perl
                ^~~~~~~
ppport.h:6145:41: note: in definition of macro 'MUTABLE_PTR'
 #  define MUTABLE_PTR(p) ({ void *_p = (p); _p; })
                                         ^
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/hv.h:651:17: note: in expansion of macro 'MUTABLE_HV'
 #define newHV() MUTABLE_HV(newSV_type(SVt_PVHV))
                 ^~~~~~~~~~
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/perl.h:188:18: note: in expansion of macro 'aTHX'
 #  define aTHX_  aTHX,
                  ^~~~
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/embed.h:532:40: note: in expansion of macro 'aTHX_'
 #define newSV_type(a)  Perl_newSV_type(aTHX_ a)
                                        ^~~~~
/usr/lib/x86_64-linux-gnu/perl/5.28/CORE/hv.h:651:28: note: in expansion of macro 'newSV_type'
 #define newHV() MUTABLE_HV(newSV_type(SVt_PVHV))
                            ^~~~~~~~~~
myobj.xs:42:19: note: in expansion of macro 'newHV'
     return (void*)newHV();

Thank you very much in advance, Brian非常感谢你,布赖恩

First of all, you might be missing some or all of the following:首先,您可能缺少以下部分或全部内容:

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

The main issue is that you aren't providing the context to the API calls.主要问题是您没有为 API 调用提供上下文

Some builds of Perl allow processes to have multiple instances of the interpreter running at once. Perl 的某些版本允许进程同时运行多个解释器实例。 If -Dmultiplicity was used when Perl was created, the build will support this.如果在创建-Dmultiplicity时使用了 -Dmultiplicity,则构建将支持这一点。 (You can check this using perl -V:usemultiplicity .) -Dmultiplicity is implied by -Dusethreads , the option to build a perl with thread support (since an instance of the interpreter is created for each thread). (您可以使用perl -V:usemultiplicity来检查这一点。) -Dmultiplicity隐含在-Dusethreads中,这是构建具有线程支持的perl的选项(因为为每个线程创建了一个解释器实例)。

As such, a large number of Perl API calls require the caller to provide a context ("THX") which identifies the interpreter to use.因此,大量的 Perl API 调用要求调用者提供标识要使用的解释器的上下文(“THX”)。 Think of the interpreter as an object (in the OOP sense of the word), and the context as the invocant.将解释器想象成 object(在 OOP 这个词的意义上),上下文作为调用者。

In XS code, a variable containing the context is automatically created for you.在 XS 代码中,会自动为您创建一个包含上下文的变量。 This variable is automatically passed to Perl API call through the use of macros.此变量通过使用宏自动传递给 Perl API 调用。

#define newSVpvn(a,b) Perl_newSVpvn(aTHX_ a,b)
//                                  ^^^^^
//                      Causes the context to be passed
//                      to Perl_newSVpvn, the real name
//                      of newSVpvn.

As such, you'll need the context to make this work (no matter which of newSVpvn and Perl_newSVpvn you use).因此,您需要上下文来完成这项工作(无论您使用哪一个newSVpvnPerl_newSVpvn )。 To obtain the context, use the following macros:要获取上下文,请使用以下宏:

  • If your function has no parameters besides the context,如果你的 function 除了上下文没有参数,
    • Use pTHX as the first parameter of your function declaration.使用pTHX作为 function 声明的第一个参数。
    • Use aTHX as the first argument in calls to your function.使用aTHX作为调用 function 的第一个参数。
  • If your function has parameters besides the context,如果您的 function 除了上下文之外还有参数,
    • Use pTHX_ as the first parameter of your function declaration.使用pTHX_作为 function 声明的第一个参数。
    • Use aTHX_ as the first argument in calls to your function.使用aTHX_作为调用 function 的第一个参数。

" p " stands for "parameter", " a " stands for "argument", and " _ " represents a comma. p ”代表“参数”,“ a ”代表“参数”,“ _ ”代表逗号。

In your case, you'd use在你的情况下,你会使用

STATIC SV *create_obj_hash(pTHX_ MyObjectInfo *o, const char *k, const char *p) {
#define create_obj_hash(a,b,c) create_obj_hash(aTHX_ a,b,c)
    ...
}

Thanks to the #define , you can continue using感谢#define ,您可以继续使用

SV *info = create_obj_hash(o, "b", o->prop_b);

Untested.未经测试。 Let me know if there are any problems.让我知道是否有任何问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM