我们项目中有一个协议打包模块,c++写的。需要移植到java和python上,不想重写,就使用了一个叫swig(http://swig.org/)的工具,从c++代码直接生成了java/python代码。推荐一下。
几点感受:
(1)swig支持的语言还是很多的,可以从c/c++生成java/python/php/R/ruby等等一堆语言,这个工具有20多年的历史了。其他语言的支持程度不了解,我们生成的java/python代码是直接用到了项目中;
(2)swig是跨平台的,linux/windows上我都成功的生成/运行过,相对来说linux上更简单;
(3)swig并不直接生成java/python代码,而是先将原始的c/c++编译成动态库so/dll,然后再生成包装层的java/python代码,使用时直接调用包装层代码即可(java的包装层就是jni代码)。这是因为各语言的特性不一致,比如c/c++中的模板、嵌套类、指针、数据类型等,在java/python中不一定完整支持。
(4)类型映射,需要将c/c++中的数据类型映射到目标语言中的类型。普通类型一般不需要处理,但char*映射到java时比较麻烦,默认是映射到string,但我们是打包协议,需要映射到byte[],于是使用typemap做了处理。
(5)c++中的模板、重载、namespace等特性是支持的,但嵌套类目前不支持。
---------------------------------
update:
关于java的jni,朋友有如下观点,这里记下作为参考:
第一,JNI程序两种内存之间的同步问题和指针处理经常会导致JVM崩溃。
第二,频繁的两种内存之间的数据交换导致性能下降,于是本机代码的优势就没有了。
我们的东西,要求尽量不使用本机代码,而是通过配置程序来使得pure java代码支持各个平台。JNI应用里面,这里我们假定是JAVA和C/C++,两边使用完全不同的内存模型。C/C++部分是我们自己来分配和释放内存,内存地址在地址空间里面是固定不变的;而JAVA部分是我们分配内存,JVM来回收内存,内存地址在地址空间是浮动的,这个差别决定了很多事情。
第一。两边的内存使用之前要先锁定,然后获取,进行处理,然后拷贝,最后解锁,以此来防止出现无效地址问题。这种做法在JVM需要进行内存回收的时候会导致程序暂停问题,同时降低了程序的运行效率。另外,在锁定的内存足够大的时候,连JVM的内存回收都会出现问题,因此本机代码的实现上必须做些工作,来保证一次不锁定太多的内存,或者JVM那边要给出很大的内存设置。
第二。对上述过程的稍不注意,就会出现非法指针问题而导致某端的崩溃,这里崩溃的不一定是JVM,C/C++部分也一样会完蛋的。
另外还有一个问题,那就是两边的异常处理,数据以及数据结构的定义上的差别,使得这点要非常小心,因为它同样涉及数据转换问题。
因此除非我们有大量成熟的C/C++程序,转换成本很高,或者不用本机代码就没办法解决,否则一般不推荐使用JNI,因为它好处没有麻烦多。
---------------------------------
update:
需要注意的是,swig是GPL license的,而我们公司禁止使用该授权的工具,因此在项目结项时还是重新写了一份java/python的协议打包模块。真悲催!