Ubuntu – How should I handle ABI incompatability between gcc-4.9 and gcc-5

14.0416.04gcc

I have recently upgraded my dev machine to Ubuntu 16.04 (fresh install, wiped 14.04)

The default version of gcc is gcc-5.3.1.

A problem that I have is a vendor supplied library is only built using gcc-4.9, which is not compatible with gcc-5.

I have asked the vendor to provide a new version of the library, but it is unlikely that that will happen any time soon.

In the meantime I have installed gcc-4.9.3 from Ubuntu's package repos.

I now have both gcc-4.9 and gcc-5 installed:

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

I tried to build our source with gcc-4.9, but now I come up against the same ABI issues, but going the other way.

The problem I have is that we have a bunch of dependencies which we would typically install from the distro packages

sudo apt-get install \
    python-dev \
    libbz2-dev \
    libboost-all-dev \
    libprotobuf-dev \
    libgoogle-perftools-dev \
    postgresql \
    libpqxx-dev

Whilst I can configure my build to use gcc-4.9

mkdir build && cd build
CC=/usr/bin/gcc-4.9 CXX=/usr/bin/g++-4.9 cmake ..
make -j8

I now get linker errors when linking against libtcmalloc_minimal.a, libprotobuf.a etc.

So the next step that I tried was to remove all the dependencies installed from the distro repos and start building the dependencies from source.

CC=/usr/bin/gcc-4.9 CXX=/usr/bin/g++-4.9 ./configure
make -j8
sudo make install

The problem here is that I'm starting to head down a rabbit-hole. Each dependency has other dependencies, and I'm not sure where it's going to end.

The other option is to downgrade back to Ubuntu 14.04 or some version which ships with gcc-4.9 instead of gcc-5.

Before I try this thurmonuclear option, I was wondering if there's a better way to do this?

Maybe it's possible to install from repos built with gcc-4.9, or some other way?

Best Answer

The problem you have is related to C++11 standard requiring a different implementation of C++ string (and list) type(s). For compatibility, g++5.2 and above compiles the new C++11 compliant type by default, (whether or not you specify -std=c++11), but you can set the macro

-D_GLIBCXX_USE_CXX11_ABI=0

to revert to the old C++ string type. New libstdc++ implementation contain both ABIs. So if you have binaries you have to link against with the old non-compliant ABI, you must set the macro above on your g++ compiles. This should produce binaries compatible with the old ABI.

Unfortunately if you are using libraries from the OS other than the C++ Standard Libraries, then unless these libraries are multi-arch in the sense of providing all functions which differ by ABI in both ABI's, then you're screwed because they'll probably only have the new ABI.

Having said that I have a problem on an old Ubuntu downloading an untrusted modern g++ which simply refuses to produce the new ABI. So it seems that backport from ppa:ubuntu-toolchain-r/test is in fact badly broken because it refuses to produce binaries according to the new ABI.

Anyhow the bottom line is when you link together everything must either be the old ABI or the new ABI. The following will tell which you are using:

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

If that has

std::basic_string<char, ....

in it, its the old ABI. If it has

std::__cxx11::basic_string<char, ...

in it, its the new ABI.

Related Question