Understanding Gcc 5's _Glibcxx_Use_Cxx11_Abi or the New Abi

How to handle dual ABI in GCC 5?

I found the solution by adding more verbosity to gcc (-v flag). If you have the same problem, you need to tell gcc to search for libraries in the repository containing the libstdc++ version of your distribution. In other words, you should try something like this:

/home/aleph/gcc/5.2.0/bin/g++ -L /home/aleph/gcc/5.2.0/lib64 main.cpp

The linking step should be correctly performed after that. However, you may not be able to run your program. Entering

./a.out

may lead to the following error:

./a.out: relocation error: ./a.out: symbol _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_, version GLIBCXX_3.4.21 not defined in file libstdc++.so.6 with link time reference

Indeed, you can check that your executable depends on the wrong version of libstdc++ by typing

ldd a.out

which should lead to something like that:

linux-vdso.so.1 =>  (0x00007ffebb722000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x0000003a71400000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x0000003d03a00000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x0000003a71000000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000003d02e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003d02a00000)

Set LD_LIBRARY_PATH to the path to your own version of libstdc++ will solve the problem:

LD_LIBRARY_PATH=/home/aleph/gcc/5.2.0/lib64 ./a.out

Hope it helps!

EDIT: as noticed by Marc, it is possible to modify the rpath, instead of modifying the environment variable LD_LIBRARY_PATH. Here is a CMake configuration script to do it.

project (example CXX)

add_executable(main main.cpp)

if(GCC_ROOT)
set(CMAKE_CXX_COMPILER ${GCC_ROOT}/bin/g++)
target_link_libraries(main ${GCC_ROOT}/lib64/libstdc++.so)
link_directories(${GCC_ROOT}/lib64)
endif(GCC_ROOT)

This script can be used with the usual combo

cmake ..
make

in a 'build' subdirectory. But it is also possible to choose our own compilers by providing the path to the root of our GCC distribution:

cmake -D GCC_ROOT=/home/aleph/gcc/5.2.0 ..
make

The script is written so that the version of libstdc++ corresponds to the version of the input GCC distribution.

_GLIBCXX_USE_CXX11_ABI, GCC 4.8 and ABI compatibility

It's possible to use the C++11 ABI with gcc 4.8.2, but it's a dangerous hack; you would be far better off if at all possible to ask your vendors to ship libraries compiled with the C++03 ABI (-D_GLIBCXX_USE_CXX11_ABI=0) or to upgrade to GCC 5 or above.

You would need to download and install gcc 5 so that you can use its libstdc++ headers and libraries, then direct gcc 4.8 to use those in preference to its own. In addition, because gcc 4.8 is missing some intrinsics required by the libstdc++ shipped with gcc 5, you would need to hack out their usage.

For example, to compile a simple single-file application that includes <string>:

/usr/local/gcc-4.8.2/bin/g++ \
-std=c++11 \
-D_GLIBCXX_USE_CXX11_ABI=1 \
-D'__is_trivially_copyable(...)=0' \
-D'__is_trivially_constructible(...)=0' \
-D'__is_trivially_assignable(...)=0' \
-nostdinc++ \
-isystem /usr/local/gcc-5.4.0/include/c++/5.4.0/ \
-isystem /usr/local/gcc-5.4.0/include/c++/5.4.0/x86_64-unknown-linux-gnu \
-L /usr/local/gcc-5.4.0/lib64
a.cpp

This is dangerous because the gcc 5.4 libstdc++ is not designed to work with gcc 4.8, and redefining the intrinsics used (__is_trivially_copyable etc.) could change the layout of structures or otherwise cause binary incompatibility between your programs and the vendor's libraries.

In order to run the resulting executable, you would also need to ensure that the dynamic linker finds a compatible libstdc++, for example by adding /usr/local/gcc-5.4.0/lib64 to /etc/ld.so.conf, or using -Wl,-rpath /usr/local/gcc-5.4.0/lib64.

Please explain the C++ ABI

Although the C++ Standard doesn't prescribe any ABI, some actual implementations try hard to preserve ABI compatibility between versions of the toolchain. E.g. with GCC 4.x, it was possible to use a library linked against an older version of libstdc++, from a program that's compiled by a newer toolchain with a newer libstdc++. The older versions of the symbols expected by the library are provided by the newer libstdc++.so, and layouts of the classes defined in the C++ Standard Library are the same.

But when C++11 introduced the new requirements to std::string and std::list, these couldn't be implemented in libstdc++ without changing the layout of these classes. This means that, if you don't use the _GLIBCXX_USE_CXX11_ABI=0 kludge with GCC 5 and higher, you can't pass e.g. std::string objects between a GCC4-compiled library and a GCC5-compiled program. So the ABI was broken.

Some C++ implementations don't try that hard to have compatible ABI: e.g. MSVC++ doesn't provide such compatibility between major compiler releases (see this question), so one has to provide different versions of library to use with different versions of MSVC++.

So, in general, you can't mix and match libraries and executables compiled with different versions even of the same toolchain.



Related Topics



Leave a reply



Submit