Используйте сгенерированный SWIG код JNI для вызова указателя функции структуры C - PullRequest
0 голосов
/ 22 февраля 2019

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)

Есть две проблемы, с которыми я сталкиваюсь с сгенерированным кодом:

  1. Я не уверен, как использовать указатель функции 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);.

Есть идеи, как заставить это работать?

...