Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle dual ABI in GCC 5?

Tags:

c++

gcc

c++11

c++14

I try to understand how to overcome problems with the dual ABI introduced in GCC 5. However, I don't manage to do it. Here is a very simple example to reproduce errors. The version of GCC I use is 5.2. As you can see, my main function (in main.cpp file) is quite simple:

// main.cpp

#include <iostream>
#include <string>

int main()
{
    std::string message = "SUCCESS!";
    std::cout << message << std::endl;
}

When I type

/home/aleph/gcc/5.2.0/bin/g++ main.cpp

I get the following error message:

/tmp/ccjsTADd.o: In function `main':
main.cpp:(.text+0x26): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)'
main.cpp:(.text+0x43): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x5c): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
main.cpp:(.text+0x8c): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
collect2: erreur: ld a retourné 1 code d'état d'exécution

If I change the value of _GLIBCXX_USE_CXX11_ABI to 0, the problem disappears.

But, how to make things work with the default ABI?

EDIT: simpler question (removed cmake script)

like image 609
Aleph Avatar asked Nov 03 '15 13:11

Aleph


People also ask

What is ABI in GCC?

The library ABI is mostly of interest for end-users who have unresolved symbols and are linking dynamically to the C++ Standard library, and who thus must be careful to compile their application with a compiler that is compatible with the available C++ Standard library binary.

Are GCC and Clang ABI compatible?

clang, modulo bugs, is fully C++ ABI compatible with GCC (they both follow the intervendor Itanium ABI) on unix systems. Make sure you use the same standard library for all components because libstdc++ and libc++ are different implementations with completely different object layouts.

Does C++ have a stable ABI?

Without a stable ABI, all parts of a program must be compiled with the same version of the same compiler. That situation creates a maintenance nightmare for distributed projects, particularly for suppliers of binary libraries. The early rapid evolution of the C++ programming language precluded a stable ABI.

What is ABI in C++?

In computer software, an application binary interface (ABI) is an interface between two binary program modules. Often, one of these modules is a library or operating system facility, and the other is a program that is being run by a user.


1 Answers

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.

like image 148
Aleph Avatar answered Nov 12 '22 01:11

Aleph