内容简介: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编译成平台相关的机器语言 。
先看结果
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)
Clang (Frontend前端)
是一个C、C++、Objective-C和Objective-C++程式语言的编译器前端
Clang源码结构
Clang步骤
clang -ccc-print-phases main.m
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
-
#include的机制是 编译器会去递回检查每个Header,header inculde的 header 文章里提了几个弱点: Compile-time scalability :耗时编译 Fragility :多引入顺序或导致宏冲突 Conventional workarounds :C语言长久的息惯,导致代码较丑 Tool confusion
-
然而编译器在碰到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 能够在源码中指出出错的具体位置。
-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
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(类型)
子类过于详细不在这多写
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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 前端科普系列(三):CommonJS 不是前端却革命了前端
- 前端科普系列(三):CommonJS 不是前端却革命了前端
- 前端技术演进(三):前端安全
- 【前端优化】前端常见性能优化
- 【前端学习笔记】前端安全详解
- 前端监控和前端埋点
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。