似乎CPAN上的一些(很多?)模块部分使用XS在C中实现,并且如果需要可以回退到纯perl实现.虽然这很聪明,但它显然会损害性能,我想知道它发生了所以我可以解决问题.
是否有停止或检测此类后备的一般方法?
有关此行为的示例,请查看(非常方便)Date :: Simple(代码段)
编辑:我已经为此创建了一张票,其中有关于这种做法的替代方案的数据.
我已经更新了代码,试图使用MY_CXT的回调,因为gcxt没有跨线程存储.然而,这个段错误在ENTER.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifndef aTHX_
#define aTHX_
#endif
#ifdef USE_THREADS
#define HAVE_TLS_CONTEXT
#endif
/* For windows */
#ifndef SDL_PERL_DEFINES_H
#define SDL_PERL_DEFINES_H
#ifdef HAVE_TLS_CONTEXT
PerlInterpreter *parent_perl = NULL;
extern PerlInterpreter *parent_perl;
#define GET_TLS_CONTEXT parent_perl = PERL_GET_CONTEXT;
#define ENTER_TLS_CONTEXT \
PerlInterpreter *current_perl = PERL_GET_CONTEXT; \
PERL_SET_CONTEXT(parent_perl); { \
PerlInterpreter *my_perl = parent_perl;
#define LEAVE_TLS_CONTEXT \
} PERL_SET_CONTEXT(current_perl);
#else
#define GET_TLS_CONTEXT /* TLS context not enabled */
#define ENTER_TLS_CONTEXT /* TLS context not enabled …
Run Code Online (Sandbox Code Playgroud) 无论perlcall(在"策略存储回调上下文信息"一节),并延伸和嵌入Perl(以下简称"回调"一节)列出了3点不同的方式来处理从XS/C调用的Perl子例程:
上面针对#3列出的示例和细节使用XS中的散列来将子ref与特定C函数相关联,但是它们预定义了固定数量的C函数,这是不合适的.
我正在使用一个XS接口到一个C库,它使用带有可选参数的回调/函数指针,例如:
blah(custom_type *o, void (*func) (void *data, int more_data), const void * data);
Run Code Online (Sandbox Code Playgroud)
这个库中的C blah将最终调用传递给它的函数以及传入的数据.
如果可能的话,我想将C API的一对一映射到Perl.例如
blah($o, \&func, $data);
Run Code Online (Sandbox Code Playgroud)
目前,我上面有#2,但是另一次调用blah()会覆盖已保存的SV*.
我将如何实施上述#3?
我有一个模块,将针对几种不同的操作系统和配置.有时,一些C代码可以使这个模块的任务更容易一些,所以我有一些C函数,我想绑定代码.我不具备绑定C函数-我不能保证最终用户甚至有一个C编译器,例如,它通常不是优雅地故障转移到完成同样的事情的纯Perl的方式有问题 - 但如果我可以从Perl脚本调用C函数,那就太好了.
还在我这儿?这是另一个棘手的部分.几乎所有的C代码都是特定于系统的 - 为Windows编写的函数不能在Linux上编译,反之亦然,而在Solaris上执行类似操作的函数看起来会完全不同.
#include <some/Windows/headerfile.h>
int foo_for_Windows_c(int a,double b)
{
do_windows_stuff();
return 42;
}
Run Code Online (Sandbox Code Playgroud)
#include <path/to/linux/headerfile.h>
int foo_for_linux_c(int a,double b)
{
do_linux_stuff(7);
return 42;
}
Run Code Online (Sandbox Code Playgroud)
此外,即使对于同一系统的本机代码,也可能只能在任何特定配置上编译其中一些.
#include <some/headerfile/that/might/not/even/exist.h>
int bar_for_solaris_c(int a,double b)
{
call_solaris_library_that_might_be_installed_here(11);
return 19;
}
Run Code Online (Sandbox Code Playgroud)
但理想情况下,我们仍然可以使用可以使用该配置进行编译的C函数.所以我的问题是:
如何有条件地编译C函数(只编译适合当前值的代码$^O
)?
如何单独编译C函数(某些函数可能无法编译,但我们仍然想使用那些函数)?
我可以在构建时(最终用户安装模块时)或在运行时(Inline::C
例如)进行此操作吗?哪种方式更好?
我如何判断哪些函数已成功编译并可从Perl中使用?
所有的想法赞赏!
更新:感谢所有回复的人.所以这就是我做的:
我考虑了一个与语句Inline::C
内部
运行时绑定的方案eval
,但最终确定了子类化Module::Build
和自定义ACTION_build
方法:
my $builderclass = Module::Build->subclass(
class => 'My::Custom::Builder',
code => <<'__CUSTOM_BUILD_CODE__,',
sub ACTION_build {
use File::Copy;
my …
Run Code Online (Sandbox Code Playgroud) 我希望在Perl中嵌入一个C代码.在这个C代码中,我想将一个巨大的文件读入内存,进行一些更改并构建一个哈希(一个自定义的).我希望从我的Perl代码中访问此哈希.可能吗?我怎样才能达到目标?
我知道几乎没有C++,所以没有帮助,而我的XS并没有好多少.我正在为C++库创建一个XS接口,我几乎所有的方法都在工作,除了一个.
Perl中的方法应如下所示:
$return_data = $obj->readPath( $path );
Run Code Online (Sandbox Code Playgroud)
该方法定义为.h文件:
int readPath(const char* path, char* &buffer, bool flag=true);
Run Code Online (Sandbox Code Playgroud)
如果以"NULL"传递,"缓冲区"将被分配.
另外两个版本的readPath具有不同的签名,但它们不是我想要的版本.(有趣的是,当我尝试编译时,它告诉我"候选人"是我不想要的两个.)那是因为它不理解"char*&"吗?
有人可以帮助我需要写的xsub吗?
我在使用Perl 5.14.2.
顺便说一句 - 我还使用了一个类型映射"long long int"到T_IV.我找不到任何关于如何正确键入long long长度的文档.任何建议我应该如何长期打字?
谢谢,
根据perlapi,sv_catpv()
工作原理如下:
将
NUL
-terminated字符串连接到SV中字符串的末尾.如果SV设置了UTF-8状态,则附加的字节应该是有效的UTF-8.处理'获得'魔法,但不是'设置'魔法.
void sv_catpv(SV *const sv, const char* ptr)
sv_catpvs()
不过我发现的大多数XS教程都使用了这个:
喜欢
sv_catpvn
,但是采用文字字符串而不是字符串/长度对.
void sv_catpvs(SV* sv, const char* s)
嗯,这不是很有帮助,所以让我们来看看sv_catpvn()
:
将字符串连接到SV中字符串的末尾.该
len
指示要复制的字节数.如果SV设置了UTF-8状态,则附加的字节应该是有效的UTF-8.处理'获得'魔法,但不是'设置'魔法.
void sv_catpvn(SV *dsv, const char *sstr, STRLEN len)
所以,sv_catpvn
做同样的事情,sv_catpv
只不过它采用的字符串长度作为一个单独的参数,并且sv_catpvs
是一样的sv_catpvn
,只不过它采用的文本字符串.
有有一些细微的差别sv_catpv
和sv_catpvs
我失踪,或者他们只是两种方法做同样的事情?
我想在我的 C 代码 (XS) 中使用 Perl 哈希作为一个集合,所以我只需要在哈希中保留键。是否可以存储 null 或其他常量值之类的内容以避免创建不必要的值?
像这样的东西:
int add_value(HV *hash, SV *value)
{
// just an example of key
char key[64];
sprintf(key, "%p", value);
if (hv_exists(hash, key, strlen(key)) return 0;
// here I need something instead of ?
return hv_stores(hash, key, ?) != NULL;
}
Run Code Online (Sandbox Code Playgroud)
可能的解决方案之一可能是存储值本身,但可能有特殊的常量 forundef
或 null。
我是Perl XS的新手.
我的简单测试函数获取一个字符串并附加一些内容.在Perl中是一个标量字符串输入和输出.
在函数中我有一个malloc.什么是正确的释放mem的方法?
SV *foo (str)
SV *str
CODE:
unsigned char *strbuf;
size_t strlen;
strbuf = (unsigned char *) SvPV (str, strlen);
int n = strlen + 10;
unsigned char *buf = malloc (n);
strncpy (buf, strbuf, strlen);
strncat (buf, "0123456789", 10);
RETVAL = newSVpv (buf, n);
OUTPUT:
RETVAL
Run Code Online (Sandbox Code Playgroud)
谢谢!克里斯
当Devel::Peek
我倾倒perl SV时,我可以看到:
SV = IV(0x1c13168) at 0x1c13178
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 2
Run Code Online (Sandbox Code Playgroud)
但找不到描述是什么pIOK
意思.
我想看看它在Devel::Peek
,perlapi
,perlguts
,perlxs
...在来源,我发现:
{SVp_IOK, "pIOK,"}
Run Code Online (Sandbox Code Playgroud)
但还是找不到什么SVp_IOK
.它是什么?
UPD
我找到了这个文件.它揭示了旗帜的含义以及它们所处的位置.(要小心这个DOC已经过时了)
此标志指示对象具有有效的非公共IVX字段值.它只能为值类型SvIV或其子类型设置.
UPD