从源代码构建的Clang编译C而不是C ++代码

时间:2014-05-11 23:19:34

标签: c++ c windows mingw clang

我最近在windows上编译了clang(主机:x86_64-pc-windows64;编译器:i686-pc-mingw32;目标:i686-pc-mingw32)。
可以找到CMakeCache(用于配置):here
我的问题是,虽然clang工作正常(对于C),clang ++(对于C ++)将成功地#34;编译和链接,但生成的程序本身不会运行,并将以错误代码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 ++)在编译和链接时没有输出。
任何人都可以暗示我为什么会这样,我该如何解决呢? 注意:Windows的clang(也是32位)的预编译快照适用于我当前的路径配置 注意:a.exe(C ++,失败)返回非零 数据:
CLANG版本: Snap:clang version 3.5 (208017); Comp:clang version 3.4 (tags/RELEASE_34/final)
LLVM文件:snapshot; compiled; diff
预处理文件:snapshot; compiled; diff
ASM文件:snapshot; compiled; diff
VERBOSE OUTPUT:snapshot; compiled

1 个答案:

答案 0 :(得分:2)

你的新clang使用不同的(不正确的)calling convention,而不是x86_thiscallcc

来自好铿锵的

snap.s

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 bitcode(*.ll个文件中)右调用约定在函数定义中和x86_thiscallcc指令之后用call标记:

<   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只使用不同的标题(或不同版本的标题,您可以使用clang编译的-H选项列出已使用的标题)。

其他方法是检查,__attribute__((__cdecl__))是否应该等于__cdecl__,并且更新版本的clang会在处理它们时更改任何内容。