iOS中的静态库和动态库

Posted DCSnail-蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS中的静态库和动态库相关的知识,希望对你有一定的参考价值。

什么是库

是共享程序代码的方式,库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。

库的类型

一般分为静态库动态库
静态库一般是xxx.a的形式,动态库一般在windows下是xxx.dll、在Linux下是xxx.so,在Mac下是系统的动态库是xxx.tbd(以前为.dylib)的形式。

静态库

利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。

动态库

对于静态函数库,动态函数库在编译的时候 并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。

静态库与动态库的区别

静态库:在编译时完整地拷贝至可执行文件中,被多次使⽤就有多份冗余拷贝。

动态库:在编译时不需要拷贝到可执行文件中,程序运行时由系统动态加载到内存,供程序调用。

共同点:静态库和动态库都是闭源库,只能拿来满足某个功能的使用,不会暴露内部具体的代码信息。

静态库和动态库的优缺对比

静态库优点:静态库在编译完成之后,库文件实际上就没有作用了,目标程序没有外部依赖,直接就可以运行。
静态库缺点:静态库需要拷贝至可执行文件中,所以会使用目标程序的体积增大。如果一次性加载的内容过多,会造成App启动慢。

动态库优点:系统只加载一次,就可以使多个程序共用,节省内存。
动态库缺点:动态载入会带来一部分性能损失,使用动态库也会使得程序依赖于外部环境;如果环境缺少动态库或者库的版本不正确,就会导致程序无法运行。

库在ios中的形式

iOS中静态库形式:xxx.axxx.framework
iOS中动态库形式:xxx.tbd(或xxx.dylib)和 xxx.framework

.framework和.a的区别

.a是一个纯二进制文件.framework中除了有二进制文件之外还有资源文件。.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用(.h等资源已经在其内部,图片资源一般再打一个.bundle文件)。

所以 .a + .h + sourceFile = .framework。总之,也建议大家使用.framework的形式。

从源码到可执行文件

先来看看编译过程,为我后面说到的做个铺垫。当我们点击了 build 之后,做了什么事情呢?

1.预处理(Pre-process):把宏替换,删除注释,展开头文件,产生 .i 文件。
2.编译(Compliling):把之前的 .i 文件转换成汇编语言,产生 .s文件。
3.汇编(Asembly):把汇编语言文件转换为机器码文件,产生 .o 文件。
4.链接(Link):对.o文件中的对于其他的库的引用的地方进行引用,生成最后的可执行文件(同时也包括多个 .o 文件进行 link)。

以一个简单的sum文件源代码为例,介绍一下从源码到app的过程。

int sum(int a, int b) 
    return a+b;

首先,先预处理为.i文件,gcc -E sum.c -o sum.i。
再编译为汇编文件, gcc -S sum.i -o sum.s。
再汇编为二进制的.o文件,gcc -c sum.s -o sum.o。
.o文件就是C/C++编译的二进制文件,因为C/C++编译的单元编译。每一个.c/.cpp文件就是一个编译单元,把所有单元都编译好之后,再连接成一个完整的程序。

静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为.a.a文件实质上就是.o文件打了个包。

动态库编译链接时,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。

iOS详细过程

Clang的任务:预处理、词法分析、语法分析、语义分析、静态分析、生成中间代码。

预处理:以#开头的代码预处理。包括引入的头文件和自定义宏。
词法分析:每一个.m源文件的声明和定义从string转化为特殊的标记流。
语法分析:将标记流解析成一颗抽象语法树( abstract syntax tree-AST)。
静态分析:包含类型检查和其他检查。
中间代码生成:生成LLVM代码。
LLVM的任务:将代码进行优化并产生汇编代码。
汇编器:将可读的汇编代码转换为机器代码,最终创建一个目标对象.o文件。
链接器的任务:把目标文件和库相连,最终输出可运行文件:a.out。

Mach-O文件

编译链接的结果应该是a.out文件的,但是有一中Mach-O文件。Mach-O是Mach Object文件格式的缩写,是mac上可执行文件的格式,目标代码,动态库,内核转储的文件格式。类似于windows上的PE格式 (Portable Executable ), linux上的elf格式 (Executable and Linking Format)。

它作为a.out格式的替代,Mach-O提供了更强的扩展性,并提升了符号表中信息的访问速度。在这里Mach-O文件其实就是a.out文件。在制作framework 的时候需要选择Mach-O Type,下面即将说到。

Mach-O Type

framework既可以是静态库又可以是动态库,gcc在编译时默认使用动态库,而且系统的framework也都是默认动态的,而我们创建的framework一般都是静态库。在Xcode中可以配置Mach-O type,为Mach-O文件设置类型,可以决定framework的类型。如下图:

Mach-O文件类型分为以下五个,整好对应上面图片中的五个选项:
Executable:应用的主要二进制。
Dynamic Library:动态链接库。
Static Library:静态链接库。
Bundle:不能被链接的tbd或dylib,只能在运行时使用dlopen()或者NSBundle动态加载,可当做macOS的插件。
Relocatable Object File:可重定向文件类型,即.m.c等文件编译出来的目标文件,文件后缀是.o

设置为Dynamic Library的framework,需要注意一点。自己编译的动态库和系统动态库在本质上是一样的,只是使用方式不一样。自己编译的动态库由于签名校验限制,只能当作静态库一样使用;系统的动态库不受签名校验限制,可以动态加载。

相关文章:
创建你自己的framework
iOS编译与app启动

以上是关于iOS中的静态库和动态库的主要内容,如果未能解决你的问题,请参考以下文章

iOS中的静态库和动态库

[iOS研习记]——谈谈静态库与动态库

静态库介绍与简单演练及同名资源冲突解决

怎么确定静态库和动态库是否带调试符号

动态加载静态库?

iOS 静态库和动态库相关