XCode 创建:静态库 && 动态库 && Framework

目录

    • 使用 XCode 创建 .a 格式的静态库
    • 使用 XCode 创建 .framework 格式的静态库
    • 使用 XCode 创建 .dylib 格式的动态库
    • 使用 XCode 创建 .framework 格式的动态库
    • 合并不同 CPU 指令集的库
    • @executable_path、@loader_path、@rpath

使用 XCode 创建 .a 格式的静态库

① 创建静态库调试项目:
新建一个用于调试静态库的 Project(HcgStaticLibraryTest)
XCode 创建:静态库 && 动态库 && Framework_第1张图片
XCode 创建:静态库 && 动态库 && Framework_第2张图片
② 创建静态库:
在 Project(HcgStaticLibraryTest) 中添加一个静态库的 Target(HcgStaticLibrary)
XCode 创建:静态库 && 动态库 && Framework_第3张图片
它会生成以下几样东西:

  1. 一个静态库的 Target(HcgStaticLibrary):在这里面修改静态库的配置,例如:支持的架构、要暴露的头文件、MachO 的相关配置 等
  2. 一个 HcgStaticLibrary 文件夹:为静态库创建的类都放在此文件夹中
  3. 一个 libHcgStaticLibrary.a 文件:在 Products 目录下,Show in Finder 可以找到编译后生成的静态库

XCode 创建:静态库 && 动态库 && Framework_第4张图片
③进行静态库代码的开发:
创建一个类 HcgStaticLibraryLog
并在这个类里面添加一个单纯打印字符串的简单方法 log
然后添加需要公开的头文件 HcgStaticLibraryLog.h
XCode 创建:静态库 && 动态库 && Framework_第5张图片
XCode 创建:静态库 && 动态库 && Framework_第6张图片
XCode 创建:静态库 && 动态库 && Framework_第7张图片
④ 编译生成静态库:
将 Target 切换到 HcgStaticLibrary,检查静态库代码生成的目标架构
并使用 Command + B 进行编译(在这里我们选择真机编译)
然后到 Products 中找到编译生成的静态库,Show in Finder 进行查看(看到 XCode 生成了真机环境对应的静态库,里面包含了我们选择公开的头文件)
XCode 创建:静态库 && 动态库 && Framework_第8张图片
XCode 创建:静态库 && 动态库 && Framework_第9张图片
XCode 创建:静态库 && 动态库 && Framework_第10张图片
⑤ 调试和使用静态库:
将 Target 切换到 HcgStaticLibraryTest,在 Build Phases - Link Binary With Libraries 中添加对静态库的引用
并在 ViewController.m 中导入相应的头文件
然后就可以使用静态库里面的方法了
XCode 创建:静态库 && 动态库 && Framework_第11张图片
XCode 创建:静态库 && 动态库 && Framework_第12张图片
⑥ 打开 .app 文件查找静态库:
找到 Products 文件夹下的 HcgStaticLibraryTest.app 文件,右键显示包内容,并没有看到静态库 libHcgStaticLibrary.a
因为静态库在链接时,会被完整地复制到 App 的 MachO 可执行文件中
XCode 创建:静态库 && 动态库 && Framework_第13张图片

使用 XCode 创建 .framework 格式的静态库

① 创建静态 Framework 调试项目:
新建一个用于调试静态 Framework 的 Project(HcgStaticFrameworkDemo)
XCode 创建:静态库 && 动态库 && Framework_第14张图片
XCode 创建:静态库 && 动态库 && Framework_第15张图片
② 创建静态 Framework:
在 Project(HcgStaticFrameworkDemo) 中添加一个 Framework 的 Target(HcgStaticFramework)
XCode 创建:静态库 && 动态库 && Framework_第16张图片
它会生成以下几样东西(其中 HcgStaticFrameworkTests 是用于对 HcgStaticFramework 进行单元测试的 Target):

  1. 一个 Framework 的 Target(HcgStaticFramework):在这里面修改 Framework 的配置,例如:支持的架构、要暴露的头文件、MachO 的相关配置 等
  2. 一个 HcgStaticFramework 文件夹:为 Framework 创建的类都放在此文件夹中
    HcgStaticFramework 文件夹中默认包含一个 HcgStaticFramework.h 和一个 Info.plist
  3. 一个 HcgStaticFramework .framework 文件:在 Products 目录下,Show in Finder 可以找到编译后生成的 Framework

