clang -E main.m -o main.i clang -S main.i -o main.s 这个过程就是把上面的main.i文件进行:词法分析、语法分析、静态分析,优化生成相应的汇编代码,最终生成main.s文件。
clang -c main.s -o main.o 将main.s文件编译成main.o文件。(也就是我们常说的目标文件)
这个过程就是把上面得到的main.s文件里面的汇编指令翻译成机器指令,最终生成等到main.o。
clang main.o -o main 这个过程就是将main.o编译成对应的Mach-O文件,也就是我们常说的可执行文件。链接的本质就是把一个或多个目标文件和需要的库(静态库/动态库,如果需要的话)组合成一个文件(Mach-O可执行文件)。
静态库是静态链接库;是多个目标文件经过压缩打包后形成的文件包。这些目标文件在编译时被链接到应用程序中。静态库通常以 .a(Unix、Linux)或 .lib(Windows)以及MacOS 独有的 .framework为扩展名。
在编译阶段,静态库的代码被直接链接到生成的可执行文件中。这个过程将库的代码和应用程序的代码合并成一个单一的可执行文件。
由于静态库的代码被嵌入到可执行文件中,生成的可执行文件在运行时不依赖于外部的库文件。这意味着可以在没有静态库的环境中运行该应用程序。
如果静态库被更新,需要重新编译和链接应用程序,以确保应用程序包含最新的库代码。
动态库是动态链接库,是实现共享函数库的一种方式。动态库在编译的时候不会被拷贝到目标程序中,目标程序只会存储下动态库的引用。
真正用到动态库内的函数时才会去查找 - 绑定 - 使用函数。
动态库的格式有:.framework、.dylib、.tbd……
动态库的代码在运行时被加载到内存中,应用程序通过链接器解析符号,并在需要时调用库中的代码。
多个应用程序可以共享同一个动态库的实例,减少内存占用。
动态库可以在应用程序启动时加载,也可以在运行过程中按需加载,提供更灵活的加载方式。
众所周知,framework其实是一种文件的打包方式,把头文件、二进制文件、资源文件封装在一起,方便管理和分发。所以动态库和静态库的文件格式都会有.framework。那么我们手头上有个framework,如何区分它的类型呢?
方法:命令行进入动态库文件,使用file命令查看输出内容可以看到区别。以静态库文件-MAMapKit.framework与动态库文件-AFNetworking.framework为例。
-MAMapKit.frameworkcd /Users/***/Desktop/Framework/MAMapKit.framework file MAMapKit 输出
MAMapKit: Mach-O universal binary with 4 architectures: [arm_v7:current ar archive random library] [arm64] MAMapKit (for architecture armv7): current ar archive random library MAMapKit (for architecture i386): current ar archive random library MAMapKit (for architecture x86_64): current ar archive random library MAMapKit (for architecture arm64): current ar archive random library archive表明这是一个静态库
-AFNetworking.frameworkcd /Users/***/Desktop/Framework/AFNetworking.framework file AFNetworking 输出
AFNetworking: Mach-O universal binary with 2 architectures: [arm_v7:Mach-O dynamically linked shared library arm_v7] [arm64:Mach-O 64-bit dynamically linked shared library arm64] AFNetworking (for architecture armv7): Mach-O dynamically linked shared library arm_v7 AFNetworking (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64 dynamically linked shared library表明这是一个动态库
静态库
动态库
注:
体积小于最小单位16k的静态库编译出来的动态库体积会等于16k。
换成动态库会导致⼀些速度变低,但是会通过延迟绑定(Lazy Binding)技术优化。
延迟绑定:首次使用的时候查找并记录方法的内存地址,后续调用就可以省略查找流程。

动态库的链接过程不同于静态库,它在编译时并不会被包含到可执行文件中,而是在运行时由操作系统的动态链接器加载。
当主程序运行时,动态链接器(如 macOS 上的 dyld,Linux 上的 ld.so,Windows 上的 LoadLibrary)会将动态库加载到一个随机的内存地址(使用地址空间布局随机化,ASLR),以提高安全性。
dyld(the dynamic link editor)是苹果的动态链接器,是苹果操作系统一个重要组成部分,在系统内核 XNU 完成 Mach-O 文件的加载,做好程序准备工作之后,交由 dyld 负责余下的工作。在 macOS 系统中,dyld 位于 D/usr/lib/dyld。
支持更多的架构及平台
通过多种方式提高了安全性
提升性能
执行流程:

dyld 3是全新的动态链接器,它完全改变了动态链接概念。dyld 3 完全兼容 dyld 2,API 接口是一样的,所以在大部分情况下,开发者不需要做额外的适配就能平滑过渡。
执行流程
dyld 3 包含这三个部分:
进程外 Mach-O 分析器和编译器 (out-of-process mach-o parser)
由于 dyld 2 存在的问题,dyld 3 中将采用提前写入把结果数据缓存成文件的方式构成一个 lauch closure(可以理解为缓存文件)
进程内引擎 执行 launch closure 处理 (in-process engine)
验证”lauch closures“是否正确,映射dylib,执行main函数。此时,它不再需要分析mach-o header和执行符号查找,节省了不少时间。
launch closure 缓存服务 (launch closure cache )
系统程序的 lauch closure 直接内置在 shared cache 中,而对于第三方APP,将在APP安装或更新时生成,这样就能保证 launch closure 总是在 APP 打开之前准备好。
大多数程序启动会使用缓存,而不需要调用进程外 mach-o分析器或编译器;并且 launch closure 比 Mach-O 更简单,它们是内存映射文件,不需要用复杂的方法进行分析,我们可以简单地验证它们,其作用是为了提高速度