iOS开发你不知道的事-编译&链接

栏目: 编程语言 · 发布时间: 5年前

内容简介:对于平常的应用程序开发,我们很少需要关注正是因为集成开发环境的强大,很多系统软件的现在我们通过一个C语言的经典例子,来具体了解一下这些机制:

对于平常的应用程序开发,我们很少需要关注 编译链接 过程。我们平常 Xcode 开发就是集成的的开发环境 (IDE) ,这样的IDE一般都将 编译链接 的过程一步完成,通常将这种 编译链接 合并在一起的过程称为 构建 ,即使使用命令行来编译一个源代码文件,简单的一句 gcc hello.c 命令就包含了非常复杂的过程!

正是因为集成开发环境的强大,很多系统软件的 运行机制与机理 被掩盖,其程序的很多莫名其妙的错误让我们无所适从,面对程序运行时种种性能瓶颈我们束手无策。我们看到的是这些问题的现象,但是却很难看清本质,所有这些问题的本质就是 软件运行背后的机理及支撑软件运行的各种平台和工具 ,如果能深入了解这些机制,那么解决这些问题就能够游刃有余。

编译流程分析

现在我们通过一个 C语言 的经典例子,来具体了解一下这些机制:

#include <stdio.h>
int main(){
    printf("Hello World");
    return 0;
}
复制代码

linux 下只需要一个简单的命令(假设源代码文件名为hello.c):

$ gcc hello.c
$ ./a.out
Hello World
复制代码

其实上述过程可以分解为四步:

  • 预处理(Prepressing)
  • 编译(Compilation)
  • 汇编(Assembly)
  • 链接(Linking)
iOS开发你不知道的事-编译&链接

预编译

首先是源代码文件 hello.c 和相关的头文件(如 stdio.h 等)被预编译器 cpp 预编译成一个 .i 文件。第一步预编译的过程相当于如下命令(-E 表示只进行预编译):

$ gcc –E hello.c –o hello.i
复制代码

还可以下面的表达

$ cpp hello.c > hello.i
复制代码

预编译过程主要处理源代码文件中以”#”开头的预编译指令。比如 #include、#define 等,主要处理规则如下:

  • 将所有的 #define 删除,并展开所有的宏定义
  • 处理所有条件预编译指令,比如 #if,#ifdef,#elif,#else,#endif
  • 处理 #include 预编译指令,将被包含的文件插入到该预编译指令的位置。
  • 删除所有的注释 ///**/
  • 添加行号和文件名标识,比如 #2 “hello.c” 2。
  • 保留所有的 #pragma 编译器指令

截图个大家看看效果

iOS开发你不知道的事-编译&链接

经过预编译后的文件 (.i文件) 不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经插入到 .i文件 中,所以当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看预编译后的文件来确定问题。

编译(compliation)

编译过程就是把预处理完的文件进行一系列的: 词法分析语法分析语义分析优化后生产相应的汇编代码文件 ,此过程是整个程序构建的核心部分,也是最复杂的部分之一。其编译过程相当于如下命令:

$ gcc –S hello.i –o hello.s
复制代码
iOS开发你不知道的事-编译&链接
通过上图我们不难得出,通过命令得到汇编输出文件 hello.s

.

汇编(assembly)

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎对应一条机器令。 所以汇编器的汇编过程相对于编译器来讲比较简单,它没复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译就可以了。其汇编过程相当于如下命令:

as hello.s –o hello.o
复制代码

或者

gcc –c hello.s –o hello.o
复制代码

或者使用 gcc 命令从 C源代码文件 开始,经过预编译、编译和汇编直接输出目标文件:

gcc –c hello.c –o hello.o
复制代码

链接(linking)

链接通常是一个让人比较费解的过程,为什么汇编器不直接输出可执行文件而是输出一个目标文件呢?为什么要链接?下面让我们来看看怎么样调用 ld 才可以产生一个能够正常运行的 Hello World 程序:

注意默认情况没有gcc / 记得 :
$ brew install gcc
复制代码

链接相应的库

iOS开发你不知道的事-编译&链接

下面在贴出我们的写出的源代码是如何变成目标代码的流程图:

iOS开发你不知道的事-编译&链接

主要通过我们的编译器做了以下任务: 扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化

到这我们就可以得到以下的文件,不知道你是否有和我一起操作,玩得感觉还是不错,继续往下面看

iOS开发你不知道的事-编译&链接

iOS的编译器

iOS现在为了达到更牛逼的速度和优化效果,采用了 LLVM

LLVM采用三相设计,前端Clang负责解析,验证和诊断输入代码中的错误,然后将解析的代码转换为LLVM IR,后端LLVM编译把IR通过一系列改进代码的分析和优化过程提供,然后被发送到代码生成器以生成本机机器代码。

iOS开发你不知道的事-编译&链接

编译器前端的任务是进行:

  • 语法分析
  • 语义分析
  • 生成中间代码(intermediate representation )

在这个过程中,会进行类型检查,如果发现错误或者警告会标注出来在哪一行。

iOS开发你不知道的事-编译&链接

以上图解内容所做的是事情和 gcc 编译一模模一样样!

iOS程序-详细编译过程

  • 1.写入辅助文件:将项目的文件结构对应表、将要执行的脚本、项目依赖库的文件结构对应表写成文件,方便后面使用;并且创建一个 .app 包,后面编译后的文件都会被放入包中;
  • 2.运行预设脚本: Cocoapods 会预设一些脚本,当然你也可以自己预设一些脚本来运行。这些脚本都在 Build Phases 中可以看到;
  • 3.编译文件:针对每一个文件进行编译,生成可执行文件 Mach-O ,这过程 LLVM 的完整流程,前端、优化器、后端;
  • 4.链接文件:将项目中的多个可执行文件合并成一个文件;
  • 5.拷贝资源文件:将项目中的资源文件拷贝到目标包;
  • 6.编译 storyboard 文件: storyboard 文件也是会被编译的;
  • 7.链接 storyboard 文件:将编译后的 storyboard 文件链接成一个文件;
  • 8.编译 Asset 文件:我们的图片如果使用 Assets.xcassets 来管理图片,那么这些图片将会被编译成机器码,除了 iconlaunchImage
  • 9.运行 Cocoapods 脚本:将在编译项目之前已经编译好的依赖库和相关资源拷贝到包中。
  • 10.生成 .app
  • 11.将 Swift 标准库拷贝到包中
  • 12.对包进行签名
  • 13.完成打包

编译过程的确是个比较复杂的过程,还有链接!并不是说难就不需要掌握,我个人建议每一个进阶路上iOS开发人员,都是要了解一下的。不需要你多么牛逼,但是你能在平时的交流讨论,面试中能点出一个两个相应的点,我相信绝对是逼格满满!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

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

High Performance Python

High Performance Python

Micha Gorelick、Ian Ozsvald / O'Reilly Media / 2014-9-10 / USD 39.99

If you're an experienced Python programmer, High Performance Python will guide you through the various routes of code optimization. You'll learn how to use smarter algorithms and leverage peripheral t......一起来看看 《High Performance Python》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

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

HSV CMYK互换工具