博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
v深入研究Clang(四) Clang编译器的简单分析
阅读量:6569 次
发布时间:2019-06-24

本文共 6594 字,大约阅读时间需要 21 分钟。

作者:

首先我们确定下Clang编译器的详细内容和涵盖范围。之前在《》中以前提到过。Clang driver(命令行表示是clang)和Clang前端(依照详细实现来说就是Clang的那些库所实现的前端)是不同的。同一时候还存在一个Clang编译器(命令行表示是clang -cc1)。Clang编译器不只包括了Clang前端,还包括使用LLVM的哭实现的编译器的中间阶段以及后端,同一时候也集成了assembler。

Clang driver有一系列的frontend action,这些frontend action定义于clang/include/clang/Frontend/FrontendOptions.h中的ActionKind枚举中。

当中一些frontend action就会触发Clang编译器(clang -cc1),比方:ASTView, EmitBC, EmitObj等。一旦触发了Clang编译器(clang -cc1)。就会执行函数cc1_main()(clang/tools/driver/cc1_main.cpp),从名字上就能够看出来,这个函数是Clang编译器(clang -cc1)的入口主函数。

举个详细的样例来看一下:

min.c

int min(int a, int b) {    if (a < b) {        return a;    }    return b;}

执行命令: clang -### min.c -o min

clang version 3.5.0 (tags/RELEASE_350/final)Target: x86_64-unknown-linux-gnuThread model: posix "/home/shining/llvm-3.5/build/bin/clang-3.5" "-cc1" "-triple" "x86_64-unknown-linux-gnu" "-emit-obj" "-mrelax-all" "-disable-free" "-main-file-name" "min.c" "-mrelocation-model" "static" "-mdisable-fp-elim" "-fmath-errno" "-masm-verbose" "-mconstructor-aliases" "-munwind-tables" "-fuse-init-array" "-target-cpu" "x86-64" "-dwarf-column-info" "-resource-dir" "/home/shining/llvm-3.5/build/bin/../lib/clang/3.5.0" "-internal-isystem" "/usr/local/include" "-internal-isystem" "/home/shining/llvm-3.5/build/bin/../lib/clang/3.5.0/include" "-internal-externc-isystem" "/usr/include/x86_64-linux-gnu" "-internal-externc-isystem" "/include" "-internal-externc-isystem" "/usr/include" "-fdebug-compilation-dir" "/home/shining/llvm-3.5/build/bin" "-ferror-limit" "19" "-fmessage-length" "80" "-mstackrealign" "-fobjc-runtime=gcc" "-fdiagnostics-show-option" "-o" "/tmp/min-75c13b.o" "-x" "c" "min.c" "/usr/bin/ld" "-z" "relro" "--hash-style=gnu" "--build-id" "--eh-frame-hdr" "-m" "elf_x86_64" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-o" "min" "/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o" "/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o" "/usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o" "-L/usr/lib/gcc/x86_64-linux-gnu/4.8" "-L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu" "-L/lib/x86_64-linux-gnu" "-L/lib/../lib64" "-L/usr/lib/x86_64-linux-gnu" "-L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../.." "-L/home/shining/llvm-3.5/build/bin/../lib" "-L/lib" "-L/usr/lib" "/tmp/min-75c13b.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "/usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o" "/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o"
-###參数是为了查看。clang driver究竟调用了哪些命令,而且不会执行这些命令。从这里能够实际看到,实际上调用的是 clang-3.5 -cc1。当中3.5是版本,所以事实上调用的就是clang编译器。

之后又调用了系统的ld loader,由于LLVM架构的loader还在开发之中。

所以,对于那些我们已经明白须要clang编译器去作的工作,我们能够不通过clang driver去隐式调用(比方上面的样例)。而是直接在命令行调用clang -cc1去执行。而且在clang -cc1之后跟clang编译器接受的參数。也能够通过clang -Xclang就能够直接将參数传递给clang编译器(clang -cc1)。以下的详细实现,将同一时候给出这两种的命令行形式,事实上执行结果差点儿是全然同样的。不同的是,使用clang -Xclang的时候,假设不加强制的參数,这里尽管-Xclang将參数传递给了clang -cc1,可是这里的clang driver依旧会继续工作的。在以下的样例中会进行分别的展示

编译器首先进行的是词法分析。我们能够通过命令行去查看进行词法分析之后的token序列究竟是怎么样的,仍然以上面的min.c为例,执行命令:

clang -cc1 -dump-tokens min.c

执行之后得到例如以下输出:

