链接到使用GCC5编译的库时,clang中的未定义引用

Joh*_*ohn 8 c++ abi clang c++11 gcc5

我尝试使用ubuntu 15.10存储库版本的libmuparser(包libmuparser2v5).用gcc编译工作正常,但不能用clang编译.我深入研究了这个问题,提出了以下最小(非)工作示例和几个问题.

考虑一个带有一个简单类的库,它接受一个string并返回一个string.

testlib.h:

#pragma once

#include <string>

struct Test {
    std::string str;

    void set(std::string s);
    std::string get();
};
Run Code Online (Sandbox Code Playgroud)

testlib.cpp:

#include "testlib.h"

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

std::string Test::get() {
    return str;
}
Run Code Online (Sandbox Code Playgroud)

这是用gcc 5.2.1编译为静态库的

g++ -Wall -c testlib.cpp -o testlib-gcc.o
ar rcs libtest-gcc.a testlib-gcc.o
Run Code Online (Sandbox Code Playgroud)

现在编译一个应用程序 main.cpp

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

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

用clang 3.6.2-1使用

clang++ main.cpp -o out-clang libtest-gcc.a
Run Code Online (Sandbox Code Playgroud)

导致错误

main.cpp:(.text+0x79): undefined reference to `Test::get()'
Run Code Online (Sandbox Code Playgroud)

现在我发现gcc5有一个名为ABI标签的新功能,可以帮助版本化库并防止链接,当它不兼容时.看着静态库

$ nm -gC libtest-gcc.a
Run Code Online (Sandbox Code Playgroud)

得到:

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> >)
Run Code Online (Sandbox Code Playgroud)

因此cxx11添加了ABI标记,get但不是set.当方法返回a时,显然添加了标记string.这就是为什么clang声称只是没有找到Test::get().

我想这样做是为了给出get一个调用签名,清楚地表明需要c ++ 11来链接该函数.对于set这是没有必要的,由于__cxx11在类型.

问题:

  • 我猜对了,还是可以添加更多内容?
  • 如果是这样,如何解决这个问题?
    • 什么可以在图书馆作家做,使库可链接到两个GCC 5.2和3.6铿锵编译的代码?(源代码更改?)
    • 什么可以在图书馆用户做编译和铿锵3.6链接反对用gcc 5.2反之亦然编译库.(源代码更改或编译标志?)
    • 有什么可以一包维护者做,使库可链接到两个GCC 5.2和3.6铿锵编译的代码?(编译标志?)
    • 这会不会被固定铛开发商在未来的版本(版本)?(默认情况下ABI兼容性?)但是现在有一个解决方案仍然很好,因为否则在ubuntu 15.10和衍生产品上很难使用clang.

附加信息:

  • 签名get是在testlib.cpp编译时定义的.因此共享对象不会有任何区别.人们也可以用nm -gC testlib-gcc.o来看符号.
  • 在用clang编译的库中,签名getTest::get().然后gcc找不到符号Test::get[abi:cxx11](),因此兼容性相互破坏.
  • 使用-D_GLIBCXX_USE_CXX11_ABI=0gcc 的编译标志(在这里找到)是没有解决方案,因为那时set的签名也改变了:( Test::set(std::string)但是get很好).
  • -stdlib=libc++在clang中使用compile标志似乎没有帮助,因为它还报告了未定义的引用Test::get()(以及更多未定义的引用).