📈
objective-c
  • 前言
  • 编译原理
    • 编译LLVM
    • 我的第一个Clang插件
    • 自定义LibTooling
    • 自定义属性
    • AST
    • Swift
  • Foundation
    • Number
    • NSString
    • Class
    • Category
    • 琐事
    • 多线程
    • ARC
    • RunLoop
    • 算法
  • Network
  • Animation
  • JavaScriptCore
  • 架构设计
  • 跨平台
    • Flutter
  • UIKit
    • UIView
    • AutoLayout
    • WebView
  • ApplePay
  • In-App Purchase
  • Reveal
  • Xcode
Powered by GitBook
On this page
  • 前言
  • 自己编译LLVM
  • 准备工作
  • 源码编译
  • 安装
  • iOS编译
  • 编译器前端
  • 编译器后端
  • 编译过程
  • 预处理&词法分析
  • 语法分析
  • 中间代码IR
  • 编译优化
  • 生成汇编
  • 生成目标
  • 生成可执行文件
  • 执行

Was this helpful?

编译原理

Previous前言Next编译LLVM

Last updated 5 years ago

Was this helpful?

本文参考

前言

一般可以将编程语言分为两种,和。

像C++,Objective C都是编译语言。编译语言在执行的时候,必须先通过编译器生成机器码,机器码可以直接在CPU上执行,所以执行效率较高。

像JavaScript,Python等都是直译式语言(脚本语言)。直译式语言不需要经过编译的过程,而是在执行的时候通过一个中间的解释器将代码解释为CPU可以执行的代码。所以,较编译语言来说,直译式语言效率低一些,但是编写的更灵活,也就是为啥JS大法好。

iOS开发目前的常用语言是:Objective和Swift。二者都是编译语言,换句话说都是需要编译才能执行的。二者的编译都是依赖于Clang + LLVM. 篇幅限制,本文只关注Objective C,因为原理上大同小异。

可能会有同学想问,我不懂编译的过程,写代码也没问题啊?这点我是不否定的。但是,充分理解了编译的过程,会对你的开发大有帮助。本文的最后,会以以下几个例子,来讲解如何合理利用XCode和编译

  • __attribute__

  • Clang警告处理

  • 预处理

  • 插入编译期脚本

  • 提高项目编译速度

三段式设计

编译主要步骤 1. 源代码(source code) -> 2. 预处理器(preprocessor) -> 3. 编译器(compiler) -> 4. 汇编程序(assembler) -> 5. 目标代码(object code) -> 6. 链接器(Linker) -> 7. 可执行文件(executables)

自己编译LLVM

废话不多说,直接进入正题😍

准备工作

Clang 需要用 CMake 和 Ninja 来编译,可以通过 Homebrew 安装

  • 安装 Homebrew

    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  • 安装 CMake 3.12.4

    brew install cmake
    brew link cmake
  • 安装 Ninja 1.8.2

    brew install ninja

    源码下载

    下载 LLVM (clang 9)

    git clone -b stable git@github.com:llvm-mirror/llvm.git llvm && git checkout -b peregrine ffe57b5e41b4027157dc01e8f9626b2e4be28eae
    #cang 源码需要安装到 llvm/tools 目录下
    git clone -b peregrine git@github.com:BinaryParadise/clang.git llvm/tools/clang

源码编译

在 llvm 同级目录下新建一个 llvm_build 目录,然后选择编译方式

1. 使用 Ninja 编译

mkdir llvm_build && cd llvm_build
cmake -G Ninja ../llvm -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../llvm_release

# 执行编译,完成后llvm_build目录大概 21 GB
ninja
# [可选]执行安装,完成后llvm_release大概 12 GB
ninja install

2. 使用 Xcode 编译

mkdir llvm_xcode && cd llvm_xcode
cmake -G Xcode $MLLVM_HOME -DCMAKE_BUILD_TYPE:STRING=MinSizeRel -DCMAKE_INSTALL_PREFIX=../llvm_release && open LLVM.xcodeproj

选择自动创建schemes,选择targetALL_BUILD,然后开始漫长的编译预计1500s

出现以下错误时,可能是权限导致,加上sudo再次尝试编译

Detecting C compiler ABI info - failed

编译成功后将权限还原到默认

sudo chown -R $(whoami) .

安装

#生成makefile
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release –enable-optimized -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_INSTALL_PREFIX=llvm_release ../llvm

#编译和安装,8表示并发编译数
make -j 8
make install

iOS编译

简单的编译过程如图

编译器前端

编译器前端的任务是进行:语法分析,语义分析,生成中间代码(intermediate representation )。在这个过程中,会进行类型检查,如果发现错误或者警告会标注出来在哪一行。

编译器后端

编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化。iOS的编译过程,后端的处理如下

  • LVVM优化器会进行BitCode的生成,链接期优化等等。

  • LLVM机器码生成器会针对不同的架构,比如arm64等生成不同的机器码。

编译过程

  • 编译信息写入辅助文件,创建文件架构 .app 文件

  • 处理文件打包信息

  • 执行 CocoaPod 编译前脚本,checkPods Manifest.lock

  • 编译.m文件,使用 CompileC 和 clang 命令

  • 链接需要的 Framework

  • 编译 xib

  • 拷贝 xib ,资源文件

  • 编译 ImageAssets

  • 处理 info.plist

  • 执行 CocoaPod 脚本

  • 拷贝标准库

  • 创建 .app 文件和签名

预处理&词法分析

  • 替换宏定义

  • 头文件的导入

  • 编译条件

  • 把代码细拆分成最小的Token(包含代码位置),如大小括号,

    等于号还有字符串等

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

语法分析

  • 验证语法是否正确

  • 将所有节点生成AST

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

中间代码IR

  • CodeGen 会负责将AST自上而下递归遍历翻译成 LLVM IR

  • IR 是编译过程的前端输出,后端的输入

clang -fmodules -S -fobjc-arc -emit-llvm main.m -o main.ll

编译优化

  • LLMV在编译时会做些优化,Xcode编译设置中可设置级别

  • 开启Bitcode会进一步优化

  • Pass 是LLVM优化的一个节点,可以自定义

clang -emit-llvm -c main.m -o main.bc

生成汇编

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

对于不想看我啰里八嗦讲一大堆原理的同学,可以直接跳到本文的最后一个章节。

Objective C采用Clang(swift采用)作为编译器前端,LLVM(Low level vritual machine)作为编译器后端。

iOS编译过程的原理和应用
iOS底层探索(二) - 写给小白看的Clang编译过程原理
编写我的第一个 Clang 插件:检测 ObjC 中的类声明规范
LLVM & Clang 入门
编译语言
直译式语言
swift
LLVM源码编译