在windows下使用llvm+clang

clangFreeBSD和Mac下C/C++语言的默认编译器。如果你在苹果下做过开发,那么应该对它很熟悉。
这套工具链有很多优点:
  1. 代码很新,架构优良。
  2. 错误信息更友好。
  3. 静态检查功能更强大。
  4. 版权限制小,易于自定义模块来扩展它的功能。
  5. 背后有Apple和Google这两家商业公司的大力支持。比如XCode现在只支持clang而不支持gcc。
  6. 支持JIT。这使得C/C++可以像java那样半编译半解释,一次编译到处执行。
  7. 支持所有主流的操作系统。
clang只是一个前端,它背后用来生成二进制机器码的叫llvm。
llvm+clang 在windows下有两种,一个是用mingw编译的,使用gcc的头文件和库。一个是用vc编译的,使用vc的头文件和库。
mingw版本的下载地址是:http://llvm.org/releases/3.6.1/LLVM-3.6.1-win32.exe 这是由官方提供的
vc版本的下载地址是:
google drive下载
这是我自己编译的,32位版本。 想自己编译clang的可参考我之前的文章.
我建议你安装vc版本的。
因为优点是:
  1. 它编译出来的是更原生态的程序。不依赖于mingw,只依赖于vc的dll。
  2. 我自己编译的这个版本功能更全,包含了llvm的JIT执行器、clang的扩展工具(如把老风格的代码转换成c++11)等等。
  3. 性能更高。
但也有一些缺点:
  1. 必须依赖于visual studio。请先安装visual studio再安装llvm。
没有安装visual studio的可以从微软的官方网站下载: http://www.microsoft.com/en-us/download/details.aspx?id=40778 。
如果已经有visual studio但是版本不是2013的,请安装vc 2013的可再分发包:http://www.microsoft.com/en-us/download/details.aspx?id=40784
clang安装好以后,你可以先打开它下面的bin目录看一眼,里面有30多个exe。主要比较常用的是:
  • clang: C语言编译器,类似于gcc
  • clang++: C++编译器,类似于g++。clang++只是clang的一个别名。
  • lld: 链接器,类似于ld。但是默认不用它,默认用vc的link.exe。
  • clang-format:按照固定的规范格式化C/C++代码,非常智能。文档请见:http://clang.llvm.org/docs/ClangFormat.html
  • clang-modernize:把按照C++98标准写的代码,转成C++11标准的。文档请见:http://clang.llvm.org/extra/ModernizerUsage.html
  • llvm-as - LLVM 汇编器
  • llvm-dis - LLVM 反汇编器
  • opt - LLVM 优化器
  • llc - LLVM 静态编译器
  • lli - LLVM的字节码执行器(某些平台下支持JIT)
  • llvm-link - LLVM的字节码链接器
  • llvm-ar - LLVM的静态库打包器,类似unix的ar。
  • llvm-nm - 类似于unix的nm。

Hello World with GNU Make

嗯,幸运的是clang以及GNU Make也有native的win32版本。
所以,如果我们写一个这样的Makefile:

CC=clang

all: hello.exe

main.o:main.c
$(CC) -c -o $@ $<
hello.exe: main.o
$(CC) -fuse-ld=lld -o $@ $<

clean:
del *.o *.exe

然后写一个简单的main.c,就可以直接make了。和在Linux下没有什么区别。
如果报告说找不到标准库的头文件,说明你没有VC的那些环境变量。要在"x64 Native Tools Command Prompt for VS 2017"里面执行make。

Win32 Hello World

然后写一个win32的hello world试下。
#include <windows.h>

int main(){  
  MessageBox(NULL,"hello\n",NULL,MB_OK);  
  return 0;
}


然后在这里面执行
C:\> clang++ -o hello.exe hello.cpp -Wl,"user32.lib"
 这个版本的clang有一个缺陷,它不会自动把-lxxx 这样的参数正确传递给vc的link.exe。所以我只能用-Wl这样的方式传。
编译好的exe执行结果如下:

Sanitizer

clang有一个王牌功能是sanitizer。它包含三种:AddressSanitizer、MemorySanitizer、ThreadSanitizer。AddressSanitizer和MemorySanitizer最初是google开发的,用于运行时检测C/C++程序中的内存错误。在编译的时候加上-fsanitizer参数,编译器就会在生成的代码中插入一些运行时检查。比如你可以拿下面的这段代码试下:
#include <stdio.h>
#include <string.h>

int main(int argc,char* argv[]){  
  char buf[4];
  strcpy(buf,argv[1]);
  printf("%s\n",buf);
  return 0;
}
它把命令行的第一个参数复制到一个临时的缓存区中,然后打印出来。
这段代码有两个bug:
  1. 在访问argv的时候可能会越界。(用户执行时没有加任何参数)
  2. buf不够长,写入时可能会越界,这将会造成严重的安全漏洞。
来,编译试下:
C:\>clang++ -fsanitize=address -o t.exe badcode.cpp -g3 -DDEBUG -D_DEBUG
然后运行:
C:\>t 3 3
C:\>t 355 355
C:\>t 3554664
(输出略)
它会提前把错误检测出来,并终止程序。
但是memory sanitizer目前在windows下还不能用。

此博客中的热门博文

少写代码,多读别人写的代码

tensorflow distributed runtime初窥