使用SWIG生成的JNI代码调用C结构的函数指针

时间:2019-02-21 22:07:05

标签: java function-pointers swig

TL; DR :查看this repo并阅读自述文件中的说明。

我想使用SWIG生成JNI代码,以与具有结构体(函数指针)的C库进行接口连接。函数指针指向的函数是在C库中定义的,因此我只希望能够从Java代码中调用它。下面是更多详细信息。

假设我在文件database.c中定义了一个C结构和相关代码:

#include <string.h>
#include <stdlib.h>

struct MyDatabase;
typedef struct MyDatabase MyDatabase;

typedef int (*SomeFuncPtr)(const char *name);

struct MyDatabase {
  char *name;
  SomeFuncPtr fPtr;
};

int myFunc(const char *name) {
  return strlen(name);
};

struct MyDatabase *new_database(char *name) {
  MyDatabase *myDB = malloc(sizeof(struct MyDatabase));
  myDB->name = strdup(name);
  myDB->fPtr = &myFunc;

  return myDB;
};

附带的标题database.h如下所示:

struct MyDatabase;
typedef struct MyDatabase MyDatabase;

typedef int (*SomeFuncPtr)(const char *name);

struct MyDatabase {
  char *name;
  SomeFuncPtr fPtr;
};

struct MyDatabase *new_database(char *name);

我有一个SWIG接口文件database_swig.i,看起来像这样:

%module database

%{
#include "database.h"
%}

%nodefaultctor MyDatabase;
%nodefaultdtor MyDatabase;

%include "database.h"

%include "cpointer.i"
%pointer_functions(MyDatabase, MyDatabaseHandle)

生成的代码面临两个问题:

  1. 我不确定如何使用定义为SomeFuncPtr fPtr;一部分的函数指针struct MyDatabase

SWIG生成的JNI代码允许我执行以下操作:

SWIGTYPE_p_MyDatabase myDBPtr = database.new_database("testing");
MyDatabase myDB = database.MyDatabaseHandle_value(myDBPtr);

myDB.getFPtr("hello"); // doesn't work - says that no arguments are expected

SWIGTYPE_p_f_p_q_const__char__int myFunc = myDB.getFPtr();
myFunc("hello"); // error about "Method call expected"

但是涉及到getFPtr的两个调用都导致错误,如上面代码中的注释中所述。

  1. %pointer_functions(MyDatabase, MyDatabaseHandle)生成的SWIG生成的JNI粘合代码导致:
public static SWIGTYPE_p_MyDatabase MyDatabaseHandle_value(SWIGTYPE_p_MyDatabase obj) {
  return new SWIGTYPE_p_MyDatabase(databaseJNI.MyDatabaseHandle_value(SWIGTYPE_p_MyDatabase.getCPtr(obj)), true);
}

当我真的想要类似的东西时:

public static MyDatabase MyDatabaseHandle_value(SWIGTYPE_p_MyDatabase obj) {
  return new MyDatabase(databaseJNI.MyDatabaseHandle_value(SWIGTYPE_p_MyDatabase.getCPtr(obj)), true);
}

这是我在提交给仓库linked to above的代码中手动对其进行编辑的内容。

this question中描述了与上述第二个问题非常相似的事物。


更新

我发现this answer使用database.h中的以下内容帮助我完成了工作:

#ifdef SWIG
#define MEMBER(name, args) name args
#else
#define MEMBER(name, args) (*name) args
#endif

struct MyDatabase {
  char *name;
  int MEMBER(fPtr,(const char *));
};

这有效,但理想情况下,我希望能够将typedef用作函数指针typedef int (*SomeFuncPtr)(const char *name);

关于如何使它起作用的任何想法?

0 个答案:

没有答案