瞻仰大佬
- Clang
- LLVM
- Swift
2010年开始编写 Swift语言,并且一我的实现了Swift的大部分基础架构;他也是 LVVM 以及 Clang的主要开发者。
html
LLVM官网前端
做用:用于优化以任意程序语言编写的程序的编译时间(compile-time)、连接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time).在2000年,Chris Lattner开发了这一套编译器工具库套件.后来随着LLVM的发展,LLVM能够用于常规编译器,JIT编译器,汇编器,调试器,静态分析工具等一系列跟编程语言相关的工做。ios
2012年,LLVM 得到美国计算机学会 ACM 的软件系统大奖,和 UNIX,WWW,TCP/IP,Apache,JAVA, Eclipse等齐名。c++
注:LLVM工程包含了一组模块化,可复用的编辑器和工具链。同其名字原意(Low Level Virtual Machine)不一样的是,LLVM不是一个首字母缩写,而是工程的名字。
git
Xcode版本 | 编译器版本 |
---|---|
Xcode3以前 | GCC |
Xcode3 | GCC与 LLVM混合编译器 |
Xcode4 | LLVM-GCC 成为默认编译器 |
Xcode4.2 | LLVM3.0成为默认编译器 |
Xcode5 | LLVM5.0, 完成 GCC到LLVM的过渡 |
GCC是 Xcode早期使用的一个强大的编译器.这个编译器被移植到各类系统中,其中就是 Mac OSX 操做系统,因此这就反映在 Xcode中,在早期的 Xcode 调试代码的一个工具就是 GDB,它是GNU调试器.github
Apple(包括中后期的NeXT)一直使用GCC做为官方的编译器。GCC做为开源世界的编译器标准一直作得不错,但Apple对编译工具会提出更高的要求。 一方面,是Apple对Objective-C语言(甚至后来对C语言)新增不少特性,但GCC开发者并不买Apple的账——不给实现,所以索性后来二者分红两条分支分别开发,这也形成Apple的编译器版本远落后于GCC的官方版本。另外一方面,GCC的代码耦合度过高,很差独立,并且越是后期的版本,代码质量越差,但Apple想作的不少功能(好比更好的IDE支持)须要模块化的方式来调用GCC,但GCC一直不给作。甚至最近,《GCC运行环境豁免条款(英文版)》从根本上限制了LLVM-GCC的开发。 因此,这种不和让Apple一直在寻找一个高效的、模块化的、协议更放松的开源替代品.
objective-c
- LLVM Core:包含一个如今的源代码/目标设备无关的优化器,一集一个针对不少主流(甚至于一些非主流)的CPU的汇编代码生成支持。
- Clang:一个C/C++/Objective-C编译器,致力于提供使人惊讶的快速编译,极其有用的错误和警告信息,提供一个可用于构建很棒的源代码级别的工具.
- dragonegg: gcc插件,可将GCC的优化和代码生成器替换为LLVM的相应工具。
- LLDB:基于LLVM提供的库和Clang构建的优秀的本地调试器。
- libc++、libc++ ABI: 符合标准的,高性能的C++标准库实现,以及对C++11的完整支持。
- compiler-rt:针对__fixunsdfdi和其余目标机器上没有一个核心IR(intermediate representation)对应的短原生指令序列时,提供高度调优过的底层代码生成支持。
- OpenMP: Clang中对多平台并行编程的runtime支持。
- vmkit:基于LLVM的Java和.NET虚拟机实
- polly: 支持高级别的循环和数据本地化优化支持的LLVM框架。
- libclc: OpenCL标准库的实现
- klee: 基于LLVM编译基础设施的符号化虚拟机
- SAFECode:内存安全的C/C++编译器
- lld: clang/llvm内置的连接器
传统的静态编译器分为三个阶段:前端、优化和后端。 算法
典型例子:GCC编译器, 如何作到解耦? 编程
不一样的前端后端使用统一的中间代码LLVM Intermediate Representation (LLVM IR)
若是须要支持一种新的编程语言,那么只须要实现一个新的前端
若是须要支持一种新的硬件设备,那么只须要实现一个新的后端
优化阶段是一个通用的阶段,它针对的是统一的LLVM IR,不管是支持新的编程语言,仍是支持新的硬件设备,都不须要对优化阶段作修改
LLVM如今被做为实现各类静态和运行时编译语言的通用基础结构(GCC家族、Java、.NET、Python、Ruby、Scheme、Haskell、D等)ubuntu
Frontend:前端
Optimizer:优化器
Backend:后端
做为LLVM提供的编译器前端,clang可将用户的源代码(C/C++/Objective-C)编译成语言/目标设备无关的IR(Intermediate Representation)实现。其可提供良好的插件支持,允许用户在编译时,运行额外的自定义动做。
在列出完整步骤以前能够先看个简单例子。看看是如何完成一次编译的。
#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;
}
复制代码
$ xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m -o main-arm64.cpp
复制代码
生成的c++文件以下
int main(){
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
int eight = 8;
int six = 6;
NSString* site = ((NSString * _Nullable (*)(id, SEL, const char * _Nonnull))(void *)objc_msgSend)((id)((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("alloc")), sel_registerName("initWithUTF8String:"), (const char *)"starming");
int rank = eight + six;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_c__8jb7vhc96p1bhvf5gl7zw_9sj925cz_T_main_9c278d_mi_0, site, rank);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
复制代码
$ clang -rewrite-objc mian.m
复制代码
$ clang -ccc-print-phases main.m
复制代码
0: input, "main.m", objective-c
1: preprocessor, {0}, objective-c-cpp-output // 预处理
2: compiler, {1}, ir // 编译生成IR(中间代码)
3: backend, {2}, assembler // 汇编器生成汇编代码
4: assembler, {3}, object // 生成机器码(目标文件)
5: linker, {4}, image // 连接
6: bind-arch, "x86_64", {5}, image // 根据运行平台,生成镜像文件(Image),也就是最后的可执行文件
复制代码
想看清clang前端的所有过程?接下来能够继续经过clang命令查看各阶段都作了哪些处理。
$ clang -E main.m
复制代码
/*
... 头文件
# 1 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/Foundation.framework/Headers/FoundationLegacySwiftCompatibility.h" 1 3
# 185 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.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;
}
复制代码
这个过程的处理包括宏的替换,头文件的导入,以及相似#if的处理。
预处理完成后就会进行词法分析,这里会把代码切成一个个 Token,好比大小括号,等于号还有字符串等。
$ clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m
复制代码
以下例子:
int testAST(int a, int b) {
while (b != 0) {
if (a > b) {
a = a - b;
} else {
b = b - a;
}
}
return a;
}
复制代码
验证语法是否正确,而后将全部节点组成抽象语法树 AST 。
$ clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
复制代码
生成以下语法树:
`-FunctionDecl 0x7ffd8f84d678 <main.m:3:1, line:13:1> line:3:5 test 'int (int, int)'
|-ParmVarDecl 0x7ffd8f84d4f8 <col:10, col:14> col:14 used a 'int'
|-ParmVarDecl 0x7ffd8f84d570 <col:17, col:21> col:21 used b 'int'
`-CompoundStmt 0x7ffd8f84dba8 <col:24, line:13:1>
|-WhileStmt 0x7ffd8f84db30 <line:4:5, line:11:5>
| |-<<<NULL>>>
| |-BinaryOperator 0x7ffd8f84d7d8 <line:4:12, col:17> 'int' '!='
| | |-ImplicitCastExpr 0x7ffd8f84d7c0 <col:12> 'int' <LValueToRValue>
| | | `-DeclRefExpr 0x7ffd8f84d778 <col:12> 'int' lvalue ParmVar 0x7ffd8f84d570 'b' 'int'
| | `-IntegerLiteral 0x7ffd8f84d7a0 <col:17> 'int' 0
| `-CompoundStmt 0x7ffd8f84db10 <col:20, line:11:5>
| `-IfStmt 0x7ffd8f84dad8 <line:6:9, line:10:9>
| |-<<<NULL>>>
| |-<<<NULL>>>
| |-BinaryOperator 0x7ffd8f84d880 <line:6:13, col:17> 'int' '>'
| | |-ImplicitCastExpr 0x7ffd8f84d850 <col:13> 'int' <LValueToRValue>
| | | `-DeclRefExpr 0x7ffd8f84d800 <col:13> 'int' lvalue ParmVar 0x7ffd8f84d4f8 'a' 'int'
| | `-ImplicitCastExpr 0x7ffd8f84d868 <col:17> 'int' <LValueToRValue>
| | `-DeclRefExpr 0x7ffd8f84d828 <col:17> 'int' lvalue ParmVar 0x7ffd8f84d570 'b' 'int'
| |-CompoundStmt 0x7ffd8f84d9a0 <col:20, line:8:9>
| | `-BinaryOperator 0x7ffd8f84d978 <line:7:13, col:21> 'int' '='
| | |-DeclRefExpr 0x7ffd8f84d8a8 <col:13> 'int' lvalue ParmVar 0x7ffd8f84d4f8 'a' 'int'
| | `-BinaryOperator 0x7ffd8f84d950 <col:17, col:21> 'int' '-'
| | |-ImplicitCastExpr 0x7ffd8f84d920 <col:17> 'int' <LValueToRValue>
| | | `-DeclRefExpr 0x7ffd8f84d8d0 <col:17> 'int' lvalue ParmVar 0x7ffd8f84d4f8 'a' 'int'
| | `-ImplicitCastExpr 0x7ffd8f84d938 <col:21> 'int' <LValueToRValue>
| | `-DeclRefExpr 0x7ffd8f84d8f8 <col:21> 'int' lvalue ParmVar 0x7ffd8f84d570 'b' 'int'
| `-CompoundStmt 0x7ffd8f84dab8 <line:8:16, line:10:9>
| `-BinaryOperator 0x7ffd8f84da90 <line:9:13, col:21> 'int' '='
| |-DeclRefExpr 0x7ffd8f84d9c0 <col:13> 'int' lvalue ParmVar 0x7ffd8f84d570 'b' 'int'
| `-BinaryOperator 0x7ffd8f84da68 <col:17, col:21> 'int' '-'
| |-ImplicitCastExpr 0x7ffd8f84da38 <col:17> 'int' <LValueToRValue>
| | `-DeclRefExpr 0x7ffd8f84d9e8 <col:17> 'int' lvalue ParmVar 0x7ffd8f84d570 'b' 'int'
| `-ImplicitCastExpr 0x7ffd8f84da50 <col:21> 'int' <LValueToRValue>
| `-DeclRefExpr 0x7ffd8f84da10 <col:21> 'int' lvalue ParmVar 0x7ffd8f84d4f8 'a' 'int'
`-ReturnStmt 0x7ffd8f84db90 <line:12:5, col:12>
`-ImplicitCastExpr 0x7ffd8f84db78 <col:12> 'int' <LValueToRValue>
`-DeclRefExpr 0x7ffd8f84db50 <col:12> 'int' lvalue ParmVar 0x7ffd8f84d4f8 'a' 'int'
复制代码
$ clang -S -fobjc-arc -emit-llvm main.m -o main.ll
复制代码
到这一步,LLVM前段编译器clang的工做已经基本作完了。
$ clang -S -emit-llvm main.m -o main.ll
复制代码
$ clang -c -emit-llvm main.m -o main.bc
复制代码
In compiler design, static single assignment form (often abbreviated as SSA form or simply SSA) is a property of an intermediate representation (IR), which requires that each variable is assigned exactly once, and every variable is defined before it is used.
– From Wikipedia
从上面的描述能够看出,SSA 形式的 IR 主要特征是每一个变量只赋值一次。相比而言,非SSA形式的IR里一个变量能够赋值屡次。
能够简化不少编译优化方法的过程;
对不少编译优化方法来讲,能够得到更好的优化结果,
下面给出一个例子:
int main() {
int x, y;
x = 1;
x = 2;
y = x;
}
复制代码
y := 1
y := 2
x := y
复制代码
显然,咱们一眼就能够看出,上述代码第一行的赋值行为是多余的,第三行使用的 y 值来自于第二行中的赋值。对于采用非 SSA 形式 IR 的编译器来讲,它须要作数据流分析(具体来讲是到达-定义分析)来肯定选取哪一行的 y 值。可是对于 SSA 形式来讲,就不存在这个问题了。以下所示:
y1 := 1
y2 := 2
x1 := y2
复制代码
咱们不须要作数据流分析就能够知道第三行中使用的y来自于第二行的定义,这个例子很好地说明了SSA的优点。除此以外,还有许多其余的优化算法在采用SSA形式以后优化效果获得了极大提升。甚至,有部分优化算法只能在SSA上作。
优化IR:(级别-03)
clang -O3 -S -fobjc-arc -emit-llvm main.m -o main.ll
复制代码
若是开启了 bitcode 苹果会作进一步的优化,有新的后端架构仍是能够用这份优化过的 bitcode 去生成。
生成字节码:
clang -emit-llvm -c main.m -o main.bc
复制代码
注:xx.bc文件是位流格式,因为是二进制的,因此直接看就是一堆乱码,查看bitcode最好的方式是用hexdump工具。
clang -S -fobjc-arc main.m -o main.s
复制代码
clang -fmodules -c main.m -o main.o
复制代码
clang main.o -o main
执行
./main
输出
starming rank 14
复制代码
1.优先编译cocopods里面的全部依赖文件
个人深圳编译流程:
brew是一个软件包管理工具,相似于centos下的yum或者ubuntu下的apt-get,很是方便,免去了本身手动编译安装的不便
brew 安装目录 /usr/local/Cellar
brew 配置目录 /usr/local/etc
brew 命令目录 /usr/local/bin
注:homebrew在安装完成后自动在/usr/local/bin加个软链接,因此日常都是用这个路径
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
复制代码
CMake是一个跨平台的编译(Build)工具,能够用简单的语句来描述全部平台的编译过程。
$ brew install cmake
复制代码
Ninja 是一个构建系统,与 Make 相似。做为输入,你须要描述将源文件处理为目标文件这一过程所需的命令。 Ninja 使用这些命令保持目标处于最新状态。 Ninja 的主要设计目标是速度。
$ brew install ninja
复制代码
// 大小648.2M
$ git clone https://git.llvm.org/git/llvm.git/
复制代码
// 大小240.6M
$ cd llvm/tools
$ git clone https://git.llvm.org/git/clang.git/
复制代码
$ cd llvm_build
$ cmake -G Ninja ../llvm -DCMAKE_INSTALL_PREFIX=LLVM的安装路径
复制代码
$ ninja
复制代码
编译完毕后, 【llvm_build】目录大概 21.05 G(仅供参考)
$ ninja install
复制代码
安装完毕后,安装目录大概 11.92 G(仅供参考)
$ cd llvm_xcode
$ cmake -G Xcode ../llvm
复制代码
在【llvm/tools/clang/tools】源码目录下新建一个插件目录,假设叫作【yb-plugin】
在【llvm/tools/clang/tools/CMakeLists.txt】最后加入内容: add_clang_subdirectory(yb-plugin),小括号里是插件目录名
# libclang may require clang-tidy in clang-tools-extra.
add_clang_subdirectory(libclang)
add_clang_subdirectory(yb-plugin)
复制代码
add_llvm_loadable_module(YBPlugin YBPlugin.cpp)
复制代码
MJPlugin是插件名,MJPlugin.cpp是源代码文件
生成xcode项目
编写插件
编译插件生成动态库文件
-Xclang -load -Xclang 动态库路径 -Xclang -add-plugin -Xclang 插件名称
复制代码
下载【XcodeHacking.zip】,解压,修改【HackedClang.xcplugin/Contents/Resources/HackedClang.xcspec】的内容,设 置一下本身编译好的clang的路径
![]()
$ sudo mv HackedClang.xcplugin `xcode-select-print- path`/../PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins
$ sudo mv HackedBuildSystem.xcspec `xcode-select-print- path`/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications
复制代码
代码混淆
APP包瘦身
开发新的编程语言