问题报错 最近Linux上编译一个项目遇到这样的报错:
ld.lld: error: undefined symbol: std::__cxx11::basic_string, std::allocator >::compare(char const*) const
>>> referenced by xxx.cc
>>>xxx.o:(tflite::FlatBufferModel::GetMinimumRuntime[abi:cxx11]() const) in archive /home/xxx/project/libtensorflow-lite.ald.lld: error: undefined symbol: std::__cxx11::basic_string, std::allocator >::_M_create(unsigned long&, unsigned long)
>>> referenced by xxx.cc
>>>xxx.o:(tflite::FlatBufferModel::GetMinimumRuntime[abi:cxx11]() const) in archive /home/xxx/project/libtensorflow-lite.a
还有一大堆类似这个:
undefined symbol: cv::imwrite(cv::String const&, cv::_InputArray const&, std::__1::vector > const&)
一个报错来源
tflite
静态库,另一个来源是opencv_world
动态库。其实不只是这两个库,编译项目时用到其他第三方库的时候也很有可能遇到这种报错
先说结论
- 解决方案1:在编译参数里加上:
-D_GLIBCXX_USE_CXX11_ABI=0
,如果不行把0改成1,如果还不行,看2:。 - 解决方案2:在编译参数里指定:
-std=c++11 -stdlib=libstdc++
,如果不行,在编译参数里指定:-std=c++11 -stdlib=libc++ -lc++ -lc++abi
注意要清除掉之前的编译产物.o .a .so .h.gch等重新编译。下面是问题分析:
出错原因 像这种
std__1
,std::__cxx11
报错报到非常底层的数据结构上,问题一般都出在链接上,像这里这两个报错,最本质的原因是:第三方库和你的项目用了不同的方式进行编译,具体是什么地方不同造成的?我已知的,有这样两个:- 采用的不同版本的C++标准,比如项目编译采用的c++11,但是第三方库,采用的c++03编译而成
- 编译采用的C库不同,如第三方库连接的是libc++.so,然而项目编译使用的libstdc++.so
这个原因导致的问题,解决方案在搜索引擎里是烂大街的,对着报错随便一搜都有,都一模一样,而且都标了原创也不写参考链接。个人认为,灵感应该都是源于stackoverflow上的这个讨论:Converting std::__cxx11::string to std::string在C++03中,基础字符串的定义是:
std::basic_string
然而在C++11中,基础字符串变成了:
std::__cxx11::basic_string
(libstdc++)或者std::__1::basic_string
(libc++)。因此编译的时候就会报错,未定义的引用什么的。那么解决呢,也很简单。如果你的第三方库是自己编译的,那么请重新用和你项目一致的编译参数重新编译一次。尤其是
-std=c++11
。如果你的第三方库不是自己编译的,那么你就需要迫使自己的项目编译和第三方库保持一致,在你的源文件中加上参数:
#define _GLIBCXX_USE_CXX11_ABI 0
0代表关闭C++11特性,1代表开启。出现上面的报错一般都是第三方库没有开启导致的,所以本地也关掉。如果改源文件不方便,也可以在编译参数中加上:
-D_GLIBCXX_USE_CXX11_ABI=0
-D就是宏定义,这样也可以。如果是C++标准不同导致的问题,上述操作会有用,就算不能完全解决问题,至少报错会变。但是我本次遇到的这个问题,按照上面这办法没用,后来经过分析,才发现了下面这种:
第二个、因为编译时采用的C库不同导致报错
很多人会怀疑这是编译器不同导致的,比如第三方库用gcc编译,而项目用clang编译,这样的话就会报出上面的问题。其实不全对、根本的原因不在编译器,而是他们采用的C库不同,gcc默认用的是libstdc++,而clang默认采用的是libc++。如果在编译时通过
-stdlib
明确指定一致,编译器一致与否是没关系的。在上面也提到了,在不同的C库当中,对于基础字符串的定义是有差异的:
std::__cxx11::basic_string
(libstdc++)std::__1::basic_string
(libc++)
libstdc++
,动态链接的时候,会记录一个名为std::__cxx11::basic_string
的符号。而这时候你变编译自己的项目,使用libc++
,它提供的是std::__1::basic_string
,那连接到第三方库,第三方库去找std::__cxx11::basic_string
这个符号,当然会找不到,报错未定义的引用。解决方案呢,就是编译时明确指定编译时所采用的C库保持一致,重新编译即可
- 使用
libstdc++
的话:加上-std=c++11 -stdlib=libstdc++
- 使用
libc++
的话:加上-std=c++11 -stdlib=libc++ -lc++ -lc++abi
我一般推荐第三方库自己编,修改编译参数和自己的项目保持一致。因为第三方库毕竟是历经检验的成熟开源项目,切换C库编译器平台什么的基本问题不大,我们自己的项目,一般很难保证有这样的高水准,换个C库啥乱七八糟错的语法错误都出来了。方法探究 未定义的引用的问题在C++的编译过程中最为常见,这个错误出现在编译的链接阶段,有九成的原因都是链接库不对导致。遇到这种问题,分析问题的本质离不开基础的编译原理,对于编译参数的基础可以参考:g++编译详解
在此呢就上面的问题进行分析,它出现了对某个函数或者数据结构未定义的引用,比如这个:
error: undefined symbol: std::__cxx11::basic_string, std::allocator >::compare(char const*) const
找不到一个名为compare的函数,返回值为basic_string。这个函数在我们的代码中没有显示调用,而是字符串在用
==
进行比较时隐式调用,所以它的报错非常常见因为我们经常会比较字符串的异同。这时候要做的就是两件事:
1、第三方库中记录的符号原型是什么?
2、我们编译时提供的符号原型是什么?
最上面的报错,可以看得出来一个是在静态库:
libtensorflow-lite.a
中,一个是在动态库libopencv_world.so
中。而且一看函数名字,明显不是我们自己写的,那么我们找找这个库中记录的符号名字是什么:nm libtensorflow-lite.a | c++filt | grep compare
文章图片
nm -D libopencv_world.so.3.4.6 | c++filt | grep compare
文章图片
你看,一个是
__cxx11
命名空间 ,一个是__1
命名空间。这两种放到一个项目里编译不打架才怪呢,当然这里的符号前面的标志都是U,也就是未定义,说明这个符号实在其他动态库里定义的。我们再看看标准库里的定义:nm -D /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | c++filt | grep compare
文章图片
nm -D /usr/lib/x86_64-linux-gnu/libc++.so.1 | c++filt | grep compare
文章图片
看到了吧:两种标准库里对应的命名空间的名字是不一样的,可以看的出来,我这里的
libopencv_world.so
是使用libc++
编译的,而libtensorflow-lite.a
是使用libstdc++
进行编译的。这个可以通过编译参数-stdlib
来指定,像我的项目这种情况下,tensorflow和opencv横竖得重新编译一个。我自己的项目使用的是clang+libc++。说以重新编译了tensorflow,效果如下:文章图片
这样就确保了libtensorflow-lite.a链接阶段找符号的时候找libc++库里的符号,就解决了报错的问题。
同样其他情况下出现莫名其妙的未定义的引用的问题,也可以参照此方法呢,先看看自己的库里记录的符号签名是什么,然后看看链接库里的符号签名是什么,如果签名一致,说明没有链接到,检查链接库的路径什么的。如果签名不一致,说明连接的库不对,考虑更换版本解决。
【Qt/C++|error: undefined symbol: std::__cxx11::basic_string和std::__1::basic_string】参考链接:
- https://stackoverflow.com/questions/24342312/clang-seems-to-use-the-gcc-libraries
- https://stackoverflow.com/questions/33394934/converting-std-cxx11string-to-stdstring
- https://blog.csdn.net/ufolr/article/details/52669333?utm_source=blogxgwz3
- https://blog.csdn.net/n_o_n/article/details/99336919
- https://www.cnblogs.com/lukybee/p/11846889.html
推荐阅读
- QT学习之路|【qt+opencv】实现人脸识别打卡系统2.0
- 微软|MSRA被曝停招国防七子及北邮学生
- Qt基础|Qt 事件处理机制简介
- Qt基础|Qt QTreeWidget 详解
- Qt基础|Qt 解析XML方式(三)流方式
- Qt基础|Qt 解析XML方式(二)SAX
- Ubuntu|Ubuntu下Qt Creator配置opencv
- Qt|windows环境下在qt中配置opencv环境