(Xcode) 編譯器小白筆記 - LLVM前端Clang

栏目: IOS · 发布时间: 5年前

内容简介:Apple(包括中后期的NeXT) 一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错,但Apple对编译工具会提出更高的要求。Clang这个软体专案在2005年由苹果电脑发起,是LLVM编译器工具集的前端(front-end),目的是输出程式码对应的抽象语法树(Abstract Syntax Tree, AST),并将程式码编译成LLVM Bitcode。接着在后端(back-end)使用LLVM编译成平台相关的机器语言 。main.m

Apple(包括中后期的NeXT) 一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错,但Apple对编译 工具 会提出更高的要求。

Clang这个软体专案在2005年由苹果电脑发起,是LLVM编译器工具集的前端(front-end),目的是输出程式码对应的抽象语法树(Abstract Syntax Tree, AST),并将程式码编译成LLVM Bitcode。接着在后端(back-end)使用LLVM编译成平台相关的机器语言 。

(Xcode) 編譯器小白筆記 - LLVM前端Clang

先看结果

main.m

#import <Foundation/Foundation.h>
#define DEFINEEight 8

int main(){
    @autoreleasepool {
        int eight = DEFINEEight;
        int six = 6;
        NSString* site = [[NSString alloc] initWithUTF8String:"starming"];
        int rank = eight + six;
        NSLog(@"%@ rank %d", site, rank);
    }
    return 0;
}

复制代码

直接编译成执行档

clang -fmodules main.m

产出 .out (executable)

(Xcode) 編譯器小白筆記 - LLVM前端Clang

Clang (Frontend前端)

是一个C、C++、Objective-C和Objective-C++程式语言的编译器前端

Clang源码结构

(Xcode) 編譯器小白筆記 - LLVM前端Clang

Clang步骤

clang -ccc-print-phases main.m

(Xcode) 編譯器小白筆記 - LLVM前端Clang
(Xcode) 編譯器小白筆記 - LLVM前端Clang

1.Input (Driver)

指定语言 , 架构, 输入file

clang -x objective-c main.m

2.Preprocessor(预处理)

import 头文件, include头文件等 ,macro宏展开,处理'#'开头指令

单做预处理, 并取得预处理结果

clang -E main.m

预处理最终结果:

# 1 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Foundation.framework/Headers/FoundationLegacySwiftCompatibility.h" 1 3
# 185 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h" 2 3
# 2 "main.m" 2


int main(){
    @autoreleasepool {
        int eight = 8;
        int six = 6;
        NSString* site = [[NSString alloc] initWithUTF8String:"starming"];
        int rank = eight + six;
        NSLog(@"%@ rank %d", site, rank);
    }
    return 0;
}

复制代码

依据上面的结果能明显看到 header被换成了明确的全局位置,常量 DEFINEEight 也被替换进代码里,讲到import 就不得不提 modules

2.1 Modules 模块 (-fmodules)

参考LLVM modules文档

文章里提及: Modules provide an alternative, simpler way to use software libraries that provides better compile-time scalability and eliminates many of the problems inherent to using the C preprocessor to access the API of a library.

Clang 以简单的 import std.io 概念取代 原本冗余的函数库(libraries)引进 #include <stdio.h> ,类似 java 的package,目前Clang

  1. #include的机制是 编译器会去递回检查每个Header,header inculde的 header 文章里提了几个弱点: Compile-time scalability :耗时编译 Fragility :多引入顺序或导致宏冲突 Conventional workarounds :C语言长久的息惯,导致代码较丑 Tool confusion

  2. 然而编译器在碰到import时,会直接载入module对应的二进制文件并取得他的api,一个module不依赖外部header,只编译一次,api也只解析一次, 当然module也有些缺点包括 namesspace(可能重名), 改库代码, 无法适应各种机器的Arch。

3 Lexical Analysis (词法分析 Lex, Tokenization) -> .i (Tokens)

