动态库和静态库

什么是库

  • 库的本质是一段编译好的二进制代码,加上头文件就可以供别人使用。
  • 库从广义上可分为开源库和闭源库, 而闭源库才分为静态库和动态库
    • 开源库:对外公开源代码, 能看到具体的代码实现, 例如Github上面的第三方开源库都称之为开源库
    • 闭源库:不公开源代码, 文件是经过编译后的二进制文件, 看不到具体实现

为什么要用库

  • 保护代码:某些代码需要给别人使用,但是我们不希望别人看到源码,就需要以库的形式进行封装,只暴露出头文件
  • 提高编译速度:对于某些不会进行大的改动的代码,我们想减少编译的时间,就可以把它打包成库,因为库是已经编译好的二进制了,编译的时候只需要 Link 一下,不会浪费编译时间

静态库和动态库

上面提到库在使用的时候需要 Link,Link 的方式有两种,静态和动态,于是便产生了静态库和动态库

静态库

静态库即静态链接库(Windows 下的 .lib,Linux 和 Mac 下的 .a)

之所以叫做静态,是因为静态库在编译的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了

所以如果两个程序都用了某个静态库,那么每个二进制可执行文件里面其实都含有这份静态库的代码

优点是编译完成之后,目标程序不再依赖库文件,直接就可以运行

缺点是会使用目标程序的体积增大

动态库

动态库即动态链接库(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib/.tbd)

与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来

优点是,不会影响目标程序的体积(不需要拷贝到目标程序中),而且同一份库可以被多个程序共享使用;同时,编译时才载入的特性,也可以让我们随时对库进行替换,而不需要重新编译代码

缺点是,动态载入会带来一部分性能损失,使用动态库也会使得程序依赖于外部环境。如果环境缺少动态库或者库的版本不正确,就会导致程序无法运行(Linux 下喜闻乐见的 lib not found 错误)

Framework

什么是 Framework

Framework 是Cocoa/Cocoa Touch程序中使用的一种资源打包方式,可以将代码文件(.a)、头文件、资源文件、说明文档等集中在一起,方便开发者使用

系统的 Framework 是动态库,开发者自己开发的 Framework 是静态库

其实是资源打包的方式,和静态库动态库的本质是没有关系的

苹果在iOS平台上规定不允许存在动态库,但是为了 App 和 Extension 能够共享代码,提出了 Embedded Framework

.a与.framework的区别

  • .a是一个纯二进制文件不能直接使用,必须要有.h文件才能使用,.h文件对外提供接口
  • .framework中除了有二进制文件之外还有资源文件,可以直接使用
    所以开发中建议使用.framework

.a、.dylib 和 .tbd

.a:静态库的后缀名
.dylib:动态库的后缀名
.tbd:text-based stub libraries,本质上就是一个YAML描述的文本文件。iOS 7 之后取代 .dylib。具体请看这里

动态 Framework 和静态 Framework

使用 file 命令可以判断 .framework 中的可执行文件是动态还是静态

1
2
3
4
5
6
file GPUImage.framework/GPUImage
GPUImage.framework/GPUImage: Mach-O universal binary with 4 architectures: [i386:Mach-O dynamically linked shared library i386] [arm64]
GPUImage.framework/GPUImage (for architecture i386): Mach-O dynamically linked shared library i386
GPUImage.framework/GPUImage (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
GPUImage.framework/GPUImage (for architecture armv7): Mach-O dynamically linked shared library arm_v7
GPUImage.framework/GPUImage (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64
1
2
3
4
5
file TVKPlayer.framework/TVKPlayer
TVKPlayer.framework/TVKPlayer: Mach-O universal binary with 3 architectures: [arm_v7:current ar archive] [arm64]
TVKPlayer.framework/TVKPlayer (for architecture armv7): current ar archive
TVKPlayer.framework/TVKPlayer (for architecture x86_64): current ar archive
TVKPlayer.framework/TVKPlayer (for architecture arm64): current ar archive

可以看到 GPUImage 有 dynamic,它是动态 framework,而 TVKPlayer 是静态的

如果是动态的 Framework,添加到工程的时候需要在 Embedded Binaries 下面手动添加,意思是嵌入,并不是嵌入 app 可执行文件,而是嵌入 app 的 bundle 文件。当一个 app 通过 Embedded 的方式嵌入一个 app 后,在打包之后解压 ipa 可以在包内看到一个 framework 的文件夹,下面都是与这个应用相关的动态 framework

如果是静态的 Framework,添加到工程的时候需要在 Linked Frameworks and Libraries 添加,这些 Framework 将会被拷贝到 App 的可执行文件中

架构

1
2
3
// 1. 模拟器使用的CPU架构: 
i386: iPhone4s - iPhone5
x86_64: iPhone5s - iPhoneX
1
2
3
4
5
6
// 2. 真机使用的CPU架构: 
armv6: iPhone、iPhone 2、iPhone 3G、iPod Touch
armv7: iPhone3Gs - iPhone4s
armv7s: iPhone5、iPhone5c
arm64: iPhone5s - iPhoneX
(没有armv64)

命令

查看 .a 支持的架构

lipo -info xxx.a

合并成通用架构

lipo -create 模拟器架构.a 真机架构.a -output 目标通用架构.a

参考

iOS - 静态库、动态库、Framework
组件化-动态库实战

    1. 什么是库
    2. 为什么要用库
  1. 静态库和动态库
    1. 静态库
    2. 动态库
  2. Framework
    1. 什么是 Framework
    2. .a与.framework的区别
    3. .a、.dylib 和 .tbd
    4. 动态 Framework 和静态 Framework
    5. 架构
    6. 命令
      1. 查看 .a 支持的架构
      2. 合并成通用架构
  3. 参考