如何将动态Swift框架添加到命令行工具

让我们逐步介绍如何尝试向命令行工具中添加动态框架,并讨论每步操作中出了什么问题。

步骤1:将其添加到“链接的框架和库”部分

这是您运行应用程序时发生的情况:

  dyld:库未加载:@ rpath / libswiftAppKit.dylib 
  引用自:/Users/seanberry/Library/Developer/Xcode/DerivedData/TestCommandLineTool-fnrmhjvjmugvqueaqvbklzwhqvuv/Build/Products/Debug/ThirdParty.framework/Versions/A/ThirdParty 
  原因:找不到图片 

ThirdParty.framework尝试在@rpath目录中找到libswiftAppKit.dylib (它是Swift标准库的一部分)。

我们可以看到ThirdParty.framework如何通过运行来定义@rpath

  $ oTool -l ThirdParty.framework / Versions / Current / ThirdParty 
 加载命令27 
指令LC_RPATH
cmdsize 48
路径@executable_path /../ Frameworks(偏移量12)
 加载命令28 
指令LC_RPATH
cmdsize 40
路径@ loader_path / Frameworks(偏移量12)

好吧,开枪。 这些与我们的命令行工具无关。 我们没有任何名为/ Frameworks或../Frameworks的文件夹。 为什么要在其中寻找Swift标准库?

因为它是为iOS和Mac应用程序构建的。 这是Mac应用程序中的目录结构:

那解释了path @executable_path/../Frameworks

对于iOS,应用程序内部的目录结构为:

这说明了path @loader_path/Frameworks (offset 12)

但是,谦虚的命令行工具开发人员呢? Swift标准库在我们的可执行文件中静态链接,但是我们的第三方框架找不到它们。 不幸的是,它们并没有存储在每台Mac上的标准位置。 开发人员可以访问埋在Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx (但请不要要求用户安装Xcode)。

那么我们该怎么办? 我见过的标准做法是为您的项目创建一个自定义框架,将所有依赖项导入其中,然后也复制快速的标准库。

步骤2:创建自定义框架并复制标准Swift库

完善! 现在,让我们继续运行命令行工具…

  objc [2335]:类别_TtC8Dispatch16DispatchWorkItem在/Users/seanberry/Library/Developer/Xcode/DerivedData/TestCommandLineTool-fnrmhjvjmugvqueaqvbklzwhqvuv/Build/Products/Debug/FirstParty.framework/Diss/10pWys/libs/libs/libs中和/ Users / seanberry / Library / Developer / Xcode / DerivedData / TestCommandLineTool-fnrmhjvjmugvqueaqvbklzwhqvuv / Build / Products / Debug / TestCommandLineTool(0x1005c7698)。  将使用两者之一。  哪一个未定义。 
  以20种不同方式重复上述错误 

您的应用程序现在可以看到两个不同的Swift标准库副本:在可执行文件中静态链接的副本和在/ Frameworks文件夹中的静态链接。

从这里有两种解决方案。

步骤3(选项A):改用Mac应用并提取可执行文件

我调查了著名的命令行工具Carthage和SwiftLint,以了解它们如何处理此问题。 原来他们没有设置为命令行工具! 他们是Mac应用! 为什么? 因为Mac应用程序不是静态链接标准库。 他们通过添加一个从应用程序包中提取可执行文件的运行阶段,将自己部署为命令行工具。

  #!/ bin / bash 
##从其应用程序包中提取迦太基CLI工具。 打算运行
#作为Xcode运行脚本构建阶段的一部分。
  cp -v“ $ {BUILT_PRODUCTS_DIR} / $ {EXECUTABLE_PATH}”“” $ {BUILT_PRODUCTS_DIR} / $ {EXECUTABLE_NAME}“ 

您可以继续这样做,没问题。 但是我找到了解决此问题的另一种方法。

步骤3(选项B):禁用静态链接

将它们添加到用户定义的构建设置中:

  SWIFT_FORCE_DYNAMIC_LINK_STDLIB是 
SWIFT_FORCE_STATIC_LINK_STDLIB否

这将强制您的可执行文件动态链接所有库。 通过将框架目录添加到“ Runpath搜索路径”,确保告诉Xcode在哪里找到它们。

@executable_path/FirstParty.framework/Versions/Current/Frameworks

祝您使用命令行工具好运!

肖恩试图让Xcode在 Livefront 上编译