此步骤是Compiler里的基本程序,将字符一个一个的读进Lexer里,并根据构词规则识别 Token(单词),此处还不会校验语法

做词法分析并把Token分析结果展示出来

clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m

每一个标记都包含了对应的源码内容和其在源码中的位置。注意这里的位置是宏展开之前的位置,这样一来,如果编译过程中遇到什么问题,clang 能够在源码中指出出错的具体位置。

(Xcode) 編譯器小白筆記 - LLVM前端Clang

-fsyntax-only : Run the preprocessor, parser and type checking stages.

4 语法分析(Semantic Analysis) -> AST

语法分析,在Clang中有Parser和Sema两个模块配合完成,验证语法是否正确,并给出正确的提示。

4.1 Parser

遍历每个Token做词句分析,生成一个 节点( Nodes )该有的资讯

4.2 Semantic

在Lex 跟 syntax Analysis之后, 也就是在这个阶段已经确保 词 句 语法已经是正确的形式了,semantic 接着做return values, size boundaries, uninitialized variables 等检查,之后根据当前的资讯,生成语意节点( Nodes ),并将所有节点组合成抽象语法书( AST )

做 语法分析 并展示 AST

clang -fmodules -fsyntax-only -Xclang -ast-dump main.m

(Xcode) 編譯器小白筆記 - LLVM前端Clang

5 抽象语法树 Abstract Syntax Tree

可以说是Clang的核心,大部分的优化, 判断都在AST处理(例如寻找Class, 替换代码...等)

此步骤会将 Clang Attr 转换成 AST 上的 AttributeList ,能在clang插件上透过 Decl::getAttr<T> 获取

Clang Attributes是 Clang 提供的一种 源码注解 ,方便开发者向编译器表达某种要求,参与控制如 Static Analyzer、Name Mangling、Code Generation 等过程, 一般以 __attribute__(xxx) 的形式出现在代码中, Ex: NS_CLASS_AVAILABLE_IOS(9_0)

结构跟其他Compiler的AST相同与其他编译器不同的是 Clang的AST是由C++构成类似Class,Variable的层级表示,其他的则是以汇编语言编写。

这代表着AST也能有对应的api,这让AST操作, 获取信息 都比较容易,甚至还夹带着地址跟代码位置。

AST Context: 存储所有AST相关资讯, 且提供ASTMatcher等遍历方法

Node三大Class Decl - Declarations(声明), Stmt - Statements(陈述句), type(类型) 子类过于详细不在这多写

(Xcode) 編譯器小白筆記 - LLVM前端Clang

6 代码生成 CodeGen -> IR中间代码(.ll)

CodeGen负责将语法树从顶至下遍历,翻译成LLVM IR,是LLVM Backend 的输入,是前后端的桥接语言。

产出IR: clang -S -fobjc-arc -emit-llvm main.m -o main.ll

LLVM IR 有三种表示格式,第一种是 bitcode 这样的存储格式,以 .bc 做后缀,第二种是可读的以 .ll,第三种是用于开发时操作 LLVM IR 的内存格式。

产出Bit clang -emit-llvm -c main.m -o main.bc

查看BitCode llvm-dis < main.bc | less

6.1 IR 优化 Optimization

IR提供了多种优化选项,-01 -02 -03 -0s.... 对应着不同的入参,有比如类似死代码清理,内联化,表达式重组,循环变量移动这样的 Pass。

(Xcode) 編譯器小白筆記 - LLVM前端Clang
(Xcode) 編譯器小白筆記 - LLVM前端Clang

以上所述就是小编给大家介绍的《(Xcode) 編譯器小白筆記 - LLVM前端Clang》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Powerful

Powerful

Patty McCord / Missionday / 2018-1-25

Named by The Washington Post as one of the 11 Leadership Books to Read in 2018 When it comes to recruiting, motivating, and creating great teams, Patty McCord says most companies have it all wrong. Mc......一起来看看 《Powerful》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具