XCode 创建:静态库 && 动态库 && Framework_第17张图片
因为 Framework 实际上是 Cocoa / Cocoa Touch 程序中使用的一种资源打包的方式,里面存储的既可以是静态库也可以是动态库
又因为 XCode 生成的 Framework 默认是动态库
所以需要到 Build Settings - Linking - MachO Type 中,将 Framework 的类型改为静态库
XCode 创建:静态库 && 动态库 && Framework_第18张图片
③ 进行静态 Framework 代码的开发:
创建一个类 HcgStaticFrameworkLog
并在这个类里面添加一个单纯打印字符串的简单方法 log
然后添加需要公开的头文件 HcgStaticFrameworkLog.h
XCode 创建:静态库 && 动态库 && Framework_第19张图片
XCode 创建:静态库 && 动态库 && Framework_第20张图片
XCode 创建:静态库 && 动态库 && Framework_第21张图片
这里有个细节:
需要在与 Framework 同名的头文件中(在这里是 HcgStaticFramework.h)导入所有需要公开的头文件
否则,使用 Framework 下相应的头文件时,会报 missing module 的警告
XCode 创建:静态库 && 动态库 && Framework_第22张图片
④ 编译生成的静态 Framework:
将 Target 切换到 HcgStaticFramework ,检查静态 Framework 代码生成的目标架构
并使用 Command + B 进行编译(在这里我们选择真机编译)
然后到 Products 中找到编译生成的静态 Framework,Show in Finder 进行查看(看到 XCode 生成了真机环境对应的静态 Framework,里面包含了我们选择公开的头文件)
XCode 创建:静态库 && 动态库 && Framework_第23张图片
XCode 创建:静态库 && 动态库 && Framework_第24张图片
XCode 创建:静态库 && 动态库 && Framework_第25张图片
⑤ 调试和使用静态 Framework:
将 Target 切换到 HcgStaticFrameworkDemo,在 Build Phases - Link Binary With Libraries 中添加对静态 Framework 的引用(XCode 默认会帮我们添加好对于 Framework 的引用)
并在 ViewController.m 中导入相应的头文件
然后就可以使用静态库里面的方法了
XCode 创建:静态库 && 动态库 && Framework_第26张图片
XCode 创建:静态库 && 动态库 && Framework_第27张图片
⑥ 打开 .app 文件查找静态 Framework:
找到 Products 文件夹下的 HcgStaticFrameworkDemo.app 文件,右键显示包内容,可以在 Frameworks 目录下找到 HcgStaticFramework.framework
注意:不管是静态 Farmework 还是动态 Framework,在 Command + B 的时候,都会被拷贝到 .app 文件的 Frameworks 目录里面
XCode 创建:静态库 && 动态库 && Framework_第28张图片

使用 XCode 创建 .dylib 格式的动态库

① 创建动态库调试项目:
新建一个用于调试动态库的 Project(HcgDylibDemo)
XCode 创建:静态库 && 动态库 && Framework_第29张图片
XCode 创建:静态库 && 动态库 && Framework_第30张图片
② 创建动态库:
在 Project(HcgDylibDemo)中添加一个动态库的 Target(HcgDylib)
iOS 下并不存在创建 dylib 动态库的模板
创建 dylib 动态库的模板位于 macOS - Framework & Library 下
从这一点可以看出,苹果不建议开发者在 iOS 项目中使用动态库
XCode 创建:静态库 && 动态库 && Framework_第31张图片
它会生成以下几样东西:

  1. 一个动态库的 Target(HcgDylib):在这里面修改动态库的配置,例如:支持的架构、要暴露的头文件、MachO 的相关配置 等
  2. 一个 HcgDylib 文件夹:为动态库创建的类都放在此文件夹中
  3. 一个 libHcgDylib.dylib 文件:在 Products 目录下,Show in Finder 可以找到编译后生成的动态库

