共享库中未定义符号异常问题求助
共享库未定义符号问题分析与解决
问题原因拆解
1. 为什么ldd未显示libA.so依赖libB.so?
链接器是从左到右按顺序处理参数的:当你把-lB放在A.cc前面时,链接器先扫描libB.so,但此时还没处理A.cc生成的目标文件,不知道需要哪些符号。链接器默认只会将被已处理目标文件引用到的库添加为依赖,所以它判定libB.so的符号未被使用,不会将其加入libA.so的依赖列表。
2. 为何链接libB.so后libA.so仍存在未定义符号?
还是参数顺序导致的问题。链接器处理完-lB后才处理A.cc的目标文件,此时发现未定义符号,但链接器不会回头重新扫描之前的库。这些未定义符号就留在了libA.so中,和libB.a里的未定义符号一致只是巧合——你确实链接了libB.so,但顺序错误导致符号未被解析。
3. 静态库链接成功的原因
先链接静态libA.a再链接B能成功,是因为静态库本质是目标文件的归档包。链接主程序时,先处理libA.a里的目标文件,产生未定义符号;之后处理libB(无论静态还是动态)时,链接器会用libB的符号解析这些未定义项,顺序正确自然就完成了链接。
解决方案(无需修改A、B的构建系统)
核心是调整链接参数顺序,让-lB出现在源文件/目标文件之后。你可以通过以下方式实现:
编译
libA.so时,在命令行追加额外的-lB到末尾:make LDFLAGS="$LDFLAGS -lB"最终链接命令会变为:
g++ -shared -fPIC -DPIC -std=c++17 -fPIC -fopenmp -I<path/to/includes> -Wl,-rpath,<path/to/libs> -L<path/to/libs> -lB A.cc -o libA.so -lB末尾的
-lB会在处理完A.cc的目标文件后被扫描,链接器能找到需要的符号,同时将libB.so添加为libA.so的依赖。更稳妥的方式是使用链接器
--no-as-needed选项,强制保留libB.so作为依赖:make LDFLAGS="-Wl,--no-as-needed -lB"这个选项会让链接器不忽略看似未被使用的共享库,确保
libB.so被加入依赖并解析所有未定义符号。
内容的提问来源于stack exchange,提问作者tegonzalo
相关产品推荐
相关产品推荐

