美文网首页
clang操作记录

clang操作记录

作者: 沉江小鱼 | 来源:发表于2020-08-06 15:22 被阅读0次

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

相关文章

网友评论

      本文标题:clang操作记录

      本文链接:https://www.haomeiwen.com/subject/rerwrktx.html