因为项目需要,需要将C++实现的算法代码改成可以被Python调用的形式。又一次要实现不同编程语言之间的通信,这一次还需要架设到服务器上去,我花了很多时间走了不少弯路才把整个过程完成。在这里记录一下防止其他人或者自己再走弯路。
首先了解到一般使用SWIG进行C++与其它语言的通信,刚开始在自己的Windows系统中完成了整个步骤,具体教程可以看(http://blog.csdn.net/a8572785/article/details/10427521)和(http://www.360doc.com/content/12/0806/17/59141_228677645.shtml)这两个博客,因为有IDE的帮助,还算简单。需要注意的是.i文件的编写,我们代码用使用到了string库,它是无法被python识别的,需要在.i文件中加上%include "std_string.i"
,类似的库还有deque,list,map,pair,set,vetor等。
但是完成后,在自己的环境中可以顺利运行,到其它环境下就会报错。
之后找到原因,这种C/C++编译的过程编译出的动态链接库一般都只能在同一个环境下生效,Windows和Linux环境更是不可能互通的。
于是我换到服务器上进行编译。第一次进行Linux上的C++编译,痛不欲生,掉入各种深坑,即使现在做完了,还有很多问题无法解释。整个过程在下面阐述:
首先,在服务器上安装SWIG和OpenCV环境,安装包都可以在官网上找到。
我这里使用的SWIG版本是3.0.12,把swig-3.0.12.tar.gz解压后进入目录,输入./configure --prefix=/usr
,有可能会出现PCRE报错,报错的话就先把PCRE安装起来,参照这个(http://chenzhou123520.iteye.com/blog/1817563)教程,安装好后再进行SWIG的configure,make,make install,最后就安装完成。
OpenCV使用的版本是3.0.0,主要参照(http://blog.csdn.net/taoyanqi8932/article/details/53424137)这里进行配置安装,第一次安装的时候很顺利,第二次碰到了error: ‘NppiGraphcutState’ has not been declared 类似的报错,网上查找后发现可能是CUDA版本与OpenCV的兼容问题,解决方案是:
解决方案:
进入opencv-3.0.0/modules/cudalegacy/src/目录,修改graphcuts.cpp文件,将:
include "precomp.hpp"
if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
改为
include "precomp.hpp"
if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || (CUDART_VERSION >= 8000)
然后make编译就可以了
将需要使用的C++代码移入统一目录下,首先要编译尝试是否能够成功运行。网上很多教程推荐使用makefile进行编译,尝试很多后都没摸到门道,疯狂报错,最后还是用最简单的方法。
用普通的g++ x.cpp -o x
报错,提示to_string无法识别,发现需要添加-std=c++11,然后报了OpenCV的错误,带有OpenCV的代码还需要加一部分参数才能编译,最后最终版本的编译代码为
g++ -std=c++11 main.cpp line.cpp -o main `pkg-config --cflags --libs opencv`
编译运行成功后,使用SWIG,swig -c++ -python x.i
产生.cxx文件和.py文件(.i文件提前编译好),cxx文件名会对应.i文件的文件名,而.py文件的文件名对应.i文件中%module的module名。
然后再进行最后一步编译产生.so文件。网上好多教程使用的是distutils工具进行编译,使用后发现不知道如何添加c++11和OpenCV的特性,最后还是选用命令行编译,尝试之后最终成功的编译代码为
g++ -shared -std=c++11 -fpic line.cpp Harmonious_wrap.cxx `pkg-config --cflags --libs opencv` -I/usr/local/include/python3.4m -o _score_module.so
其中.so的文件名为之前编译产生的.py的文件名前再加一个下划线。别问我为什么这么写,我也不知道,具体细节因为对g++编译器不太理解,暂时还不清楚,尝试了无数遍后发现这样写是没有报错的。
在不同的Ubuntu环境下,include的位置不同,有的没有local,需要切到文件夹里去找一下
最后大功告成。直接打开python调用score_module就成功过了。