首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用SWIG创建java共享库时出现SIGSEGV错误

使用SWIG创建java共享库时出现SIGSEGV错误
EN

Stack Overflow用户
提问于 2013-01-19 21:17:59
回答 2查看 1.1K关注 0票数 3

因此,我正在尝试使用SWIG将一个C库(libnfc)移植到Java。

我已经有了一个编译好的共享库,一个基本的"nfc_version()“方法调用就可以工作了。但是,调用"nfc_init()“来设置会导致SIGSEGV错误。直接调用nfc库就可以了。

我用来生成共享库的命令:

代码语言:javascript
复制
swig -java -I../libnfc/include nfclib.i 
gcc -c -I/usr/lib/jvm/java-7-openjdk-i386/include/ -I/usr/lib/jvm/java-7-openjdk-i386/include/linux nfclib_wrap.c
gcc -shared nfclib_wrap.o ../build/libnfc/libnfc.so libnfc_wrap.so

libnfc.i文件:

代码语言:javascript
复制
%module nfc
%{
#include <nfc/nfc.h>
#include <nfc/nfc-types.h>
#include <nfc/nfc-emulation.h>
%}

%include <nfc/nfc.h>
%include <nfc/nfc-types.h>
%include <nfc/nfc-emulation.h>

也就是说,它应该包含libnfc提供的所有方法。

下面是我得到的错误日志:http://openetherpad.org/AyVDsO4XTg

显然,可能无法从我提供的信息中获得特定的解决方案。但是,任何可以尝试的建议都会非常感谢(我在这里的知识已经到了尽头)。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-01-21 02:33:06

总是自动将相同的指针传递给函数,这在SWIG中是相当简单的。例如,给定“头”文件test.h,它捕获了问题的核心部分:

代码语言:javascript
复制
struct context; // only used for pointers

void init_context(struct context **ctx) { *ctx=malloc(1); printf("Init: %p\n", *ctx); }
void release_context(struct context *ctx) { printf("Delete: %p\n", ctx); free(ctx); }

void foo(struct context *ctx) { printf("foo: %p\n", ctx); }

我们可以包装它,并自动将全局上下文传递到任何需要传入的地方,方法如下:

代码语言:javascript
复制
%module test

%{
#include "test.h"

// this code gets put in the generated C output from SWIG, but not wrapped:
static struct context *get_global_ctx() {
  static struct context *ctx = NULL;
  if (!ctx) 
    init_context(&ctx);
  return ctx;
}
%}

%typemap(in,numinputs=0) struct context *ctx "$1=get_global_ctx();"

%ignore init_context; // redundant since we call it automatically

%include "test.h"

这为struct context *ctx设置了一个类型映射,它不是从Java获取输入,而是在匹配的任何地方自动调用get_global_ctx()

这可能足以让Java开发人员使用一个合理的界面,但这并不理想:它强制上下文是全局的,这意味着任何Java应用程序都不能同时使用多个上下文。

考虑到Java是一种面向对象的语言,一种更好的解决方案是使上下文成为第一类对象。我们也可以让SWIG为我们生成这样一个界面,尽管它有点复杂。我们的SWIG模块文件变成:

代码语言:javascript
复制
%module test

%{
#include "test.h"
%}

// These get called automatically, no need to expose:
%ignore init_context;
%ignore delete_context;

// Fake struct to convince SWIG it should be an object:
struct context {
  %extend {
    context() {
      // Constructor that gets called when this object is created from Java:
      struct context *ret = NULL;
      init_context(&ret); 
      return ret;
    }
    ~context() {
      release_context($self);
    }
  }
};

%include "test.h"

我们可以成功地执行这段代码:

代码语言:javascript
复制
public class run {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    context ctx = new context();
    // You can't count on the finalizer if it exits:
    ctx.delete();
    ctx = null;
    // System.gc() might also do the trick and in a longer
    // running app it would happen at some point probably.
  }
}

提供:

代码语言:javascript
复制
Init: 0xb66dab40
Delete: 0xb66dab40

在动态类型语言中,这将是完成困难的部分-我们可以使用一种或另一种形式的元编程来根据需要插入成员函数。因此,我们可以完全按照预期说出类似于new context().foo();的内容。Java是静态类型的,所以我们需要更多的东西。我们可以通过多种方式在SWIG中做到这一点:

  1. 接受我们现在可以非常愉快地调用test.foo(new context());了-它看起来仍然很像Java语言中的C,所以我建议如果你最终编写了很多看起来像C的Java语言,那么它可能是一种代码味道。
  2. 使用%extend (手动)将方法添加到context类中,test.i中的%extend变成:

