利用SWIG轉換C++接口到Java接口

    SWIG(Simplified Wrapper and Interface Generator)是一個將C/C++接口轉換爲其餘語言接口的工具,從而能夠講C/C++的庫集成到其餘語言的系統中。目前SWIG已經能夠支持Python, Java, C#,Ruby,PHP,R語言等十多種語言。 
    本文介紹一下在Liuux平臺上如何將C++接口轉換爲Java接口。 
    1、首先先編寫一個C++的動態庫。 
    代碼以下: 
    一、接口文件定一個。 
     C++沒有像Java/C#同樣的interface關鍵詞,可是能夠用虛基類來定義接口個,虛基類一樣是隻有定義,沒有實現類,它的功能現放在繼承類中實現。 
   
C++ geometryapi.h代碼   收藏代碼
  1. #ifndef __GEOMETRY_API_H__  
  2. #define __GEOMETRY_API_H__  
  3. //===========================================================================  
  4. class Geometry;  
  5. class GeometryFactory;  
  6.   
  7. //---------------------------------------------------------------------------  
  8. /*  
  9.  * 說明:幾何對象類  
  10.  */  
  11. class Geometry  
  12. {  
  13. public:  
  14.         Geometry(){}  
  15.         virtual ~Geometry(){}  
  16. public:  
  17.         virtual const char* GetType() = 0;  
  18.         virtual void Release() = 0;  
  19. };  
  20. //---------------------------------------------------------------------------  
  21. /*  
  22.  * 說明:幾何對象工廠類  
  23.  */  
  24. class GeometryFactory  
  25. {  
  26. public:  
  27.         GeometryFactory(){}  
  28.         virtual ~GeometryFactory(){}  
  29. public:  
  30.         virtual Geometry* CreateGeometry() = 0;  
  31. };  
  32. //---------------------------------------------------------------------------  
  33. /*  
  34.  * 說明:C函數,用於獲取GeometryFactory類的一個實例  
  35.  */  
  36. extern "C"  
  37. {  
  38.         GeometryFactory* meGetGeometryFactoryInstance();  
  39. }  
  40. //===========================================================================  
  41. #endif  
  42.       

    二、Geometry接口的實現類GeometryImpl 
   
C++ geoemtryimpl.h代碼   收藏代碼
  1. #ifndef __GEOMETRY_IMPL_H__  
  2. #define __GEOMETRY_IMPL_H__  
  3.   
  4. #include "GeometryAPI.h"  
  5.   
  6. class GeometryImpl : public Geometry  
  7. {  
  8. public:  
  9.         GeometryImpl();  
  10.         virtual ~GeometryImpl();  
  11. public:  
  12.         virtual const char* GetType();  
  13.         virtual void Release();  
  14. };  
  15. #endif  
  16.       

   
C++ geoemtryimpl.cpp代碼   收藏代碼
  1. #include "GeometryImpl.h"  
  2.   
  3. GeometryImpl::GeometryImpl()  
  4. {  
  5. }  
  6. GeometryImpl::~GeometryImpl()  
  7. {  
  8. }  
  9. const char* GeometryImpl::GetType()  
  10. {  
  11.     return "GeometryImpl";  
  12. }  
  13. void GeometryImpl::Release()  
  14. {  
  15.     delete this;  
  16. }  
  17.       

    三、GeometryFactory接口的實現類GeometryFactoryImpl 
C++ geometryfactoryimpl.h代碼   收藏代碼
  1. #ifndef __GEOMETRY_FACTORY_IMPL_H__  
  2. #define __GEOMETRY_FACTORY_IMPL_H__  
  3.   
  4. #include "GeometryAPI.h"  
  5.   
  6. class GeometryFactoryImpl : public GeometryFactory  
  7. {  
  8. public:  
  9.         GeometryFactoryImpl();  
  10.         virtual ~GeometryFactoryImpl();  
  11. public:  
  12.         virtual Geometry* CreateGeometry();  
  13. };  
  14. #endif  

    此時的目錄結構爲: 
        include     存放.h文件 
        src         存放.cpp文件 
    四、編寫makefile,編譯動態庫 
C++ makefile代碼   收藏代碼
  1. OBJS=GeometryFactoryImpl.o \  
  2.      GeometryImpl.o  
  3.   
  4. INCLUDE=-I../include   
  5. TARGET=libgemt.so  
  6. CPPFLAG=-shared -WI  
  7. CC=g++  
  8. LDLIB=  
  9.   
  10. $(TARGET) : $(OBJS)  
  11.     $(CC) $(CPPFLAG) $(INCLUDE) -o $(TARGET) $(OBJS) $(LDLIB)  
  12. $(OBJS) : %.o : %.cpp  
  13.     $(CC) -c -fPIC $(INCLUDE) $< -o $@  
  14. clean:  
  15.     -rm -f $(OBJS)  
  16. install:  
  17.     cp $(TARGET) /usr/lib  

    將makefile文件放到src目錄下,而後進入src目錄,執行make命令,編譯so庫。 
    #make 
    編譯完成後將生成libgemt.so動態庫。 
f6e585b9-f78f-31ac-b30a-d93462e13b0c.png 
     這個C++庫用到了C++裏面的虛基類,純虛函數,繼承,C函數,靜態變量等概念。下面就看一下SWIG如何將這個C++的so庫轉換爲Java接口。 

   2、利用SWIG將C++接口轉換爲Java接口 
   一、SWIG接口文件(.i) 
      SWIG須要編寫一個後綴爲.i的接口文件,把C++接口的定義寫在.i文件中,也能夠將C++的頭文件include到.i文件中。這裏咱們將C++接口文件GeometryAPI.h include到.i文件中,文件名爲gemt4j.i。 
     
