Конфигурация SWIG для обработки входного параметра FILE * C в Java - PullRequest
1 голос
/ 30 ноября 2011

Как бы вы настроили SWI-файл .i для обработки типа C FILE *?Приведенная ниже функция устанавливает файл так, чтобы в него можно было записывать вывод журнала.Мне нужно позвонить, если из класса Java.В настоящее время SWIG генерирует открытую статическую функцию void setLogFile (SWIGTYPE_p_FILE fd), когда я просто включаю заголовочный файл C в функцию ниже.Есть идеи?

C Функция:

void setLogFile(FILE *fd);

Я попытался # 1, используя приведенное ниже, и получил следующее исключение:

test.i:

%module Example
%{
#include "headerLogFile.h"
%}

%inline %{
void setLogFile(const char *fn) {
  FILE *f = fopen(fn, "w");
  setLogFile(f);
}
%}
%ignore setLogFile; 
%include "headerLogFile.h"

Исключение:

[exec] test_wrap.c:193: error: conflicting types for 'setLogFile'
[exec] /test/include/headerLogFile.h:96: error: previous declaration of 'setLogFile' was here
[exec] test_wrap.c: In function `setLogFile':
[exec] test_wrap.c:195: warning: passing arg 1 of `setLogFile' from incompatible pointer type

1 Ответ

2 голосов
/ 30 ноября 2011

Учитывая test.h, который выглядит так:

#include <stdio.h>

inline void setLogFile(FILE *fd) {
  fprintf(fd, "Test\n");
  fflush(fd);
}

Я вижу три подхода, которые вы могли бы выбрать, чтобы обернуть эту функцию:

Метод 1 - Передача String из Java:

Предоставьте Java функцию, которая ожидает, что имя файла передается как String, а не FILE*:

%module method1

%{
#include "test.h"
%}

%inline %{
void setLogFile(const char *fn) {
  FILE *f = fopen(fn, "w");
  setLogFile(f);
}
%}

Используется %inline, чтобы дать команду SWIG обернуть эту функцию одновременно с ее определением. Если вы по-прежнему используете %include "test.h", возможно, вы захотите скрыть оригинальную версию от SWIG .


Метод 2 - Оберните больше stdio.h:

Оберните больше, чем просто setLogFile, оберните вещи как fopen, fmemopen и т. Д. В зависимости от ситуации. (Мне не очень нравится это решение, поэтому я не стал примером для него)


Метод 3 - Предоставьте интерфейс Java, который принимает FileOutputStream:

%module method3

%{
#include "test.h"
#include <cassert>
%}

// 3:
%typemap(jni) FILE *fd "jobject"
// 1:
%typemap(jstype) FILE *fd "java.io.FileOutputStream"
// 2:
%typemap(jtype) FILE *fd "java.io.FileDescriptor"
// 4:
%typemap(in) (FILE *fd) {
  jfieldID field_fd;
  jclass class_fdesc;
  int rawfd;
  class_fdesc = jenv->FindClass("java/io/FileDescriptor");
  assert(class_fdesc);
  field_fd = jenv->GetFieldID(class_fdesc, "fd", "I");
  assert(field_fd);
  rawfd = jenv->GetIntField($input, field_fd);
  $1 = fdopen(rawfd, "w");
  // Add some code to throw a Java exception if $1 is NULL (i.e. error)
}
// 5: 
%typemap(javain, pre="    retainFD = $javainput;",
         throws="java.io.IOException") FILE *fd "$javainput.getFD()"
// 6:
%pragma(java) modulecode=%{
  private static java.io.FileOutputStream retainFD;
%}

%include "test.h"

Это делает следующие вещи:

  1. Мы хотим, чтобы вход для фактической общедоступной части модуля был java.io.FileOutputStream.
  2. Однако на стороне Java кода JNI вместо этого будет взято java.io.FileDescriptor.
  3. Сторона C ++ кода JNI увидит это как jobject
  4. На стороне C ++ мы собираемся сделать что-то немного злое - прочитайте личное поле int в классе FileDescriptor ( см. Здесь ). Это, вероятно, не переносимо, и чтение закрытых частей классов обычно считается плохим, но оно позволяет нам получить то, что мы можем передать fdopen(), чтобы получить FILE* для "настоящего" вызова
  5. В основном, эта карта типов берет FileOutputStream и вызывает getFD() для получения объекта FileDescriptor. Он также добавляет спецификацию исключения для соответствия getFD() и выполняет еще одну функцию, которая является частью следующей точки
  6. Мы должны быть уверены, что Java не будет собирать мусор и завершать FileOutputStream, что закроет дескриптор файла и лишит законной силы наш FILE*. Мы делаем это, сохраняя ссылку на FileOutputStream, которую нам дали в переменной private static. pre="... из предыдущей карты типов приводит к тому, что самая последняя сохраняется до тех пор, пока мы не перейдем к другой. (Если мы дважды позвоним setLogFile, то все в порядке и на самом деле хорошо, что мы выпустим нашу ссылку на предыдущий FileOutputStream)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...