JNI wrapper for C function using SWIG - what should be the typemap?(使用 SWIG 的 C 函数的 JNI 包装器 - 类型映射应该是什么?)
问题描述
I am trying to create the JNI wrapper for the following functions in C:
int err = new_instance(const char* name, instance_t* instance);
name
- input, instance
- output
int err = get_value(const instance_t instance, int *val);
instance
- input, val
- output
where instance_t
is defined as:
typedef void* instance_t;
I am all lost in the SWIG manual for Java, since it doesn't simply support input parameters as the output type. I had no problems whatsoever with the Python wrapper (shown below).
What is the correct way of using typemap in the case of Java?
// instance_t [argout]
%typemap(in, numinputs=0) instance_t* instance (instance_t temp = 0) {
$1 = &temp;
}
%typemap(argout) instance_t *instance {
%append_output(PyLong_FromLongLong((long long)* $1));
}
// instance_t [in]
%typemap(in) instance_t instance {
$1 = (instance_t) PyLong_AsLongLong($input);
}
You can do this using SWIG and Java in several different ways. I've created the following header to illustrate all my examples, based on what you showed in the question:
typedef void* instance_t;
int new_instance(const char* name, instance_t * instance);
int get_value(const instance_t instance, int *val);
Writing some Java in the interface:
We can use the cpointer.i from the SWIG library to give us the functions we need to write a Java overload that calls the default version of new_instance
(which we make private since it becomes an implementation detail).
%module test
%{
#include "test.h"
%}
%include <cpointer.i>
// Have SWIG create a helper class for "pointer to pointer" type of handle
%pointer_class(instance_t, inst_ptr);
// Hide default version of new_instance
%javamethodmodifiers new_instance "private";
// Supply Java version of new_instance now with useful method signature
%pragma(java) modulecode=%{
public static SWIGTYPE_p_void new_instance(String name) {
inst_ptr ptr = new inst_ptr();
final int err = new_instance(name, ptr.cast());
if (0!=err) {
// throw or whatever
}
return ptr.value();
}
%}
%include "test.h"
Note that this example probably leaks as is since ptr.value()
is non-owning by default.
Writing some C in the interface:
In this next example we write an "overload" (but since I assumed you're writing C and not C++ we had to use %rename
to make this work) in C alone, specifically for the SWIG interface. The original version of the function gets ignored completely since it's pretty useless to us.
%module test
%{
#include "test.h"
%}
// Hide the default new_instance
%ignore new_instance;
%include "test.h"
// Pretend our wrapper specific "overload" was called new_instance all along
%rename(new_instance) new_instance_overload;
// Don't leak our new instance
%newobject new_instance;
// Declare, define and wrap a special version of new_instance
%inline %{
instance_t new_instance_overload(const char* name) {
instance_t result = NULL;
const int err = new_instance(name, &result);
if (err) {
// See later on/other Q for cross language exception example
}
return result;
}
%}
Using typemaps
We can actually do something very similar to your Python example using Java typemaps, although the process is more convoluted since Java has strong typing and we need to respect that.
This solution is also substantially similar to my older answer on the same underlying issue, with the additional complexity that getting strong typing working in Java (instead of just SWIGTYPE_p_void
) is trickier here when the underlying typedef is to void*
instead of a forward declaration of a struct.
%module test
%{
#include "test.h"
%}
// Provide 'instance' class for strong typing (instead of void* semantics)
%rename(Instance) instance;
%nodefaultctor;
struct instance {};
typedef instance * instance_t;
// Don't leak (not that we have a destructor yet, but...)
%newobject new_instance;
// Change new_instance to return instance of Instance
%typemap(jstype) int new_instance "$typemap(jstype,instance_t)";
%typemap(jni) int new_instance "$typemap(jni,instance_t)";
%typemap(jtype) int new_instance "$typemap(jtype,instance_t)";
// Hide the instance_t argument and use a temporary instead under the hood
%typemap(in,numinputs=0) instance_t * ($1_basetype tmp) %{
$1 = &tmp;
%}
// After the call copy the result back
%typemap(argout) instance_t * %{
*($1_ltype)&$result = *$1;
%}
// Inside Java construct the proxy with the correct long pointer
%typemap(javaout) int new_instance {
return new $typemap(jstype,int new_instance)($jnicall, $owner);
}
// Some error handling
%javaexception("Exception") new_instance {
$action
if (!result) {
// JNI code to raise exception, untested in this form
jclass clazz = JCALL1(FindClass, jenv, "Exception");
JCALL2(ThrowNew, jenv, clazz, "Failure creating thing");
return $null;
}
}
%include "test.h"
I would encourage you to look at the generated code around the call to new_instance()
to fully understand what these typemaps are doing.
As far as the call to get_value
is concerned the instance_t
gets handled automatically from the interface above and the int*
arg out needs to get handled either similary to the above example, or using a trick with an array containing only one element:
%include <typemaps.i>
%apply int *OUTPUT { int *val };
%include "test.h"
Which you would then call as:
int outarr[] = new int[1];
final int err = test.get_value(instance, outarr);
// outarr[0] then constains the value
Of course you could then take that trick and use something like the %pragma(java) modulecode
of my first example in this answer to supply another overload that behaves more naturally:
%javamethodmodifiers get_value "private";
%pragma(java) modulecode=%{
public static int get_value(Instance instance) {
int outarr[] = new int[1];
final int err = test.get_value(instance, outarr);
if (0!=err) {
// throw, blah blah
}
return outarr[0];
}
%}
(Note that this trick with arrays would also have worked for a fourth solution to the instance_t*
problem, but because it's not a primitive type there's a lot more work involved for no real gain)
这篇关于使用 SWIG 的 C 函数的 JNI 包装器 - 类型映射应该是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用 SWIG 的 C 函数的 JNI 包装器 - 类型映射应该是什么?
基础教程推荐
- Java 中保存最后 N 个元素的大小受限队列 2022-01-01
- 如何对 HashSet 进行排序? 2022-01-01
- Spring Boot Freemarker从2.2.0升级失败 2022-01-01
- 如何强制对超级方法进行多态调用? 2022-01-01
- 如何使用 Stream 在集合中拆分奇数和偶数以及两者的总和 2022-01-01
- 如何使用 Eclipse 检查调试符号状态? 2022-01-01
- 由于对所需库 rt.jar 的限制,对类的访问限制? 2022-01-01
- 如何在不安装整个 WTP 包的情况下将 Tomcat 8 添加到 Eclipse Kepler 2022-01-01
- 首次使用 Hadoop,MapReduce Job 不运行 Reduce Phase 2022-01-01
- 在螺旋中写一个字符串 2022-01-01