当前位置: 首页 > 面试题库 >

使用SWIG制作Java共享库时发生SIGSEGV错误

宋华美
2023-03-14
问题内容

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

我已经准备好编译共享库,并且基本的“ nfc_version()”方法调用将起作用。但是,调用“
nfc_init()”进行设置会导致SIGSEGV错误。直接调用nfc库就可以了。

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

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文件:

%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

显然,根据我提供的信息,可能无法使用特定的解决方案。但是,对任何尝试的建议都将不胜感激(在这里,我的知识还算够用)。


问题答案:

要始终自动将同一指针传递给函数,在SWIG中非常简单。例如,给定“头”文件test.h,它捕获了问题的核心部分:

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); }

我们可以包装它,并通过执行以下操作自动将全局上下文传递到期望的任何地方:

%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是一种OO语言,一种更好的解决方案是使上下文成为一流的Object。我们也可以让SWIG为我们生成这样的接口,尽管它有些复杂。我们的SWIG模块文件变为:

%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"

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

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.
  }
}

给出:

Init: 0xb66dab40
Delete: 0xb66dab40

在动态类型的语言中,这将是困难的部分-我们可以根据需要使用一种形式或另一种形式的元编程来插入成员函数。这样我们就能说出new context().foo();完全像预期的那样。尽管Java是静态类型的,所以我们还需要更多。我们可以通过多种方式在SWIG中进行此操作:

  1. 接受我们现在可以test.foo(new context());很开心地调用-尽管它仍然看起来很像Java中的C,所以如果您最终编写了很多看起来像C的Java,我建议它可能是一种代码味道。

  2. 使用%extend至(手动地)添加方法进上下文类,则%extend在test.i变为:

    %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);
    }
    void foo() {
      foo($self);
    }
    

    }

  3. 与一样%extend,但是使用typemap在Java端写胶水:

    %typemap(javacode) struct context %{
    

    public void foo() {
    $module.foo(this);
    }
    %}

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

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

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

%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:

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库:

%module test

%{
#include "test.h"
%}

%include <cpointer.i>

%pointer_functions(struct context *,context_ptr);

%include "test.h"

然后可以将其用作:

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()本质上颠覆类型系统的调用。



 类似资料:
  • 我有一个Jenkins文件,我正在尝试从共享库实例化groovy类。我得到“无法解决类测试” 我有一个src/com/org/foo。共享库中的groovy文件: 我正试图在我的Jenkins文件中实例化它 如果我将文件作为一个类引用(我没有对其构造函数的访问权限),那么它就会起作用。即: 这很好,让我使用foo函数。但是,我失去了赋予类常量并用参数构造它的能力。 知道如何定义和使用共享库中的类吗

  • 我有一个CMACE项目,它的下一个结构是: 输出树为: 如果我在linux下编译程序,所有的工作都很完美,但是当我在Windows下做的时候,编译很好,但是app.exe不执行;我得到下一个错误: 我怀疑不要链接internal.cpp,因为当我将它的过程移到internal.h中时,就可以很好地工作。 有什么需要帮忙的吗? 以下是文件:root::cmakelists.txt app::cmak

  • 问题内容: 我正在使用SWIG制作C 库的Java包装器(关于Json(反)序列化),以便在Android上使用它。我用C 定义了一个抽象类,代表一个可以(反序列化)的对象: 现在,我正在尝试从此类生成Java接口。这是我的SWIG界面: 但是生成的Java代码(显然是,因为我无法找出如何告诉SWIG这是一个接口)是一个简单的类,带有两个方法和一个默认的构造函数/析构函数: 如何使用SWIG生成有

  • 我通过jenkins管道(共享库)运行此代码。 它在本地工作,但在Jenkins管道中,我得到以下错误: 请帮帮我

  • 问题内容: 两个共享库liba.so和libb.so。liba.so使用libb.so。所有c文件都使用-fPIC编译。链接使用- shared。当我们在liba.so上调用dlopen时,它无法在libb.so中找到符号…我们得到“未定义符号”错误。我们可以dlopen libb.so没有错误。我们知道liba正在找到libb,因为我们没有得到文件未找到错误。删除libb.so时,出现文件未找到

  • 问题内容: 我正在做centos。我在系统上安装了1.45.0 Boost版本。程序已正确编译,但是每当我键入命令以查看输出时,就会出现以下错误: ./a.out:加载共享库时出错:libboost_thread.so.1.45.0:无法打开共享库文件:没有此类文件或目录 问题答案: 您是如何安装Boost库的? 您可能遇到的问题是链接器找不到库,并且在构建程序时,必须手动指定其他库路径来搜索库。