构建共享库时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++11clang++ -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&amp;&amp;); ; 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(默认)

ctags:加载共享库时出错:libgpm.so.1:无法打开共享对象文件:没有这样的文件或目录

Zynq 开发板上直接使用g++ 编译应用软件

使用 dpc++ 从 sycl 程序创建静态或共享库

g++ 和 clang++ 使用变量模板和 SFINAE 的不同行为