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::resizeopencv-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的主要内容,如果未能解决你的问题,请参考以下文章

如何确定最快的链接顺序?

opencv静态链接库cmake链接顺序问题

将静态本机库链接到托管 C++ 项目会在

CMake和静态库顺序

C++静态库与动态库详解

如何将本机 C++ 静态库链接到托管 C++ 程序集