%extend { context() { //从Java创建此对象时调用的构造函数: struct context *ret = NULL;init_context(&ret);return ret;} ~context() { release_context($self);} void foo() { foo($self);}}

  • %extend一样,但使用类型映射在Java端编写粘合剂:

%typemap(javacode)结构上下文%{ public void foo() { $module.foo(this);} %}

(注意:这需要在接口文件中足够早才能工作)

请注意,我在这里没有展示我的上下文结构的真实定义-它总是遵循我的“库”,任何需要真实定义的地方,因此不透明的指针仍然是完全不透明的。

使用双指针包装init_context的一个更简单的解决方案是使用%inline提供一个仅在包装器中使用的额外函数:

代码语言:javascript
复制
%module test

%{
#include "test.h"
%}

%inline %{
  struct context* make_context() {
    struct context *ctx;
    init_context(&ctx);
    return ctx;
  }
%}

%ignore init_context;

%include "test.h"

足以让我们编写以下Java代码:

代码语言:javascript
复制
public class run {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    // This object behaves exactly like an opaque pointer in C:
    SWIGTYPE_p_context ctx = test.make_context();
    test.foo(ctx);
    // Important otherwise it will leak, exactly like C
    test.release_context(ctx);
  }
}

另一种方法,但类似的方法包括使用cpointer.i library

代码语言:javascript
复制
%module test

%{
#include "test.h"
%}

%include <cpointer.i>

%pointer_functions(struct context *,context_ptr);

%include "test.h"

然后,您可以将其用作:

代码语言:javascript
复制
public class run {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    SWIGTYPE_p_p_context ctx_ptr = test.new_context_ptr();
    test.init_context(ctx_ptr);
    SWIGTYPE_p_context ctx = test.context_ptr_value(ctx_ptr);
    // Don't leak the pointer to pointer, the thing it points at is untouched
    test.delete_context_ptr(ctx_ptr);
    test.foo(ctx);
    // Important otherwise it will leak, exactly like C
    test.release_context(ctx);
  }
}

还有一个pointer_class宏,它比这个更面向对象,可能更值得使用。但重点是,您提供了使用不透明指针对象的工具,SWIG使用这些对象来表示它一无所知的指针,但避免了getCPtr()调用,因为这些调用本身就会破坏类型系统。

票数 5
EN

Stack Overflow用户

发布于 2013-01-24 06:52:24

所以Flexo的答案是解决这个问题的正确方法,但SWIG还提供了"cpointer.i“模块(在这里描述:http://www.swig.org/Doc1.3/SWIGDocumentation.html#Library_nn3),它允许我快速组合出一个解决方案,这样我就可以测试我的基本库是否正常工作。为了完整起见,我想我会给出这个答案,并为遇到这个问题的任何人提供一个替代方案。

之所以需要这样做,是因为我会将SWIG生成的内容描述为不对称。基类型对象有一个属性swigCPtr,它是该对象的内存地址(“自身指针”)。然后,要创建指针,只需从基类型获取swigCptr,并将其传递到swig生成的指针类型(SWIGTYPE_p_X)的构造函数中。但是指针类型只存在于Java语言中,并且只保存swigCptr的值。没有保存该指针的'c‘内存块。因此,在指针类型中没有swigCPtr的等价物。也就是说,指针类型中没有存储自指针,就像基类型中存储了自指针一样。

所以你不能让一个指针指向一个指针(SWIGTYPE_p_p_X),因为在构造它的时候,你没有指针的地址来传递它。

我的新'.i‘文件如下所示:

代码语言:javascript
复制
%module nfc
%{
#include <nfc/nfc.h>
#include <nfc/nfc-types.h>
#include <nfc/nfc-emulation.h>
%}

%include <nfc/nfc.h>
%include <nfc/nfc-types.h>
%include <nfc/nfc-emulation.h>

%include "cpointer.i"
%pointer_functions(nfc_context*, SWIGTYPE_p_p_nfc_context)

最后一个宏的作用是提供4/5的函数来制作指针。这些函数都接受并返回swig应该已经生成的类型。Java中让nfc_init和nfc_open命令工作的新用法:

代码语言:javascript
复制
SWIGTYPE_p_p_nfc_context context_p_p = nfc.new_SWIGTYPE_p_p_nfc_context();
nfc.nfc_init(context_p_p);
//get the context pointer after init has set it up (the java doesn't represent what's happening in the c) 
SWIGTYPE_p_nfc_context context_p = nfc.SWIGTYPE_p_p_nfc_context_value(context_p_p);
SWIGTYPE_p_nfc_device pnd = nfc.nfc_open(context_p, null);

请注意,我必须在init命令完成后从双指针中获取指针,因为存储在java指针对象中的信息与C 'world‘是分开的。因此,检索context_p_p的“值”将给出一个具有正确指针值的context_p。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14414779

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档