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