我!终于!成功在MAC下面把opencv4程序静态编译起来了!
先上compile的命令:
g++ -std=c++11 main.cpp preprocess.cpp -framework Foundation -framework OpenCL -framework CoreMedia -framework AudioToolbox -framework CoreVideo -framework AVFoundation -framework CoreFoundation -framework CoreGraphics -I./include -L./lib -lopencv_videoio -lopencv_gapi -lopencv_features2d -lopencv_photo -lopencv_ts -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_core -lippiw -lippicv -ljpeg -llibpng -littnotify -lade -lIlmImf -lzlib -llibjpeg-turbo -lquirc -llibjasper -llibtiff -llibwebp -o main
有没有发现有什么不对?没错就是挂在-L和-I前的一堆 -framework,微笑,因为MAC OS下自己有一堆的framework,opencv在MAC下编译会依赖这些静态库,所以编译的时候需要把他们一起连接上,这也是为什么即使把opencv的静态库全部连接上并整理好依赖关系还会出现
Undefined symbols for architecture x86_64:
"_CFDataGetBytePtr", referenced from:
CvVideoWriter_AVFoundation::writeFrame(_IplImage const) in libopencv_videoio.a(cap_avfoundation_mac.mm.o)
"_CFRelease", referenced from:
CvCaptureFile::~CvCaptureFile() in libopencv_videoio.a(cap_avfoundation_mac.mm.o)
CvCaptureFile::grabFrame() in libopencv_videoio.a(cap_avfoundation_mac.mm.o)
releaseCallback(void, void const) in libopencv_videoio.a(cap_avfoundation_mac.mm.o)
"_CGColorSpaceCreateDeviceRGB", referenced from:
CvVideoWriter_AVFoundation::writeFrame(_IplImage const) in libopencv_videoio.a(cap_avfoundation_mac.mm.o)
"_CGColorSpaceRelease", referenced from:
CvVideoWriter_AVFoundation::writeFrame(_IplImage const*) in libopencv_videoio.a(cap_avfoundation_mac.mm.o)
类似于这种错误(方便复制错误的旁友搜到这个帖子)
回归正题
1. MAC OS下静态编译
参考https://shiffman.net/opencv/2011/01/23/how-to-build-opencv-static-libraries-mac-os-x/
这篇里的with_ffmpeg去掉的话就不能进行视频处理,所以如果要处理视频的话请看下面的更新。
其实就是在CMAKE里把BUILD_SHARED_LIBRARIES=OFF, CMAKE GUI的确很好用,安利。不过这样编译的静态库好像缺了一个libippicv.a,我是直接在opencv的安装目录下找到的,所以可能不用自己重新静态编译,直接下载的Opencv安装目录下的静态库也能用。
2. 静态链接
首先把头文件全部拷贝到当前目录的include下,静态库全部拷贝到当前目录的lib下。
因为opencv的静态库之间还有依赖性,所以直接一股脑放上去是不行的。在电脑里已经安装了opencv的情况下可以参考 pkg-config --cflags --libs opencv4出来的动态库的顺序。
如果依然搞不清顺序,可以查看undefined symbol的错误信息,比如“_WebPDecodeBGRAInto”, 利用 nm lib/*.a -A| grep "_WebPDecodeBGRAInto" 可以找到含有此标志的.a文件,其中U代表引用别的静态库此标志,D代表定义此标志(大概?不懂静态库编译,从我的搜索结果来看好像是这样)把D的文件放到U的后面就可以了,比如此处把-lwebp 放在-lopencv_imgcodecs的后面。
最后当你发现有的symbol在/usr/local/下所有的静态库文件都找不到的时候。。。。
谷歌会发现这个symbol原来在OSX的framework中,微笑.jpg。
于是我发现了-framework Foundation -framework OpenCL -framework CoreMedia -framework AudioToolbox -framework CoreVideo -framework AVFoundation -framework CoreFoundation -framework CoreGraphics,最后把这些framework都加上,终于大功告成啦!
(碎碎念:写Opencv的程序花了一天,想compile成独立的可执行程序断断续续花了三周真是遭不住。尝试过动态连接+用install_name_tool 修改程序动态库的路径,opencv的动态库是没问题了,但是opencv_core依赖的一个openblasp库不知道为什么即使打包在文件夹里依然会显示no suitable image found, did find error... 大概意思好像是虽然有这个文件但是文件有问题?不合适,这真的不合适_> 有旁友动态连接成功了的话请告诉我怎么搞! 拜谢!)
更新(错误方法):
程序运行时发现video capture报错无法运行,搜索之后发现是缺了ffmpeg的库,系统自带的ffmpeg有动态库和静态库,但是opencv编译时去掉了WITH_FFMPEG,没去掉的话也是默认连接动态库,因此在opencv的CMAKE里把ffmpeg相关的库都修改成静态库:
重新编译opencv,这时候make又会开始报Undefined symbol的错误,又要回过头调查每个ffmpeg的库依赖(MMP)
更更新:
上面的方法直接使用ffmpeg静态库的时候还不知道ffmpeg依赖libbz2和libiconv,libiconv的静态库标志和动态库标志又不一样,一个是_libiconv_open一个是_iconvopen,系统自己的ffmpeg里面的libavcodec又有一大堆依赖,纠结了很久libiconv怎么处理甚至还差点把电脑弄坏= =。
终于发现其实可以自己重新编译一次ffmpeg,有把iconv去掉这一个选项!
所以步骤为
- 下载ffmpeg源码并编译
./configure --enable-static --disable-iconv --disable-gnutls --disable-libbluray --disable-x86asm --enable-avresample
gnutls和libbluray一个没找到静态库一个静态库有一堆依赖-皿-,系统自带的ffmpeg里有他们不过ffmpeg的configure默认是disable的,加一个保险一点。 --disable-iconv和--enable-avresample是必需的因为默认Iconv会编译进去以及不编译avresample的静态库,但是这个库又是opencv会引用的。 - 下载libbz2源码并编译
因为这个静态库很好编译所以我没有尝试ffmpeg编译时能不能去掉这个库, 查看了一下configure里没有对这个库disable的说明所以我猜可能是不能去掉的。 -
修改opencv CMAKE
shared-library和之前一样去掉✅
新的ffmpeg路径:
这里虽然有libiconv的路径,但是因为这个是ffmpeg的dependency不是opencv的dependency,所以后面compile的时候可以忽略这个库,就不会发生symbol undifined的问题啦!
要注意configure以后一定要往下拉看video IO模块ffmpeg有没有显示yes:
这些版本其实都是动态库的版本不用管
generate并重新编译opencv。 - 用新的opencv和ffmpeg静态库替代之前的库, 在compile的时候添加依赖项然后就可以运行视频处理了!
可能需要添加一些ffmpeg的依赖库,不过这个时候的依赖库都是系统里可以很容易找到静态库的了,找不到的symbol可以用nm $(find /usr/ -type f -name "*.a") -A |grep "_aom_codec_av1_cx"
这个命令行寻找需要的symbol在哪。
最后的compile命令:
g++ -std=c++11 main.cpp preprocess.cpp -lavformat -lavcodec -lavdevice -lavfilter -lavutil -lswresample -lavresample -lswscale -llzma -framework Security -framework VideoToolbox -framework CoreServices -framework Foundation -framework OpenCL -framework CoreMedia -framework AudioToolbox -framework CoreVideo -framework AVFoundation -framework CoreFoundation -framework CoreGraphics -framework Cocoa -framework Accelerate -framework QuartzCore -I./include -L./lib -lopencv_videoio -lopencv_gapi -lopencv_features2d -lopencv_photo -lopencv_ts -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_core -lippiw -lippicv -ljpeg -llibpng -littnotify -lade -lIlmImf -lzlib -llibjpeg-turbo -lquirc -llibjasper -llibtiff -llibwebp -lssl -lcrypto -lcharset -lbz2 -lxvidcore -o main
新加的有ffmpeg的几个库,Security, VideoToolBox, CoreServices framework, 还有最后的ssl, crypto, charset, bz2, xvidcore库,除了libbz2需要自己编译静态库,别的都是系统里就有的。