我应该如何处理 gcc-4.9 和 gcc-5 之间的 ABI 不兼容问题?

Ste*_*mer 4 gcc 14.04 16.04

我最近将我的开发机器升级到 Ubuntu 16.04(全新安装,擦除 14.04)

gcc 的默认版本是gcc-5.3.1.

我遇到的一个问题是供应商提供的库仅使用 gcc-4.9 构建,这与 gcc-5 不兼容。

我已要求供应商提供该库的新版本,但这不太可能很快发生。

与此同时,我已经gcc-4.9.3从 Ubuntu 的包 repos安装了。

我现在已经安装了 gcc-4.9 和 gcc-5:

ls -l /usr/bin/gcc*
lrwxrwxrwx 1 root root      5 May  9 11:49 /usr/bin/gcc -> gcc-5
-rwxr-xr-x 1 root root 838008 Apr 13 23:23 /usr/bin/gcc-4.9
-rwxr-xr-x 1 root root 915704 Apr 13 11:29 /usr/bin/gcc-5
Run Code Online (Sandbox Code Playgroud)

我试图用 gcc-4.9 构建我们的源代码,但现在我遇到了相同的 ABI 问题,但反其道而行之。

我的问题是我们有一堆依赖项,我们通常会从发行版包中安装这些依赖项

sudo apt-get install \
    python-dev \
    libbz2-dev \
    libboost-all-dev \
    libprotobuf-dev \
    libgoogle-perftools-dev \
    postgresql \
    libpqxx-dev
Run Code Online (Sandbox Code Playgroud)

虽然我可以将我的构建配置为使用 gcc-4.9

mkdir build && cd build
CC=/usr/bin/gcc-4.9 CXX=/usr/bin/g++-4.9 cmake ..
make -j8
Run Code Online (Sandbox Code Playgroud)

我现在在链接时遇到链接器错误libtcmalloc_minimal.alibprotobuf.a等等。

因此,我尝试的下一步是删除从发行版存储库安装的所有依赖项,并开始从源代码构建依赖项。

CC=/usr/bin/gcc-4.9 CXX=/usr/bin/g++-4.9 ./configure
make -j8
sudo make install
Run Code Online (Sandbox Code Playgroud)

这里的问题是我开始进入一个兔子洞。每个依赖项都有其他依赖项,我不确定它会在哪里结束。

另一种选择是降级回 Ubuntu 14.04 或带有 gcc-4.9 而不是 gcc-5 的某些版本。

在我尝试这个 thurmonuclear 选项之前,我想知道是否有更好的方法来做到这一点?

也许可以从使用 gcc-4.9 或其他方式构建的存储库安装?

小智 9

您遇到的问题与 C++11 标准有关,需要 C++ 字符串(和列表)类型的不同实现。为了兼容性,g++5.2及以上默认编译新的C++11兼容类型,(不管你是否指定-std=c++11),但是你可以设置宏

-D_GLIBCXX_USE_CXX11_ABI=0
Run Code Online (Sandbox Code Playgroud)

恢复到旧的 C++ 字符串类型。新的 libstdc++ 实现包含两个ABI。因此,如果您有二进制文件必须与旧的不兼容 ABI 链接,则必须在 g++ 编译时设置上面的宏。这应该会生成与旧 ABI 兼容的二进制文件。

不幸的是,如果您使用的是操作系统中的库而不是 C++ 标准库,那么除非这些库在提供所有功能的意义上都是多架构的,这些功能在两个ABI中因 ABI 而异,那么您就搞砸了,因为它们可能只会拥有新的 ABI。

话虽如此,我在旧 Ubuntu 上下载了一个不受信任的现代 g++ 时遇到了问题,它只是拒绝生成新的 ABI。因此,似乎 backport fromppa:ubuntu-toolchain-r/test实际上已严重损坏,因为它拒绝根据新的 ABI 生成二进制文件。

无论如何,当您将所有内容链接在一起时,底线必须是旧的 ABI 或新的 ABI。以下将告诉您正在使用哪个:

g++ --version
echo '#include <string>' > test.cpp
echo 'void f(std::string s) {}' >> test.cpp
cat test.cpp
g++ -std=gnu++11 -c -o test.o test.cpp
nm test.o | c++filt
Run Code Online (Sandbox Code Playgroud)

如果那有

std::basic_string<char, ....
Run Code Online (Sandbox Code Playgroud)

其中,它是旧的ABI。如果有

std::__cxx11::basic_string<char, ...
Run Code Online (Sandbox Code Playgroud)

其中,它是新的ABI。