美文网首页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