• Stars
    star
    468
  • Rank 93,767 (Top 2 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created over 2 years ago
  • Updated 17 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Cargo subcommand for creating WebAssembly components based on the component model proposal.

cargo component

A Bytecode Alliance project

A cargo subcommand for building WebAssembly components according to the component model proposal.

build status Crates.io version Download docs.rs docs

Overview

cargo component is a cargo subcommand for creating WebAssembly components using Rust as the component's implementation language.

Notice

cargo component is considered to be experimental and is not currently stable in terms of the code it supports building.

Until the component model stabilizes, upgrading to a newer cargo component may cause build errors for existing component projects.

Requirements

  1. The cargo component subcommand is written in Rust, so you'll want the latest stable Rust installed.

Installation

To install the cargo component subcommand, run the following command:

cargo install --git https://github.com/bytecodealliance/cargo-component --locked

The currently published crate on crates.io is a nonfunctional placeholder and these instructions will be updated to install the crates.io package once a proper release is made.

Motivation

Today, developers that target WebAssembly typically compile a monolithic program written in a single source language to a WebAssembly module. The WebAssembly module can then be used in all sorts of places: from web browsers to cloud compute platforms. WebAssembly was intentionally designed to provide the portability and security properties required for such environments.

However, WebAssembly modules are not easily composed with other modules into a single program or service. WebAssembly only has a few primitive value types (integer and floating point types) and those are inadequate to describe the complex types that developers would desire to exchange between modules.

To make things even more challenging, WebAssembly modules typically define their own local linear memories, meaning one module can't access the (conceptual) address space of another. Something must sit between the two modules to facilitate communication when pointers are passed around.

While it is possible to solve these challenges with the existing WebAssembly standard, doing so is burdensome, error-prone, and requires foreknowledge of how the WebAssembly modules are implemented.

WebAssembly Component Model

The WebAssembly component model proposal provides a way to simplify the process of building WebAssembly applications and services out of reusable pieces of functionality using a variety of source languages, all while still maintaining the portability and security properties of WebAssembly.

At its most fundamental level, WebAssembly components may be used to wrap a WebAssembly module in a way that describes how its interface, a set of functions using complex value types (e.g. strings, variants, records, lists, etc.), is translated to and from the lower-level representation required of the WebAssembly module.

This enables WebAssembly runtimes to know specifically how they must facilitate the exchange of data between the discrete linear memories of components, eliminating the need for developers to do so by hand.

Additionally, components can describe their dependencies in a way that modules simply cannot today; they can even control how their dependencies are instantiated, enabling a component to virtualize functionality needed by a dependency. And because different components might have a shared dependency, hosts may even share the same implementation of that dependency to save on host memory usage.

Cargo Component

A primary goal of cargo component is to try to imagine what first-class support for WebAssembly components might look like for Rust.

That means being able to reference WebAssembly components via Cargo.toml and have WebAssembly component dependencies used in the same way as Rust crate dependencies:

  • add a dependency on a WebAssembly component to Cargo.toml
  • reference it like you would an external crate (via <name>::...) in your source code
  • build using cargo component build and out pops your component!

To be able to use a WebAssembly component from any particular programming language, bindings must be created by translating a WebAssembly component's interface to a representation that a specific programming language can understand.

Tools like wit-bindgen exist to generate those bindings for different languages, including Rust.

wit-bindgen even provides procedural macros to generate the bindings "inline" with the component's source code.

Unlike wit-bindgen, cargo component doesn't use procedural macros or a build.rs file to generate bindings. Instead, it generates them into external crates that are automatically provided to the Rust compiler when building your component's project.

This approach does come with some downsides, however. Commands like cargo metadata and cargo check used by many tools (e.g. rust-analyzer) simply don't work because they aren't aware of the generated bindings. That is why replacement commands such as cargo component metadata and cargo component check exist.

The hope is that one day (in the not too distant future...) that WebAssembly components might become an important part of the Rust ecosystem such that cargo itself might support them.

Until that time, there's cargo component!

Status

A quick note on the implementation status of the component model proposal.

At this time of this writing, no WebAssembly runtimes have fully implemented the component model proposal.

Wasmtime has implementation efforts underway to support it, but it's still a work-in-progress.

Until runtime support grows and additional tools are implemented for linking components together, the usefulness of cargo component today is effectively limited to creating components that runtime and tooling developers can use to test their implementations.

WASI Support

Currently cargo component targets wasm32-wasi by default.

As this target is for a preview1 release of WASI, the WebAssembly module produced by the Rust compiler must be adapted to the preview2 version of WASI supported by the component model.

The adaptation is automatically performed when wasm32-wasi is targeted.

To prevent this, override the target to wasm32-unknown-unknown using the --target option when building. This, however, will disable WASI support.

Use the preview2 version of wasi-common in your host to run components produced by cargo component.

When the Rust compiler supports a preview2 version of the WASI target, support in cargo component for adapting a preview1 module will be removed.

Getting Started

Use cargo component new --lib <name> to create a new reactor component.

This will create a wit/world.wit file describing the world that the component will target:

package my-org:my-component

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

The component will export a hello-world function returning a string.

The implementation of the component will be in src/lib.rs:

struct Component;

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

bindings::export!(Component);

Here bindings is the bindings crate that cargo component generated for you.

The export! macro informs the bindings that the Component type exports all interfaces listed in Cargo.toml.

Usage

The cargo component subcommand has some analogous commands to cargo itself:

  • cargo component new β€” creates a new WebAssembly component Rust project.
  • cargo component add β€” adds a component interface dependency to a cargo manifest file.
  • cargo component build β€” builds a WebAssembly component from a Rust project using the wasm32-wasi target by default.
  • cargo component doc β€” generates API documentation for a WebAssembly component from a Rust project.
  • cargo component metadata β€” prints package metadata as cargo metadata would, except it also includes the metadata of generated bindings.
  • cargo component check β€” checks the local package and all of its dependencies (including generated bindings) for errors.
  • cargo component clippy β€” same as cargo clippy but also checks generated bindings.
  • cargo component update β€” same as cargo update but also updates the dependencies in the component lock file.
  • cargo component publish - publishes a WebAssembly component to a warg component registry.
  • cargo component key - manages signing keys for publishing WebAssembly components.
  • cargo component wit - manages the target WIT package of the component.

More commands will be added over time.

Using rust-analyzer

rust-analyzer is an extremely useful tool for analyzing Rust code and is used in many different editors to provide code completion and other features.

rust-analyzer depends on cargo metadata and cargo check to discover workspace information and to check for errors.

Because cargo component generates code for dependencies that cargo itself is unaware of, rust-analyzer will not detect or parse the generated bindings; additionally, diagnostics will highlight any use of the generated bindings as errors.

To solve this problem, rust-analyzer must be configured to use the cargo-component executable as the cargo command. By doing so, the cargo component metadata and cargo component check subcommands will inform rust-analyzer of the generated bindings as if they were normal crate dependencies.

To configure rust-analyzer to use the cargo-component executable, set the rust-analyzer.server.extraEnv setting to the following:

"rust-analyzer.server.extraEnv": { "CARGO": "cargo-component" }

By default, cargo component new will configure Visual Studio Code to use cargo component by creating a .vscode/settings.json file for you. To prevent this, pass --editor none to cargo component new.

Please check the documentation for rust-analyzer regarding how to set settings for other IDEs.

Contributing to cargo component

cargo component is a Bytecode Alliance project, and follows the Bytecode Alliance's Code of Conduct and Organizational Code of Conduct.

Getting the Code

You'll clone the code via git:

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

Testing Changes

We'd like tests ideally to be written for all changes. Test can be run via:

cargo test

You'll be adding tests primarily to the tests/ directory.

Submitting Changes

Changes to cargo component are managed through pull requests (PRs). Everyone is welcome to submit a pull request! We'll try to get to reviewing it or responding to it in at most a few days.

Code Formatting

Code is required to be formatted with the current Rust stable's cargo fmt command. This is checked on CI.

Continuous Integration

The CI for the cargo component repository is relatively significant. It tests changes on Windows, macOS, and Linux.

It also performs a "dry run" of the release process to ensure that release binaries can be built and are ready to be published (coming soon).

Publishing (coming soon)

Publication of this crate is entirely automated via CI. A publish happens whenever a tag is pushed to the repository, so to publish a new version you'll want to make a PR that bumps the version numbers (see the bump.rs scripts in the root of the repository), merge the PR, then tag the PR and push the tag. That should trigger all that's necessary to publish all the crates and binaries to crates.io.

More Repositories

1

wasmtime

A fast and secure runtime for WebAssembly
Rust
15,075
star
2

wasm-micro-runtime

WebAssembly Micro Runtime (WAMR)
C
4,925
star
3

lucet

Lucet, the Sandboxing WebAssembly Compiler.
Rust
4,065
star
4

cranelift

Cranelift code generator
2,488
star
5

javy

JS to WebAssembly toolchain
Rust
2,240
star
6

rustix

Safe Rust bindings to POSIX-ish APIs
Rust
1,424
star
7

wasm-tools

CLI and Rust libraries for low-level manipulation of WebAssembly modules
Rust
1,270
star
8

wit-bindgen

A language binding generator for WebAssembly interface types
Rust
1,024
star
9

wizer

The WebAssembly Pre-Initializer
Rust
932
star
10

wasmtime-go

Go WebAssembly runtime powered by Wasmtime
Go
771
star
11

cap-std

Capability-oriented version of the Rust standard library
Rust
646
star
12

cranelift-jit-demo

JIT compiler and runtime for a toy language, using Cranelift
Rust
636
star
13

jco

JavaScript toolchain for working with WebAssembly Components
Rust
598
star
14

cargo-wasi

A lightweight Cargo subcommand to build Rust code for the `wasm32-wasi` target
Rust
439
star
15

wasmtime-dotnet

.NET embedding of Wasmtime https://bytecodealliance.github.io/wasmtime-dotnet/
C#
409
star
16

wasmtime-py

Python WebAssembly runtime powered by Wasmtime
Python
385
star
17

wasi-rs

Experimental WASI API bindings for Rust
Rust
254
star
18

ComponentizeJS

JS -> WebAssembly Component
Rust
213
star
19

wasi.dev

JavaScript
209
star
20

regalloc2

A new register allocator
Rust
200
star
21

registry

WebAssembly Registry (Warg)
Rust
189
star
22

wasmparser

A simple event-driven library for parsing WebAssembly binary files
178
star
23

wasmtime-demos

Historical and dated demos for Wasmtime usage and WASI content
C#
153
star
24

WASI-Virt

Virtual implementations of WASI APIs
Rust
139
star
25

componentize-py

Rust
138
star
26

wrpc

Wasm component-native RPC framework
Rust
114
star
27

wat

Rust WAT and WAST parser (WebAssembly Text Format)
113
star
28

wac

WebAssembly Composition (WAC) tooling
Rust
107
star
29

regalloc.rs

Modular register allocator algorithms
Rust
106
star
30

wasmtime-rb

Ruby WebAssembly runtime powered by Wasmtime
Rust
95
star
31

spidermonkey-wasm-rs

Rust
87
star
32

wasmtime-cpp

C++
81
star
33

preview2-prototyping

Polyfill adapter for preview1-using wasm modules to call preview2 functions.
Rust
79
star
34

wasm-interface-types

Raw Rust toolchain support for Wasm Interface Types
Rust
70
star
35

component-docs

Documentation around creating and using WebAssembly Components
Rust
68
star
36

sightglass

A benchmark suite and tool to compare different implementations of the same primitives.
C
67
star
37

wasm-tools-go

WebAssembly + Component Model tools for Go
Go
60
star
38

rfcs

RFC process for Bytecode Alliance projects
60
star
39

StarlingMonkey

The StarlingMonkey JS runtime
C++
58
star
40

wasm-pkg-tools

Rust
56
star
41

target-lexicon

Target "triple" support
Rust
48
star
42

wit-deps

WIT dependency manager
Rust
47
star
43

userfaultfd-rs

Rust bindings for the Linux userfaultfd functionality
Rust
43
star
44

wasi-nn

High-level bindings for wasi-nn system calls
CSS
42
star
45

system-interface

Extensions to the Rust standard library
Rust
41
star
46

waffle

Wasm Analysis Framework For Lightweight Experiments
Rust
34
star
47

wasmprinter

Rust library to print a WebAssembly binary to its textual format
32
star
48

wasm-component-ld

Command line linker for creating WebAssembly components
Rust
31
star
49

meetings

Python
28
star
50

wamr-rust-sdk

Rust
28
star
51

wasm-score

A benchmark for standalone WebAssembly
C
26
star
52

weval

the WebAssembly partial evaluator
Rust
25
star
53

spidermonkey-wasm-build

Utilities to compile SpiderMonkey to wasm32-wasi
JavaScript
24
star
54

vscode-wit

Visual Studio Code extension to recognize and highlight the WebAssembly Interface Type (WIT) IDL.
TypeScript
22
star
55

filecheck

Library for writing tests for utilities that read text files and produce text output
Rust
21
star
56

componentize-dotnet

Tooling for creating WebAssembly components from C#
C#
17
star
57

cranelift.vim

Vim editor configuration for working with cranelift IR (clif) files
Vim Script
15
star
58

arf-strings

Encoding and decoding for ARF strings
C
13
star
59

SIG-Guest-Languages

Special Interest Group (SIG) whose goal is to investigate how best to integrate Wasm and components into dynamic programming language ecosystems in a way that feels native to those ecosystems.
13
star
60

SIG-Registries

11
star
61

governance

11
star
62

subscribe-to-label-action

A GitHub action that allows users to subscribe to a label and automatically get @'d when the label is applied
JavaScript
11
star
63

bytecodealliance.org

CSS
10
star
64

wasm-spec-interpreter

Rust bindings for the Wasm spec interpreter.
Rust
10
star
65

spidermonkey-wasi-embedding

Shell
9
star
66

wamr-app-framework

WebAssembly Micro Runtime Application Framework
C
9
star
67

wasm-parallel-gzip

Some example scripts for building a parallel compression/decompression tool for WebAssembly
Makefile
8
star
68

fs-set-times

Set filesystem timestamps
Rust
6
star
69

wasmtime-libfuzzer-corpus

libFuzzer corpus for our wasmtime fuzz targets
Shell
6
star
70

rust-oci-wasm

A Rust implementation of the OCI artifact specification for WebAssembly
Rust
6
star
71

arena-btree

Rust
6
star
72

cm-go

Go
6
star
73

sig-embedded

6
star
74

wamr-python

Python
6
star
75

wamr.dev

The WAMR homepage
HTML
5
star
76

wasmtime.dev

The Wasmtime homepage
CSS
4
star
77

libc-test

Mirror of git://nsz.repo.hu:49100/repo/libc-test (see https://wiki.musl-libc.org/libc-test.html for more information)
C
4
star
78

actions

GitHub actions to setup wasm-tools and wasmtime
TypeScript
3
star
79

wasmtime-wasi-nn

2
star
80

cranelift.dev

CSS
1
star
81

label-messager-action

Automatically leave a message when an issue or pull request has a certain label
JavaScript
1
star
82

wasm-ml-meetings

Informal working group for machine learning and WebAssembly, especially wasi-nn
1
star