XCode 创建:静态库 && 动态库 && Framework_第32张图片
因为,dylib 动态库默认是给 macOS 平台上的 App 使用的
所以,Target(HcgDylib)里面的相关配置,默认都是 macOS 平台的
为了让动态库(libHcgDylib.dylib)能够在 iOS 平台上使用,需要修改 Target(HcgDylib)里面的一些配置:

  1. 将 Build Settings - Architectures - Base SDK,由 macOS 改为 iOS
  2. 将 Build Settings - Signing - Code Signing Identity,由 Apple Development 改为 iOS Developer(记得选择相应的 Development Team)
  3. 将 Build Settings - Deployment - Installation Directory 改为 @executable_path/HcgFrameworks(一般情况下,动态库都放在 .app 文件的 Frameworks 目录下,这里为了演示,改为 @executable_path/HcgFrameworks 目录)

XCode 创建:静态库 && 动态库 && Framework_第33张图片
XCode 创建:静态库 && 动态库 && Framework_第34张图片
XCode 创建:静态库 && 动态库 && Framework_第35张图片
③ 进行动态库代码的开发:
创建一个类 HcgDylibLog
并在这个类里面添加一个单纯打印字符串的简单方法 log
然后添加需要公开的头文件 HcgDylibLog.h
XCode 创建:静态库 && 动态库 && Framework_第36张图片
XCode 创建:静态库 && 动态库 && Framework_第37张图片
XCode 创建:静态库 && 动态库 && Framework_第38张图片
④ 编译生成的动态库:
将 Target 切换到 HcgDylib,检查动态库代码生成的目标架构
并使用 Command + B 进行编译(在这里我们选择真机编译)
然后到 Products 中找到编译生成的动态库,Show in Finder 进行查看(看到 XCode 生成了真机环境对应的动态库,里面包含了我们选择公开的头文件)
XCode 创建:静态库 && 动态库 && Framework_第39张图片
XCode 创建:静态库 && 动态库 && Framework_第40张图片
XCode 创建:静态库 && 动态库 && Framework_第41张图片
⑤ 调试和使用动态库:
将 Target 切换到 HcgDylibDemo,在 Build Phases - Link Binary With Libraries 中添加对动态库的引用
因为,动态库(libHcgDylib.dylib)在 Target(HcgDylibDemo)进行编译的时候,不会自动拷贝到安装包(HcgDylibDemo.app)中
所以,需要在 Target(HcgDylibDemo)的 Build Phases 中,新建一个 Copy File,使用 Copy File 在编译阶段将动态库(libHcgDylib.dylib)拷贝到 Target(HcgDylibDemo)安装包(HcgDylibDemo.app)中
(这里有个细节需要注意:Copy File 的 SubPath 需要和动态库 Target(HcgDylib) - Build Settings - Deployment - Installation Directory 中设置的目录保持一致,否则 dyld 会无法加载动态库 libHcgDylib.dylib)
XCode 创建:静态库 && 动态库 && Framework_第42张图片
Target(HcgDylibDemo)中引用动态库(libHcgDylib.dylib)的相关配置都设置完毕之后
在 ViewController.m 中导入相应的头文件
然后就可以使用动态库里面的方法了
XCode 创建:静态库 && 动态库 && Framework_第43张图片
⑥ 打开 .app 文件查找动态库:
找到 Products 文件夹下的 HcgDylibDemo.app 文件,右键显示包内容,看到动态库被拷贝到了我们指定的目录下(@executable_path/HcgFrameworks)
XCode 创建:静态库 && 动态库 && Framework_第44张图片

使用 XCode 创建 .framework 格式的动态库

