构建共享库时G++和clang++与标准库不兼容?
Posted
技术标签:
【中文标题】构建共享库时G++和clang++与标准库不兼容?【英文标题】:G++ and clang++ incompatibility with standard library when building shared libraries? 【发布时间】:2016-02-23 19:23:20 【问题描述】:如果我有一个包含以下内容的文件 clang.cpp:
#include <map>
void myfunc()
std::map<int, int> mymap;
const int x = 20;
myfoo[x] = 42;
和 main.cpp 包含:
void myfunc();
int main() myfunc();
编译clang++ -g clang.cpp -shared -fPIC -o libclang.so -stdlib=libstdc++ -std=c++11
和clang++ -g main.cpp -L -Wl.,-rpath=. -lclang -lstdc++ -o a.out -stdlib=libstc++ -std=c++11
会运行良好。
但是,如果我添加 gcc.cpp 包含:
#include <tuple>
template std::pair<int const, int>::pair(std::piecewise_construct_t, std::tuple<int const&>, std::tuple<>);
然后还使用g++ -g gcc.cp -shared -fPIC -o libgcc.so
将其编译为共享库并将链接命令更改为clang++ -g main.cpp -L -Wl.,-rpath=. -lgcc -lclang -stdlib=libstdc++ -std=c++11 -o a.out
,然后运行./a.out
将出现段错误。
我不知道该怎么做,因为当使用相同的 c++ 标准库时,clang 和 gcc 应该是 ABI 兼容的。我的版本是 3.6.2 用于 clang,5.2.1 用于 gcc,与 ubuntu 一起提供。
【问题讨论】:
由于您只在一个源文件/翻译单元中声明专业化,这听起来像是违反 ODR。 模板在两个单元中都被实例化:myfoo[x] = 42
是在clang.cpp
文件中实例化的地方。在实际情况下,您获得此结果的方式是当 gcc.cpp
包含 unordered_map.h
并且您在该文件中有类似于 clang.cpp
的代码。
你不能这样做。您不能只通过链接来注入专业化。最终项目中的每个文件都必须在编译时知道它是专用的,否则您就违反了一个定义规则(一个专用,一个非专用)。
@MarkB 这不是一个明确的专业化;这是一个明确的实例化。这些都很好。
目前有大量关于按值传递空类型的 ABI 的讨论。这可能是相关的。
【参考方案1】:
给定
int f(std::tuple<const int &> t)
return std::get<0>(t);
Clang 生成
f(std::tuple<int const&>): # @f(std::tuple<int const&>)
movl (%rdi), %eax
retq
当 GCC 生成时
f(std::tuple<int const&>):
movq (%rdi), %rax
movl (%rax), %eax
ret
换句话说,Clang 期望元组本身通过寄存器传递,而 GCC 期望地址在寄存器中传递(并且元组在堆栈上传递)。
混搭,你会得到“有趣”的结果。
【讨论】:
更短的例子:struct Tuple int a; Tuple(Tuple&&); ; int f(Tuple t) return t.a;
我非常确信该错误存在于 clang 中(尽管可以为 C++11 澄清 ABI),如果有人可以在那里报告它会很好......
这里正在进行讨论:sourcerytools.com/pipermail/cxx-abi-dev/2016-February/…以上是关于构建共享库时G++和clang++与标准库不兼容?的主要内容,如果未能解决你的问题,请参考以下文章
将 clang 构建的可执行文件与 g++-v6 构建的 boost 库链接的错误
G++ 和 Clang++ - 命名空间标准 _GLIBCXX_VISIBILITY(默认)