前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2019-04-08 Swig java Jni开发指南

2019-04-08 Swig java Jni开发指南

作者头像
oracle3
发布2022-05-13 08:32:25
5500
发布2022-05-13 08:32:25
举报
文章被收录于专栏:oracle3技术大杂烩

Swig java Jni开发指南 目录 Swig java Jni开发指南

  1. Swig参考文档
  2. 全局变量
  3. 常量
  4. 只读变量
  5. 枚举
  6. 函数
  7. 结构体
  8. 调用函数指针
  9. 回调
  10. 类型转换
  11. 两个常用命令

简介: JNI:Java Native Interface,它允许Java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用约定即可。 JNA:Java Native Access是一个开源的Java框架,是Sun公司推出的一种调用本地方法的技术,是建立在经典的JNI基础之上的一个框架。之所以说它是JNI的替 代者,是因为JNA大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境就可以完成。 Swig可以根据c或c++代码生成jni代码的工具,大大简化jni的开发 Jnaerator可以根据c或c++代码生成jna代码的工具,大大简化jna的开发 从难易度看,使用jnaerator开发jna最简单,代码基本都是自动生成,但是jna开发有个很大的缺点,就是如果c代码过于复杂,比如出现java调用c,然后c再回调java,java返回的结果c还需要继续处理的时候,经常出现不可控制的crash,而jna算是中间层,这个层出现的错误完全无法调试,被逼无奈,我们的项目先用jna开发,不得不转jni开发,在使用swig的过程中,也遇到不少问题,因此总结如下:

  1. Swig参考文档 http://www.swig.org/Doc3.0/SWIGDocumentation.html swig是一个编译时软件开发工具,它能生成将用c/c++编写的原生模块与包括java在内的其他编程语言进行链接的必要代码。Swig不仅是一个代码生成器,还是一个接口编译器。它不定义新的协议,也不是一个组件框架或者一个特定的运行时库。Swig把接口文件看做输入,并生成必要的代码在java中展示接口,从而让java能够理解原生代码中的接口定义。Swig不是一个存根生成器;它产生将要被编译和运行的代码。 Swig可应用于包括windows、mac os x和linux在内的大多数操作系统平台。大家可以参考官网文档安装。 使用swig需要生成一个.i的接口文件,swig接口文件包含函数原型、类和变量声明,它的语法和普通的c/c++头文件一样。除了c/c++关键字和预处理器指令,接口文件还包含swig特有的预处理器指令,该指令可用于优化生成封装代码。
  2. 全局变量 a) 编写example.h
代码语言:javascript
复制
int counter = 0;   

b) 编写example.i

代码语言:javascript
复制
%module example  
%{  
#include "example.h"  
%}  
  
extern int counter;  

c) 编写runme.java

代码语言:javascript
复制
/ runme.java  
 
ublic class runme {  
 static {  
   System.loadLibrary("example");  
 }  
 
 public static void main(String argv[]) {  
   System.out.println(example.getCounter());  
   example.setCounter(1);  
   System.out.println(example.getCounter());  
 }  

d) 执行以下命令

代码语言:javascript
复制
swig -java example.i  
gcc -Wall -Wl,--kill-at -I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" -shared -s -o example.dll *.c  
javac -d . *.java  
java -cp . runme  
  1. 常量 a) 编写example.i
代码语言:javascript
复制
%module example  
  
/* 用define指令定义常量 */  
#define MAX_WIDTH 640  
/* 用%constant指令定义常量 */  
%constant int MAX_HEIGHT = 320;  

b) 编写runme.java

代码语言:javascript
复制
// runme.java  
  
public class runme {  
  static {  
    System.loadLibrary("example");  
  }  
  
  public static void main(String argv[]) {  
    System.out.println(example.MAX_WIDTH);  
        System.out.println(example.MAX_HEIGHT);  
      }  
    }  

c) 执行以下命令,同1.d

  1. 只读变量 区别只是在生成的包装类中,只读的只有get函数,读写的有get和set函数 a) 编写example.h
代码语言:javascript
复制
/* 只读变量 */  
int readOnly;  
  
/* 读-写变量 */  
int readWrite; 

b) 编写example.i

代码语言:javascript
复制
%module example  
%{  
#include "example.h"  
%}  
  
/* 只读变量 */  
%immutable readOnly;  
int readOnly;  
  
/* 读-写变量 */  
int readWrite; 

c) 编写runme.java

代码语言:javascript
复制
// runme.java  
  
