我最近在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
答案 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会在处理它们时更改任何内容。