8

I try to use the ubuntu 15.10 repository version of libmuparser (package libmuparser2v5). Compiling with gcc works fine, but not with clang. I dug deeper into this to come up with the following minimal (not) working example and a few questions.

Consider a library with a simple class that takes a string and returns a string.

testlib.h:

#pragma once

#include <string>

struct Test {
    std::string str;

    void set(std::string s);
    std::string get();
};

testlib.cpp:

#include "testlib.h"

void Test::set(std::string s) {
    str = s;
}

std::string Test::get() {
    return str;
}

This is compiled with gcc 5.2.1 as static library with

g++ -Wall -c testlib.cpp -o testlib-gcc.o
ar rcs libtest-gcc.a testlib-gcc.o

Now compiling an application main.cpp

#include <iostream>
#include "testlib.h"

int main()
{
    Test p;
    p.set("Hello!");
    std::cout << p.get() << std::endl;
    return 0;
}

with clang 3.6.2-1 by using

clang++ main.cpp -o out-clang libtest-gcc.a

results in the error

main.cpp:(.text+0x79): undefined reference to `Test::get()'

Now I found out that gcc5 has a new feature, called ABI tags, to help versioning libraries and prevent linking, when it is not compatible. Looking at the static library

$ nm -gC libtest-gcc.a

gives:

testlib-gcc.o:
0000000000000026 T Test::get[abi:cxx11]()
0000000000000000 T Test::set(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)

So the ABI tag cxx11 has been added for get but not for set. The tag is apparently added, when a method returns a string. That is why clang claims only about not finding Test::get().

I guess this is done to give get a calling signature that makes clear that c++11 is required to link with that function. For set this is not necessary, due to the __cxx11 in the type.

Questions:

  • Am I right with my guess or is there maybe something more to be added?
  • If so, how to fix this?
    • What can a library writer do to make a library linkable to both gcc 5.2 and clang 3.6 compiled code? (Source code changes?)
    • What can a library user do to compile and link with clang 3.6 against a library compiled with gcc 5.2 or vice versa. (Source code changes or compilation flags?)
    • What can a package maintainer do to make a library linkable to both gcc 5.2 and clang 3.6 compiled code? (Compilation flags?)
    • Will this be fixed by the clang developers in future version (which version)? (ABI compatibility by default?) However it would still be nice to have a solution now, since otherwise clang is hard to use on ubuntu 15.10 and derivatives.

Additional information:

  • The signature of get is defined when testlib.cpp is compiled. Thus a shared object would not make any difference. One can also use nm -gC testlib-gcc.o to see the symbols.
  • In a library compiled with clang the signature of get is Test::get(). Then gcc cannot find the symbol Test::get[abi:cxx11](), so the compatibility is mutually broken.
  • Using the compile flag -D_GLIBCXX_USE_CXX11_ABI=0 for gcc (found here) is no solution, since then the signature of set is also changed: Test::set(std::string) (but get is fine then).
  • Using the compile flag -stdlib=libc++ in clang does not seem to help, since it also reports the undefined reference to Test::get() (and a lot more undefined references).
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
John
  • 1,472
  • 1
  • 19
  • 22
  • When you use `-D_GLIBCXX_USE_CXX11_ABI=0`, you need to use it with the program you compile with Clang too, if it uses the GCC standard library (libstdc++). The `std::__cxx11` is a private GCC standard library-only namespace, if I [read this right](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html). – Some programmer dude Oct 27 '15 at 12:49
  • @JoachimPileborg: Yes, compiling both library and application with `-D_GLIBCXX_USE_CXX11_ABI=0` helps. However, my actual use case here is a library in the repository, that is compiled with `-D_GLIBCXX_USE_CXX11_ABI=1`. It seems not to be possible to use the abi_tag ("cxx11") attribute in clang. So is it simply not possible maybe? – John Oct 27 '15 at 13:11
  • In that case it's not possible, unless there's a fix in the clang source repositories and you build clang from source. Oh, there *is* an [issue in the clang issue tracker for this](https://llvm.org/bugs/show_bug.cgi?id=23529), but it doesn't seem to be merged into trunk yet. – Some programmer dude Oct 27 '15 at 13:20
  • 1
    Compatibility of libraries/objects compiled with different C++ compilers is a nightmare since C++11 and the recommendation is not to rely on it. Having said that, the problem is mostly limited to `std::string` (and related classes such as `std::stringstream`) and if you can avoid using any library functionality using `string`s (which may include catching exceptions by type), you may be okay (that's my experience). – Walter Oct 29 '15 at 10:24

0 Answers0