带你了解静态库原理

iOS 中常用的库文件格式 有 .a .dylib .framework .xcframework,今天我们来探索一下 .a文件,也就是静态库。

.a文件

查看.a文件信息

首先我们先看下 .a文件是什么,我们来查看 AFNetWorking里面的.a信息。

bel@beldeMacBook-Pro AFNetworking % file libAFNetworking.a
libAFNetworking.a: current ar archive

我们可以看到它其实是一个文档格式
man ar: 查看 ar 的含义

NAME
     ar -- create and maintain library archives
SYNOPSIS
     ar -d [-TLsv] archive file ...
     ar -m [-TLsv] archive file ...
     ar -m [-abiTLsv] position archive file ...
     ar -p [-TLsv] archive [file ...]
     ar -q [-cTLsv] archive file ...
     ar -r [-cuTLsv] archive file ...
     ar -r [-abciuTLsv] position archive file ...
     ar -t [-TLsv] archive [file ...]
     ar -x [-ouTLsv] archive [file ...]     

我们可以看到 ar 可以创建并修改归档文件
拆分为.o 文件
我们将.a文件拆开

bel@beldeMacBook-Pro AFNetworking % ar -t libAFNetworking.a 
__.SYMDEF
AFAutoPurgingImageCache.o
AFHTTPSessionManager.o
AFImageDownloader.o
AFNetworkActivityIndicatorManager.o
AFNetworking-dummy.o
AFNetworkReachabilityManager.o
AFSecurityPolicy.o
AFURLRequestSerialization.o
AFURLResponseSerialization.o
AFURLSessionManager.o
UIActivityIndicatorView+AFNetworking.o
UIButton+AFNetworking.o
UIImageView+AFNetworking.o
UIProgressView+AFNetworking.o
UIRefreshControl+AFNetworking.o
WKWebView+AFNetworking.o

从这一点我们可以看出,.a文件是.o文件的合集。
链接静态库
我们新建一个文件夹,将AFNetWorking导入,并新建一个test.m文件


image.png

在test.m中,我们添加如下代码

#import <Foundation/Foundation.h>
#import <AFNetworking.h>

int main(){
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    NSLog(@"testApp----%@", manager);
    return 0;
}

生成目标文件

我们将 test.m编译为 .o文件。

clang -x objective-c \
-target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-I ./AFNetworking \
-c test.m -o test.o

ps;iOS开发交流技术群:欢迎你的加入,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长

-x: 指定语言类型。
-target: 指定架构。
-fobjc-arc: ARC环境。
-isysroot: 编译的SDK路径。
-I :指定头文件位置, 对应Xcode中的 header search path。
-c xxx.m -o xxx.o: 将.m文件编译为 .o 文件。

这样我们就将 test.m编译为了test.o文件。


image.png

链接目标文件生成可执行文件
我们在编译的时候已经指明了语言,在链接的时候就不用指定语言了

clang -target x86_64-apple-macos11.1 \

-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk \
-L./AFNetworking \
-lAFNetworking \  
test.o -o test

-L< dir > : 指定库文件路径(.a.dylib库文件),对应Xcode中的Library search Path
-l< libarayr_name>:指定链接的库文件名称(.a.dylib库文件)。对应Xcode中的 other link flags

-L,-l的查找规则为先找 lib + < library_name>的动态库,找不到,再去找 lib+< library_name>的静态库 还找不到,就报错。
链接的过程就是将重定位表中的符号进行重定位,用来绑定真实的符号地址。链接文件的三要素为1,库文件的头文件位置。2,库文件路径。3,库文件名称。

ps;iOS开发交流技术群:欢迎你的加入,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长

静态库原理

我们新建一个 StaticLibrary文件


image.png

并新建TestExample文件,在.m 文件中,我们只是简单输出一段字符

@implementation TestExample

- (void)test:(_Nullable id)e {
    NSLog(@"TestExample----");
}
@end

1,将 TestExample.m 文件编译为.o 文件

clang -x objective-c \                         
-target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-c TestExample.m -o TestExample.o

2,我们将 TestExample.o的名字修改为 TestExample.dylib,最后,将 .dylib去掉


image.png

我们使用 file 命令来查看当前文件

file libTestExample.dylib
libTestExample.dylib: Mach-O 64-bit object x86_64

即使我们将名字改掉了,其本身还是一个目标文件。
现在我们使用 test.m 文件去链接 libTestExample看它是否能够正常运行,如果能正常运行,我们就从侧面验证了 静态库文件是.o文件的合集。
ps;iOS开发交流技术群:欢迎你的加入,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长

我们将test.m 编译为 test.o文件

clang -x objective-c \
-target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-I./StaticLibrary \
> -c test.m -o test.o

3,用 test.o 链接 libTestExample

clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
-L./StaticLibrary \
-lTestExample \    
test.o -o test

链接成功之后
image.png

4,运行 test可执行文件,在终端中 输入 lldb进入lldb环境

image.png

5,在lldb中运行

(lldb) file test
Current executable set to '/Users/bel/Desktop/静态库原理/test' (x86_64).
(lldb) r 
Process 99621 launched: '/Users/bel/Desktop/静态库原理/test' (x86_64)
2021-03-06 23:37:58.265213+0800 test[99621:13587736] testApp----
2021-03-06 23:37:58.265760+0800 test[99621:13587736] TestExample----
Process 99621 exited with status = 0 (0x00000000) 
(lldb) 

我们的可执行文件可以正常运行

这说明我们的静态库文件链接成功了,就说明了静态库是.o文件的合集。

静态库合并

我们前面讲到,静态库就是.o文件的合集,我们可以把多个静态库的.o文件合并到一起,对静态库进行合并,接下来,我们将 libAFNetworking.a和libSDWebImage.a两个静态库进行合并。

image.png

我们先来查看下 libtool命令的含义

man libtool
NAME
       libtool - create libraries
       ranlib - add or update the table of contents of archive libraries

该命令用来创建库文件或者更新一系列的静态库文件

libtool \
-static \
-o \
> libAll.a \
> ./libAFNetworking.a \
> ./libSDWebImage.a  

这样就完成了静态库的.o 文件的合并。

静态库与Framework
.framework 对于静态库文件来说就是.a文件加headers的集合,我们按照.framework的样式,添加如下文件。


image.png

我们先将 test.m 编译为目标文件

clang -x objective-c -target x86_64-apple-macos11.1 -fobjc-arc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -I./Frameworks/TestFramework.framework/Headers -c test.m -o test.o

然后对framework进行链接

 clang -target x86_64-apple-macos11.1 -fobjc-arc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -F./Frameworks -framework TestExample test.o -o test

-F< directory>: 在指定目录寻找framework。
-framework < framework_name> 指定链接的framework名称

附录
本文使用的Clang指令汇总

 clang命令参数:
     -x: 指定编译文件语言类型
     -g: 生成调试信息
     -c: 生成目标文件,只运行preprocess,compile,assemble,不链接
     -o: 输出文件
     -isysroot: 使用的SDK路径
     1. -I<directory> 在指定目录寻找头文件 header search path
     2. -L<dir> 指定库文件路径(.a\.dylib库文件) library search path
     3. -l<library_name> 指定链接的库文件名称(.a\.dylib库文件)other link flags -lAFNetworking
     -F<directory> 在指定目录寻找framework framework search path
     -framework <framework_name> 指定链接的framework名称 other link flags -framework AFNetworking

lldb相关指令

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。