① 创建动态 Framework 调试项目:
新建一个用于调试动态 Framework 的 Project(HcgEmbeddedFrameworkDemo)
XCode 创建:静态库 && 动态库 && Framework_第45张图片
XCode 创建:静态库 && 动态库 && Framework_第46张图片
② 创建动态 Framework:
在 Project(HcgEmbeddedFrameworkDemo)中添加一个 Framework 的 Target(HcgEmbeddedFramework)
XCode 创建:静态库 && 动态库 && Framework_第47张图片
它会生成以下几样东西(其中 HcgEmbeddedFrameworkTests 是用于对 HcgEmbeddedFramework 进行单元测试的 Target):

  1. 一个 Framework 的 Target(HcgEmbeddedFramework):在这里面修改 Framework 的配置,例如:支持的架构、要暴露的头文件、MachO 的相关配置 等
  2. 一个 HcgEmbeddedFramework 文件夹:为 Framework 创建的类都放在此文件夹中
    HcgEmbeddedFramework 文件夹中默认包含一个 HcgEmbeddedFramework.h 和一个 Info.plist
  3. 一个 HcgEmbeddedFramework .framework 文件:在 Products 目录下,Show in Finder 可以找到编译后生成的 Framework

XCode 创建:静态库 && 动态库 && Framework_第48张图片
Framework 实际上是 Cocoa / Cocoa Touch 程序中使用的一种资源打包的方式,里面存储的既可以是静态库也可以是动态库
虽然,XCode 生成的 Framework 默认是动态库
但是,为了严谨,还是到 Build Settings - Linking - MachO Type,检查一下 Framework 的类型
XCode 创建:静态库 && 动态库 && Framework_第49张图片
③ 进行动态 Framework 代码的开发:
创建一个类 HcgEmbeddedFrameworkLog
并在这个类里面添加一个单纯打印字符串的简单方法 log
然后添加需要公开的头文件 HcgEmbeddedFrameworkLog.h
XCode 创建:静态库 && 动态库 && Framework_第50张图片
XCode 创建:静态库 && 动态库 && Framework_第51张图片
XCode 创建:静态库 && 动态库 && Framework_第52张图片
这里有个细节:
需要在与 Framework 同名的头文件中(在这里是 HcgEmbeddedFramework.h)导入所有需要公开的头文件
否则,使用 Framework 下相应的头文件时,会报 missing module 的警告
XCode 创建:静态库 && 动态库 && Framework_第53张图片
④ 编译生成的动态 Framework:
将 Target 切换到 HcgEmbeddedFramework ,检查动态 Framework 代码生成的目标架构
并使用 Command + B 进行编译(在这里我们选择真机编译)
然后到 Products 中找到编译生成的动态 Framework,Show in Finder 进行查看(看到 XCode 生成了真机环境对应的动态 Framework,里面包含了我们选择公开的头文件)
XCode 创建:静态库 && 动态库 && Framework_第54张图片
XCode 创建:静态库 && 动态库 && Framework_第55张图片
XCode 创建:静态库 && 动态库 && Framework_第56张图片
⑤ 调试和使用动态 Framework:
将 Target 切换到 HcgEmbeddedFrameworkDemo,在 Build Phases - Link Binary With Libraries 中添加对动态 Framework 的引用(XCode 默认会帮我们添加好对于 Framework 的引用)
并在 ViewController.m 中导入相应的头文件
然后就可以使用动态库里面的方法了
XCode 创建:静态库 && 动态库 && Framework_第57张图片
XCode 创建:静态库 && 动态库 && Framework_第58张图片
⑥ 打开 .app 文件查找动态 Framework:
找到 Products 文件夹下的 HcgEmbeddedFrameworkDemo.app 文件,右键显示包内容,可以在 Frameworks 目录下找到 HcgEmbeddedFramework.framework
注意:不管是静态 Farmework 还是动态 Framework,在 Command + B 的时候,都会被拷贝到 .app 文件的 Frameworks 目录里面
XCode 创建:静态库 && 动态库 && Framework_第59张图片

