动态库
是编译器链接的最终产物
,系统的动态库是直接存放在手机里面的,一般为tbd
格式,tbd文件里面存放了系统动态库具体的位置,通过install_name
找到了这个动态库的位置,然后启动时候dyld
就知道去哪里加载这个系统动态库。
而我们自己生成的动态库,是需要签名的。在审核中苹果不仅需要你动态库和app的签名一致
,而且苹果会在你上架的时候再经过一次AppStore的签名
,防止插件化在线更新动态库
什么是tdb格式
-tdb
全称text-based stub libraries
,本质上就是一个YAML描述文本文件
-作用是用于记录动态库的一些信息,包括导出符号
、动态库的架构信息
、动态库依赖信息
等
- 避免在真机开发中直接使用传统动态库,减少包大小
准备工作
- 新建
test.m
#import <Foundation/Foundation.h>
#import <AFNetworking.h>
int main(){
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSLog(@"testApp----%@", manager);
return 0;
}
- 同一目录下,加入
AFNetworking
动态库
image.png
链接动态库
我们按照链接静态库的方式来尝试链接动态库
-
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.3.sdk \
-I./AFNetworking \
-c test.m -o test.o
-
test.o
-->test
可执行文件
clang -x objective-c \
-target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \
-L./AFNetworking \
-lAFNetworking
-c test.o -o test
- 执行
test
会报一个dyld: Library not loaded:
、image not found
的错误
image.png
手动生成动态库并链接
- 新建
TestExample.h
、TestExample.m
#import <Foundation/Foundation.h>
@interface TestExample : NSObject
- (void)lg_test:(_Nullable id)e;
@end
#import "TestExample.h"
@implementation TestExample
- (void)lg_test:(_Nullable id)e {
NSLog(@"TestExample----");
}
@end
- 新建
test.m
#import <Foundation/Foundation.h>
#import "TestExample.h"
int main(){
NSLog(@"testApp----");
TestExample *manager = [TestExample new];
[manager lg_test: nil];
return 0;
}
-
按照图中目录结构排放
image.png
-
test.m
文件编译成test.o
-
TestExample.m
编译成TestExample.o
-
TestExample.o
编译成TestExample.a
libtool -static -arch_only x86_64 TestExample.o -o libTestExample.a
-
libTestExample.a
编译成libTestExample.dylib
ld -dylib -arch x86_64 \
-macosx_version_min 11.1 \
-syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \
-lsystem -framework Foundation \
-all_load \ //导出所有符号
libTestExample.a -o libTestExample.dylib
-
test.o
链接libTestExample.dylib
生成可执行文件test
clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \
-L./dylib \
-lTestExample \
test.o -o test
- 执行
test
,发现还是报同样错误
image.png
脚本
echo "编译test.m --- test.o"
clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \
-I./dylib \
-c test.m -o test.o
pushd ./dylib
echo "编译TestExample.m --- TestExample.o"
clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \
-c TestExample.m -o TestExample.o
echo "编译TestExample.o --- libTestExample.a"
# Xcode->静态库
libtool -static -arch_only x86_64 TestExample.o -o libTestExample.a
echo "编译TestExample.m --- libTestExample.dylib"
# -dynamiclib: 动态库
# dylib 最终链接产物 -》
ld -dylib -arch x86_64 \
-macosx_version_min 11.1 \
-syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \
-lsystem -framework Foundation \
-all_load \
libTestExample.a -o libTestExample.dylib
popd
echo "链接libTestExample.dylib -- test EXEC"
clang -target x86_64-apple-macos11.1 \
-fobjc-arc \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk \
-L./dylib \
-lTestExample \
test.o -o test
动态路径
-
动态库的
load Command
路径是保存在自己的mach-o文件中 -
可以通过下面命令查找路径
//TestExample 动态库
otool -l TestExample | grep 'DYLIB' -A 5
image.png
- 通过
install_name_tool -id
添加绝对路径到动态库中
install_name_tool -id /Users/yangyangpeng/Downloads/动态库原理/dylib/TestExample TestExample
image.png
@rpath
可执行文件会在自己的mach-o
中保存@rpath
在load command
,运行时dyld
会根据@rpath
路径查找动态库,保存一个或多个路径变量
- 下图中
test
链接了TestExample.framework
,所有如果需要通过install_name_tool
修改路径,那就是install_name_tool -id @rpath/Frameworks/TestExample.framework/TestExample
image.png
- 可执行文件的
@rpath
可以通过install_name_tool
命令修改
install_name_tool -add_rpath <路径> <可执行文件>
@executable_path
- 表示
可执行程序
所在的目录,解析为可执行文件的绝对路径
@loader_path
- 表示被加载的
Mach-O
所在的目录,每次加载时,都可能被设置为不同的路径,由上层指定
动态库链接动态库
当一个可执行文件链接了一个动态库,然后动态库又链接了一个动态库,我们可以使用@loader_path
导出符号
- 如果我们需要在可执行文件中使用动态库1链接的动态库2方法
我们需要将动态库2的符号导出,导出后会在动态库1中增加一个LC_REEXPORT_DYLIB
- 通过
-Xlinker -reexport_framework
方法导出符号
-Xlinker -reexport_framework -Xlinker framework2
image.png
网友评论