假期学习--iOS 编译链接
iOS 编译链接
编译流程
四步:
1.预处理
2.编译
3.汇编
4.链接
大概的步骤如下:
预处理
作为编译的第一步,将.m文件转换为.i文件 ;
预处理是要处理源代码中所有以#开头的所有预编译指令 ;
规则如下:
#define
删除,并展开对应的宏定义。- 处理所有的条件预编译指令。如
#if
、#ifdef
、#else
、#endif
。 #include
&#import
包含的文件递归插入到此处(含#处)。- 删除所有的注释 //、/**/等。
- 添加行号和文件名标识。如 # 1 “main.m"(编译调试会用到)。
编译
将.i文件转成.s文件 ;
这个过程中会进行词法分析,语法分析,静态分析,优化生成相应的汇编代码 ,最终生成.s文件 ;
- 词法分析:把源代码的字符序列分割成一个个
token
(关键字、表示符、字面量、特殊符号),比如把标识符放到符号表里面。 - 语法分析: 生成抽象语法树AST,此时运算符号的优先级确定了;有些符号具有多重含义也确定了,比如:*是乘号还是对指针取内容;
表达式不合法
、括号不匹配
等等,都会报错。 - 静态分析:分析
类型声明
和匹配问题
。比如整型和字符串相加,肯定会报错。 - 中间语法生成:
CodeGen
根据AST(抽象语法树)
自上向下逐步翻译成LLVM IR
,并且对在编译期就可以确定的表达式进行优化,比如代码里面的a=1+3,可以优化成a=4。(假如开启了bitcode) - 目标代码生成与优化: 根据中间语法生成依赖具体机器的汇编语言;并优化汇编语言。这个过程中,假如有变量且定义在同一个编译单元里,那么就给这个变量分配空间,确定变量的地址。假如变量或者函数不定义在这个编译单元里面,那就等到链接的时候才能确定地址。
汇编
将.s转换为.o文件 ;
这个过程就是把.s文件中的汇编指令转换为机器指令,生成.o文件 ;
链接
将.o文件转换为Mach-o文件,也就是我们常说的可执行文件 ;
链接就是把一个或多个目标文件和需要的库(静态库和动态库)组合成一个Mach-o文件 ;(所以我们也说Mach-o文件是.o文件的集合) ;
静态库和动态库
静态库
在链接阶段,会将汇编生成的.o文件和所需要的库一起链接打包到Mach-o文件中,这种对应的链接方式被称为静态链接 ;
静态库的特点
- 静态库对函数库的链接是放在编译时期完成的。
- 程序在运行时与函数库再无瓜葛,移植方便。
- 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
动态库
动态库在编译流程中不会被链接,而是在运行时才被载入 ;
不同的应用程序如果调用相同的库,只需要一份共享的库 ,关于库的更新也只需要更新动态库就行了 ;既规避了空间浪费的问题 ,也解决了静态库对程序的更新、部署和发布页会带来麻烦。
动态库的特点
- 动态库把对一些库函数的链接载入推迟到程序运行的时期。
- 可以实现进程之间的资源共享。(因此动态库也称为共享库)将一些程序升级变得简单。
- 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。
静态库和动态库的区别
1.链接方式的不同:静态库是在编译时将库的代码打包到可执行程序中,因此生成的可执行程序包含了所有用到的库函数的代码。动态库则是在运行时动态加载到程序中的,因此生成的可执行文件并不包含库函数的实现代码,而只是引用了动态库的接口。
2.内存使用方式不同:由于静态库的代码被打包进了可执行程序中,所以在程序运行时,静态库中的代码被复制到了程序使用的内存中;而动态库的代码在程序运行时才会被加载到内存中,因此动态库的代码实现被复制进内存,会占用额外的内存空间。但是与静态库相比,动态库的内存使用方式具有更好的空间和性能优势,因为多个程序可以共享同一个动态库,而不需要重复加载相同的库文件,从而减少了系统的内存占用。
3.更新和维护的方式不同:静态库的代码被打包成可执行程序的一部分,因此静态库的更新和维护需要重新进行编译和部署,才能让所有使用了该静态库的程序都能够得到更新的代码。动态库可以独立于程序进行更新,因为动态库作为一个单独的文件存在于系统中,可以被多个程序共享。因此,当需要更新动态库时,只需要替换掉旧的动态库文件,不需要重新编译和部署所有使用了该动态库的程序。