Gemt4j.i代碼   收藏代碼
  1. /* File : gemt4j.i */  
  2. %module gemt4j  
  3. %{  
  4. #include "GeometryAPI.h"  
  5. %}  
  6. %include "GeometryAPI.h"  
  7.         

    module是模塊名。SWIG將C函數經過Java的JNI轉換爲JAVA方法,這些方法都以靜態方法的方式封裝到一個與模塊名同名的Java類中。 
    新建一個swig文件夾,將gemt4j.i文件存放到swig文件夾中。此時的目錄結構爲: 
         2d32edf6-60b3-31f7-9312-80a91592ecd7.png 
    一、生成java類和wrap文件 
    編寫好.i文件,就能夠用swig生成java類和C++接口的wrap文件。 
    執行一下命令 
    #swig -c++ -java -package com.test -outdir ./ -I../include gemt4j.i 
    swig參數說明: 
         1)-c++ -java 
            告訴swig將C++接口轉換爲java接口。若是是將C接口轉換爲java接口,就不須要-c++,直接寫 swig -java就能夠。 
         2)-package 
            生成的java類的包的名稱 
         3) -I 
            gemt4j.i中include的.h文件的路徑 
         4)gemt4j.i 
            swig的.i文件 
      執行這條命令後,將在swig路徑下生成幾個文件 
         1)gemt4j_wrap.cxx 
            C++文件,包裝器文件。它將C++類的方法轉換爲C的函數。 
         2)gemt4j.java 
            這是與剛纔定義的module同名的一個類。 
         3)gemt4jJNI.java 
            打開這個文件能夠看到,C++類的方法都轉化爲Java的靜態方法。 
         4)其餘與C++類同名的Java類 
            每個C++類都被轉化爲與之對應的Java類,而且類名,方法明徹底同樣。 
    二、編譯gemt4j_wrap.cxx文件爲so庫 
       1) java頭文件 
          編譯gemt4j_wrap.cxx須要用到jni的頭文件jni.h 
          在個人機器上jdk安裝在/opt/jdk1.5.0_20/下, 
          須要包行兩個路徑: 
             1)/opt/jdk1.5.0_20/include/ 
             2) /opt/jdk1.5.0_20/include/linux/ 
        2) libgemt.so庫 
           還須要連接剛纔編譯好的libgemt.so庫 
       編寫makefile文件 
Makefile代碼   收藏代碼
  1. OBJS=gemt4j_wrap.o  
  2. INCLUDE=-I../include \  
  3.      -I/opt/jdk1.5.0_20/include \  
  4.      -I/opt/jdk1.5.0_20/include/linux  
  5. TARGET=libgemt4j.so  
  6. CPPFLAG=-shared -WI  
  7. CC=g++  
  8. LDLIB=-lgemt  
  9. $(TARGET) : $(OBJS)  
  10.     $(CC) $(CPPFLAG) $(INCLUDE) -o $(TARGET) $(OBJS) $(LDLIB)  
  11. $(OBJS) : %.o : %.cxx  
  12.     $(CC) -c -fPIC $(INCLUDE) $< -o $@  
  13. clean:  
  14.     -rm -f $(OBJS)  
  15. install:  
  16.     cp $(TARGET) /usr/lib  

    生成libgemt4j.so庫,jni就是經過這個庫調用libgemt.so庫中的類和方法的。 

    到如今爲止,就經過SWIG將C++接口轉換爲Java接口。 

3、使用SWIG生成的Java接口 
    一、編譯Java文件 
        進入swig目錄,SWIG生成的Java文件如今都在這裏。 
        #javac *.java 
        生成class文件。 
        剛纔咱們設定的java包是com.test 
        建立com/test目錄,將class文件移動到com/test目錄下,而後打包 
        #cd swig 
        #tar -cvf gemt4j.jar ./com 
        生成gemt4j.jar包 
    二、將libgemt4j.so放到java的library path路徑下。 
        能夠經過下面的方式查一下java的library path路徑 
       
Java代碼   收藏代碼
  1. class test{  
  2.     public static void main(String[] argv){  
  3.         System.out.println(System.getProperty("java.library.path"));  
  4.     }  
  5. }  

        我這裏的library pah爲:/opt/jdk1.5.0_20/jre/lib/i386 
        把libgemt4j.so放到這個路徑下便可。 
     三、編寫java代碼。 
       
Java代碼   收藏代碼
  1. import com.test.*;  
  2.   
  3. class test{  
  4.     static {  
  5.         System.loadLibrary("gemt4j");  
  6.     }  
  7.   
  8.     public static void main(String argv[]){  
  9.         GeometryFactory factory = null;  
  10.         factory = gemt4j.meGetGeometryFactoryInstance();  
  11.         if(factory==null){  
  12.             System.out.println("null GeometryFactory");  
  13.             return;  
  14.         }  
  15.         Geometry geometry = null;  
  16.         geometry = factory.CreateGeometry();  
  17.         if(geometry==null){  
  18.             System.out.println("null geometry");  
  19.             return;  
  20.         }  
  21.         System.out.println(geometry.GetType());  
  22.         geometry.Release();       
  23.     }  
  24. }  

         說明: 
            System.loadLibrary("gemt4j"); 
            用於裝載libgemt4j.so庫。 
            其餘代碼與普通的java無異。 
        編譯java文件: 
        #javac -cp /home/hawk/code/swig/dll/java/gemt4j.jar test.java 
        執行test程序 
        #java -cp /home/hawk/code/swig/dll/java/gemt4j.jar:/home/hawk/code/swig/dll/java test 
        輸出結果爲: 
        GeometryImpl
 
  

      能夠看出,實現了Java調用C++類庫libgemt.so 

轉載於:https://www.cnblogs.com/pandans/archive/2011/04/07/2007544.htmlhtml