SWIG:映射 typedef 的数组

Posted

技术标签:

【中文标题】SWIG:映射 typedef 的数组【英文标题】:SWIG: Mapping an array of a typedef 【发布时间】:2015-09-21 03:04:01 【问题描述】:

我正在使用 SWIG 为一些 C++ 类创建一个 Ruby Wrapper。这是给我带来麻烦的 C++ 方法的签名:

virtual LogP wordProb(VocabIndex word, const VocabIndex *context);

这是 VocabIndex 的定义:

#ifdef USE_SHORT_VOCAB
typedef unsigned short  VocabIndex;
#else
typedef unsigned int    VocabIndex;
#endif

这是我从 Ruby 脚本中调用它的方式:

index = 8
context = [index]
puts ngram.wordProb(index, context)

这是我在运行脚本时遇到的错误:

ngram.rb:26:in `wordProb': Expected argument 2 of type VocabIndex const *, but got Array [8] (TypeError)
    in SWIG method 'wordProb'
    from ngram.rb:26:in `<main>'

我尝试的解决方案

在阅读了docs(是的,我使用的是 SWIG 2.0)之后,我在我的 .i 文件中尝试了这个:

%module rubylm

%
#include "srilm-1.7.1/lm/src/Ngram.h"
%

%include "srilm-1.7.1/lm/src/Counts.h"
%include "srilm-1.7.1/lm/src/Ngram.h"
%include "typemaps.i"

virtual LogP Ngram::wordProb(VocabIndex word, const VocabIndex *INPUT);

swig 命令运行良好,但是当我尝试构建包装库时,我得到了这个:

NgramWrapper_wrap.cxx:148:17: fatal error: tcl.h: No such file or directory
 #include <tcl.h>

所以我启动了一个终端(这是一个 Ubuntu 机器)并运行:

sudo apt-get install tcl-dev

这安装了 tcl 8.6,它将其头文件放在 /usr/include/tcl8.6 目录中。所以我在构建 NgramWrapper_wrap.o 的 Makefile 行中添加了包含目录:

NgramWrapper_wrap.o: NgramWrapper_wrap.cxx
    $(CC) $(CFLAGS) NgramWrapper_wrap.cxx -I $(RUBY_SRC) -I $(MISC_INCLUDE) -I $(DSTRUCT_INCLUDE) -I /usr/include/tcl8.6

但是,我仍然遇到构建错误。这就是我被难住的地方:

NgramWrapper_wrap.cxx:10812:34: error: ‘RARRAY_LEN’ was not declared in this scope
     int size = RARRAY_LEN(objv[3]); 
                                  ^
NgramWrapper_wrap.cxx:10816:5: error: ‘VALUE’ was not declared in this scope
     VALUE *ptr = RARRAY_PTR(objv[3]);
     ^
NgramWrapper_wrap.cxx:10816:12: error: ‘ptr’ was not declared in this scope
     VALUE *ptr = RARRAY_PTR(objv[3]);
            ^
NgramWrapper_wrap.cxx:10816:36: error: ‘RARRAY_PTR’ was not declared in this scope
     VALUE *ptr = RARRAY_PTR(objv[3]);
                                    ^
NgramWrapper_wrap.cxx:10819:35: error: ‘StringValuePtr’ was not declared in this scope
       arg3[i]= StringValuePtr(*ptr); 
                                   ^
NgramWrapper_wrap.cxx: In function ‘int _wrap_NgramCountWrapper_run(ClientData, Tcl_Interp*, int, Tcl_Obj* const*)’:
NgramWrapper_wrap.cxx:10908:34: error: ‘RARRAY_LEN’ was not declared in this scope
     int size = RARRAY_LEN(objv[3]); 
                                  ^
NgramWrapper_wrap.cxx:10912:5: error: ‘VALUE’ was not declared in this scope
     VALUE *ptr = RARRAY_PTR(objv[3]);
     ^
NgramWrapper_wrap.cxx:10912:12: error: ‘ptr’ was not declared in this scope
     VALUE *ptr = RARRAY_PTR(objv[3]);
            ^
NgramWrapper_wrap.cxx:10912:36: error: ‘RARRAY_PTR’ was not declared in this scope
     VALUE *ptr = RARRAY_PTR(objv[3]);
                                    ^
NgramWrapper_wrap.cxx:10915:35: error: ‘StringValuePtr’ was not declared in this scope
       arg3[i]= StringValuePtr(*ptr); 

我能想到的只是 Ruby、Swig 和 Tcl 之间的一些版本不匹配。但是我怎么知道要使用哪个 Tcl 版本呢?我搜索了文档无济于事...

【问题讨论】:

Carrays.i 是快速解决方案:swig.org/Doc2.0/Library.html#Library_carrays 对 ruby​​ 的了解比我还多,你可以做一些更聪明的事情。 如果我尝试使用 carrays.i,我会遇到与尝试使用 typemaps.i 时相同的构建错误。我的 Ruby-Swig-Tcl 组合出了点问题。我现在能想到的就是降级 Tcl。会试试的。 【参考方案1】:

嗯。

我刚刚做了以下

人声.i

%module rubylm

%
#include "Ngram.h"
%

%include "Ngram.h"
%include "typemaps.i"

virtual LogP Ngram::wordProb(VocabIndex word, const VocabIndex *INPUT);

Ngram.h

#pragma once

#ifdef USE_SHORT_VOCAB
typedef unsigned short  VocabIndex;
#else
typedef unsigned int    VocabIndex;
#endif

typedef int LogP;

class NGram 
 public:
  LogP wordProb(VocabIndex word, const VocabIndex *context);
;

执行的命令

swig2.0 -ruby -c++ vocal.i

紧随其后

g++ -c vocal_wrap.cxx -I/usr/include/ruby-2.1.0 -I/usr/include/x86_64-linux-gnu/ruby-2.1.0

没有任何错误。你忘了 -c++ 选项吗,为什么需要 tcl.h

【讨论】:

当我 %include typemaps.icarrays.i 时出现 Tcl 依赖。如果我查看生成的代码,就在开头有这一行:#define SWIGTCL。 -c++ 选项一直存在,我使用的是 Makefile。顺便说一句,您使用的是 ruby​​ 2.1.0,而我使用的是 1.9.3。这可能是个问题吗? 也许吧。我想我会浏览包含的标题,看看是否缺少一些定义。请记住 SWIG 不会递归标头。也可能是包含了错误的 typemaps.i。 @dario_ramos 我在生成的代码中没有得到#define SWIGTCL。我认为可能包含的typemaps.icarrays.i 是错误的。您正在为 Ruby 包装代码 我有办法检查吗?或者也许在 %include 指令中使用绝对路径...我会试试的 还要验证参数 -ruby 是否传递给 SWIG 而不是 -tcl。还要检查 swig 目录中 ruby​​ 文件夹中的 typemaps.i 是否正确。

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

Typedef、Ruby 和 SWIG

SWIG 无法正确转换 typedef 类型

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

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

SWIG:没有定义类型映射

如何定义 swig 类型映射以将 unsigned char* 返回到 java