Swig介绍
swig github SWIG (Simplified Wrapper and Interface Generator)
可以用来在多个编程语言之间进行跨语言封装接口,实现不同编程语言之间的调用。
本文是使用Swig生成Java接口调用C++编译的Linux 平台的so
首先需要安装Swig Swig安装方法
类型映射
如何将C++中的类型映射到Java常用的类:swig typemaps
std::string
比如常用c++的std::string和java的String可以在.i文件中加%include “std_string.i”
Java Array
使用Java Array对应C的指针和长度,例如 java的int[] 转成c++的int * 和长度。
在example.i里面加如下定义:
%include "arrays_java.i"
%apply short[] {short *};
详细列表如下图:
Java 调用C++ SO
主要步骤如下:
- 开发C++相关代码如下面example.h和example.cpp加上下面4步骤中提到的自动生成的C++ JNI文件
- 选择接口文件比如:example.h
- 编写Swig要求的接口描述文件,下面的example.i文件内容
- 使用Swig命令自动生成Java接口类文件和C++的JNI的example_warp.cpp(需要加到SO工程编译)。Java工程需要指定API的包名:
swig -c++ -java -package com.example.ai -outdir java/ example.i
- 将步骤4中生成的Java类等放到Java工程src目录,将第一步的SO库放到Java能找到路径的动态库目录里面。按下面的Java示例即可调用SO函数。
example.h 实例:
/* File : example.h */
class Shape {
public:
Shape() {
nshapes++;
}
virtual ~Shape() {
nshapes--;
}
double x, y;
void move(double dx, double dy);
void copyIntArray(int *pArray, int nArraySize);
virtual double area() = 0;
virtual double perimeter() = 0;
static int nshapes;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) { }
virtual double area();
virtual double perimeter();
};
class Square : public Shape {
private:
double width;
public:
Square(double w) : width(w) { }
virtual double area();
virtual double perimeter();
};
example.cxx
/* File : example.cxx */
#include "example.h"
#define M_PI 3.14159265358979323846
/* Move the shape to a new location */
void Shape::move(double dx, double dy) {
x += dx;
y += dy;
}
int Shape::nshapes = 0;
double Circle::area() {
return M_PI*radius*radius;
}
double Circle::perimeter() {
return 2*M_PI*radius;
}
double Square::area() {
return width*width;
}
void copyIntArray(int *pArray, int nArraySize) {
for(int i=0; i<nArraySize; ++i){
printf("%d ", pArray[i];);
}
printf("\n");
}
double Square::perimeter() {
return 4*width;
}
example.i
或者使用效率更高的
/* File : example.i */
%module example
%include "carrays.i"
%include "stdint.i"
%{
#include "example.h"
%}
// 将short *的不定长数组自动生成使用函数
%array_functions(int, shortArray);
/*%array_functions(int, shortArray); 会生成如下函数:
int *new_intArray(int nelements);
void delete_intArray(int *x);
int intArray_getitem(int *x, int index);
void intArray_setitem(int *x, int index, int value);
*/
/* Let's just grab the original header file here */
%include "example.h"
Java 示例代码
// This example illustrates how C++ classes can be used from Java using SWIG.
// The Java class gets mapped onto the C++ class and behaves as if it is a Java class.
public class runme {
static {
try {
System.loadLibrary("example");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
System.exit(1);
}
}
public static void main(String argv[])
{
// ----- Object creation -----
System.out.println( "Creating some objects:" );
Circle c = new Circle(10);
System.out.println( " Created circle " + c );
Square s = new Square(10);
System.out.println( " Created square " + s );
// ----- Access a static member -----
System.out.println( "\nA total of " + Shape.getNshapes() + " shapes were created" );
// ----- Member data access -----
// Notice how we can do this using functions specific to
// the 'Circle' class.
c.setX(20);
c.setY(30);
// Now use the same functions in the base class
Shape shape = s;
shape.setX(-10);
shape.setY(5);
System.out.println( "\nHere is their current position:" );
System.out.println( " Circle = (" + c.getX() + " " + c.getY() + ")" );
System.out.println( " Square = (" + s.getX() + " " + s.getY() + ")" );
// ----- Call some methods -----
System.out.println( "\nHere are some properties of the shapes:" );
Shape[] shapes = {c,s};
for (int i=0; i<shapes.length; i++)
{
System.out.println( " " + shapes[i].toString() );
System.out.println( " area = " + shapes[i].area() );
System.out.println( " perimeter = " + shapes[i].perimeter() );
}
// Notice how the area() and perimeter() functions really
// invoke the appropriate virtual method on each object.
// ----- Delete everything -----
System.out.println( "\nGuess I'll clean up now" );
// Note: this invokes the virtual destructor
// You could leave this to the garbage collector
c.delete();
s.delete();
System.out.println( Shape.getNshapes() + " shapes remain" );
System.out.println( "Goodbye" );
}
}