文章目录了解Swift中二进制文件的演变。命令行工具相关。综上所述。在iOS和macOS开发中,Swift包如今变得越来越重要。Apple努力弥合这些差距并解决阻止开发人员将他们的库和依赖项从Carthage[1]或CocoaPods[2]等其他依赖项管理器迁移到Swift包依赖项管理器的问题。无法添加构建步骤等问题。对于任何依赖于某些代码生成的库来说,这都是游戏规则的改变者,例如协议和Swift生成。了解二进制在Swift中的演变为了充分了解Apple的Swift团队在二进制目标方面采取的一些步骤以及他们引入的一些新API,我们需要了解它们的来源。在随后的部分中,我们将研究Apple架构的演变以及二进制对象的API在过去几年中发生演变的原因,尤其是自Apple发布自己的芯片以来。FatBinaries和FrameworksFramework如果您曾经处理过二进制依赖项,或者如果您曾经创建过自己的可执行文件,那么您会熟悉术语fatbinary。这些扩展(或扩大)的可执行文件是为几种不同的体系结构本地构建的切片。这允许库所有者分发在所有预期目标体系结构上运行的单个二进制文件。当无法公开源代码或处理非常大的代码存储库时,将库预编译为可执行文件是有意义的,因为预编译源代码并将它们作为二进制文件分发将节省构建程序在其应用程序上的构建时间。当开发人员发现自己没有必要构建很少更改的依赖项时,Pods[3]就是一个很好的例子。这是一个常见问题,它激发了cocoapods-binary[4]等项目的灵感,它预编译pod依赖项以减少客户端构建时间。框架嵌入静态二进制文件对于应用程序可能就足够了,但是如果需要某些资源(例如资产或头文件),则需要将这些资源与包含所有切片的胖二进制文件捆绑在一起,形成所谓的框架文件。这就是GoogleCast[5]等预编译库在转换为使用xcframework进行分发之前所做的事情——下一节将详细介绍这种转换的原因。到目前为止,一切都很好。如果我们要预编译一个用于分发的库,胖二进制文件听起来很理想,对吧?而且,如果我们需要捆绑一些其他资源,我们可以只使用一个框架。一个二进制来统治他们!XCFrameworks框架嗯,不完全是。胖二进制文件的一个大问题是您不能拥有两个架构相同但命令/指令不同的片。这曾经很好,因为设备和模拟器总是具有不同的架构,但随着AppleSilicon计算机(M1)的推出,模拟器和设备共享相同的架构(arm64),但具有不同的加载程序命令。这与面向未来的二进制目标相结合,就是Apple引入XCFrameworks[6]的原因。在BogoGiertler撰写的这篇精彩文章中,您可以阅读更多关于为iOS设备构建的arm64切片与为适用于M1mac的iOS模拟器构建的arm64切片之间的区别。XCFrameworks[7]现在允许将多个二进制文件捆绑在一起,解决了M1Mac引入的设备和模拟器架构冲突问题,因为我们现在可以为每个用例提供包含相关切片的二进制文件。事实上,如果我们需要,我们可以走得更远,例如,在同一个xcframework中捆绑一个包含iOS目标的UIKit接口的二进制文件和一个包含macOS的AppKit接口的二进制文件,然后让Xcode建立所需的目标体系结构决定使用哪一个。在Swift包中,任何其他可以作为binaryTarget[8]包含在项目中的目标都可以包含在包中。同样的操作也适用于框架。命令行工具相关自从Swift5.6版本引入了Swift包管理器[9]的可扩展构建工具后,就可以在构建过程中的不同时间执行命令。这是iOS社区一直叫嚣已久的东西,比如格式化源代码、代码生成,甚至为度量代码库收集度量。Swift5.6中所有这些所谓的插件[10]最终都需要调用可执行文件来执行特定任务。这是二进制文件再次参与Swift包的地方。在大多数情况下,对于我们的iOS开发人员来说,这些工具将来自不同的架构切片,它们也支持macOS——AppleSilicon的arm64架构和IntelMac的x86_64架构。SwiftLint[11]或SwiftGen[12]等开发工具就是这种情况。在这种情况下,可以使用包含可执行文件(本地或远程)的.zip文件的路径创建一个新的二进制目标。注意可执行文件必须在.zip文件的根目录下,否则找不到。ArtifactBundles目前命令行工具采用的方法只适用于macOS架构。但我们不能忘记,Linux机器也支持Swift包。这意味着如果您想同时支持M1mac(arm64)和Linuxarm64机器,上面的胖二进制方法将不起作用-请记住,一个二进制文件不能包含具有相同架构的多个片。在这个阶段可能会想,我们不能只使用xcframeworks吗?不,因为它们在Linux操作系统上不受支持!Apple已经考虑到这一点,作为Swift5.6的一部分发布,此外还引入了可扩展构建工具[13]、ArtifactBundles[14]和其他对二进制目标的改进。工件包是包含工件的目录。这些工件需要包含受支持架构的所有不同二进制文件。使用位于ArtifactBundle目录根目录中的清单文件(info.json)指定二进制文件和受支持架构的路径。您可以将此清单文件视为地图或指南,以帮助Swift确定哪些可执行文件适用于哪些体系结构以及可以在何处找到它们。以SwiftLint为例SwiftLint[15]作为Swift代码的静态代码分析工具在整个社区被广泛使用。由于很多人都非常渴望在他们的SwiftPM项目中使用这个插件,我认为这将是一个很好的例子来展示我们如何将他们发布页面上的分布式可执行文件转换为兼容macOS架构和Linuxarm64兼容的工件包裹。让我们从下载两个可执行文件(macOS[16]和Linux[17])开始。此时,可以创建捆绑结构。为此,创建一个名为swiftlint.artifactbundle的目录并在其根目录添加一个空的info.json:mkdirswiftlint.artifactbundletouchswiftlint.artifactbundle/info.json现在可以使用schemaVersion填充清单文件,这可能在artifact包和artifacts中的未来版本变化有两个变体,将很快定义:{"schemaVersion":"1.0","artifacts":{"swiftlint":{"version":"0.47.0",#使用的SwiftLint版本"type":"executable","variants":[]},}}最后需要做的是将二进制文件添加到包中,然后将它们作为变体添加到信息中。json文件。让我们首先创建目录并将二进制文件放在那里(一个用于macOS的swiftlint-macos/swiftlint,一个用于Linux的swiftlint-linux/swiftlint)。添加这些后,变量在清单文件中可用:{"schemaVersion":"1.0","artifacts":{"swiftlint":{"version":"0.47.0",#使用的SwiftLint版本"type“:“可执行文件”,“变体”:[{“路径”:“swiftlint-macos/swiftlint”,“supportedTriples”:[“x86_64-apple-macosx”,“arm64-apple-macosx”]},{“路径":"swiftlint-linux/swiftlint","supportedTriples":["x86_64-unknown-linux-gnu"]},]},}}为此,您需要为每个变量指定二进制文件的相对路径(来自工件包目录根目录)和支持的三元组。如果您不熟悉目标三元组[18],它们是一种选择在其上构建二进制文件的体系结构的方法。请注意,这不是主机(构建可执行文件的机器)的体系结构,而是目标机器(应该运行所述可执行文件的机器)。这些三元组具有以下格式:----并非所有字段都是必需的,如果其中一个字段未知并且要使用默认值,则可以将其省略或替换为unknown关键字。可执行文件的体系结构切片可以通过运行文件找到,它将打印捆绑的任何切片的供应商、系统和体系结构。在这种情况下,为这两个命令运行它会显示:swiftlint-macos/swiftlintswiftlint:Mach-Ouniversalbinarywith2architectures:[x86_64:Mach-O64-bitexecutablex86_64][arm64]swiftlint(forarchitecturex86_64):Mach-O64-bitexecutablex86_64swiftlint(forarchitecturearm64):Mach-O64-bitexecutablearm64swiftlint-linux/swiftlint->fileswiftlintswiftlint:ELF64-bitLSBsharedobject,x86-64,version1(SYSV),动态链接,解释器/lib64/ld-linux-x86-64.so.2,用于GNU/Linux3.2.0,带有debug_info,没有被剥离,这带来了上面显示的两个三元组以支持macOS(x86_64-apple-macosx,arm64-apple-macosx)和三重Linux支持(x86_64-unknown-linux-gnu)。与XCFrameworks类似,工件包也可以通过使用binaryTarget包含在Swift包中。结论简而言之,我们可以将2022年如何在Swift包中使用二进制文件的最佳实践总结如下:案例(iOS设备、macOS设备和iOS模拟器)。如果您需要创建一个插件并运行一个可执行文件,您应该将其嵌入为一个工件包,其中包含用于不同支持架构的二进制文件。参考文献[1]迦太基:https://github.com/Carthage/Carthage。[2]CocoaPods:https://github.com/CocoaPods/CocoaPods。[3]Pods:https://cocoapods.org/。[4]cocoapods-binary:https://github.com/leavez/cocoapods-二进制。[5]谷歌:https://developers.google.com/cast/docs/ios_sender#manual_setup。[6]XCFrameworks:https://developer.apple.com/videos/play/wwdc2019/416/。[7]XCFrameworks:https://help.apple.com/xcode/mac/11.4/#/dev6f6ac218b。[8]binaryTarget:https://developer.apple.com/documentation/swift_packages/distributing_binary_frameworks_as_swift_packages。[9]可扩展构建工具:https://github.com/apple/swift-evolution/blob/main/proposals/0303-swiftpm-extensible-build-tools.md。[10]插件:https://github.com/apple/swift-evolution/blob/main/proposals/0303-swiftpm-exte""nsible-build-tools.md#plugin-api。[11]SwiftLint:https://github.com/realm/SwiftLint。[12]SwiftGen:https://github.com/SwiftGen/SwiftGen。[13]可扩展构建工具:https://github.com/apple/swift-evolution/blob/main/proposals/0303-swiftpm-extensible-build-tools.md。[14]ArtifactBundles:https://github.com/apple/swift-evolution/blob/main/proposals/0305-swiftpm-binary-target-improvements.md。[15]SwiftLint:https://github.com/realm/SwiftLint。[16]macOS:https://github.com/realm/SwiftLint/releases/download/0.47.0/portable_swiftlint.zip。[17]Linux:https://github.com/realm/SwiftLint/releases/download/0.47.0/swiftlint_linux.zip。[18]target-triples:https://clang.llvm.org/docs/CrossCompilation.html#target-triples。
