就我而言,iOS开发的过程中接触到的编译链接方面的知识很少,这部分知识还是很重要的。
对于iOS的编译链接过程来说并不难,和微机原理的汇编过程还是挺像的。今天对于编译链接的过程学习和了解一下。
参考:iOS程序员的自我修养-编译、链接过程
参考:iOS编译过程
计算机语言有机器语言,汇编语言和高级语言。对于OC这种高级语言来说分为 编译语言和解释型语言。
php,javascript
等在iOS的编译和链接过程中,不同的文件后缀名代表不同的文件类型和中间过程。
.i
文件:.i
文件是预处理器处理源代码之后生成的文件,其中包含了宏展开、条件编译等预处理操作后的代码。
.s
文件:.s
文件是汇编器生成的汇编代码文件。它将预处理器生成的 .i
文件翻译成机器指令的文本表示形式,每个汇编指令对应一条机器指令。
.o
文件:.o
文件是编译器生成的目标文件,也被称为对象文件。它包含了汇编器生成的机器指令以及一些符号表、重定位信息和其他调试信息。
.m
文件:.m
文件是 Objective-C 源代码文件的常见扩展名。它包含了 Objective-C 的代码,可以与 C 和 C++ 代码混合使用。
这些文件在编译和链接过程中的不同阶段产生,并在整个过程中相互转换和传递,最终生成可执行文件或库文件。
上面说过OC/swift都是编译语言,在执行的时候通过编译器生成机器码,机器码可以直接在CPU上执行,效率更快。
OC的编译是基于Clang/ LLVM来编译的,简单了解LLVM是一个模块化的可重用的编译器和工具技术的集合,Clang是LLVM的子程序,C,C++,OC都是Clang的子程序。其目的就是更快的效率编译出更好的程序。
编译链接过程:预处理 -> 词法分析 -> 语法分析 -> 静态分析 -> 生成中间代码和优化 -> 汇编 -> 链接 =
预处理 -> 编译 -> 汇编 -> 链接
1,预处理:macro 宏, import 头文件替换及处理其他的预编译指令,产生.i文件
。(都是以#号开头)
2,编译:把预处理完的一系列文件进行一系列词法、语法、语义分析,并且优化后生成相应的汇编代码,产生.s文件
;
3,汇编:汇编器将汇编代码生成机器指令,输出目标文件,产生.o文件
(根据汇编指令和机器指令的对照表一一翻译就可以了);
4,链接:在一个文件中可能会到其他文件,因此,还需要将编译生成的目标文件和系统提供的文件组合到一起,这个过程就是链接。经过链接,最后生成可执行文件
。
经过编译和链接,才会把写的代码转换成计算机能识别的二进制指令。
clang -E main.m -o main.i
处理源代码文件中的以"#"开头的预编译指令
#if/#ifdef/#else/#endif。
"#include/#import"
包含的文件递归插入到此处。如“# 1 "main.m"”
,编译调试会用到。总结编译器在预处理阶段处理结果:
(#include,#import)
使用对应文件.h的内容替换这一行的内容,所以尽量减少头文件中的#import,使用@class替代,把#import放到.m文件中。)(#if,#else,#endif)
clang -S main.i -o main.s
编译过程也分为 词法分析 -> 语法分析 -> 静态分析 最后优化生成相应的汇编代码,得到.s文件
NSObject*
对象发送了一个 hello
消息,那么 clang 就会报错,同样,给属性设置一个与其自身类型不相符的对象,编译器会给出一个可能使用不正确的警告。clang -c main.s -o main.o
在这一阶段,汇编器将上一步生成的可读的汇编代码转化为机器代码。最终产物就是 以 .o 结尾的目标文件。使用Xcode构建的程序会在DerivedData目录中找到这个文件。
clang main.o -o main
这一阶段是将上个阶段生成的目标文件和引用的静态库链接起来,最终生成可执行文件,链接器解决了目标文件和库之间的链接。
使用clang main.m生成可执行文件a.out(不指定名字默认为a.out),使用file a.out
可以看到其类型信息:
a.out: Mach-O 64-bit executable x86_64
可以看出可执行文件类型为 Mach-O
类型,在 MAC OS 和 iOS 平台的可执行文件都是这种类型。
Mach-O(Apple官方文档)
编译链接是一iOS文件从开始到变成可执行的文件的过程,我们不去研究原理,但是对于整个流程的掌握还是很有必要的。