ABI 稳定性和更多
在 macOS、iOS、watchOS 和 tvOS 上稳定 Swift 的 ABI 一直以来的长期目标。虽然稳定的 ABI 对于任何语言的成熟度来说都是一个重要的里程碑,但对 Swift 生态系统的最终好处是为应用程序和库启用二进制兼容性。这篇文章描述了二进制兼容性在 Swift 5 中的含义,以及它在 Swift 未来版本中将如何演变。
您可能会问:其他平台呢?ABI 稳定性是为每个编译和运行它的操作系统实现的。Swift 的 ABI 目前声明在 Apple 平台上为 Swift 5 稳定。随着 Swift 在 Linux、Windows 和其他平台上的开发成熟,Swift 核心团队将评估在这些平台上稳定 ABI。
Swift 5 为应用程序提供二进制兼容性:保证未来,使用一个版本的 Swift 编译器构建的应用程序将能够与使用另一个版本构建的库进行通信。即使在使用与旧语言版本的兼容模式时也是如此 (-swift-version 4.2
)。
在这个例子中,使用 Swift 5.0 构建的应用程序将可以在安装了 Swift 5 标准库的系统上运行,也可以在安装了假设的 Swift 5.1 或 Swift 6 的系统上运行。
(当然,本文中 Swift 5.0 之后的所有版本号均为假设)
对于 Apple 操作系统,ABI 稳定性意味着部署到这些操作系统即将发布的版本的应用程序将不再需要在应用程序包中嵌入 Swift 标准库和“overlay”库,从而缩小它们的下载大小;Swift 运行时和标准库将随操作系统一起发布,就像 Objective-C 运行时一样。
有关这如何影响提交到 App Store 的应用程序的更多信息,请参阅 Xcode 10.2 发行说明。
模块稳定性
ABI 稳定性是关于在运行时混合使用 Swift 版本。那么编译时呢?目前,Swift 使用一种名为“swiftmodule”的不透明归档格式来描述库的接口,例如框架“MagicKit”,而不是手动编写的头文件。但是,“swiftmodule”格式也与当前版本的编译器相关联,这意味着如果 MagicKit 是使用不同版本的 Swift 构建的,则应用程序开发人员无法 import MagicKit
。也就是说,应用程序开发人员和库作者必须使用相同版本的编译器。
为了消除这个限制,库作者需要一个目前正在实现的功能,称为模块稳定性。这涉及到用模块的文本摘要来扩充不透明格式,类似于您在 Xcode 的“Generated Interface”视图中看到的内容,以便客户端可以使用模块,而无需关心它是用哪个编译器构建的。您可以在 Swift 论坛上阅读更多相关信息。
例如,您可以使用 Swift 6 构建一个框架,该框架的接口可以被 Swift 6 和未来的 Swift 7 编译器读取。
再次强调,这里的所有 Swift 版本号均为假设。
库演进
到目前为止,我们一直在讨论更改编译器,但保持 Swift 代码不变。那么应用程序正在使用的库的更改呢?今天,当 Swift 库发生更改时,任何使用该库的应用程序都必须重新编译。这有一些优点:因为编译器知道应用程序正在使用的库的确切版本,它可以做出额外的假设,从而减小代码大小并使应用程序运行得更快。但是这些假设对于库的下一个版本可能不再成立。
此功能是库演进支持:发布新版本的库而无需重新编译其客户端。这种情况发生在 Apple 更新操作系统中的库时,但当一家公司的二进制框架依赖于另一家公司的二进制框架时,这也非常重要。在这种情况下,更新第二个框架理想情况下不需要重新编译第一个框架。
在这个例子中,应用程序是针对框架的原始版本(黄色)构建的。通过库演进支持,它将可以在具有黄色版本的系统上运行,也可以在较新的、改进的红色版本上运行。
Swift 已经实现了对库演进的支持,非正式地称为“弹性”。对于需要它的库来说,这是一个可选功能,它使用尚未最终确定的注释来在性能和未来灵活性之间取得平衡,您可以在标准库的源代码中看到这一点。第一个通过 Swift 演进过程的是 @inlinable
,在 Swift 4.2 中添加 (SE-0193)。期待未来出现更多关于库演进支持的提案。
总结
当 Swift 具备… | …那么您可以更改… | 状态 |
---|---|---|
ABI 稳定性 | Swift 标准库 |
macOS、iOS、watchOS 和 tvOS 上的 Swift 5 |
模块 稳定性 (以及 ABI 稳定性) |
编译器 | 正在积极开发中 |
库演进支持 | 您的库的 API | 已基本实现,但需要通过 Swift 演进过程 |