21 个版本 (13 个重大更新)

新版本 0.15.0 2024年7月31日
0.13.2 2024年6月1日
0.10.1 2024年3月13日
0.6.0 2023年12月22日
0.1.0 2021年12月2日

#41 in Cargo 插件

Download history 8169/week @ 2024-04-16 6434/week @ 2024-04-23 2162/week @ 2024-04-30 2732/week @ 2024-05-07 716/week @ 2024-05-14 772/week @ 2024-05-21 974/week @ 2024-05-28 871/week @ 2024-06-04 649/week @ 2024-06-11 812/week @ 2024-06-18 1173/week @ 2024-06-25 1020/week @ 2024-07-02 1775/week @ 2024-07-09 1582/week @ 2024-07-16 2256/week @ 2024-07-23 1431/week @ 2024-07-30

每月下载量 7,230
3 个包中使用 (通过 golem-wasm-rpc-stubgen)

Apache-2.0 WITH LLVM-exception

315KB
7K SLoC

cargocomponent

一个 Bytecode Alliance 项目

Cargo 子命令,用于根据 组件模型建议 构建 WebAssembly 组件。

build status Crates.io version Download docs.rs docs

概述

cargo component 是一个 cargo 子命令,用于使用 Rust 作为组件实现语言来创建 WebAssembly 组件

注意

cargo component 被视为实验性的,并且就其支持的代码构建而言目前是不稳定的。

在组件模型稳定之前,升级到较新的 cargo component 可能会导致现有组件项目出现构建错误。

要求

  1. cargo component 子命令是用 Rust 编写的,因此您需要安装 最新的稳定版 Rust
  2. cargo component 在Linux上需要一个有效的OpenSSL安装。请参阅安装说明这里
  3. cargo component 还需要一个有效的C工具链。请确保您的环境中有一个有效的 cc 命令(或等效命令)。

安装

要从源代码安装 cargo component 子命令,请运行以下命令

cargo install cargo-component --locked

如果您已安装 cargo-binstall 工具,则可以通过预构建发布工件安装 cargo component,从而节省安装时间

cargo binstall cargo-component

动机

今天,针对WebAssembly的开发者通常会将用单一源语言编写的单体程序编译成WebAssembly模块。WebAssembly模块可以用于各种地方:从网络浏览器到云计算平台。WebAssembly有意设计为提供此类环境所需的可移植性和安全性属性。

然而,WebAssembly模块不容易与其他模块组合成单个程序或服务。WebAssembly只有少数几种原始值类型(整数和浮点类型),这些类型不足以描述开发者希望在模块间交换的复杂类型。

更具有挑战性的是,WebAssembly模块通常定义自己的本地线性内存,这意味着一个模块无法访问另一个模块的(概念上的)地址空间。必须在两个模块之间放置某些内容,以便在传递指针时促进通信。

虽然可以通过现有的WebAssembly标准解决这些挑战,但这样做既费力又容易出错,并且需要事先了解WebAssembly模块的实现方式。

WebAssembly组件模型

WebAssembly组件模型提案提供了一种通过使用各种源语言的可重复使用功能组件来简化构建WebAssembly应用程序和服务的流程,同时仍保持WebAssembly的可移植性和安全性属性。

在最基本层面上,WebAssembly组件可以用来封装WebAssembly模块,以描述其接口的转换方式,该接口是一组使用复杂数值类型的函数(例如字符串、变体、记录、列表等),以及这些函数如何转换为WebAssembly模块所需的底层表示形式。

这使得WebAssembly运行时可以知道如何具体地促进组件离散线性内存之间的数据交换,从而消除开发者手动执行此操作的需要。

此外,组件可以以模块目前无法做到的方式描述其依赖项;它们甚至可以控制依赖项的实例化方式,使组件能够虚拟化依赖项所需的功能。由于不同的组件可能具有共享的依赖项,因此宿主甚至可以共享该依赖项的同一实现,以节省宿主内存使用。

Cargo组件

cargo component 的一个主要目标是尝试想象Rust对WebAssembly组件的一级支持可能是什么样的。

这意味着能够通过 Cargo.toml 引用WebAssembly组件,并以与Rust crate依赖项相同的方式使用WebAssembly组件依赖项

  • 将WebAssembly组件依赖项添加到 Cargo.toml
  • 就像引用外部crate(通过 bindings::<name>::...)一样,在您的源代码中引用它
  • 使用 cargo component build 构建,您的组件就会出现!

为了能够在任何特定的编程语言中使用WebAssembly组件,必须创建绑定,将WebAssembly组件的接口转换为特定编程语言可以理解的表达。

wit-bindgen 这样的工具存在,用于为不同的语言生成这些绑定,包括Rust。

wit-bindgen 还提供了过程宏,可以生成与组件源代码“内联”的绑定。

wit-bindgen 不同,cargo component 直接在项目的 src/bindings.rs 中生成绑定,这样绑定是根据从 Cargo.toml 中解析的依赖关系生成的,而不是解析组件接口的本地定义。

希望有一天(在不远的将来……)WebAssembly组件可能成为Rust生态系统的重要组成部分,以至于 cargo 本身可能支持它们。

直到那时,有 cargo component

WASI 支持

