Undefined reference in clang when linking to a library compiled with GCC5

こ雲淡風輕ζ 提交于 2019-12-06 23:28:54

问题


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).

来源:https://stackoverflow.com/questions/33368237/undefined-reference-in-clang-when-linking-to-a-library-compiled-with-gcc5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!