SWIG typedef - Perl 数组

Posted

技术标签:

【中文标题】SWIG typedef - Perl 数组【英文标题】:SWIG typedef - Perl array 【发布时间】:2016-10-04 16:54:22 【问题描述】:

我有一个 SWIG 文件来为语言进行许多绑定。 C源码中有一个变量,它是一个定长列表,整数类型。当我在 Perl 中访问它时,它没有任何项目 - 只是表明它是一个 ARRAY。

Python 中也存在同样的问题,但我可以使用 SWIG 类型映射解决该问题:

#ifdef SWIGPYTHON
%typemap(out) int [ANY] 
   ...

好的,我想用 Perl 再做一次——但我不是 Perl 专家,所以我可以为 Perl 修复这个类型映射。这是我尝试的:

#ifdef SWIGPERL
%typemap(out) int [ANY] 
    SV* sv = newSV(0);
    AV* av = (AV *)sv_2mortal((SV *)newAV());
    int i = 0,len = 0;
    printf("len: %d\n", $1_dim0);
    len = $1_dim0;

    for (i = 0; i < len ; i++) 
        SV* perlval = newSV(0);
        sv_setiv(perlval, (IV)$1[i]);
        av_push(av, perlval);
    
    SvSetSV($result, newRV_noinc((SV *)av));

#endif

perl 脚本在运行时显示“len: 10”,但数组为空:

$i=1;
foreach(@m) 
    print $i, "'", $_, "'\n";
    $i=$i+1;

结果是:

0''

我错过了什么?

谢谢,

一个。

编辑:这是 Perl 脚本:

#!/usr/bin/perl

use example1;

# this function set up the built-in list in example1 module
example1::get_att(7);
my @m = $example1::m->ilist;

# "m" is a C structure in C source, and it has an "int ilist[10];" member.
# get_att(int n) will fill this list with "n" number
# This will be accesable in binded lanugage (eg in Python) as like this:
# print m.ilist  -> [0, 3, 6, 9, 12, 15, 18, 0, 0, 0]
$i = 0;
foreach(@m) 
    print $i, "'", $_, "'\n";
    $i=$i+1;

现在,这个脚本产生了这个结果:

len: 10
0''

“len: 10”输出来自 SWIG typedef - 请参阅“printf("len: %d..." 行...

【问题讨论】:

我已经完成了帖子 - 请参阅“编辑”部分。你还需要什么? Crossposted. 是的,这是交叉发布的 - 是否有任何论坛/邮件列表列表,取决于 ***,并将标记为交叉发布?我认为 SO 和 Perlmonks 是两个不同的地方。无论如何,我为crosspost道歉,对不起。 【参考方案1】:

我以前没有使用过 SWIG,但我认为了解它可能会很有趣。在阅读了几个小时的documentation 之后,我想我可能已经找到了可以解决您问题的东西。首先我们需要接口文件example.i

%module example

%typemap(out) int [ANY] 
    AV* av = newAV();
    int i = 0,len = 0;
    len = $1_dim0;

    for (i = 0; i < len ; i++) 
        SV* perlval = newSV(0);
        sv_setiv(perlval, (IV)$1[i]);
        av_push(av, perlval);
    
    $result = newRV_noinc((SV*) av );
    sv_2mortal( $result );
    argvi++;


%typemap(in) int [ANY] 
  AV *tempav;
  I32 len;
  int i;
  SV  **tv;
  if (!SvROK($input))
    croak("Argument $argnum is not a reference.");
  if (SvTYPE(SvRV($input)) != SVt_PVAV)
    croak("Argument $argnum is not an array.");
  tempav = (AV*)SvRV($input);
  len = av_len(tempav);
  $1 = (int *) malloc((len+1)*sizeof(int));
  for (i = 0; i <= len; i++) 
    tv = av_fetch(tempav, i, 0);
    $1[i] = (int) SvIV(*tv);
  


%typemap(freearg) int * 
  free($1);


%typemap(memberin) int [ANY] 
  int i;
  for (i = 0; i < $1_dim0; i++) 
      $1[i] = $input[i];
  


%inline %

struct m 
    int ilist[3];
;

%

然后我们需要创建一个Perl脚本来测试example::m包:

use feature qw(say);
use strict;
use warnings;

use example;

my $m = example::m->new();
$m->ilist = [1, 2, 3];
my $list = $m->ilist;

my $i = 0;
for ( @$list ) 
    say "$i: '$_'";
    $i=$i+1;

现在的输出是(编译接口文件并运行 Perl 脚本之后):

0: '1'
1: '2'
2: '3'

注意

我首先使用

安装了 SWIG 3.0.8(在 Ubuntu 16.04 上)
$ sudo apt-get install swig

然后我编译了接口文件example.i使用:

$ swig -perl5 example.i
$ gcc -fpic -c -Dbool=char -D_GNU_SOURCE \ 
   -I/usr/lib/x86_64-linux-gnu/perl/5.22/CORE example_wrap.c
$ gcc -shared example.o example_wrap.o -o example.so

【讨论】:

嗨,Håkon,非常感谢您的帮助。看起来我的 SWIG 文件、类型映射和除 Perl 文件之外的所有组件都是正确的。我不是 Perl 大师(我真的不了解 Perl),我只是搞砸了数组的分配和遍历 - 请参阅此处的 Perl 脚本:perlmonks.org/?node_id=1164929。再次感谢!

以上是关于SWIG typedef - Perl 数组的主要内容,如果未能解决你的问题,请参考以下文章

Typedef、Ruby 和 SWIG

SWIG 无法正确转换 typedef 类型

使用 swig 包装时避免“未使用的 typedef”警告

使用 SWIG 在 Python 中访问 C++ typedef

为啥 SWIG 需要辅助函数来处理数组?

如何在 Perl 中使用 SWIG?