c++静态库链接顺序引发的bug
Posted 爆米花好美啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++静态库链接顺序引发的bug相关的知识,希望对你有一定的参考价值。
最近做个OpenCV的项目,搞了半个月一直解决不了,最后发现是静态库链接顺序的问题
问题描述以及解决办法
最近用emsdk将c/c++转到wasm,用到emsdk里面./emcc来编译c/c++,注意emsdk自带的clang版本是clang3.x
# Makefile
-lopencv_core -lopencv_highgui -lopencv_imgproc
编译后出现一下错误,很多网友也有此问题Building with opencv works well until I use cv::resize, opencv-3-4-3-in-emscripten-cannot-work
error: undefined symbol: _Z7cvFloorRKN2cv10softdoubleE
warning: To disable errors for undefined symbols use `-s ERROR_ON_UNDEFINED_SYMBOLS=0`
error: undefined symbol: _Z7cvRoundRKN2cv10softdoubleE
error: undefined symbol: _Z9cvRound64RKN2cv10softdoubleE
error: undefined symbol: _ZN2cv10softdoubleC1Ei
error: undefined symbol: _ZN2cv10softdoubleC1Ex
error: undefined symbol: _ZNK2cv10softdoubledvERKS0_
error: undefined symbol: _ZNK2cv10softdoublemiERKS0_
error: undefined symbol: _ZNK2cv10softdoublemlERKS0_
error: undefined symbol: _ZNK2cv10softdoubleplERKS0_
Error: Aborting compilation due to previous errors
一直无法用cvresize函数,很是奇怪,最后无意发现一个链接 undefined reference to cv::softdouble::operator/,试着调整了一下静态库的链接顺序,改为
# Makefile
-lopencv_highgui -lopencv_imgproc -lopencv_core
编译成功!
Why
- 传统的Unix编译环境下, 静态库的加载是顺序搜索一遍, 遇到没链接的函数就记下, 如果这个函数在后面的库或obj中出现了, 链接器就会把这个函数所在的obj链接过去, 不包含未链接函数的obj就会被忽略过去(静态库也只是obj的简单打包而已).
- 因为lopencv_imgproc依赖lopencv_core,而当lopencv_imgproc中的cv::resize()需要lopencv_core的cvFloor时已经不可用了,很脑残的设计,不知道为什么在前面链接过就失效了
- 所以如果库A依赖库B, 链接的顺序就应该写为A B, 如果相互依赖就应该为A B A或者B A B的顺序
而我在本地用clang时这个顺序就没啥问题,而且caffe提供的顺序也是lopencv_core在前面,我猜是后面高版本的gcc/clang都已经“修复”了这个傻傻的设计。
大多现代的编译链都不会有这个问题, 但是传统, 标准以及我手里的这个编译链(emsdk的低版本clang)却都是这样的, 为了通用, 以后还是注意点吧.
以上是关于c++静态库链接顺序引发的bug的主要内容,如果未能解决你的问题,请参考以下文章