int 'int'	 [StartOfLine]	Loc=
identifier 'min' [LeadingSpace] Loc=
l_paren '(' Loc=
int 'int' Loc=
identifier 'a' [LeadingSpace] Loc=
comma ',' Loc=
int 'int' [LeadingSpace] Loc=
identifier 'b' [LeadingSpace] Loc=
r_paren ')' Loc=
l_brace '{' [LeadingSpace] Loc=
if 'if' [StartOfLine] [LeadingSpace] Loc=
l_paren '(' [LeadingSpace] Loc=
identifier 'a' Loc=
less '<' [LeadingSpace] Loc=
identifier 'b' [LeadingSpace] Loc=
r_paren ')' Loc=
l_brace '{' [LeadingSpace] Loc=
return 'return' [StartOfLine] [LeadingSpace] Loc=
identifier 'a' [LeadingSpace] Loc=
semi ';' Loc=
r_brace '}' [StartOfLine] [LeadingSpace] Loc=
return 'return' [StartOfLine] [LeadingSpace] Loc=
identifier 'b' [LeadingSpace] Loc=
semi ';' Loc=
r_brace '}' [StartOfLine] Loc=
eof '' Loc=
或者选用: clang -Xclang -dump-tokens min.c

输出信息例如以下:

int 'int'	 [StartOfLine]	Loc=
identifier 'min' [LeadingSpace] Loc=
l_paren '(' Loc=
int 'int' Loc=
identifier 'a' [LeadingSpace] Loc=
comma ',' Loc=
int 'int' [LeadingSpace] Loc=
identifier 'b' [LeadingSpace] Loc=
r_paren ')' Loc=
l_brace '{' [LeadingSpace] Loc=
if 'if' [StartOfLine] [LeadingSpace] Loc=
l_paren '(' [LeadingSpace] Loc=
identifier 'a' Loc=
less '<' [LeadingSpace] Loc=
identifier 'b' [LeadingSpace] Loc=
r_paren ')' Loc=
l_brace '{' [LeadingSpace] Loc=
return 'return' [StartOfLine] [LeadingSpace] Loc=
identifier 'a' [LeadingSpace] Loc=
semi ';' Loc=
r_brace '}' [StartOfLine] [LeadingSpace] Loc=
return 'return' [StartOfLine] [LeadingSpace] Loc=
identifier 'b' [LeadingSpace] Loc=
semi ';' Loc=
r_brace '}' [StartOfLine] Loc=
eof '' Loc=
/usr/bin/ld: cannot find /tmp/min-3cce9d.o: No such file or directoryclang-3.5: error: linker command failed with exit code 1 (use -v to see invocation)
明显能够看到,使用-Xclang的时候,把-dump-tokens參数传递给了clang -cc1,可是clang driver依旧工作,而且调用了ld.

能够使用clang -### -Xclang -dump-tokens min.c命令进行验证。

看过了词法分析阶段,我们再看下clang编译器语法分析来的AST nodes。

使用命令:clang -cc1 -fsyntax-only -ast-dump min.c

或者:clang -fsyntax-only -Xclang -ast-dump min.c

输出结果一样:

TranslationUnitDecl 0x6bc3a40 <
>
|-TypedefDecl 0x6bc3f40 <
>
implicit __int128_t '__int128'|-TypedefDecl 0x6bc3fa0 <
>
implicit __uint128_t 'unsigned __int128'|-TypedefDecl 0x6bc42f0 <
>
implicit __builtin_va_list '__va_list_tag [1]'`-FunctionDecl 0x6bc4490
line:1:5 min 'int (int, int)' |-ParmVarDecl 0x6bc4350
col:13 used a 'int' |-ParmVarDecl 0x6bc43c0
col:20 used b 'int' `-CompoundStmt 0x6bc46f8
|-IfStmt 0x6bc4668
| |-<<
>> | |-BinaryOperator 0x6bc45c0
'int' '<' | | |-ImplicitCastExpr 0x6bc4590
'int'
| | | `-DeclRefExpr 0x6bc4540
'int' lvalue ParmVar 0x6bc4350 'a' 'int' | | `-ImplicitCastExpr 0x6bc45a8
'int'
| | `-DeclRefExpr 0x6bc4568
'int' lvalue ParmVar 0x6bc43c0 'b' 'int' | |-CompoundStmt 0x6bc4648
| | `-ReturnStmt 0x6bc4628
| | `-ImplicitCastExpr 0x6bc4610
'int'
| | `-DeclRefExpr 0x6bc45e8
'int' lvalue ParmVar 0x6bc4350 'a' 'int' | `-<<
>> `-ReturnStmt 0x6bc46d8
`-ImplicitCastExpr 0x6bc46c0
'int'
`-DeclRefExpr 0x6bc4698
'int' lvalue ParmVar 0x6bc43c0 'b' 'int'

通过clang -### -fsyntax-only -Xclang -ast-dump min.c查看实际执行命令。事实上跟使用clang -cc1是同样的。

參考资料:

1. 《Getting Started with LLVM Core Libraries》

2.  Code of clang

本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5138868.html,如需转载请自行联系原作者

你可能感兴趣的文章