clang是编译器前端,用来做预处理,词法分析,语法分析,它可以把结果转换为抽象语法树AST,然后交给LLVM编译器后端,最终生成可执行程序。
代码的编译过程可以分为预处理,词法分析,语法分析,语义分析,目标代码,链接,生成可执行程序,本文在MacOS平台结合clang命令完成一段C++代码的编译。
新建一个文件main.cpp,写入C++代码。
#include <iostream>
#define STR "Hello world"
int main(int argc, const char * argv[]) {
std::string a = STR;
std::cout << a << std::endl;
return 0;
}
我们先使用clang命令查看这个段代码的编译过程,由于代码是C++,需要使用clang++
clang++ -ccc-print-phases main.cpp
终端输出了信息
+- 0: input, "main.cpp", c++
+- 1: preprocessor, {
0}, c++-cpp-output
+- 2: compiler, {
1}, ir
+- 3: backend, {
2}, assembler
+- 4: assembler, {
3}, object
+- 5: linker, {
4}, image
6: bind-arch, "x86_64", {
5}, image
input指的是输入源码文件,preprocessor是预处理,compiler是编译器前端,compiler做词法分析,语法分析,语义分析。随后backend生成汇编,生成目标文件。linker是链接,生成image。最后bind-arch处理架构信息,生成架构相关的image文件。
1.查看preprocessor预处理过程
clang++ -E main.cpp -o main.i
生成的main.i文件很长,滑动到底部可以看到源码部分
int main(int argc, const char * argv[]) {
std::string a = "Hello world";
std::cout << a << std::endl;
return 0;
}
可以看到预处理阶段,宏定义被展开,代码部分还未处理。
2.查看词法分析
clang++ -fmodules -E -Xclang -dump-tokens main.cpp
生成的词法分析结果很长,这里仅截取一小段
identifier 'std' [StartOfLine] [LeadingSpace] Loc=<main.cpp:14:5>
coloncolon '::' Loc=<main.cpp:14:8>
identifier 'cout' Loc=<main.cpp:14:10>
lessless '<<' [LeadingSpace] Loc=<main.cpp:14:15>
identifier 'a' [LeadingSpace] Loc=<main.cpp:14:18>
lessless '<<' [LeadingSpace] Loc=<main.cpp:14:20>
identifier 'std' [LeadingSpace] Loc=<main.cpp:14:23>
coloncolon '::' Loc=<main.cpp:14:26>
identifier 'endl' Loc=<main.cpp:14:28>
semi ';' Loc=<main.cpp:14:32>
return 'return' [StartOfLine] [LeadingSpace] Loc=<main.cpp:15:5>
numeric_constant '0' [LeadingSpace] Loc=<main.cpp:15:12>
semi ';' Loc=<main.cpp:15:13>
r_brace '}' [StartOfLine] Loc=<main.cpp:16:1>
eof '' Loc=<main.cpp:16:2>
词法分析就是对源码进行解析,生成一个个token,从结果看std,::,cout,a等符号都被识别出来。左侧是token的类型,比如identifier标识符,semi分号,eof是文件末尾。右侧记录了每个符号在源码的中行号列号。
3.语法分析
clang++ -fmodules -fsyntax-only -Xclang -ast-dump main.cpp
4.语义分析
clang++ -S -emit-llvm main.cpp
当前目录会生成main.ll语法分析文件
5.汇编文件
clang++ -S main.cpp
当前目录会生成main.s的汇编文件
6.生成目标文件
clang++ -c main.s
当前目录会生成main.o目标文件,这个文件是二进制形式的。
7.生成可执行文件
clang++ main.cpp -o main
当前目录生成main文件,在命令行中执行./main 即可运行程序,输出Hello world