如何配置 SWIG .i 文件来处理 C FILE * 类型?下面的函数设置一个文件,以便可以将日志输出写入其中。我需要从 Java 类中调用 if 。目前,当我仅将 C 头文件包含在以下函数中时,SWIG 会生成 public static void setLogFile(SWIGTYPE_p_FILE fd) 函数。有任何想法吗?
C 函数:
void setLogFile(FILE *fd);
我尝试使用下面的#1 并得到以下异常:
测试.i:
%module Example
%{
#include "headerLogFile.h"
%}
%inline %{
void setLogFile(const char *fn) {
FILE *f = fopen(fn, "w");
setLogFile(f);
}
%}
%ignore setLogFile;
%include "headerLogFile.h"
异常(exception):
[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
最佳答案
给出的 test.h 看起来像:
#include <stdio.h>
inline void setLogFile(FILE *fd) {
fprintf(fd, "Test\n");
fflush(fd);
}
我可以看到您可能选择采用三种方法来包装此函数:
方法 1 - 从 Java 传递 String
:
向 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"
那么您可能会想要 hide the original version from SWIG .
方法 2 - 包装更多 stdio.h:
不仅仅封装 setLogFile
,还可以根据需要封装 fopen
、fmemopen
等内容。 (我个人不太喜欢这个解决方案,所以我没有为此做一个例子)
方法 3 - 公开一个采用 FileOutputStream
的 Java 接口(interface):
%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"
这会执行以下操作:
- 我们希望模块实际公共(public)部分的输入为
java.io.FileOutputStream
。 - JNI 代码的 Java 端将采用
java.io.FileDescriptor
来代替。 - JNI 代码的 C++ 端会将其视为
作业对象
- 在 C++ 方面,我们要做一些有点邪恶的事情 - 读取
FileDescriptor
类中的私有(private)int
字段 ( see here )。这可能是不可移植的,并且读取类的私有(private)部分通常被认为是不好的,但它允许我们获取可以传递给 fdopen() 的东西,以获取FILE*
“真正的”电话 - 大多数情况下,此类型映射采用
FileOutputStream
并对其调用getFD()
以获取其FileDescriptor
对象。它还添加了一个异常规范来匹配getFD()
并执行另一个函数,该函数是下一点的一部分 - 我们需要确保 Java 不会进行垃圾收集并最终确定
FileOutputStream
,这会关闭文件句柄并使我们的FILE*
无效。我们通过在private static
变量中保留对FileOutputStream
的引用来实现此目的。前一个类型映射的pre="...
会导致保留最新的类型映射,直到我们更改为另一个类型映射。(如果我们确实调用setLogFile
两次就可以了,事实上,我们发布了对之前FileOutputStream
的引用,这很好)
关于java - 在 Java 中处理 FILE * C 输入参数的 SWIG 配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8320605/