问题
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 whentestlib.cpp
is compiled. Thus a shared object would not make any difference. One can also usenm -gC testlib-gcc.o
to see the symbols. - In a library compiled with clang the signature of
get
isTest::get()
. Then gcc cannot find the symbolTest::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)
(butget
is fine then). - Using the compile flag
-stdlib=libc++
in clang does not seem to help, since it also reports the undefined reference toTest::get()
(and a lot more undefined references).
来源:https://stackoverflow.com/questions/33368237/undefined-reference-in-clang-when-linking-to-a-library-compiled-with-gcc5