当指定 O2 标志时,gcc 链接到错误的 GLIBCXX 版本
gcc links to wrong GLIBCXX version when O2 flag is specified
我有一个使用 Makefile 构建的共享库文件。我 运行 遇到一个问题,在构建库之后,我会遇到可怕的 GLIBCXX_ not found
linker 错误。
这个案例特别st运行ge。当我使用 -g3
标志编译时,我没有得到错误。如果我用 -O2
编译,我会得到错误。
因此,当我使用 -O2
和 运行 ldd
编译 .so
文件时,我得到:
$ ldd MYLIB.so.1
./MYLIB.so.1: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by ./MYLIB.so.1)
linux-vdso.so.1 => (0x00007fff21e8d000)
libz.so.1 => /lib64/libz.so.1 (0x00002b2cd4c40000)
libpng12.so.0 => /usr/lib64/libpng12.so.0 (0x00002b2cd4e54000)
libjpeg.so.62 => /usr/lib64/libjpeg.so.62 (0x00002b2cd5079000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00002b2cd529b000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00002b2cd54b7000)
libm.so.6 => /lib64/libm.so.6 (0x00002b2cd57b8000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00002b2cd5a3b000)
libc.so.6 => /lib64/libc.so.6 (0x00002b2cd5c49000)
/lib64/ld-linux-x86-64.so.2 (0x0000003891400000)
所以在这里,出于某种原因,/usr/lib64/libstdc++.so.6
正在寻找 GLIBCXX_3.4.9
,它在 /usr/lib64/libstdc++.so.6
中不存在,我们可以使用 strings
实用程序看到:
$ strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_FORCE_NEW
所以,为了进一步调查这个问题,我 运行 nm
针对编译后的 .so
文件,并尝试找到正在寻找的符号 GLIBCXX_3.4.9
$ nm --demangle MYLIB.so.1 | grep GLIBCXX_3.4.9
U std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long)@@GLIBCXX_3.4.9
U std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)@@GLIBCXX_3.4.9
好的,看起来一些标准的 C++ ostream
代码需要 GLIBCXX_3.4.9。好的...但是似乎只有这个符号需要 GLIBCXX_3.4.9。其他一切正确 links 与 GLIBCXX_3.4
:
$nm --demangle MYLIB.so.1 | grep GLIBCXX
U std::string::find(char const*, unsigned long, unsigned long) const@@GLIBCXX_3.4
U std::string::compare(char const*) const@@GLIBCXX_3.4
U std::string::compare(std::string const&) const@@GLIBCXX_3.4
U std::logic_error::what() const@@GLIBCXX_3.4
U std::runtime_error::what() const@@GLIBCXX_3.4
U std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::str() const@@GLIBCXX_3.4
U std::basic_iostream<char, std::char_traits<char> >::~basic_iostream()@@GLIBCXX_3.4
... etc ...
那么这可能是什么原因造成的?为什么一个特定的符号 link GLIBCXX_3.4.9 而其他符号不会?更多 st运行ge - 只有当我用 -O2
.
编译时才会发生这种情况
我对此感到很困惑。那么,发生这种情况的可能原因有哪些? linker/compiler 链如何确定特定符号所在的 GLIBCXX 版本?
这只是意味着您正在使用比 /usr/lib64/libstdc++.so
库所属的更新的 GCC 进行编译,并且您没有告诉动态链接器如何找到正确的 libstdc++.so
对 GLIBCXX_3.4.9 的引用意味着您至少使用 GCC 4.2.0 进行编译,但系统 libstdc++.so 来自旧版本 4.1.1 或 4.1.2。
它只是 -O2 的问题这一事实并不真正相关,如果您使用更新的 GCC 进行编译,则需要使用它的 libstdc++.so,句号。似乎除非您使用 -O2 进行编译,否则您实际上不会对较新的 libstdc++ 产生硬依赖。所以但这只是机会,如果您对代码进行任何小的更改导致它的优化略有不同,它可能会发生变化。
你需要阅读https://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.how_to_set_paths and https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dynamic_or_shared.html#manual.intro.using.linkage.dynamic
Why would one particular symbol link GLIBCXX_3.4.9, but the rest don't?
因为其他符号在 GCC 3.4 和 4.2 之间没有变化,并且旧 libstdc++.so 中符号的版本与构建可执行文件时链接的版本相同。
找不到的符号是 GCC 4.2 中的新符号,因此它获得了更新的符号版本,并且在旧库中找不到。
我有一个使用 Makefile 构建的共享库文件。我 运行 遇到一个问题,在构建库之后,我会遇到可怕的 GLIBCXX_ not found
linker 错误。
这个案例特别st运行ge。当我使用 -g3
标志编译时,我没有得到错误。如果我用 -O2
编译,我会得到错误。
因此,当我使用 -O2
和 运行 ldd
编译 .so
文件时,我得到:
$ ldd MYLIB.so.1
./MYLIB.so.1: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by ./MYLIB.so.1)
linux-vdso.so.1 => (0x00007fff21e8d000)
libz.so.1 => /lib64/libz.so.1 (0x00002b2cd4c40000)
libpng12.so.0 => /usr/lib64/libpng12.so.0 (0x00002b2cd4e54000)
libjpeg.so.62 => /usr/lib64/libjpeg.so.62 (0x00002b2cd5079000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00002b2cd529b000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00002b2cd54b7000)
libm.so.6 => /lib64/libm.so.6 (0x00002b2cd57b8000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00002b2cd5a3b000)
libc.so.6 => /lib64/libc.so.6 (0x00002b2cd5c49000)
/lib64/ld-linux-x86-64.so.2 (0x0000003891400000)
所以在这里,出于某种原因,/usr/lib64/libstdc++.so.6
正在寻找 GLIBCXX_3.4.9
,它在 /usr/lib64/libstdc++.so.6
中不存在,我们可以使用 strings
实用程序看到:
$ strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_FORCE_NEW
所以,为了进一步调查这个问题,我 运行 nm
针对编译后的 .so
文件,并尝试找到正在寻找的符号 GLIBCXX_3.4.9
$ nm --demangle MYLIB.so.1 | grep GLIBCXX_3.4.9
U std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long)@@GLIBCXX_3.4.9
U std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)@@GLIBCXX_3.4.9
好的,看起来一些标准的 C++ ostream
代码需要 GLIBCXX_3.4.9。好的...但是似乎只有这个符号需要 GLIBCXX_3.4.9。其他一切正确 links 与 GLIBCXX_3.4
:
$nm --demangle MYLIB.so.1 | grep GLIBCXX
U std::string::find(char const*, unsigned long, unsigned long) const@@GLIBCXX_3.4
U std::string::compare(char const*) const@@GLIBCXX_3.4
U std::string::compare(std::string const&) const@@GLIBCXX_3.4
U std::logic_error::what() const@@GLIBCXX_3.4
U std::runtime_error::what() const@@GLIBCXX_3.4
U std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::str() const@@GLIBCXX_3.4
U std::basic_iostream<char, std::char_traits<char> >::~basic_iostream()@@GLIBCXX_3.4
... etc ...
那么这可能是什么原因造成的?为什么一个特定的符号 link GLIBCXX_3.4.9 而其他符号不会?更多 st运行ge - 只有当我用 -O2
.
我对此感到很困惑。那么,发生这种情况的可能原因有哪些? linker/compiler 链如何确定特定符号所在的 GLIBCXX 版本?
这只是意味着您正在使用比 /usr/lib64/libstdc++.so
库所属的更新的 GCC 进行编译,并且您没有告诉动态链接器如何找到正确的 libstdc++.so
对 GLIBCXX_3.4.9 的引用意味着您至少使用 GCC 4.2.0 进行编译,但系统 libstdc++.so 来自旧版本 4.1.1 或 4.1.2。
它只是 -O2 的问题这一事实并不真正相关,如果您使用更新的 GCC 进行编译,则需要使用它的 libstdc++.so,句号。似乎除非您使用 -O2 进行编译,否则您实际上不会对较新的 libstdc++ 产生硬依赖。所以但这只是机会,如果您对代码进行任何小的更改导致它的优化略有不同,它可能会发生变化。
你需要阅读https://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.how_to_set_paths and https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dynamic_or_shared.html#manual.intro.using.linkage.dynamic
Why would one particular symbol link GLIBCXX_3.4.9, but the rest don't?
因为其他符号在 GCC 3.4 和 4.2 之间没有变化,并且旧 libstdc++.so 中符号的版本与构建可执行文件时链接的版本相同。
找不到的符号是 GCC 4.2 中的新符号,因此它获得了更新的符号版本,并且在旧库中找不到。