合并不同 CPU 指令集的库

  • iOS 设备的 CPU 架构

    // iOS 设备所对应的 CPU 架构
    2013 A7 芯片 arm64 : iPhone 5S
    2014 A8 芯片 arm64 : iPhone 6、iPhone 6 Plus
    2015 A9 芯片 arm64 : iPhone 6S、iPhone 6S Plus 
    2016 A10 芯片 arm64 : iPhone 7、iPhone 7 Plus、iPad (2018)
    2017 A11 芯片 arm64 : iPhone 8、iPhone 8 Plus、iPhone X
    2018 A12 芯片 arm64e : iphone XS、iphone XS Max、iphoneXR
    armv7 : iPhone4|iPhone4S|iPad|iPad2|iPad3(The New iPad)|iPad mini|iPod Touch 3G|iPod Touch4
    armv7s : iPhone5|iPhone5C|iPad4(iPad with Retina Display)
    	
    // 模拟器和真机输出的可执行文件的架构类型
    32 bit 模拟器:Intel i386 
    64 bit 模拟器:Intel x86_64
    32 bit 真机 : armv7 / armv7s
    64 bit 真机 : arm64 / arm64e
    
  • 合并 .a 格式的静态库

    将两个单一平台的静态库:libHcgStaticLibrary_armv7s.a、libHcgStaticLibrary_arm64.a
    合并成一个通用平台的静态库:libHcgStaticLibrary_standard.a
    再配合上头文件,就可以提供给其他人调用
    XCode 创建:静态库 && 动态库 && Framework_第60张图片

    /Users/Airths/Desktop/StaticLibrary
    ~/Desktop/StaticLibrary > lipo -info libHcgStaticLibrary_armv7s.a
    Non-fat file: libHcgStaticLibrary_armv7s.a is architecture: armv7s
    
    ~/Desktop/StaticLibrary > lipo -info libHcgStaticLibrary_arm64.a
    Non-fat file: libHcgStaticLibrary_arm64.a is architecture: arm64
    
    ~/Desktop/StaticLibrary > lipo -create libHcgStaticLibrary_armv7s.a libHcgStaticLibrary_arm64.a -o libHcgStaticLibrary_standard.a
    ~/Desktop/StaticLibrary > lipo -info libHcgStaticLibrary_standard.a
    Architectures in the fat file: libHcgStaticLibrary_standard.a are: armv7s arm64
    
  • 合并 .dylib 格式的动态库

    将两个单一平台的动态库:libHcgDylib_armv7s.dylib、libHcgDylib_arm64.dylib
    合并成一个通用平台的动态库:libHcgDylib_standard.dylib
    再配合上头文件,就可以提供给其他人调用
    XCode 创建:静态库 && 动态库 && Framework_第61张图片

    /Users/Airths/Desktop/dylib
    ~/Desktop/dylib > lipo -info libHcgDylib_armv7s.dylib
    Non-fat file: libHcgDylib_armv7s.dylib is architecture: armv7s
    
    ~/Desktop/dylib > lipo -info libHcgDylib_arm64.dylib
    Non-fat file: libHcgDylib_arm64.dylib is architecture: arm64
    
    ~/Desktop/dylib > lipo -create libHcgDylib_armv7s.dylib libHcgDylib_arm64.dylib -o libHcgDylib_standard.dylib
    ~/Desktop/dylib > lipo -info libHcgDylib_standard.dylib
    Architectures in the fat file: libHcgDylib_standard.dylib are: armv7s arm64
    
  • 合并 .framework 格式的库(静态库或者动态库)

    Framework 实际上是 Cocoa / Cocoa Touch 程序中使用的一种资源打包的方式,可以将二进制代码文件、头文件、资源文件、说明文档等按一定的结构打包在一起,方便管理和分发

    严格意义上讲,Framework 与 库(静态库 .a | 动态库 .dylib)这两个概念不在同一个维度上。Framework 不是库,它只是一种打包方式,它既可以是静态库也可以是动态库

    因此,合并 Framework 格式的库,实际上合并的是 Framework 目录里面的二进制代码文件
    并且,为了符合 Framework 的文件结构,需要将合并完的结果,替换回原来的 Framework 目录中
    XCode 创建:静态库 && 动态库 && Framework_第62张图片

    /Users/Airths/Desktop/dylibFramework
    ~/Desktop/dylibFramework > lipo -info HcgEmbeddedFramework_armv7s
    Non-fat file: HcgEmbeddedFramework_armv7s is architecture: armv7s
    
    ~/Desktop/dylibFramework > lipo -info HcgEmbeddedFramework_arm64
    Non-fat file: HcgEmbeddedFramework_arm64 is architecture: arm64
    
    ~/Desktop/dylibFramework > lipo -create HcgEmbeddedFramework_armv7s HcgEmbeddedFramework_arm64 -o HcgEmbeddedFramework
    ~/Desktop/dylibFramework > lipo -info HcgEmbeddedFramework
    Architectures in the fat file: HcgEmbeddedFramework are: armv7s arm64
    
  • 注意

    ① lipo 命令用于查看、拆分、合并 machO 格式的文件
    .a 格式的静态库、.dylib 格式的动态库、.framework 格式的库(里面的二进制可执行文件)都是 machO 文件

    ② 我们看到:
    支持 i386 和 x86_64 架构的库只能用于模拟器,在真机上调用会报错
    支持 armv7 和 arm64 架构的库只能用于真机,在模拟器上调用会报错
    如果在开发阶段,为了调试方便(模拟器调试 + 真机调试),可以使用 lipo 命令合并模拟器和真机上的同一个库
    即,lipo 命令可以将 i386、x86_64、armv7、armv7s、arm64、arm64e 这些平台的库,合并成一个通用库

