Wacro(WebAssembly Macros)是使用 WebAssembly 构建 Swift 宏提案的一个概念验证实现,该提案已提交给 GSoC 2024(提案链接)。
截至目前,Wacro 已经允许库作者使用 WebAssembly 构建宏,并且用户可以像使用其他 Swift 库一样使用它们:请参阅试用部分了解详情。 但是,目前存在一些性能缺陷,这些缺陷可以通过在编译器/SwiftPM 中实现来解决。
Wacro 不是 GSoC 提交项目:它的存在仅仅是为了表明这是可能的(甚至无需修改编译器或 SwiftPM!),因为 GSoC 提案进展缓慢。一个实际的实现应该集成到编译器和 SwiftPM 中,以提高可用性和性能。
🐇 目前的 Swift 宏在编译时速度非常慢。 这是因为大多数宏依赖于源代码形式的 swift-syntax
(Swift 的语法解析库),而它是一个非常大的库,需要很长时间才能构建。
🤝 SwiftPM 当前只允许链接到软件包的单个版本。 因此,如果两个宏依赖于冲突的 swift-syntax 版本,SwiftPM 将拒绝构建。
🔐 Swift 宏旨在“纯粹”,并且不能访问系统资源。 目前,这在 macOS 上通过系统沙箱实现。 但是,据我所知,宏在 Linux 上没有被沙盒化; 虽然可以使用 命名空间 在某种程度上弥补这一点,但这可能需要相当大的努力,而且命名空间被广泛认为不是安全边界。
Wacro 将宏分解为两个阶段
.executableTarget
而不是 .macro
,并且 2)它依赖于 WacroPluginRaw
而不是 SwiftCompilerPlugin
。 该二进制文件被检入源代码控制(理想情况下,可以指向远程资源,但这可能需要 SwiftPM 的支持。).macro
目标,其中宏实现了 WacroPluginHost
。 此一致性的唯一要求是 providingLibrary: URL
,它指向原始宏的文件路径。当宿主宏被调用时,WacroPluginHost
启动一个 WebAssembly “运行器”,该运行器与原始宏通信以执行实际工作。
借助 Swift 6.0,对 WASM 和 WASI 的支持现在已经上游化。 这意味着给定 WASI SDK,一个普通的 Swift 6.0 工具链可以开箱即用地构建 WASI 二进制文件。
Wacro 目前提供两种执行 WebAssembly 二进制文件的方法
WKWebView
的 WebAssembly 支持来及时评估宏。--disable-sandbox
,因为 WKWebView 使用 XPC。WasmKit 目前是默认的运行器,因为它是跨平台的并且可以在沙箱中运行。 切换到 WebKit 的说明在以下部分中。
理想的运行器可能是这两者的混合。 在 macOS 上,将 WebKit 运行器移动到 Swift Driver 中将允许它在不禁用宏沙箱的情况下使用。 同时,WasmKit 可以在系统不提供 WebKit 的其他平台上使用。
请参阅 WacroExample 存储库。 您可以克隆它并运行 ExampleClient
,或者在任何项目中使用 ExampleLibrary
作为依赖项! 请注意,现在可能会出现一些意想不到的性能问题,但如果它进入 Swift 编译器,这些问题将得到补救。 有关详细信息,请参阅以下部分
注意:本节是关于构建时间性能的。 运行时性能将与典型的宏相同。 WebAssembly 执行过程仅在构建时进行。
make clean
开始干净的构建。 wasm 二进制文件本身被保留下来,因为我们关注的是客户端而不是宏作者的性能。time make client [RELEASE=1] [WK=1]
执行 WasmKit/WebKit 构建。WacroExample/Package.swift
以将 ExampleClient
直接链接到 ExampleRaw
来执行 SwiftSyntax 构建。所有值均以秒为单位。
类型 | WasmKit | WebKit | SwiftSyntax |
---|---|---|---|
干净 (debug) | 33.8 | 19.2 | 29.0 |
干净 (release) | 32.0 | 18.4 | 183.2 |
增量 (debug) | 9.8 | 1.3 | 0.6 |
增量 (release) | 1.1 | 1.5 | 0.8 |
是的,你没看错。 基于 WasmKit 的宏在发布模式下构建更快,因为 WasmKit 本身是用优化编译的,因此可以更快地解释 wasm 宏。 理想情况下,与 SwiftPM 的更深入集成将确保 WasmKit 本身始终在发布模式下构建。