public class runme {  
  static {  
    System.loadLibrary("example");  
  }  
  
  public static void main(String argv[]) {  
    System.out.println(example.getReadOnly());  
    example.setReadWrite(10);  
    System.out.println(example.getReadWrite());  
  }  
}

d) 执行以下命令,同1.d

  1. 枚举 a) 编写example.h
代码语言:javascript
复制
/* 匿名枚举 */  
enum {ONE = 1, TWO = 2, THREE, FOUR};  
/* 命名枚举 */  
enum Color { RED = 1, GREEN, BLANK, YELLOW};  
  
enum SeasonEnum{ SPRING = 1,SUMMER,AUTUMN,WINTER};  

b) 编写example.i

代码语言:javascript
复制
%module example  
%{  
#include "example.h"  
%}  
  
/* 匿名枚举 */
enum {ONE = 1, TWO = 2, THREE, FOUR};  
/* 命名枚举 */  
enum Color { RED = 1, GREEN, BLANK, YELLOW};  
/* 类型不安全,这个用起来最简单 */  
%include "enumtypeunsafe.swg"  
%javaconst(1);  
enum SeasonEnum{ SPRING = 1,SUMMER,AUTUMN,WINTER};  

c) 编写runme.java

代码语言:javascript
复制
// runme.java  
  
public class runme {  
  static {  
    System.loadLibrary("example");  
  }  
  
  public static void main(String argv[]) {  
    System.out.println(example.ONE + "," + example.TWO + "," + example.THREE + "," + example.FOUR);  
    System.out.println(Color.RED.swigValue() + "," + Color.GREEN.swigValue() + "," + Color.BLANK.swigValue() + "," + Color.YELLOW.swigValue());  
    System.out.println(SeasonEnum.SPRING + "," + SeasonEnum.SUMMER + "," + SeasonEnum.AUTUMN + "," + SeasonEnum.WINTER);  
  }  
}  

d) 执行以下命令,同1.d

  1. 函数 这里直接抄swigwin-3.0.12\Examples\java\simple a) 编写example.c
代码语言:javascript
复制
/* File : example.c */  
  
/* A global variable */  
double Foo = 3.0;  
  
/* Compute the greatest common divisor of positive integers */  
int gcd(int x, int y) {  
  int g;  
  g = y;  
  while (x > 0) {  
    g = x;  
    x = y % x;  
    y = g;  
  }  
  return g;  
}  

b) 编写example.i

代码语言:javascript
复制
/* File : example.i */  
%module example  
  
%inline %{  
extern int    gcd(int x, int y);  
extern double Foo;  
%}  

c) 编写runme.java

代码语言:javascript
复制
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[]) {  
    // Call our gcd() function  
      
    int x = 42;  
    int y = 105;  
    int g = example.gcd(x,y);  
    System.out.println("The gcd of " + x + " and " + y + " is " + g);  
      
    // Manipulate the Foo global variable  
      
    // Output its current value  
    System.out.println("Foo = " + example.getFoo());  
      
    // Change its value  
    example.setFoo(3.1415926);  
      
    // See if the change took effect  
    System.out.println("Foo = " + example.getFoo());  
  }  
}  

d) 执行以下命令,同1.d

  1. 结构体 a) 编写example.h
代码语言:javascript
复制
// example.h  
  
struct Books  
{  
   char  title[50];  
   char  author[50];  
   char  subject[100];  
   int   book_id;  
};  
  
extern void show(struct Books* book);  

b) 编写example.c

代码语言:javascript
复制
// example.c  
#include <stdio.h>  
#include "example.h"  
  
// struct Books book = {"C 语言", "RUNOOB", "编程语言", 123456};  
void show(struct Books* book)  
{  
    printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book->title, book->author, book->subject, book->book_id);  
}  

c) 编写example.i

代码语言:javascript
复制
/* File : example.i */  
%module example  
  
%{  
#include "example.h"  
%}  
  
%include "example.h"  

d) 编写runme.java

代码语言:javascript
复制
// runme.java  
  
public class runme {  
  static {  
    System.loadLibrary("example");  
  }  
  
  public static void main(String argv[]) {  
      
    Books book = new Books();  
    book.setTitle("C 语言");  
    book.setAuthor("RUNOOB");  
    book.setSubject("编程语言");  
    book.setBook_id(123456);  
      
    example.show(book);  
  }  
}  

e) 执行以下命令,同1.d

  1. 类 这里直接抄swigwin-3.0.12\Examples\java\ class,对比java调用c的结构体来看,两个的处理完全一样,都是把c的结构或类包装成java类使用 a) 编写example.h
