2019-04-08 Swig java Jni開發(fā)指南

Swig java Jni開發(fā)指南
目錄
Swig java Jni開發(fā)指南

  1. Swig參考文檔
  2. 全局變量
  3. 常量
  4. 只讀變量
  5. 枚舉
  6. 函數(shù)
  7. 結(jié)構(gòu)體
  8. 調(diào)用函數(shù)指針
  9. 回調(diào)
  10. 類型轉(zhuǎn)換
  11. 兩個常用命令

簡介:
JNI:Java Native Interface,它允許Java代碼和其他語言(尤其C/C++)寫的代碼進行交互,只要遵守調(diào)用約定即可。
JNA:Java Native Access是一個開源的Java框架,是Sun公司推出的一種調(diào)用本地方法的技術(shù),是建立在經(jīng)典的JNI基礎(chǔ)之上的一個框架。之所以說它是JNI的替 代者,是因為JNA大大簡化了調(diào)用本地方法的過程,使用很方便,基本上不需要脫離Java環(huán)境就可以完成。
Swig可以根據(jù)c或c++代碼生成jni代碼的工具,大大簡化jni的開發(fā)
Jnaerator可以根據(jù)c或c++代碼生成jna代碼的工具,大大簡化jna的開發(fā)
從難易度看,使用jnaerator開發(fā)jna最簡單,代碼基本都是自動生成,但是jna開發(fā)有個很大的缺點,就是如果c代碼過于復(fù)雜,比如出現(xiàn)java調(diào)用c,然后c再回調(diào)java,java返回的結(jié)果c還需要繼續(xù)處理的時候,經(jīng)常出現(xiàn)不可控制的crash,而jna算是中間層,這個層出現(xiàn)的錯誤完全無法調(diào)試,被逼無奈,我們的項目先用jna開發(fā),不得不轉(zhuǎn)jni開發(fā),在使用swig的過程中,也遇到不少問題,因此總結(jié)如下:

  1. Swig參考文檔
    http://www.swig.org/Doc3.0/SWIGDocumentation.html
    swig是一個編譯時軟件開發(fā)工具,它能生成將用c/c++編寫的原生模塊與包括java在內(nèi)的其他編程語言進行鏈接的必要代碼。Swig不僅是一個代碼生成器,還是一個接口編譯器。它不定義新的協(xié)議,也不是一個組件框架或者一個特定的運行時庫。Swig把接口文件看做輸入,并生成必要的代碼在java中展示接口,從而讓java能夠理解原生代碼中的接口定義。Swig不是一個存根生成器;它產(chǎn)生將要被編譯和運行的代碼。
    Swig可應(yīng)用于包括windows、mac os x和linux在內(nèi)的大多數(shù)操作系統(tǒng)平臺。大家可以參考官網(wǎng)文檔安裝。
    使用swig需要生成一個.i的接口文件,swig接口文件包含函數(shù)原型、類和變量聲明,它的語法和普通的c/c++頭文件一樣。除了c/c++關(guān)鍵字和預(yù)處理器指令,接口文件還包含swig特有的預(yù)處理器指令,該指令可用于優(yōu)化生成封裝代碼。
  2. 全局變量
    a) 編寫example.h
int counter = 0;   

b) 編寫example.i

%module example  
%{  
#include "example.h"  
%}  
  
extern int counter;  

c) 編寫runme.java

/ 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) 執(zhí)行以下命令

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
%module example  
  
/* 用define指令定義常量 */  
#define MAX_WIDTH 640  
/* 用%constant指令定義常量 */  
%constant int MAX_HEIGHT = 320;  

b) 編寫runme.java

// 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) 執(zhí)行以下命令,同1.d

  1. 只讀變量
    區(qū)別只是在生成的包裝類中,只讀的只有g(shù)et函數(shù),讀寫的有g(shù)et和set函數(shù)
    a) 編寫example.h
/* 只讀變量 */  
int readOnly;  
  
/* 讀-寫變量 */  
int readWrite; 

b) 編寫example.i

%module example  
%{  
#include "example.h"  
%}  
  
/* 只讀變量 */  
%immutable readOnly;  
int readOnly;  
  
/* 讀-寫變量 */  
int readWrite; 

c) 編寫runme.java

// 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) 執(zhí)行以下命令,同1.d

  1. 枚舉
    a) 編寫example.h
/* 匿名枚舉 */  
enum {ONE = 1, TWO = 2, THREE, FOUR};  
/* 命名枚舉 */  
enum Color { RED = 1, GREEN, BLANK, YELLOW};  
  
enum SeasonEnum{ SPRING = 1,SUMMER,AUTUMN,WINTER};  

b) 編寫example.i

%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

// 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) 執(zhí)行以下命令,同1.d

  1. 函數(shù)
    這里直接抄swigwin-3.0.12\Examples\java\simple
    a) 編寫example.c
