美文网首页iOS底层
iOS 动态库(一)

iOS 动态库(一)

作者: 木扬音 | 来源:发表于2021-07-15 00:41 被阅读0次

动态库是编译器链接的最终产物,系统的动态库是直接存放在手机里面的,一般为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.hTestExample.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中保存@rpathload 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

image.png

导出符号

  • 如果我们需要在可执行文件中使用动态库1链接的动态库2方法
    我们需要将动态库2的符号导出,导出后会在动态库1中增加一个LC_REEXPORT_DYLIB
  • 通过-Xlinker -reexport_framework方法导出符号
-Xlinker -reexport_framework -Xlinker framework2
image.png

相关文章

网友评论

    本文标题:iOS 动态库(一)

    本文链接:https://www.haomeiwen.com/subject/mdkupltx.html