@executable_path、@loader_path、@rpath

  • dylib(动态库)的 Buling Settings - Linking - Dynamic Library Install Name

    Dynamic Library Install Name 本质上是一个路径,用于告诉动态链接器在运行时到哪里寻找需要的库

    比如,动态库 libFoo.dylib 的 Dynamic Library Install Name 为(/usr/lib/libFoo.dylib)
    那么 libFoo.dylib 在编译阶段被"链接"到 bar.app 上时, libFoo.dylib 的 Dynamic Library Install Name 会被拷贝到 bar.app 的 MachO 文件里面
    当 bar.app 在运行过程中需要调用 libFoo.dylib 的时候,动态链接器会从 bar.app 的 MachO 文件里面找到 libFoo.dylib 的 Dynamic Library Install Name,并到相应路径下(/usr/lib/libFoo.dylib)寻找和加载 libFoo.dylib 这个库

    这里有个细节需要注意:
    在 XCode 中 dylib(动态库)的 Buling Settings - Linking 下
    Dynamic Library Install Name 被设置为宏 $(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)
    Dynamic Library Install Name Base 被设置为宏 $(INSTALL_PATH)
    
    而 dylib(动态库)的 Buling Settings - Deployment 下
    Installation Directory 即为宏 $(INSTALL_PATH)
    
    这也是为什么,在上面 [使用 XCode 创建 .dylib 格式的动态库] 这一小节中
    可以通过修改 Installation Directory 来修改动态库安装路径的原因
    

    XCode 创建:静态库 && 动态库 && Framework_第63张图片
    dylib(动态库)的安装路径(Installation Directory / Dynamic Library Install Name / Dynamic Library Install Name Base)
    可以通过下列 4 种方式设置:
    ① Absolute paths(绝对路径)
    ② @executable_path
    ③ @loader_path
    ④ @rpath

  • Absolute paths(绝对路径)

    适用于安装在共享目录下的动态库(共享目录的路径是固定的),例如:
    Install path = /Library/Frameworks/Foo.framework/Versions/A/Foo

  • @executable_path

    适用于内置在应用程序包里面的动态库(此时,动态库相对于应用程序可执行文件的位置是固定的)
    @executable_path 将被解析成应用程序可执行文件所在的目录

    路径名称 路径值
    Install path @executable_path/…/Frameworks/Foo.framework/Versions/A/Foo
    Application location /Applications/Foo.app
    Executable path /Applications/Foo.app/Contents/MacOS
    Framework location /Applications/Foo.app/Contents/Frameworks/Foo.framework
    动态链接器根据以上路径信息最终解解析出来的 Install Path /Applications/Foo.app/Contents/MacOS/…/Frameworks/Foo.framework/Versions/A/Foo
  • @loader_path

    适用于内置在 Plug-Ins 里面的动态库(此时,动态库相对于 Plug-Ins 代码的位置是固定的)
    @loader_path 将被解析成调用动态库的可执行文件所在的目录
    因为,Plug-Ins 无法事先知道它将被安装在哪里,也无法知道调用它的程序的位置
    所以,在这种情况下使用 @executable_path 无法达到我们想要的效果

    路径名称 路径值
    Install path @loader_path/…/Frameworks/Foo.framework/Versions/A/Foo
    Application location /Applications/Foo.app
    Plug-in location /Library/Application Support/Foo/Plug-Ins/Bar.bundle
    Executable path /Applications/Foo.app/Contents/MacOS
    Loader path /Library/Application Support/Foo/Plug-Ins/Bar.bundle/Contents/MacOS
    Framework location /Library/Application Support/Foo/Plug-Ins/Bar.bundle/Contents/Frameworks/Foo.framework
    动态链接器根据以上路径信息最终解解析出来的 Install Path /Library/Application Support/Foo/Plug-Ins/Bar.bundle/Contents/MacOS/…/Frameworks/Foo.framework/Versions/A/Foo

    注意:
    如果动态库的调用者不是 Plug-Ins,而是应用程序的可执行文件
    那么,@loader_path == @executable_path

  • @rpath

    我们来理一理:
    ① Absolute paths 适用于安装在共享目录下的动态库,但不适用于内置在应用程序内的动态库
    ② @executable_path 适用于内置在应用程序内的动态库,但不适用于内置在 Plug-Ins 里面的动态库
    ③ @loader_path 适用于内置在 Plug-Ins 里面的动态库,也适用于内置在应用程序里面的动态库
    那么,是不是今后只要把所有的动态库的安装位置(Install path)都设置为 @loader_path 相关的,就一劳永逸了呢?

    我们思考一个问题:
    虽然 @executable_path 和 @loader_path 可以避免动态库的安装位置(Install path)直接使用绝对路径所带来的问题,增加了动态库安装位置(Install path)设置时的灵活性
    但是 @executable_path 和 @loader_path 所带来的灵活性是有限的。因为不论是 @executable_path,还是 @loader_path,都要求动态库相对于可执行文件的位置是固定的(即要求动态库的安装位置相对于可执行文件要有固定的层级结构)

    假设有两个应用,Bar.app 与 Lar.app,使用同一个动态库 libFoo.dylib
    Bar.app 要求动态库安装在 /Applications/Bar.app/Contents/MacOS/Library 下
    Lar.app 要求动态库安装在 /Applications/Lar.app/Contents/Library 下

    此时动态库的安装位置(Install path),无论是使用 @executable_path 或者 @loader_path,都不能同时满足这两个应用的需求,除非重新设置动态库的安装位置(Install path),再打包出一个新的动态库

    造成这个问题的根本原因是:
    动态库的主要作用是在不同的应用程序之间共享代码,以优化整体的性能
    在开发动态库的时候,我们不能确切地知道各个调用者将会如何使用动态库,将会把动态库安装在哪里,动态库安装的目录层次结构是否相同
    因此,在动态库中单方面确定动态库的安装位置(Install path)是不合适的,这在设计上不够灵活

    既然动态库是供不同应用程序调用的,那么动态库的安装位置(Install path)就应该与调用它的每个一应用程序分别商定,并把安装位置(Install path)的商定结果放在调用动态库的应用程序上

    ① @rpath 是一组存放在应用程序中的路径列表,用于告诉动态链接器到哪里寻找动态库(动态库需要以 @rpath 作为其 Install Path 的开头,才会触发动态链接器进行 @rpath 路径检索)。@rpath 的作用类似于系统环境变量 PATH
    ② 当动态库使用 @rpath 作为 Install Path 的时候,调用动态库的应用程序需要到自己的 Build Settings - Linking - Runpath Search Paths 中设置 @rpath 的详细路径列表
    ③ 使用 @rpath 作为 Install Path 的动态库,可以被不同的应用程序所调用,而不用受限于 @executable_path 或 @loader_path(因为不同的应用程序可以设置适合自己的 @rpath)

你可能感兴趣的:(iOS,安全攻防)