前言
今天是举国同庆的国庆假期的第一天,早上看到庄严的升旗激动坏了,中午都没睡觉,刷着朋友圈看着大家都在玩着,心想要不没事就写点东西吧。有个小伙伴写文章后都会发给我看一下(挑剔的我,开始给挑毛病),还鼓励我继续写技术文档,说实话好久没写了,有点乱,凑合着看吧,欢迎扔砖头。最后祝大家国庆假期快乐,玩的开心哟~~~
很久前学了点关于LLVM的东西,一直没有时间整理,现在抽时间来总结一下,废话不多说,现在开始正经起来。
LLVM
一、简介
1、什么是LLVM
LLVM项目是模块化、可重用的编译器以及工具链技术的集合。曾在2012年获得软件系统奖项。
有些文章把LLVM当做Low Level Virtual Machine(低级虚拟机)的缩写简称,官方描述如下:
The name "LLVM" itself is not an acronym; it is the full name of the project.
“LLVM”这个名称本身不是首字母缩略词,它是项目的全名
2、创始人
Chris Lattner,看到这个名字有没有很熟悉?对了!他就是Swift之父
3、编译器的架构
A、传统的编译器架构
Frontend:前端
词法分析、语法分析、语义分析、生成中间代码
Optimizer:优化器
中间代码优化
Backend:后端
生成机器码
B、LLVM架构
不同的前端后端使用统一的中间代码LLVM Intermediate Representation(LLVM IR)
如果需要支持一种新的变成语言,那么只需要实现一个新的前端
如果需要支持一种新的硬件设备,那么只需要实现一个新的后端
优化阶段是一个通用的阶段,它针对的是统一的LLVM IR,不论是支持新的编程语言,还是只是新的硬件设备都不需要对优化阶段做修改
相比之下,GCC的前端和后端没分的太开,前端后端耦合在一起,所以GCC为了支持一门新的语言或者为了支持一个新的目标平台就变得特别困难
LLVM现在被作为实现各种静态和运行时编译语言的通用基础结构(GCC家族、Java、 .NET、Python、Ruby、Schem、Haskell、D等)
Clang
1、什么是Clang
LLVM项目的一个子项目
基于LLVM架构的C/C++/Objective-C编译器前端
2、相比于GCC,Clang具有的优点有以下几点:
编译速度快:在某些平台上,Clang的编译速度显著的快过GCC(Debug模式下编译OC速度比GCC快3倍)
占用内存小:Clang生成的AST所占用的内存是GCC的五分之一左右
模块化设计:Clang采用基于库的模块化设计,易于IDE集成及其他用途的重用
诊断信息可读性强:在编译过程中,Clang穿件并保留了大量详细的元数据(metadata),有利于调试和错误报告
设计清晰简单,容易理解,易于扩展增强
Clang与LLVM
OC源文件的编译过程
命令行查看编译的过程:
$ clang -ccc-print-phases main.m
查看preprocessor(预处理)的结果:
$ clang -E main.m
词法分析,生成Token:
$ clang -fmodules -E -Xclang -dump-tokens main.m
语法分析,生成语法树(AST,Abstract Syntax Tree):
$ clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
LLVM IR
LLVM IR有3种表示形式:
1、text:便于阅读的文本格式,类似于汇编语言,拓展名 .||
$ clang -S -emit-llvm main.m
2、memory:内存格式
3、bitcode:二进制格式,拓展名 .bc
$ clang -c -emit-llvm main.m
源码下载
1、下载LLVM
$ git clone https://git.llvm.org/git/llvm.git/
2、下载Clang
$ cd llvm/tools
$ git clone https://git.llvm.org/git/clang.git/
源码编译
安装cmake和ninja(先安装brew,https://brew.sh/)
$ brew install cmake
$ brew install ninja
ninja如果安装失败,可以直接从github获取release版放入【/usr/local/bin】中
https://github.com/ninja-build/ninja/releases
在LLVM源码同级目录下新建一个【llvm_build】目录(最终会在【llvm_build】目录下生成【build。ninja】)
$ cd llvm_build
$ cmake -G Ninja ../llvm -DCMAKE_INSTALL_PREFIX=LLVM的安装路径
依次执行编译、安装指令
$ ninja
$ ninja install
也可以生成Xcode项目再进行编译,但是速度很慢(可能需要1个多小时)
在llvm同级目录下新建一个【llvm_xcode】目录
$ cd llvm_xcode
$ cmake -G Xcode ../llvm
Clang插件开发
1 -- 插件目录
在【clang/tools】源码目录下新建一个插件目录,假设叫做【mj-plugin】
在【clang/tools/CMakeLists.txt】最后加入内容: add_clang_subdirectory(mj-plugin),小括号里是插件目录名
2 -- 插件必要文件
在【mj-plugin】目录下新建一个【CMakeLists.txt】,文件内容是:add_llvm_loadable_module(MJPlugin MJPlugin.cpp)
MJPlugin是插件名,MJPlugin.cpp是源代码文件
3 -- 编写插件源码
4 -- 编译插件
利用cmake生成的Xcode项目来编译插件(第一次编写完插件,需要利用cmake重新生成一下Xcode项目)
插件源代码在【Sources/Loadable modules】目录下可以找到,这样就可以直接在Xcode里编写插件代码
选择MJPlugin这个target进行编译,编译完会生成一个动态库文件
5 -- 加载插件
在Xcode项目中指定加载插件动态库:BuildSettings > OTHER_CFLAGS
-Xclang -load -Xclang 动态库路径 -Xclang -add-plugin -Xclang 插件名称
6 -- Hack Xcode
首先要对Xcode进行Hack,才能修改默认的编译器
下载【XcodeHacking.zip】,解压,修改【HackedClang.xcplugin/Contents/Resources/HackedClang.xcspec】的内容,设置一下自己编译好的clang的路径
然后在XcodeHacking目录下进行命令行,将XcodeHacking的内容剪切到Xcode内部
$ 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
7 -- 修改Xcode的编译器
8 -- 编译项目
编译项目后,会在编译日志看到MJPlugin插件的打印信息(如果插件更新了,最好先Clean一下项目)
9 -- 更多
关于AST的资料
https://clang.llvm.org/doxygen/namespaceclang.htmlp
https://clang.llvm.org/doxygen/classclang_1_1Decl.htmlp
https://clang.llvm.org/doxygen/classclang_1_1Stmt.html
10 -- 应用结果
以上就是该阶段的全部内容了,虽然在自己操作的过程中因为电脑内存太小而导致没有全部完成,有点小遗憾,希望阅读该文章的小伙伴们能够成功哟~加油~
感谢MJ大神,欢迎点赞,打赏哟~~~