OpenCV编译完成后无法生成cv2.so原因分析。
Bug背景
OpenCV编译
OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,轻量级而且高效实现了图像处理和计算机视觉方面的很多通用算法。在当前的版本中,OpenCV将函数模块分为主库与contrib库管理。因此,虽然python语言的opencv接口可以通过pip实现简易版安装,但是如果需要使用到完整OpenCV库的功能(包括Caffe深度学习框架编译的应用等),则需要采用传统的源码编译的方式。
OpenCV本身因版本交替,就较为容易出现与安装说明不相符,参数调整,模块数据调整,与操作系统不兼容等各种问题,而这些问题都有可能引发最后编译bug的生成。
场景背景
此次bug场景出现在了最近一次对另一个bug场景复现过程当中。原先需复现的场景(也就是一开始想要用来做软件测试课程报告的场景)主要是在Caffe深度学习框架的编译过程中对matlab接口,即matcaffe的编译报错。而在Caffe框架编译中,则首先需要完成OpenCV的编译。然而,在OpenCV编译完成后,则出现了编译无法生成cv2.so的bug。
该bug在之前的项目经历当中都从未出现且在网上没有一个明确的对该bug的解释以及解决方案,最终花费了较长的时间才得到解决,因此特做此记录。
该bug场景可在相同环境中复现。
实际bug场景
实际环境
本次bug场景的相关实际系统环境如下:
操作系统:Ubuntu16.04 LTS
CUDA9.0
CUDNN7.5
Anaconda2 (Python2.7)
相关硬件如下:
显卡:NVIDIA MX150 2G
安装所需相关依赖如下:
build-essential cmake git pkg-config
libjpeg8-dev libtiff5-dev libjasper-dev libpng12-dev
libgtk2.0-dev
libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
libatlas-base-dev gfortran
安装python相关库如下:
numpy imutils
Opencv版本:
3.4.0 3.4.6
实际流程
OpenCV在获得OpenCV包以及OpenCV-contrib包之后,编译流程如下:
1 | mkdir build && cd build |
上述流程都能够顺利完成。
实际bug描述
当在Anacond虚拟环境下使用python需要调用Opencv接口时,需要将在安装路径下的cv2.so链接到虚拟环境下的python路径当中:
1 | cd ~/anaconda2/envs/caffe/lib/python2.7/site-pakages/ |
通过如下语句进行OpenCV编译是否成功进行测试:
1 | import cv2 |
则出现报错:
1 | ImportError: No module named cv2 |
报错显示,在python当中并不能正确的引入OpenCV库。
第一时间考虑链接的问题,通过ls -l命令后可以发现当前链接是个坏链,因此查看安装路径发现编译过程并没有生成cv2.so。
该bug定位以及修复的难点在于:
- 整个编译过程(见2.2)没有出现interrupt,没有报error,无法通过error对bug进行定位。
- OpenCV本身编译中的许多not found warning最终只是对个别模块的支持受限,对OpenCV正常使用不造成影响,因此对通过log排查bug造成难度。
- 此次bug在网上并没有一致的案例,属于较为特殊的情况。
Bug成因
成因分析
要清楚bug的成因,首先要知道cv2.so是什么。
cv2.so是支持python调用OpenCV的动态链接库,即在python程序运行时能够被动态的申请并调用,因此cv2.so的缺失,与OpenCV源码在对支持python的接口部分编译出现了问题,或者是OpenCV编译时并没有编译python接口模块。
前面在2.2与2.3中提到,在该bug场景当中,整个编译流程并没有interrupt,因此编译报错的情况首先应可以排除,那么cv2.so无法生成的原因就可以限定于是OpenCV没有编译python接口模块。
那么,为什么OpenCV没有编译python接口呢?
2.3中提到,OpenCV在一些not found warning中,会对模块的编译产生受限,那么python接口的未编译就极有可能是因为OpenCV在cmake阶段查询python环境时,未查询到python的某部分环境,在编译阶段无法链接所需python库,最终导致了python接口的未编译。
最终在cmake的log文件当中:
1 | -- Could NOT find PythonLibs (missing: PYTHON_INCLUDE_DIRS) |
验证了当前猜想。
因此,我们可以归结出OpenCV编译无法生成cv2.so在该场景下的成因,即是当前环境下python库的缺失。
补充
3.1中已对bug成因进行了分析,在这里补充一下为什么在已有python环境的情况下,依然会有类库依赖缺失问题。
Linux发行版通常会把类库的头文件和相关的pkg-config分拆成一个单独的xxx-dev(el)包。针对python环境下,该类库即python-dev。
那么什么情况需要安装python-dev?
需要自己安装一个源外的python类库, 而这个类库内含需要编译的调用python API的c/c++文件(如:安装使用WiringpisPi库需要python-dev)。
你自己写的一个程序编译需要链接libpythonXX.(a/so)(注:以上不含使用ctypes/ffi或者裸dlsym方式直接调用libpython.so)
其他正常使用python或者通过安装源内的python类库的不需要python-dev.
发现并修复bug过程
4中归纳1-3中发现并修复bug的过程:
查看cv2.so链接状态,并发现cv2.so缺失。
进行重编译,确认流程步骤完整,并尝试bug复现。
查看cmake过程的log文件,未发现实际相关error。查看lib文件夹下libopencv类库链接正常。
确认是否为cmake参数问题,核对参数,并对相关参数条件覆盖测试(各取OFF/ON)。依然无法修复bug,排除cmake参数问题。
尝试使用OpenCV3.4.6(原3.4.0)进行编译,仍然无法修复bug,排除版本更替丢失或兼容性问题。
查询到一个案例(见参考资料),该案例因在python中没有安装numpy库依赖,导致最终cv2.so无法生成。该案例提供了本bug场景的一个解决思路,即cv2.so的生成失败可能与python环境缺失相关。
查看log文件,发现python类库在编译过程中并未找到,支持了步骤6中的猜想。
“sudo apt-get install python2.7-dev”安装python类依赖。
重新编译,成功生成cv2.so,并可通过“import”测试。
参考资料
百度百科(opencv):
https://baike.baidu.com/item/opencv/10320623?fr=aladdin
pyimagesearch(Install OpenCV 3.0 and Python 2.7+ on Ubuntu):
https://www.pyimagesearch.com/2015/06/22/install-opencv-3-0-and-python-2-7-on-ubuntu/
cnblogs(没有cv2.so文件):
https://www.cnblogs.com/whu-zeng/p/6284795.html
cnblogs(python和python-dev):
https://www.cnblogs.com/cj2014/p/3848673.html
csdn(Linux下动态库和静态库的制作及使用):