TL; DR : посмотрите на этот репо и прочитайте описание в README.
Я хочу использовать SWIG для генерации кода JNI для взаимодействия сБиблиотека C, которая имеет структуру с членом, который является указателем на функцию.Функция, на которую указывает указатель функции, определена в библиотеке C, поэтому я просто хочу иметь возможность вызывать ее из своего кода Java.Подробнее см. Ниже.
Скажем, у меня есть структура C и связанный с ней код, определенный в файле, database.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)
Есть две проблемы, с которыми я сталкиваюсь с сгенерированным кодом:
- Я не уверен, как использовать указатель функции
SomeFuncPtr fPtr;
, определенный как часть struct MyDatabase
.
Код JNI, сгенерированный SWIG, позволяет мне:
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
приводят к ошибке, как отмечено в комментариях к коду выше.
SWIG-сгенерированный код JNI-клея, сгенерированный для
%pointer_functions(MyDatabase, MyDatabaseHandle)
, приводит к:
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);
}
, что ямы вручную отредактировали его в коде, прикрепленном к репо , связанному с указанным выше .
Что-то очень похожее на вторую проблему, перечисленную выше, описано в этот вопрос .
ОБНОВЛЕНИЕ :
Я нашел этот ответ , который помог мне заставить что-то работать, используя следующее в 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);
.
Есть идеи, как заставить это работать?