目前 cargo component 默认以 wasm32-wasip1 为目标。

由于这个目标是WASI的preview1版本,Rust编译器生成的WebAssembly模块必须适应组件模型支持的WASI的preview2版本。

当使用内置的WASI适配器(该适配器是从Wasmtime存储库快照的)针对 wasm32-wasip1 时,自动执行此适配。

您可以通过在 Cargo.toml 中的 [package.metadata.component] 表中设置 adapter 设置来覆盖内置适配器,以指定要使用的适配器模块的路径。

要构建适配器模块,克隆 Wasmtime存储库 并运行以下命令

# Add the wasm32-unknown-unknown target if you haven't already
rustup target add wasm32-unknown-unknown

git checkout $REV

git submodule update --init

cargo build -p wasi-preview1-component-adapter --target wasm32-unknown-unknown --release

cp target/wasm32-unknown-unknown/release/wasi_snapshot_preview1.wasm $PROJECT

其中 $REV 是您要使用的Wasmtime提交哈希,而 $PROJECT 是您的组件项目的路径。

接下来,编辑 Cargo.toml 以指向适配器

[package.metadata.component]
adapter = "wasi_snapshot_preview1.wasm"

当Rust编译器支持preview2版本的WASI目标时,cargo component中对适配preview1模块的支持将被移除。

入门

使用 cargo component new --lib <名称> 来创建一个新的库(反应器)组件。

库组件没有导出 run(即 Rust 中的 main)函数,而是打算作为库使用,而不是运行后退出的命令。如果没有 --lib 标志,cargo component 默认创建命令组件。

这将创建一个 wit/world.wit 文件,描述组件将要针对的世界。

package my-org:my-component;

/// An example world for the component to target.
world example {
    export hello-world: func() -> string;
}

组件将导出一个返回字符串的 hello-world 函数。

组件的实现将在 src/lib.rs 中。

#[allow(warnings)]
mod bindings;

use bindings::Guest;

struct Component;

impl Guest for Component {
    /// Say hello!
    fn hello_world() -> String {
        "Hello, World!".to_string()
    }
}

bindings::export!(Component with_types_in bindings);

bindings 模块包含与组件针对的世界相对应的类型和特质;它是通过 cargo component 自动生成的。

用法

cargo component 子命令有一些类似于 cargo 自身的命令

  • cargo component new —— 创建一个新的 WebAssembly 组件 Rust 项目。
  • cargo component add —— 将组件接口依赖添加到 cargo 清单文件中。
  • cargo component update —— 与 cargo update 相同,但还会更新组件锁定文件中的依赖。
  • cargo component publish - 将 WebAssembly 组件发布到 warg 组件注册表中。

无法识别的命令将传递给 cargo 本身,但仅在更新了组件包的绑定信息之后。

直接传递给 cargo 的命令示例包括:buildcheckdocclippy 和来自 cargo-expand 的扩展命令,如 expand

某些命令行选项,如 --target--release,将由 cargo component 检测,以确定 build 命令的输出文件应该组件化。

使用 rust-analyzer

rust-analyzer 是一个分析 Rust 代码的极其有用的工具,被用于许多不同的编辑器中,以提供代码补全和其他功能。

rust-analyzer 依赖于 cargo metadatacargo check 来发现工作区信息并检查错误。

为确保 rust-analyzer 能够发现最新的绑定信息,必须配置 rust-analyzer 使用 cargo component check 作为检查命令。

要将 rust-analyzer 配置为使用 cargo component 可执行文件,将 rust-analyzer.check.overrideCommand 设置更改为以下内容

{
    "rust-analyzer.check.overrideCommand": [
        "cargo",
        "component",
        "check",
        "--workspace",
        "--all-targets",
        "--message-format=json"
    ],
}

默认情况下,cargo component new 将通过为你创建一个 .vscode/settings.json 文件来配置 Visual Studio Code 以使用 cargo component check。为了防止这种情况,请将 --editor none 传递给 cargo component new

请查看 rust-analyzer 的文档,了解如何为其他 IDE 设置设置。

cargo component 做出贡献

cargo component 是一个 Bytecode Alliance 项目,遵循 Bytecode Alliance 的 Code of ConductOrganizational Code of Conduct

获取代码

您将使用 git 克隆代码

git clone https://github.com/bytecodealliance/cargo-component

测试更改

我们希望为所有更改编写测试。测试可以通过以下方式运行

cargo test

您主要将在 tests/ 目录中添加测试。

提交更改

cargo component 的更改通过拉取请求(PR)进行管理。每个人都可以提交拉取请求!我们将在最多几天内尝试审阅它或回复它。

代码格式化

代码必须使用当前 Rust 稳定的 cargo fmt 命令进行格式化。这将在 CI 中进行检查。

持续集成

cargo component 仓库的 CI 相对重要。它在 Windows、macOS 和 Linux 上测试更改。

发布

此 crate 的发布完全通过 CI 自动化。每当向仓库推送标签时就会发生发布,因此要发布新版本,您需要提交一个提高版本号的 PR(请参阅 ci/publish.rs 脚本),合并 PR,然后标记 PR 并推送标签。这将触发所有必要的操作来发布所有 crate 和二进制文件到 crates.io。

依赖关系

~28–44MB
~732K SLoC