代码语言:javascript
复制
/* File : example.h */  
  
class Shape {  
public:  
  Shape() {  
    nshapes++;  
  }  
  virtual ~Shape() {  
    nshapes--;  
  }  
  double  x, y;  
  void    move(double dx, double dy);  
  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();  
};  

b) 编写example.cxx

代码语言:javascript
复制
/* 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;  
}  
  
double Square::perimeter() {  
  return 4*width;  
}  

c) 编写example.i

代码语言:javascript
复制
/* File : example.i */  
%module example  
  
%{  
#include "example.h"  
%}  
  
/* Let's just grab the original header file here */  
%include "example.h"  

d) 编写runme.java

代码语言:javascript
复制
// 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" );  
  }  
}  

e) 执行以下命令

代码语言:javascript
复制
swig -c++ -java example.i  
g++ -Wall -Wl,--kill-at -I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" -shared -s -o example.dll *.cxx  
javac -d . *.java  
java -cp . runme  
  1. 调用函数指针 重点:这个只能获得函数指针,然后多写个函数把函数指针传递给c层来调用,java层没有找到方法调用 这种方法会出现一些比较奇怪的类名,例如:SWIGTYPE_p_f_float_float__float,为了类名可读,可以用下一部分说的回调来处理,只是不需要java继承,直接get出来,然后调用run就可以用了 a) 编写example.h
代码语言:javascript
复制
/**************************************** 
 * 函数指针结构体 
 ***************************************/  
typedef float (*callback_t)(float a, float b);  
  
typedef struct _OP {  
    callback_t p_add;   
    callback_t p_sub;   
    callback_t p_mul;   
    callback_t p_div;   
} OP;   
  
extern OP* get_init_op(void);  
extern float add_sub_mul_div(float a, float b, callback_t fun);  

b) 编写example.i

代码语言:javascript
复制
/* File : example.i */  
%module example  
%{  
#include "example.h"  
%}  
  
%include "example.h"  

c) 编写example.c

代码语言:javascript
复制
#include <stdio.h>  
#include <stdlib.h>  
#include "example.h"  
  
/**************************************** 
 * 加减乘除函数 
 ***************************************/  
float ADD(float a, float b)   
{  
    return a + b;  
}  
  
float SUB(float a, float b)   
{  
    return a - b;  
}  
  
float MUL(float a, float b)   
{  
    return a * b;  
}  
  
float DIV(float a, float b)   
{  
    return a / b;  
}  
  
/**************************************** 
 * 初始化函数指针 
 ***************************************/  
OP* get_init_op(void)  
{  
        OP *op = (OP *)malloc(sizeof(OP));   
    op->p_add = ADD;  
    op->p_sub = SUB;  
    op->p_mul = MUL;  
    op->p_div = DIV;  
    return op;  
}  
  
/**************************************** 
 * 库函数 
 ***************************************/  
float add_sub_mul_div(float a, float b, callback_t fun)  
{  
    return fun(a, b);  
}  
  
int main()   
{  
    OP *op = get_init_op();   
          
    /* 直接使用函数指针调用函数 */   
    printf("ADD = %f, SUB = %f, MUL = %f, DIV = %f\n", (op->p_add)(1.3, 2.2), (*op->p_sub)(1.3, 2.2),   
            (op->p_mul)(1.3, 2.2), (*op->p_div)(1.3, 2.2));  
       
    /* 调用回调函数 */   
    printf("ADD = %f, SUB = %f, MUL = %f, DIV = %f\n",   
            add_sub_mul_div(1.3, 2.2, ADD),   
            add_sub_mul_div(1.3, 2.2, SUB),   
            add_sub_mul_div(1.3, 2.2, MUL),   
            add_sub_mul_div(1.3, 2.2, DIV));  
  
    return 0;   
}  

d) 编写runme.java

代码语言:javascript
复制
// runme.java  
  
public class runme {  
  static {  
    System.loadLibrary("example");  
  }  
  
  public static void main(String argv[]) {  
      
    OP op = example.get_init_op();  
  
    System.out.println(example.add_sub_mul_div(1.3f, 2.2f,op.getP_add()));  
    System.out.println(example.add_sub_mul_div(1.3f, 2.2f,op.getP_sub()));  
    System.out.println(example.add_sub_mul_div(1.3f, 2.2f,op.getP_mul()));  
    System.out.println(example.add_sub_mul_div(1.3f, 2.2f,op.getP_div()));  
  }  
}  

