利用 SWIG 转换 C/C++ 接口到 Java 接口

    SWIG(Simplified Wrapper and Interface Generator)是一个将C/C++接口转换为其他语言接口的工具,从而可以讲C/C++的库集成到其他语言的系统中。目前SWIG已经可以支持Python, Java, C#,Ruby,PHP,R语言等十多种语言。
    本文介绍一下在Liuux平台上如何将C++接口转换为Java接口。
    一、首先先编写一个C++的动态库。
    代码如下:
    1、接口文件定一个。
     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.       

    2、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.       

    3、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文件
    4、编写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动态库。
利用 SWIG 转换 C/C++ 接口到 Java 接口_第1张图片
     这个C++库用到了C++里面的虚基类,纯虚函数,继承,C函数,静态变量等概念。下面就看一下SWIG如何将这个C++的so库转换为Java接口。

   二、利用SWIG将C++接口转换为Java接口
   1、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文件夹中。此时的目录结构为:
       
    1、生成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类,并且类名,方法明完全一样。
    2、编译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接口。

三、使用SWIG生成的Java接口
    1、编译Java文件
        进入swig目录,SWIG生成的Java文件现在都在这里。
        #javac *.java
        生成class文件。
        刚才我们设定的java包是com.test
        创建com/test目录,将class文件移动到com/test目录下,然后打包
        #cd swig
        #tar -cvf gemt4j.jar ./com
        生成gemt4j.jar包
    2、将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放到这个路径下即可。
     3、编写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

转自: http://yingchao.iteye.com/blog/625797

你可能感兴趣的:(java,java,java,java,C++,C++,c,c,swig,swig)