LLVM不仅仅是一个编译器,同时提供了模块化的功能和库,用于编译器的开发和功能扩展。常规的一个编译器分为前端、优化器和后端,LLVM编译器也不例外,Clang就是属于一个编译器的前端部分,LLVM属于优化器和后端,当然LLVM也可以支持其他类型的前端,比如GCC前端编译器。
Clang的安装
- apt安装
本文介绍到的LLVM-Clang就是使用Clang前端的LLVM编译器,一般情况下LLVM都会说使用Clang作为前端,Clang是专为LLVM而开发的,所以这是最佳的搭配。在ubuntu系统上安装:
sudo apt-get install clang
sudo apt-get install llvm
要注意的是clang和llvm实际上是两个东西,llvm类似于一个容器,可以使用clang作为前端插件,也可以使用其他类型的前端插件,因此我们需要安装两个。
- 官网下载整包安装
在llvm的官网 http://clang.llvm.org/get_started.html 可以查看已经编译好的各个平台的release版本,Clang也会作为llvm release的一部分一起发布:http://releases.llvm.org/
- 源码编译安装
参考官网 http://clang.llvm.org/get_started.html 上的步骤,其实也很简单,下载源码后配置一下cmake,编译、安装即可。
Clang的使用
LLVM(low level virtual machine)顾名思义它是一种虚拟机,它在对代码进行处理的时候都需要使用IR中间文件,所以源代码要被先转换为LLVM IR中间文件(LLVM Intermediate Representation)。
LLVM在对程序进行优化的时候全部都是以IR的形式来进行优化的,它类似于是一种被LLVM所使用的一种语言,可以跨平台使用,因此所有平台上的LLVM都可以解释同一份IR,然后LLVM后端再利用IR生成不同平台上的机器码,此种类型的程序才可以正常运行。
LLVM IR文件(文本形式)
生成文本格式的IR文件:
clang -O3 -emit-llvm helloworld.c -S -o helloworld.ll
LLVM IR文件(二进制形式)
直接编译生成二进制格式IR文件:
clang -O3 -emit-llvm helloworld.c -c -o helloworld.bc
LLVM IR文件格式转换
.bc和.ll文件的转换:
llvm-as helloworld.ll //llvm .ll -> .bc assembler
llvm-dis helloworld.bc //llvm .bc -> .ll disassembler
LLVM IR生成平台对应的汇编文件
通过IR文件生成符合目标平台上的汇编文件,LLVM后端做的事情,通过llc进行操作:
llc helloworld.ll -o helloworld.S
LLVM IR生成平台对应的可执行文件
通过IR文件生成符合目标平台上的可执行文件,LLVM后端做的事情,通过llc进行操作:
llc -filetype=obj helloworld.ll -o helloworld
llc -filetype=obj helloworld.bc -o helloworld
LLVM IR文件link操作
llvm-link func1.bc func2.bc -o linked.bc
交叉编译
交叉编译arm64平台andoird native程序
clang -O3 -emit-llvm helloworld.c -c -target aarch64-none-linux-android -o helloworld.bc # 生成aarch64-none-linux-android目标的IR文件
clang -O3 -emit-llvm helloworld.c -S -target aarch64-none-linux-android -o helloworld.ll # 生成aarch64-none-linux-android目标的IR文件
llc -march=aarch64 helloworld.bc -o hello.S #生成aarch64平台上的汇编文件
llc -march=aarch64 -filetype=obj helloworld.bc -o hello #生成aarch64平台上的可执行文件
参考文档:
https://zhuanlan.zhihu.com/p/66793637
https://llvm.org/docs/LangRef.html
https://llvm.org/