undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE

一、问题背景

我是在搭建kvm+qemu+libvirt环境,在安装好所有rpm依赖后启动libvirt时报错 (code=exited, status=3),根据提示通过 journalctl -xeu libvirtd.service查看日志,发现是

内部错误:Failed to load module '/usr/lib64/libvirt/storage-backend/libvirt_storage_backend_rbd.so': /usr/lib64/ceph/libceph-common.so.2: undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE

undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE_第1张图片

undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE_第2张图片

首先我查询了下libceph-common.so.2库起源,发现是我安装的一个rpm包。

undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE_第3张图片

这个包是我通过src编译出来的,所以rpm包肯定没问题,既然是这个库找不到一个定义,那就是这个库依赖的别的第三方库可能找不到这个定义,于是ldd查询这个库的依赖:

undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE_第4张图片

可以看到这个库确实找不到这个symbol变量。

二、搜寻原因

首先根据undefined symbol搜寻,因为我是linux下rpmbuild编译的,不在VS或eclipse等IDE中,所以先查阅了一下 undefined symbol 可能的原因 来指引一下接下来的排查方向

  • 依赖库未找到: 这是最常见的原因,一般是没有指定查找目录,或者没有安装到系统查找目录里

  • 链接的依赖库不一致: 编译的时候使用了高版本,然后不同机器使用时链接的却是低版本,低版本可能缺失某些 api

  • 符号被隐藏: 如果动态库编译时被默认隐藏,外部代码使用了某个被隐藏的符号。

  • c++ abi 版本不一致: 最典型的例子就是 gcc 4.x 到 gcc 5.x 版本之间的问题,在 4.x 编辑的动态库,不能在 5.x 中链接使用

这篇文章解释了出现symbol Undefine的大概原因:

undefined reference to symbol xxxxx和undefined symbol:xxxx错误的原因分析以及解决方法-CSDN博客Linux下编译程序时,经常会遇到“undefined reference to XXX” 报错,这里总结一些可能的原因和解决方案,给需要的朋友:说到undefined reference error,先提一下Linux gcc链接规则:编译源代码时,链接的时候查找顺序是:(1) -L 指定的路径, 从左到右依次查找(2) 由环境变量 LIBRARY_PATH 指定的路径,https://blog.csdn.net/prettyshuang/article/details/48676815?spm=1001.2014.3001.5506这篇文章给出了一种CMake编译顺序导致出错的场景:

undefined symbol问题的查找、定位与解决方法-CSDN博客今天被客户测出来一个问题:程序执行中报错,报错内容如下XXXX:symbol lookup error:/home/....../libpdfium.so:undefined symbol:CRYPT_MD5Generate报错分析: 这个问题表明是符号未定义的问题,而且直接定位于产品链接的第三方动态库libpdfium.so中,于是从libpdfium.so中着手。..._undefined symbolhttps://blog.csdn.net/buknow/article/details/96130049这篇文章给出以一种通过修改CMakeLists.txt添加-disable-new-dtags 编译选项的解决:

rpath在ubuntu18.04的坑_刀么克瑟拉莫的博客-CSDN博客rpathhttps://blog.csdn.net/random_repick/article/details/122980119?spm=1001.2014.3001.5501这位兄台几乎总结了以上方法:

undefined symbol的解决记录_undefined symbol怎么解决_刀么克瑟拉莫的博客-CSDN博客一、看这里说,是链接顺序的问题,于是在CMakeLists里加了这个: -Wl,--start-group ${PROJECT_SOURCE_DIR}/lib/libngraph.so ${PROJECT_SOURCE_DIR}/lib/libinference_engine_legacy.so libinference_engine_transformations.so ${PROJECT_SOURCE_DIR}/lib/libinference_engine_undefined symbol怎么解决https://blog.csdn.net/random_repick/article/details/122886311我大概排除了下,采用了在CMakeLists.txt里面添加-disable-new-dtags的方法尝试(解压rpmbild/SOUCRE/xxx.tar.gz,将源码修改后提取patch,最后将patch放到rpmbild/SOUCRE/下并修改spec文件添加相应的Patch), 可奈何还没编译出rpm包(ceph编包速度有点慢,我的6CPU虚机编译的要一两小时),就已经找到了其他方法根除原因。

三、原因

其实搜寻了这么多,我基本对这个Undefined Symbol的原因有了个大概判定,基本可以推测是编译时和链接时用的动态库不一致导致,因为我就是在一台编译机上编rpm包,然后跑到另一台机器上安装运行的。

所以我尝试去分析这个变量,首先根据网上提示的用c++filt命令去解析这个Symbol最原始的信息以求去找源码查看,发现这个变量原始值是zero_or_powers_of_10_32_new,且来自fmt。

undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE_第5张图片

拿到变量名后,理论上需要针对libceph-common.so库所依赖的每一个库进行搜寻,去查找这个变量到底属于那个库。但这里c++filt已经解析出该变量属于fmt,且ldd发现libceph-common.so也确实依赖libfmt.so,另外有个特殊情况就是其中依赖的那个libfmt.so库也是我自己编译安装的,所以基本可以断定问题就出在这个fmt库。

undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE_第6张图片

于是首先分别探查我的编译机器 和 运行机器上 这个fmt库的版本

发现两者确实不一样,差距是fmt-7.1.3  对 fmt-7.1.0

于是去fmt官网https://github.com/fmtlib/fmt/tags?after=7.1.3去分别下载这两个版本的源码包,然后解压、查询有无此变量。

undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE_第7张图片

至此,原因找到:

Undefined Symbol正是由于fmt版本导致,该变量在fmt-7.1.3(编译机器)上有,而在fmt-7.1.0(运行机器)上无。

找到原因后,解决问题变得简单了,直接重新编译一版fmt-7.1.3对应的rpm (将spec中的Source0更换成7.1.3的版本号,其余的类似更改)并安装在运行机器上就可以了:

undefined symbol: _ZN3fmt2v76detail10basic_dataIvE27zero_or_powers_of_10_32_newE_第8张图片

你可能感兴趣的:(Linux,linux)