e) 执行以下命令,同1.d

  1. 回调 这个c代码搞不定,只能通过c++类实现,参考上例修改实现 参考:swigwin-3.0.12\Examples\java\callback a) 编写example.h
代码语言:javascript
复制
class Callback {  
public:  
    virtual ~Callback() {}  
    virtual float run(float a, float b) {return 0;}  
};  
  
class OP {  
public:  
    Callback *p_add;  
    Callback *p_sub;  
    Callback *p_mul;  
    Callback *p_div;  
      
public:  
    OP(): p_add(0),p_sub(0),p_mul(0),p_div(0) {}  
    ~OP() {   
    }  
      
    float add_sub_mul_div(float a, float b, Callback* fun) {  
        if(fun != NULL) {  
            return fun->run(a, b);  
        }  
        printf("add_sub_mul_div error\n");  
        return 0;  
    }  
};  

b) 编写example.i 重点:这里必须设置%module(directors="1") example 并且指定回调类: %feature("director") Callback;

代码语言:javascript
复制
/* File : example.i */  
%module(directors="1") example  
%{  
#include "example.h"  
%}  
  
%feature("director") Callback;  
%include "example.h"

c) 编写runme.java

代码语言:javascript
复制
// runme.java  
  
public class runme {  
  static {  
    System.loadLibrary("example");  
  }  
  
  public static void main(String argv[]) {  
      
    OP op = new OP();  
    op.setP_add(new JavaCallbackAdd());  
    op.setP_sub(new JavaCallbackSub());  
    op.setP_mul(new JavaCallbackMul());  
    op.setP_div(new JavaCallbackDiv());  
  
    System.out.println(op.add_sub_mul_div(1.3f, 2.2f,op.getP_add()));  
    System.out.println(op.add_sub_mul_div(1.3f, 2.2f,op.getP_sub()));  
    System.out.println(op.add_sub_mul_div(1.3f, 2.2f,op.getP_mul()));  
    System.out.println(op.add_sub_mul_div(1.3f, 2.2f,op.getP_div()));  
      
    System.out.println(op.getP_add().run(1.3f, 2.2f));  
    System.out.println(op.getP_sub().run(1.3f, 2.2f));  
    System.out.println(op.getP_mul().run(1.3f, 2.2f));  
    System.out.println(op.getP_div().run(1.3f, 2.2f));  
      
  }  
}  
  
  
class JavaCallbackAdd extends Callback  
{  
  public float run(float a, float b) {  
    return a + b;  
  }  
}  
  
class JavaCallbackSub extends Callback  
{  
  public float run(float a, float b) {  
    return a - b;  
  }  
}  
  
class JavaCallbackMul extends Callback  
{  
  public float run(float a, float b) {  
    return a * b;  
  }  
}  
  
class JavaCallbackDiv extends Callback  
{  
  public float run(float a, float b) {  
    return a / b;  
  }  
}  

d) 执行以下命令

代码语言:javascript
复制
swig -c++ -java example.i  
g++ -Wall -Wl,--kill-at -I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" -shared -s -o example.dll *.cxx  
javac -d . *.java  
java -cp . runme  
  1. 类型转换 a) 错误的情况 C函数包装
代码语言:javascript
复制
%module example  
  
int add_option(const unsigned char *data);  

得到的包装函数: public static int add_option(SWIGTYPE_p_unsigned_char data) 其中SWIGTYPE_p_unsigned_char完全无法赋值,也就是无法使用 b) 正确的处理

代码语言:javascript
复制
%module example  
  
%include <arrays_java.i>  
%apply signed char *INOUT { unsigned char * };  
%apply signed char[] { const unsigned char * };  
  
int add_option(const unsigned char *data); 

这样就可以得到包装函数: public static int add_option(byte[] data) c) 更多的类型转换

代码语言:javascript
复制
%include "typemaps.i"  
%include "stdint.i"  
%include "arrays_java.i"  
%include "carrays.i"  
  
typedef int8_t Int8;  
typedef uint8_t Uint8;  
typedef int16_t Int16;  
typedef uint16_t Uint16;  
typedef uint32_t Int32;  
typedef uint32_t Uint32;  
  1. 两个常用命令 a) Javah javah –jni Java类名,可以通过java类生成.h 头文件 b) javap javap -s -p Java类名 用来输出一个Java类的方法的签名,用于c调用java类获得methid的时候使用
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档