Clang从源代码编译C而不是c++代码

Clang built from source compiles C but not C++ code

本文关键字:c++ 代码 源代码 编译 Clang      更新时间:2023-10-16

我最近在windows上编译了clang (host: x86_64-pc-windows64;编译器:i686-pc-mingw32;目标:i686-pc-mingw32)。
CMakeCache(用于配置)可以在这里找到:
我的问题是,虽然clang工作得很好(对于C), clang++(对于c++)将"成功"编译和链接,但结果程序本身不会运行,并将以错误代码1退出。下面是一个示例(oh-my-zsh):

➜  bin  cat test.c
#include <stdio.h>
int main()
{
        printf("Hello World!n");
        return 0;
}
➜  bin  cat test.cpp
#include <iostream>
int main()
{
        std::cout<<"Hello World!"<<std::endl;
        return 0;
}
➜  bin  ./clang++ test.cpp -o a.exe
➜  bin  ./clang test.c -o b.exe
➜  bin  ./a.exe
➜  bin  ./b.exe
Hello World!
➜  bin

如图所示,b.exe(在C中)工作正常,但a.exe (c++)在编译和链接时没有输出。
有没有人提示我为什么这是如此,我怎么能解决它?
注意:clang的预编译快照(也是32位)在我当前的路径配置下工作良好。
注意:a.exe (c++, failed)返回非零。
数据:
铿锵声版本:Snap: clang version 3.5 (208017);Comp: clang version 3.4 (tags/RELEASE_34/final)
LLVM文件:快照;编译;diff
预处理文件:快照;编译;diff
ASM文件:快照;编译;diff
详细输出:快照;编制

您的新clang使用不同的(不正确的)调用约定,而不是x86_thiscallcc

snap.s from good clang:

movl    $__ZStL8__ioinit, %ecx
calll   __ZNSt8ios_base4InitC1Ev
movl    %esp, %ecx
movl    $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%ecx)
movl    %eax, %ecx
calll   __ZNSolsEPFRSoS_E

与自定义clang相同的代码,comp.s:

leal    __ZStL8__ioinit, %eax
movl    %eax, (%esp)
calll   __ZNSt8ios_base4InitC1Ev
movl    %eax, (%esp)
movl    %ecx, 4(%esp)
calll   __ZNSolsEPFRSoS_E

和其他几个

在llvm位码(*.ll文件)中,右调用约定在函数定义和call指令之后标记为x86_thiscallcc:

<   call void @_ZNSt8ios_base4InitC1Ev(%"class.std::ios_base::Init"* @_ZStL8__ioinit)
>   call x86_thiscallcc void @_ZNSt8ios_base4InitC1Ev(%"class.std::ios_base::Init"* @_ZStL8__ioinit)
< declare void @_ZNSt8ios_base4InitC1Ev(%"class.std::ios_base::Init"*) #0
> declare x86_thiscallcc void @_ZNSt8ios_base4InitC1Ev(%"class.std::ios_base::Init"*) #0
32c33
< declare void @_ZNSt8ios_base4InitD1Ev(%"class.std::ios_base::Init"*) #0
> declare x86_thiscallcc void @_ZNSt8ios_base4InitD1Ev(%"class.std::ios_base::Init"*) #0
<   call void @_ZNSt8ios_base4InitD1Ev(%"class.std::ios_base::Init"* @_ZStL8__ioinit)
>   call x86_thiscallcc void @_ZNSt8ios_base4InitD1Ev(%"class.std::ios_base::Init"* @_ZStL8__ioinit)
<   %3 = call %"class.std::basic_ostream"* @_ZNSolsEPFRSoS_E(%"class.std::basic_ostream"* %2, %"class.std::basic_ostream"* (%"class.std::basic_ostream"*)* @_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
>   %call1 = call x86_thiscallcc %"class.std::basic_ostream"* @_ZNSolsEPFRSoS_E(%"class.std::basic_ostream"* %call, %"class.std::basic_ostream"* (%"class.std::basic_ostream"*)* @_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
< declare %"class.std::basic_ostream"* @_ZNSolsEPFRSoS_E(%"class.std::basic_ostream"*, %"class.std::basic_ostream"* (%"class.std::basic_ostream"*)*) #0
> declare x86_thiscallcc %"class.std::basic_ostream"* @_ZNSolsEPFRSoS_E(%"class.std::basic_ostream"*, %"class.std::basic_ostream"* (%"class.std::basic_ostream"*)*) #0

在预处理文件中,我看到了差异。在snap.E中,许多函数是用__attribute__((__cdecl__))定义的,而在comp.E中,它们只用__cdecl__定义。您应该检查预处理后定义不同的原因。我认为,新的clang可能会预定义不同的宏集(gcc有-dM -E选项转储预定义的,不知道如何在clang中做到这一点)。或者你的clang只是使用不同的头文件(或者不同版本的头文件,你可以用-H选项列出clang编译时使用的头文件)。

另一种方法是检查__attribute__((__cdecl__))是否应该等于__cdecl__,以及新版本的clang是否在处理它们时改变了任何东西