1. 介绍
clang提供了一些命令,让我们可以对编译的过程进行一些配置和查看,下面我们就对一些常用的指令进行一个基本的介绍.
2. 常用指令
2.1 查看编译的步骤
clang -ccc-print-phases main.m
输出结果如下:
0: input, "main.m", objective-c / 找到main.m文件
1: preprocessor, {0}, objective-c-cpp-output / 预处理器,处理include、import、宏定义
2: compiler, {1}, ir / 编译器编译,编译成ir中间代码
3: backend, {2}, assembler / 后端,生成目标代码
4: assembler, {3}, object / 汇编
5: linker, {4}, image / 链接其他动态库静态库
6: bind-arch, "x86_64", {5}, image / 编译成适合某个架构的代码
2.2 将.m文件转换成.cpp文件
cd 到.m文件在的目录下,然后:
clang -rewrite-objc main.m
会在目录下生成main.cpp文件,如果有报错,请自行查找解决办法。
2.3 查看操作内部命令,可以使用 -###命令
clang -### main.m -o main
2.4 查看预编译的结果
clang -E main.m
这个命令敲出,终端就会打印许多信息,直接拉到最下面,看到输出的:
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"Hello, World!");
int index = 10 + 1;
NSLog(@"%d",index);
}
return 0;
}
源代码:
#import <Foundation/Foundation.h>
#define aaa 10
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
int index = aaa + 1;
NSLog(@"%d",index);
}
return 0;
}
我们可以看到,预编译阶段把宏定义处理了。
2.5 词法分析
预处理完成后就会进行词法分析,这里会把代码切成一个个 Token,比如大小括号,等于号还有字符串等:
clang -fmodules -E -Xclang -dump-tokens main.m
输出如下:
annot_module_include '#import <Foundation/Foundation.h>
#define aaa 10
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
' Loc=<main.m:9:1>
int 'int' [StartOfLine] Loc=<main.m:13:1>
identifier 'main' [LeadingSpace] Loc=<main.m:13:5>
l_paren '(' Loc=<main.m:13:9>
int 'int' Loc=<main.m:13:10>
identifier 'argc' [LeadingSpace] Loc=<main.m:13:14>
comma ',' Loc=<main.m:13:18>
const 'const' [LeadingSpace] Loc=<main.m:13:20>
char 'char' [LeadingSpace] Loc=<main.m:13:26>
star '*' [LeadingSpace] Loc=<main.m:13:31>
identifier 'argv' [LeadingSpace] Loc=<main.m:13:33>
l_square '[' Loc=<main.m:13:37>
r_square ']' Loc=<main.m:13:38>
r_paren ')' Loc=<main.m:13:39>
l_brace '{' [LeadingSpace] Loc=<main.m:13:41>
at '@' [StartOfLine] [LeadingSpace] Loc=<main.m:14:5>
identifier 'autoreleasepool' Loc=<main.m:14:6>
l_brace '{' [LeadingSpace] Loc=<main.m:14:22>
identifier 'NSLog' [StartOfLine] [LeadingSpace] Loc=<main.m:16:9>
l_paren '(' Loc=<main.m:16:14>
at '@' Loc=<main.m:16:15>
string_literal '"Hello, World!"' Loc=<main.m:16:16>
r_paren ')' Loc=<main.m:16:31>
semi ';' Loc=<main.m:16:32>
int 'int' [StartOfLine] [LeadingSpace] Loc=<main.m:17:9>
identifier 'index' [LeadingSpace] Loc=<main.m:17:13>
equal '=' [LeadingSpace] Loc=<main.m:17:19>
numeric_constant '10' [LeadingSpace] Loc=<main.m:17:21 <Spelling=main.m:11:13>>
plus '+' [LeadingSpace] Loc=<main.m:17:25>
numeric_constant '1' [LeadingSpace] Loc=<main.m:17:27>
semi ';' Loc=<main.m:17:28>
identifier 'NSLog' [StartOfLine] [LeadingSpace] Loc=<main.m:18:9>
l_paren '(' Loc=<main.m:18:14>
at '@' Loc=<main.m:18:15>
string_literal '"%d"' Loc=<main.m:18:16>
comma ',' Loc=<main.m:18:20>
identifier 'index' Loc=<main.m:18:21>
r_paren ')' Loc=<main.m:18:26>
semi ';' Loc=<main.m:18:27>
r_brace '}' [StartOfLine] [LeadingSpace] Loc=<main.m:19:5>
return 'return' [StartOfLine] [LeadingSpace] Loc=<main.m:20:5>
numeric_constant '0' [LeadingSpace] Loc=<main.m:20:12>
semi ';' Loc=<main.m:20:13>
r_brace '}' [StartOfLine] Loc=<main.m:21:1>
eof '' Loc=<main.m:21:2>
可以看出,词法分析的时候,将上面的代码拆分一个个token,后面数字表示某一行的第几个字符,例如第一个int,表示第13行第1个字符。
2.6 语法树-AST
语法分析,生成语法树(AST,Abstract Syntax Tree):
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
输出:
TranslationUnitDecl 0x7fb8a8036608 <<invalid sloc>> <invalid sloc> <undeserialized declarations>
|-TypedefDecl 0x7fb8a8036ea0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x7fb8a8036ba0 '__int128'
|-TypedefDecl 0x7fb8a8036f10 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x7fb8a8036bc0 'unsigned __int128'
|-TypedefDecl 0x7fb8a8036fb0 <<invalid sloc>> <invalid sloc> implicit SEL 'SEL *'
| `-PointerType 0x7fb8a8036f70 'SEL *' imported
| `-BuiltinType 0x7fb8a8036e00 'SEL'
|-TypedefDecl 0x7fb8a8037098 <<invalid sloc>> <invalid sloc> implicit id 'id'
| `-ObjCObjectPointerType 0x7fb8a8037040 'id' imported
| `-ObjCObjectType 0x7fb8a8037010 'id' imported
|-TypedefDecl 0x7fb8a8037178 <<invalid sloc>> <invalid sloc> implicit Class 'Class'
| `-ObjCObjectPointerType 0x7fb8a8037120 'Class' imported
| `-ObjCObjectType 0x7fb8a80370f0 'Class' imported
|-ObjCInterfaceDecl 0x7fb8a80371d0 <<invalid sloc>> <invalid sloc> implicit Protocol
|-TypedefDecl 0x7fb8a8037548 <<invalid sloc>> <invalid sloc> implicit __NSConstantString 'struct __NSConstantString_tag'
| `-RecordType 0x7fb8a8037340 'struct __NSConstantString_tag'
| `-Record 0x7fb8a80372a0 '__NSConstantString_tag'
|-TypedefDecl 0x7fb8a880bc00 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x7fb8a80375a0 'char *' imported
| `-BuiltinType 0x7fb8a80366a0 'char'
|-TypedefDecl 0x7fb8a880bee8 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag [1]'
| `-ConstantArrayType 0x7fb8a880be90 'struct __va_list_tag [1]' 1
| `-RecordType 0x7fb8a880bcf0 'struct __va_list_tag'
| `-Record 0x7fb8a880bc58 '__va_list_tag'
|-ImportDecl 0x7fb8a88b6178 <main.m:9:1> col:1 implicit Foundation
`-FunctionDecl 0x7fb8a88b6440 <line:13:1, line:21:1> line:13:5 main 'int (int, const char **)'
|-ParmVarDecl 0x7fb8a88b61d0 <col:10, col:14> col:14 argc 'int'
|-ParmVarDecl 0x7fb8a88b62f0 <col:20, col:38> col:33 argv 'const char **':'const char **'
`-CompoundStmt 0x7fb8a88c3658 <col:41, line:21:1>
|-ObjCAutoreleasePoolStmt 0x7fb8a88c3610 <line:14:5, line:19:5>
| `-CompoundStmt 0x7fb8a88c35e8 <line:14:22, line:19:5>
| |-CallExpr 0x7fb8a80d62c0 <line:16:9, col:31> 'void'
| | |-ImplicitCastExpr 0x7fb8a80d62a8 <col:9> 'void (*)(id, ...)' <FunctionToPointerDecay>
| | | `-DeclRefExpr 0x7fb8a80d61b0 <col:9> 'void (id, ...)' Function 0x7fb8a88b6580 'NSLog' 'void (id, ...)'
| | `-ImplicitCastExpr 0x7fb8a80d62e8 <col:15, col:16> 'id':'id' <BitCast>
| | `-ObjCStringLiteral 0x7fb8a80d6230 <col:15, col:16> 'NSString *'
| | `-StringLiteral 0x7fb8a80d6208 <col:16> 'char [14]' lvalue "Hello, World!"
| |-DeclStmt 0x7fb8a88c3488 <line:17:9, col:28>
| | `-VarDecl 0x7fb8a88c33c0 <col:9, col:27> col:13 used index 'int' cinit
| | `-BinaryOperator 0x7fb8a88c3468 <line:11:13, line:17:27> 'int' '+'
| | |-IntegerLiteral 0x7fb8a88c3428 <line:11:13> 'int' 10
| | `-IntegerLiteral 0x7fb8a88c3448 <line:17:27> 'int' 1
| `-CallExpr 0x7fb8a88c3588 <line:18:9, col:26> 'void'
| |-ImplicitCastExpr 0x7fb8a88c3570 <col:9> 'void (*)(id, ...)' <FunctionToPointerDecay>
| | `-DeclRefExpr 0x7fb8a88c34a0 <col:9> 'void (id, ...)' Function 0x7fb8a88b6580 'NSLog' 'void (id, ...)'
| |-ImplicitCastExpr 0x7fb8a88c35b8 <col:15, col:16> 'id':'id' <BitCast>
| | `-ObjCStringLiteral 0x7fb8a88c3518 <col:15, col:16> 'NSString *'
| | `-StringLiteral 0x7fb8a88c34f8 <col:16> 'char [3]' lvalue "%d"
| `-ImplicitCastExpr 0x7fb8a88c35d0 <col:21> 'int' <LValueToRValue>
| `-DeclRefExpr 0x7fb8a88c3538 <col:21> 'int' lvalue Var 0x7fb8a88c33c0 'index' 'int'
`-ReturnStmt 0x7fb8a88c3648 <line:20:5, col:12>
`-IntegerLiteral 0x7fb8a88c3628 <col:12> 'int' 0
在终端敲出的时候,终端很直观的帮我们用颜色区分。
2.7 生成中间代码
完成这些步骤后就可以开始IR(intermediate representation)中间代码的生成了,CodeGen 会负责将语法树自顶向下遍历逐步翻译成 LLVM IR,IR 是编译过程的前端的输出后端的输入。
clang -S -fobjc-arc -emit-llvm main.m -o main.ll
2.8 生成汇编
clang -S -fobjc-arc main.m -o main.s
2.9 生成目标文件
clang -fmodules -c main.m -o main.o
网友评论