转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2861

Clang最近越来越火,多个linux版本已经打算用Clang代替GCC作为默认编译器了。去年Clang宣布改进Windows的支持,所以我打算尝试一下用Clang在Windows上编译KlayGE。一来是想用Clang的静态检查工具来减少bug,二来是为以后移植到MacOSX和iOS做准备。

在这个过程中,发现到处是坑,而且最终问题也还没解决。这里把我遇到的麻烦做个总结,希望能抛砖引玉。也希望有经验的朋友能可以帮忙出出主意。

麻烦1:MinGW还是VC

Clang 3.4提供了预编译的Windows版下载,下了之后直接安装即可。在VC里可以看到多了LLVM-xxxx的toolset。按说能直接用它编译原有工程,但试一下才发现,很多VC的编译选项clang-cl并不支持。看了帮助发现可以用-Qunused-arguments这个参数来隐藏不支持的选项。紧接着就遇到第二个问题,VC中有些C++11的头文件,比如atomic,用Clang会产生很多编译错误。看来这条路走不通。毕竟Windows平台是Clang的实验平台,而clang-cl是实验平台上的实验原型,先不用它了。

另一条路是把Clang的编译器拷贝到MinGW里,寄生在MinGW的基础设施中使用。Linux等平台上的Clang一直都是这么用的,所以这么做相对靠谱一些。按照文档,Clang只支持4.3-4.5的MinGW32,以及4.5-4.7的MinGW-w64。而我机器上是4.8.2的MinGW-w64,不打算换成老版本。这种情况下我就只能在cmake脚本里把一些头文件目录加进去,让Clang可以找到地方。

第一个麻烦解决,选择MinGW。

麻烦2:C++库

由于libc++目前只支持OSX,在Windows上千疮百孔。和前面一样,这部分得用MinGW的C++库。由于MinGW有各种编译版本,目录结构不尽相同。比如,Mingw-builds的x64版目录结构是lib/gcc/i686-w64-mingw32/4.8.2/include/c++/,x86版则是lib/gcc/x86_64-w64-mingw32/4.8.2/include/c++。其他编译版还有比较短的目录结构,比如i686-w64-mingw32/include/c++/这样的。这里需要在cmake脚本里做一下检测,把存在的目录添加进去。不但要添加lib/gcc/i686-w64-mingw32/4.8.2/include/c++/,还得添加lib/gcc/i686-w64-mingw32/4.8.2/include/c++/i686-w64-mingw32,否则会找不到bits/c++config.h。

第二个麻烦解决,需要手动指定C++库的目录。

麻烦3:头文件

真正开始编译的时候,C++库仍会带来一些麻烦,比如说找不到ia32intrin.h之类。即便把MinGW中包含这些头文件的目录添加进去,会出现找不到__buitin_rdtsc等内建函数。而这些__builtin*函数是GCC专有的,Clang文档特别说明了此处不兼容,而是用了另一套命名方式。误打误撞发现需要把Clang的lib/clang目录拷贝到MinGW的lib目录下,才能索引到正确的头文件。

第三个麻烦解决,需要拷贝lib/clang。

麻烦4:128位的数据类型

紧接着,第四个麻烦出现了。MinGW 4.8.2默认是支持long double和long long这样的128位数据类型的,而Clang不支持。这里的hack是在包含bits/c++config.h之后,立刻把
_GLIBCXX_USE_FLOAT128和_GLIBCXX_USE_INT128给#undef掉。这样MinGW的头文件就不会在试图使用128位的数据类型了。

第四个麻烦解决,#undef两个宏。

麻烦5:异常处理方式

至此,已经可以成功地用Clang进行编译了。但连接的时候出了状况,报找不到很多导出函数,以及_Unwind_Resume和__gxx_personality_v0。查了一些地方才知道,Clang只支持Dwarf2的异常处理方式,而我的MinGW是SJLJ的。换成Dwarf2的MinGW之后,这两个异常相关的函数能找到了。

第五个麻烦解决,只能选用Dwarf2的MinGW。

麻烦6:Mangling

剩下的问题是,凡是自定义的导出函数都报找不到符号。最后在LLVM的bug列表中找到了这个ticket。他们居然在写-export的时候多了一个下划线 _,使得export用的符号和编译器生成的符号不一致。这个bug在2011年就被报告了,一直到现在都没有被解决。而在解决之前,似乎没办法绕开这个bug。

第六个麻烦,没找到解决方法。

总结

其他麻烦其实是有的,比如用__declspec(dllexport)导出一个类的时候,会有warning。这也是一个2011年就存在的bug,到现在都没解决。甚至有人提交了补丁,也一直没有人处理。类似的情况还有很多,所以目前来说Clang在Windows上基本没法用起来。