6 个版本

0.2.3 2020 年 10 月 14 日
0.2.2 2020 年 9 月 14 日
0.2.1 2020 年 7 月 21 日
0.1.1 2020 年 5 月 24 日

#wasm-file 中排名 20

每月下载次数 25

MIT 许可证 MIT

82KB
859

cargo watt

Watt 是一个用于执行编译为 WebAssembly 的 Rust 过程宏的运行时。

我假设你熟悉 watt,dtolnay 用于在 WebAssembly 解释器中执行过程宏的 crate。

在那里,工具改进被列为 待完成的工作,而这个 cargo 子命令旨在实现这一点。其目的是

  1. 编译现有过程宏 crate 以供 watt 运行时使用,无需手动干预
  2. 验证 wasm 文件是否从特定的源编译而来

使用 cargo watt 编译的一些流行过程宏列表可在 此处 获取。

先决条件

要使用 cargo watt,你需要安装 rustc 的 wasm32 工具链

$ rustup target add wasm32-unknown-unknown

此外,为了优化 wasm 文件的大小,将使用 wasm-strip (wabt) 和 wasm-opt (binaryen)。要排除优化,请使用 --no-wasm-opt--no-wasm-strip

构建过程宏 crate (cargo watt build)

首先通过复制一个crate(可以是本地目录、Git仓库或crates.io上的crate)到/tmp来构建工作。然后,将crate类型更改为cdylib,将proc-macro2修复为dtolnay的proc_macro2。接下来,将其中所有的过程宏替换为pub #[no_mangle] extern "C"函数和将proc_macro替换为proc_macro2,请参见这里

目前,简单的crate已经可以编译,但还需要做更多工作以支持更广泛的crate。因为我们只是更改了一些签名并寄希望于最好的结果,有时一些东西会停止工作。为了“修复”这个问题(尽管这更像是一种黑客行为),我们执行以下操作

  • syn替换为这个syn补丁,该补丁基本上将所有实例的proc_macro替换为proc_macro2(请参见这里)并删除了对wasm32-unknown-unknown的条件编译
  • proc_macro进行字面搜索和替换为proc_macro2。这听起来可能有些愚蠢,但在我测试中这效果不错。

当然,一些crate仍然无法编译,在这种情况下,你需要自己调整一些东西。值得注意的是,任何依赖于synstructureproc_macro_error的东西都不会工作,也许将来会提供这些补丁。

最后,生成一个shim crate,它调用生成的WebAssembly文件并执行标记树转换。

作为用户,你所需要做的就是

$ cargo watt build --crate serde-derive
  INFO  cargo_watt > download crate 'serde-derive' into temporary directory...
  INFO  cargo_watt > begin compiling crate...
     Updating git repository `https://github.com/dtolnay/watt`
     Updating git repository `https://github.com/jakobhellermann/syn-watt`
     Updating crates.io index
    Compiling syn v1.0.22 (https://github.com/jakobhellermann/syn-watt#0f0ace5e)
    Compiling serde_derive v1.0.110 (/tmp/cargo-watt-crate)
     Finished release [optimized] target(s) in 19.65s
  INFO  cargo_watt > finished in 19.65s
  INFO  cargo_watt > compiled wasm file is 2.65mb large
  INFO  cargo_watt > generated crate in "serde_derive-watt"

或者,你可以获取一个Git仓库(cargo watt build --git https://github.com/idanarye/rust-typed-builder)或使用本地路径(cargo watt build ./path/to/crate)。

默认情况下,cargo watt将包括原始crate的所有文件(即测试、文档等)在新生成的crate中。如果您只想有Cargo.tomlsrc/lib.rssrc/the-macro.wasm,可以使用--only-copy-essential选项。

注意事项

一些过程宏crate需要导出实际宏之外的其他东西,因此它们被分割成一个常规的Rust crate,导出一些Trait/函数,然后从这个crate中重新导出宏。

这就是为什么例如 cargo watt --crate thiserror 会告诉你 thiserror 不是一个 proc macro crate 的原因。相反,你需要运行 cargo watt --crate thiserror-impl[patch] thiserror-impl 到你的生成的 crate 中。

此外,如果 Cargo.lock 文件中指定的 syn 版本比 我修补的版本 更新,这将导致编译错误。在大多数情况下,更新就像在上游上重新分叉分支一样简单,但应该有一些自动化处理,但目前还没有。

验证编译(cargo watt verify

在 WebAssembly 中运行宏的隔离属性确保它无法无限制地访问文件或网络,但它生成的代码仍然可能是有害的。因此,能够验证编译的二进制 wasm 文件确实是由某个源编译的非常重要,这样就可以手动进行审计。

就像构建子命令一样,cargo watt verify 与本地项目、远程 git 仓库和 crates.io 的 crate 一起工作,你可以这样使用

$ cargo watt build --crate serde-derive
 ...
$ cargo watt verify serde-derive_watt/src/serde-derive.wasm --crate serde-derive
 INFO  cargo_watt::wasm > finished in 17.3s
 Success!

然而,目前 Linux 上编译的 crate 将与 macOS 上的不同如果你知道这是为什么以及如何修复它,请告诉我。


安装

$ cargo install cargo-watt

性能

这会对编译时间产生多大的影响?

我对以下依赖项的 crate 进行了分析

tokio = { version = "0.2", features = ["macros"] }
thiserror = "1.0"

[patch.crates-io]
tokio-macros = { git = "https://github.com/jakobhellermann/watt-contrib" }
thiserror-impl = { git = "https://github.com/jakobhellermann/watt-contrib" }

没有修补

Profile without watt

有修补

Profile with watt

这是一个 6 秒与 17 秒的差距,所以还不错。当然,在真实的项目中,你会有更多非宏的 crate,因此加速效果不那么明显,但仍然更快。


LICENSE

MIT © Jakob Hellermann

依赖项

~9–21MB
~323K SLoC