g++-9链接libstdc++.so.6.0.30时引用高版本GLIBCXX符号疑问
使用g++-9/g++-10/g++-11搭配libstdc++.so.6.0.30时,调用std::condition_variable::wait会引用GLIBCXX_3.4.30符号,但搭配libstdc++.so.6.0.29时则引用GLIBCXX_3.4.11符号。我预期链接libstdc++.so.6.0.30时也使用GLIBCXX_3.4.11符号,请问我的预期有误还是这是异常情况?
最简示例代码
// main.cpp #include <condition_variable> #include <mutex> int main(int argc, char** argv) { std::mutex mtx; std::condition_variable cv; std::unique_lock<std::mutex> lck(mtx); cv.wait(lck); return 0; }
验证步骤
- 编译命令:
g++-9 main.cpp -o main - 查看GLIBCXX符号版本:
strings main | grep GLIBCXX
链接libstdc++.so.6.0.30时输出
GLIBCXX_3.4.11 GLIBCXX_3.4.30 GLIBCXX_3.4 _ZSt9terminatev@GLIBCXX_3.4 _ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE@GLIBCXX_3.4.30 _ZSt20__throw_system_errori@GLIBCXX_3.4.11 _ZNSt18condition_variableC1Ev@GLIBCXX_3.4.11 _ZNSt18condition_variableD1Ev@GLIBCXX_3.4.11
链接libstdc++.so.6.0.29时输出
GLIBCXX_3.4.11 _ZSt20__throw_system_errori@GLIBCXX_3.4.11 _ZNSt18condition_variableC1Ev@GLIBCXX_3.4.11 _ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE@GLIBCXX_3.4.11 _ZNSt18condition_variableD1Ev@GLIBCXX_3.4.11
你的预期没有错误,这并非异常情况,而是libstdc++符号版本机制的正常表现,且可以通过编译选项调整达到你的需求。
原因解释
libstdc++.so.6.0.30中,std::condition_variable::wait的实现被更新,新增了带GLIBCXX_3.4.30后缀的符号,但旧版本的GLIBCXX_3.4.11符号依然存在于库中。当g++-9链接新版本libstdc++时,链接器默认会优先选择该函数的最新符号版本,而非旧版本。
解决方案:强制指定旧符号版本
如果你想让程序链接到GLIBCXX_3.4.11版本的符号,可通过以下步骤实现:
- 创建版本脚本文件(例如
version.lds),内容如下:
GLIBCXX_3.4.11 { *; };
- 修改编译命令,加入版本脚本参数:
g++-9 main.cpp -o main -Wl,--version-script=version.lds
编译完成后,再用strings main | grep GLIBCXX验证,会发现std::condition_variable::wait已经引用GLIBCXX_3.4.11符号,和链接libstdc++.so.6.0.29时的效果一致,程序可在支持GLIBCXX_3.4.11的旧系统上运行。
补充说明
libstdc++的符号版本机制核心是向前兼容:新版本库能运行旧程序,但新编译的程序若使用了新符号,就无法在仅安装旧库的系统上运行。你的需求本质是让新编译的程序兼容旧系统,因此强制指定旧符号版本是合理且有效的解决方案。
内容的提问来源于stack exchange,提问作者lfreist

