【问题标题】:Binding with SWIG - typedef'ed types bound incorrectly使用 SWIG 绑定 - typedef 的类型绑定不正确
【发布时间】:2012-07-22 14:58:50
【问题描述】:

我有这样的 swig.i 文件:

%module ogr_api

%{
#include "ogr_api.h"
%}

%inline %{
typedef void *OGRSFDriverH;
%}

/* OGRSFDriverRegistrar */

OGRDataSourceH OGROpen( const char *, int, OGRSFDriverH * )`

我得到以下 .c 包装器:

...
SWIGEXPORT void * D_OGROpen(char * jarg1, int jarg2, void * jarg3) {
...

即 SWIG 将 OGRSFDriverH 转换为 void*。我需要保存类型名称。我该怎么办?

我在第一个参数中也丢失了 const,但这是下一个问题。

【问题讨论】:

  • 我有点假设您的目标语言是 Java,但在这种情况下,通常在 SWIG 问题中值得一提并不重要,因为某些功能/选项是特定于语言的。
  • 以防万一 - 我的目标语言是 D
  • 也许你应该试试 DStep - github.com/jacob-carlborg/dstep

标签: d typedef swig


【解决方案1】:

假设我正确理解了您的问题,您有许多不透明的“句柄”,在 C 中实际上是 typedefs 到 void*,但在您生成的界面中,您希望强制执行更强的类型检查。 (请注意,此处的默认行为是正确的,因为它允许使用与 C 完全一致的用法)。您想防止将一种句柄意外地提供给采用“不同”void* 的函数,即将typedef 公开为一种strong typedef

您可以使用 SWIG 轻松做到这一点。要记住的关键是您提供给 SWIG 的接口文件并不总是必须与 real C 类型完全匹配,只要最终生成的代码仍然正确且合法。

我举了一个例子来说明这一点。给定一个头文件,这在原理上可能与您的 ogr_api.h 相似:

#include <stdio.h>

typedef void * HandleType1;
typedef void * HandleType2;

void foo(HandleType1) {printf("foo\n");}
void bar(HandleType2) {printf("bar\n");}

您希望只能使用HandleType1 调用foo 和使用HandleType2 调用bar

我使用以下接口来获取此类行为:

%module test

%{
#include "test.h"
%}

%nodefaultctor HandleType1;
struct HandleType1 {};
%nodefaultctor HandleType2;
struct HandleType2 {};

void foo(HandleType1*);
void bar(HandleType2*);

%inline {
  // just for testing - presumably you have a creator in your real API
  HandleType1* geth1() { return NULL; }
  HandleType2* geth2() { return NULL; }
}

由此生成的代码非常好,因为它不会尝试做任何 void* 无法完成的事情,而且它们都被视为包装器中的指针。

需要%nodefaultctor 以防止 SWIG 尝试根据我们告诉它的谎言构造新句柄,否则会出现编译器错误。 (你可能也想抑制析构函数,或者自定义它,因为这将调用free)。

这会生成一个 Java 接口,该接口只允许为每个函数使用正确的句柄。我对此进行了测试:

public class run {
  public static void main(String[] args) {
    System.loadLibrary("test");
    test.foo(test.geth1());
    //test.bar(test.geth1());
    //test.foo(test.geth2());
    test.bar(test.geth2());
  }
}

这有点花招,但它确实有效,看看生成的包装器来说服自己。

按预期编译和运行。如您所愿,注释掉的行会给出错误。


对于特定于 D 的解决方案,我知道 typedef 提供了强大的 typedef(不像 alias 更像 C 中的 typedef)我认为您可以使用类似的东西:

%module test

typedef void * HandleType1;
typedef void * HandleType2;

%pragma(d) proxydmodulecode = %{
  typedef void * HandleType1;
  typedef void * HandleType2;
%}

%typemap(dtype) HandleType1* "HandleType1";
%typemap(dtype) HandleType2* "HandleType2";

void foo(HandleType1* h1);
void bar(HandleType2* h2);

生成你想要的界面。 typemaps修改D接口中使用的类型,%pragmatypedef插入到生成接口的(代理)部分。

【讨论】:

  • 你理解我的问题是对的。我得到了我想要的——强大的类型检查,它工作得很好。但是使用类而不是纯指针会破坏我的代码(我的目标语言是 D)。你能举例说明如何避免在这种情况下使用类吗?
  • 如果您将typedef 保留在imdmodulecode 中,它可能希望成为%typemap(dtype) HandleType1* "$imdodule.HandleType1"; 等。
  • 我更喜欢按照您的建议使用 proxydmodulecode,而不是使用“$imdmodule”,因为之后它需要在任何地方使用模块名称。看来你已经解决了我的问题:) 我得到了我想要的,但我稍后会彻底检查,今天做不到。尽管如此,还是感谢您的帮助!我很感激! )
猜你喜欢
  • 1970-01-01
  • 2013-06-01
  • 2010-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多