/* 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

/* File : example.i */  
%module example  
  
%inline %{  
extern int    gcd(int x, int y);  
extern double Foo;  
%}  

c) 編寫runme.java

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) 執(zhí)行以下命令,同1.d

  1. 結(jié)構(gòu)體
    a) 編寫example.h
// 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

// 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

/* File : example.i */  
%module example  
  
%{  
#include "example.h"  
%}  
  
%include "example.h"  

d) 編寫runme.java

// 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) 執(zhí)行以下命令,同1.d


  1. 這里直接抄swigwin-3.0.12\Examples\java\ class,對比java調(diào)用c的結(jié)構(gòu)體來看,兩個的處理完全一樣,都是把c的結(jié)構(gòu)或類包裝成java類使用
    a) 編寫example.h
/* 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

/* 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

/* File : example.i */  
%module example  
  
%{  
#include "example.h"  
%}  
  
/* Let's just grab the original header file here */  
%include "example.h"  

d) 編寫runme.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" );  
  }  
}  

e) 執(zhí)行以下命令

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. 調(diào)用函數(shù)指針
    重點:這個只能獲得函數(shù)指針,然后多寫個函數(shù)把函數(shù)指針傳遞給c層來調(diào)用,java層沒有找到方法調(diào)用
    這種方法會出現(xiàn)一些比較奇怪的類名,例如:SWIGTYPE_p_f_float_float__float,為了類名可讀,可以用下一部分說的回調(diào)來處理,只是不需要java繼承,直接get出來,然后調(diào)用run就可以用了
    a) 編寫example.h
/**************************************** 
 * 函數(shù)指針結(jié)構(gòu)體 
 ***************************************/  
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

/* File : example.i */  
%module example  
%{  
#include "example.h"  
%}  
  
%include "example.h"  

c) 編寫example.c

#include <stdio.h>  
#include <stdlib.h>  
#include "example.h"  
  
/**************************************** 
 * 加減乘除函數(shù) 
 ***************************************/  
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;  
}  
  
/**************************************** 
 * 初始化函數(shù)指針 
 ***************************************/  
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;  
}  
  
/**************************************** 
 * 庫函數(shù) 
 ***************************************/  
float add_sub_mul_div(float a, float b, callback_t fun)  
{  
    return fun(a, b);  
}  
  
int main()   
{  
    OP *op = get_init_op();   
          
    /* 直接使用函數(shù)指針調(diào)用函數(shù) */   
    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));  
       
    /* 調(diào)用回調(diào)函數(shù) */   
    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

// 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) 執(zhí)行以下命令,同1.d

  1. 回調(diào)
    這個c代碼搞不定,只能通過c++類實現(xiàn),參考上例修改實現(xiàn)
    參考:swigwin-3.0.12\Examples\java\callback
    a) 編寫example.h
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
重點:這里必須設(shè)置%module(directors="1") example
并且指定回調(diào)類:
%feature("director") Callback;

/* File : example.i */  
%module(directors="1") example  
%{  
#include "example.h"  
%}  
  
%feature("director") Callback;  
%include "example.h"

c) 編寫runme.java

// 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) 執(zhí)行以下命令

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. 類型轉(zhuǎn)換
    a) 錯誤的情況
    C函數(shù)包裝
%module example  
  
int add_option(const unsigned char *data);  

得到的包裝函數(shù):
public static int add_option(SWIGTYPE_p_unsigned_char data)
其中SWIGTYPE_p_unsigned_char完全無法賦值,也就是無法使用
b) 正確的處理

%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); 

這樣就可以得到包裝函數(shù):
public static int add_option(byte[] data)
c) 更多的類型轉(zhuǎn)換

%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調(diào)用java類獲得methid的時候使用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,727評論 0 3
  • 【程序1】 題目:古典問題:有一對兔子,從出生后第3個月起每個月都生一對兔子,小兔子長到第三個月后每個月又生一對兔...
    開心的鑼鼓閱讀 3,347評論 0 9
  • 小編費力收集:給你想要的面試集合 1.C++或Java中的異常處理機制的簡單原理和應(yīng)用。 當JAVA程序違反了JA...
    八爺君閱讀 4,673評論 1 114
  • 50道經(jīng)典Java編程練習(xí)題,將數(shù)學(xué)思維運用到編程中來。抱歉哈找不到文章的原貼了,有冒犯的麻煩知會聲哈~ 1.指數(shù)...
    OSET我要編程閱讀 7,173評論 0 9
  • 讀經(jīng)宜冬,其神專也;讀史宜夏,其時久也;讀諸子宜秋,其致別也;讀諸 集宜春,其機暢也。 經(jīng)傳宜獨坐讀;史鑒宜與友共...
    姓安名蟲的安聰閱讀 540評論 0 1