最近尝试给两个ARM板子与用交叉编译配置OpenCV,为此查了很多资料,学了很多交叉编译的操作。 经过多次的交叉编译全都失败,都不能成功的在目标板上运行简单的OpenCV的Demo程序。最后都是在对板子失去希望的时候,破罐破摔的直接用ARM板自己编译。讽刺的是,这样虽然效率低到极致,但最后还真的成功了…… 在Demo程序在ARM板自行编译成功的OpenCV环境中顺利的跑起来的时候,笔者感觉茫然无措,根本没有什么开心的情绪,一是感觉终于解脱了,二是感觉自己学了这么长时间的交叉编译,最后还是没有用,还写了这么多技术博客,深深的无力感…… 笔者决定还是痛定思痛,还是得总结一下这段时间交叉编译的错误所在。在中间的一些操作中,笔者总感觉自己交叉编译的过程中,就是还是那么差了一点点才导致失败。虽然已经没有精力再重新搞一遍交叉编译。这些疑点还是可以记录下来,以后有机会的时候,笔者会重新拿出来看,也许真的是这些原因导致我交叉编译错误呢?
笔者的两个ARM板配置如下:
之前笔者写的交叉编译相关技术文章地址如下: 《 Ubuntu 14.04 LTS下使用arm-linux-gcc交叉编译OpenCV 2.4.9》 《Windows系统下远程连接BeagleBone Black开源电路板桌面》 《Windows系统下通过PSCP传输文件至BeagleBone Black》 《交叉编译学习笔记(一)——交叉编译和交叉工具链》 《交叉编译学习笔记(二)——交叉编译器的命名规则》 《程序生成之编译、链接、加载浅析》
BeagleBone Black(即BBB)上OpenCV的编译是真的痛苦。 主要原因是它的4GBytes的容量实在让我绝望,而且我拿到板子的时候基本上也只有1GBytes的剩余容量了,OpenCV编译过程中生成的中间文件大小都得有2GB啊…… 这导致笔者几乎从一开始就否定了直接用BBB编译的想法,一直在尝试交叉编译……
讽刺的是交叉编译一直失败,最后我还是直接在ARM上编译成功的,即先设置各项CMake选项,然后对OpenCV进行make操作,最后make install,并make clean清除中间文件。
为什么笔者能在1GBytes的剩余容量中编译出2GB的中间文件?这就是最蛋疼的地方所在…… 笔者OpenCV源码路径是/root/Desktop/opencv-2.4.9
,编译生成路径是源码路径下的/build路径。在make过程中,中间文件基本存在于/root/Desktop/opencv-2.4.9/build/module
中,所以在make过程中,笔者会在终端显示已经将上一个模块编译结束后,直接手动将对应模块路径下的中间文件删除……
笔者当时想反正make install
指令的目标一般都是/include
, /lib
, /bin
文件夹,这些中间文件占的空间又这么大,删除也不会对make install
指令有什么影响……
事实证明我是正确的,但是过程很繁琐,不能像在PC机上编译时,只要放在那里编译就好,笔者可以去看电视剧…… 这种盯着终端输出信息,手动删除编译中间文件的操作,需要进行两遍:make一次,make install一次。如果中间跑神了,make过程中出现了错误提示说容量不够导致make失败,那就惨了,需要重新多来一次……
最后make, make install成功后,写了一个Demo文件test_opencv.cpp,内容如下:
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
const char* imagename = "/root/Desktop/miska.jpg";
Mat img = imread(imagename);
if(img.empty())
{
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
}
else
printf("Read Image Success.\n");
Mat imgGray;
cvtColor(img, imgGray, CV_BGR2GRAY);
const char* imgGrayName = "/root/Desktop/miska_gray.jpg";
vector<int> params;
params.push_back(CV_IMWRITE_JPEG_QUALITY);
params.push_back(90);
imwrite(imgGrayName, imgGray, params);
if(imgGray.empty())
{
fprintf(stderr, "Can not save image %s\n", imgGrayName);
return -1;
}
else
printf("Save Image Gray Success.\n");
imshow("Image", imgGray);
waitKey();
return 0;
}
然后在cpp文件所在目录下,输入指令如下:
arm-linux-gnueabihf-g++ `pkg-config --cflags --libs opencv` test_opencv.cpp -lpthread -lrt -o test_opencv_g++_show
然后就生成了test_opencv_g++_show的可执行文件。这时候输入指令:
./test_opencv_g++_show
便出现如图所示:
除了显示出图片之外,在桌面上还存储了相应的灰度图.jpg文件miska_gray.jpg。
这就是笔者愚蠢但有效的移植方法……
其实上面成功的内容并不是在make install之后直接就完成的。 笔者对test_opencv.cpp进行编译指令如下:
arm-linux-gnueabihf-g++ `pkg-config --cflags --libs opencv` test_opencv.cpp -lpthread -lrt -o test_opencv_g++_show
却出现如下错误提示:
error while loading shared libraries: libopencv_highgui.so.2.4
后来笔者参考了网上的资料,原来是笔者的OpenCV路径没有设置。
参考地址:
http://blog.csdn.net/gaobobo138968/article/details/24253703
http://blog.csdn.net/fangquan1980/article/details/49363173
首先,笔者在进行make install命令之前,设定的install路径为/usr/local/arm/opencv-install/
,生成的库文件都是动态链接库。而在Linux系统中,文件/etc/ld.so.conf
中记录着动态函数库所在目录。所以笔者需要在/etc/ld.so.conf
中将路径/usr/local/arm/opencv-install/
添加进去。
然后就需要执行指令:
ldconfig
这样就将/etc/ld.so.conf
中的内容读入了高速缓存,同时/etc/ld.so.cache
文件中开始记录数据。
重新用arm-linux-gnueabihf-g++编译Demo程序,就编译成功,且能成功运行了。
之前笔者的OpenCV是交叉编译的,且交叉编译的过程已经在我之前的文章中《 Ubuntu 14.04 LTS下使用arm-linux-gcc交叉编译OpenCV 2.4.9》有过记录。
笔者把编译后的目录opencv-install放置在和PC机相同的路径(即/usr/local/arm/opencv-install/
)
之后使用arm-linux-gnueabihf-g++编译Demo程序,然而出现错误:
/usr/local/arm/opencv-install/lib/libopencv_calib3d.so: flie not recognized: File format not recognized
collect2: ld returned 1 exit status
也就是因为这个原因,笔者放弃了用PC机交叉编译……
网上查了查原因,有人出现这样的问题,但却是因为文件格式,或者是x86的32/64位系统版本,或者是直接就没有用arm-linux-gcc系列的编译器之类的原因,况且我用的也是arm平台的编译器(笔者在PC机端用的编译器是arm-none-linux-gcc-4.3.2,在BeagleBone Black板上的编译器是4.6.3版本的arm-linux-gnueabihf-gcc),虽然版本不同,但笔者认为在PC机上用的编译器应该是被BBB的编译器向下兼容的。
对于这种情况,笔者感觉只有两种操作可能解决: 1、用4.6.3版本的arm-linux-gnueabihf-gcc编译相关库;(其实也尝试过,但是在编译ffmpeg源码时貌似出了问题…… ) 2、当时确实没有用过ldconfig命令,也可能是这个原因?……
这个本来都不想回忆的,因为实在太低级失误了…… 笔者曾经用了gcc的编译器编译Demo程序,然而库文件是交叉编译的arm-linux-gcc版本,结果肯定是运行不了的…… 具体什么情况忘了,记着这个教训就好了……
虽然交叉编译失败,但是ARM本机编译方面,相比起来迅为的ARM开发板比BBB简单的多了。毕竟i.MX6Q的CPU可以使用多核编译,而且eMMC容量也大得多,所以不需要盯着终端输出信息各种手动删除中间文件腾空间,只需要简单的cmake, make, make install,之后就可以编译运行了…… 其他的基本可以参照BBB的成功范例。
i.MX6Q的系统是和PC机一样的Ubuntu,所以错误情况比较少,基本上还是可以参考BBB的总结……(原谅笔者的懒惰,一是因为错误情况少,二是因为时间稍微有点久远了……)
笔者真的是已经没有精力再专门重新编译了……所以只有在此处记录为博客,以后如果真有重新交叉编译的情况,再重新尝试。 希望个人的错误总结也可以有点价值吧。