我为以下c ++代码创建了JNI包装器.
add.h
class MyClass
{
public:
int add(int x, int y, int &z);
int sub(int x, int y);
};
Run Code Online (Sandbox Code Playgroud)
上面提到的代码是.h文件
add.cpp
int MyClass::add(int x, int y, int &sum)
{
sum=x+y;
return 0;
}
int MyClass::sub(int x, int y)
{
return x - y;
}
Run Code Online (Sandbox Code Playgroud)
swig.i
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
%}
%include "arrays_java.i"
%include "typemaps.i"
%include "add.h"
Run Code Online (Sandbox Code Playgroud)
对于上面提到的.cpp文件,我需要生成JNI包装器并在Java代码上使用它.当我尝试执行swig命令时,我将获得SWIGTYPE_p_int.java文件以及JNI文件.任何人都可以帮我解决这个问题吗?
要包装C++"通过非const引用返回"函数,可以打开很多选项.简而言之,您可以做以下之一:
%extend提供返回,而不是过载.(可选择隐藏原件)SWIGTYPE_p_int更多人合作.(可选择在Java中构建一个重载)OUTPUT映射来获取带有数组的引用语义我将在这里展示每个选项的示例.
%extend用于提供过载这里的基本想法是,我们将在这里编写一个全新的重载,SWIG包含一些简单的内容.使用%extend下面的语法,我们可以创建一个新的,仅包装器的重载,它使用临时存储值,然后如果一切顺利则返回它.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
#include <exception>
%}
%extend MyClass {
int add(int x, int y) {
int z;
const int result = $self->add(x,y,z);
if (0 == result) return z;
throw std::exception();
// TODO: use SWIG's exception support
}
}
%ignore MyClass::add(int,int,int&); // Optional: hide the original overload
%include "add.h"
Run Code Online (Sandbox Code Playgroud)
由于原始返回的int似乎表明函数本身的成功/失败,我们可以更自然地将它映射到Java中的异常.(此处省略详细信息,请参阅我在XXX的回答了解更多信息)
此解决方案的效果与前一个类似,但以不同的方式实现.这里我们使用intypemap numinputs=0来设置一个临时变量,我们可以tmpz在调用时使用().out typemap然后只检查来自真实函数调用的返回代码,argout typemap将tempoary复制到结果中.我包含了比这里真正需要的更多的类型图,因为偶然的z和现有的函数返回是相同的类型但是如果不是这样的话我们需要它们.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
#include <exception>
%}
// These aren't actually needed here because the fuction already returns in
%typemap(jni) int MyClass::add "jint";
%typemap(jtype) int MyClass::add "int";
%typemap(jstype) int MyClass::add "int";
%typemap(javaout) int MyClass::add {
return $jnicall;
}
// These create a temporary and map it to the return value for us
%typemap(argout) int& z {
$result = (jint)tmpz$argnum;
}
%typemap(out) int MyClass::add {
if ($1 != 0) {
throw std::exception();
// TODO: exceptions as in other examples
}
}
%typemap(in,numinputs=0) int& z (int tmpz) {
$1 = &tmpz;
}
%include "add.h"
Run Code Online (Sandbox Code Playgroud)
在这里,我们将使用SWIG的cpointer.i库来帮助我们处理SWIGTYPE_p_int对象,并为Java用户透明地执行此操作.为此,我们使用javacode类型映射为其创建临时变量z,然后将其传递到原始SWIG生成的函数(可以将其设置为私有以隐藏它).与其他示例一样,我们可以通过抛出异常来处理返回值指示错误的情况,这次虽然已经是Java代码正在执行抛出,但稍微简单一些.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
%}
%include "cpointer.i"
%pointer_class(int,IntPointer);
%typemap(javacode) MyClass %{
public int add(int x, int y) {
IntPointer z = new IntPointer();
int ret = this.add(x,y,z.cast());
if (ret != 0) throw new Exception();
return z.value();
}
%}
%javamethodmodifiers MyClass::add(int,int,int&) "private" // Optional
%include "add.h"
Run Code Online (Sandbox Code Playgroud)
OUTPUT类型地图这在功能上与之前的解决方案非常相似,改变之后不是使用SWIG提供的辅助类型来处理int指针,而是使用数组并利用Java的"引用时通过引用传递"语义来实现相同的结果.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
%}
%include <typemaps.i>
%apply int *OUTPUT { int & z };
%typemap(javacode) MyClass %{
public int add(int x, int y) {
int[] z = new int[1];
int ret = this.add(x,y,z);
if (ret != 0) throw new Exception();
return z[0];
}
%}
%javamethodmodifiers MyClass::add(int,int,int&) "private"
%include "add.h"
Run Code Online (Sandbox Code Playgroud)
您可以使用添加其他类型%inline.然后欺骗SWIG使用它而不是int&引用.如果我们允许隐式转换,这很好.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
%}
%inline %{
struct IntWrapper {
int value;
// Enable transparent conversion for the SWIG argument
operator int&() {
return value;
}
};
%}
class MyClass
{
public:
int add(int x, int y, IntWrapper& z); // lie to SWIG, but we'll make it up later with implict conversion
int sub(int x, int y);
};
//%include "add.h" // Don't do this now because we need the lie above
Run Code Online (Sandbox Code Playgroud)
与前面的示例一样,我们可以选择使用重载和方法修饰符用法从Java用户隐藏此实现细节.
有关上述几个示例中提出的例外情况的更多信息,请参见此处或此处.