Top Related Projects
The WebAssembly Binary Toolkit
🚀 The leading Wasm Runtime supporting WASIX, WASI and Emscripten
Emscripten: An LLVM-to-WebAssembly Compiler
A TypeScript-like language for WebAssembly.
Facilitating high-level interactions between Wasm modules and JavaScript
A fast and secure runtime for WebAssembly
Quick Overview
Wasm-tools is a collection of low-level WebAssembly tools developed by the Bytecode Alliance. It provides a suite of utilities for working with WebAssembly modules, including parsing, validation, transformation, and code generation. These tools are designed to be used as both command-line utilities and as libraries in Rust projects.
Pros
- Comprehensive set of tools for WebAssembly manipulation and analysis
- High performance due to implementation in Rust
- Actively maintained by the Bytecode Alliance, ensuring compatibility with latest WebAssembly standards
- Flexible usage as both CLI tools and Rust libraries
Cons
- Steep learning curve for users unfamiliar with WebAssembly internals
- Limited documentation for some advanced features
- Primarily focused on low-level operations, which may not be suitable for high-level WebAssembly development
Code Examples
- Parsing a WebAssembly module:
use wasm_tools::parser::parse;
let wasm_bytes = std::fs::read("module.wasm").unwrap();
let module = parse(&wasm_bytes).unwrap();
println!("Module sections: {:?}", module.sections());
- Validating a WebAssembly module:
use wasm_tools::validator::validate;
let wasm_bytes = std::fs::read("module.wasm").unwrap();
match validate(&wasm_bytes) {
Ok(_) => println!("Module is valid"),
Err(e) => println!("Validation error: {:?}", e),
}
- Transforming a WebAssembly module:
use wasm_tools::transform::{TransformConfig, transform};
let wasm_bytes = std::fs::read("module.wasm").unwrap();
let config = TransformConfig::default().with_optimization_level(2);
let transformed = transform(&wasm_bytes, &config).unwrap();
std::fs::write("optimized.wasm", transformed).unwrap();
Getting Started
To use wasm-tools in your Rust project, add the following to your Cargo.toml
:
[dependencies]
wasm-tools = "0.2"
Then, you can import and use the tools in your Rust code:
use wasm_tools::parser::parse;
use wasm_tools::validator::validate;
fn main() {
let wasm_bytes = std::fs::read("module.wasm").unwrap();
let module = parse(&wasm_bytes).unwrap();
validate(&wasm_bytes).unwrap();
println!("Module parsed and validated successfully");
}
Competitor Comparisons
The WebAssembly Binary Toolkit
Pros of wabt
- Mature project with a longer history and wider adoption
- Supports a broader range of WebAssembly tools and utilities
- Extensive documentation and examples available
Cons of wabt
- Written in C++, which may be less accessible for some developers
- Slower development cycle compared to wasm-tools
- Less focus on newer WebAssembly proposals and features
Code Comparison
wabt:
#include "src/binary-reader.h"
#include "src/error-formatter.h"
Result ReadBinaryInterp(const void* data,
size_t size,
const ReadBinaryOptions* options,
ErrorHandler* error_handler,
ModuleDesc* out_module) {
BinaryReader reader(data, size, options, error_handler);
return reader.ReadModule(out_module);
}
wasm-tools:
use wasm_tools::parser::Parser;
let wasm = std::fs::read("input.wasm")?;
let mut parser = Parser::new(0);
let module = parser.parse_module(&wasm)?;
Summary
Both wabt and wasm-tools are valuable projects for working with WebAssembly. wabt offers a more comprehensive set of tools and has a longer history, while wasm-tools focuses on newer WebAssembly features and has a more modern, Rust-based implementation. The choice between them depends on specific project requirements and developer preferences.
🚀 The leading Wasm Runtime supporting WASIX, WASI and Emscripten
Pros of Wasmer
- More comprehensive runtime environment for WebAssembly
- Supports multiple backends (LLVM, Cranelift, Singlepass)
- Provides a package manager (WAPM) for WebAssembly modules
Cons of Wasmer
- Larger project scope may lead to increased complexity
- Potentially higher resource usage due to full runtime implementation
- Less focused on low-level WebAssembly tooling
Code Comparison
Wasmer (runtime execution):
let module = Module::from_file(store, "example.wasm")?;
let import_object = imports! {};
let instance = Instance::new(&module, &import_object)?;
let result = instance.exports.get_function("main")?.call(&[])?;
Wasm-tools (manipulation and validation):
let wasm = wat::parse_file("example.wat")?;
let module = Module::new(&wasm)?;
validate(&module)?;
let text = print(&module);
Summary
Wasmer focuses on providing a complete WebAssembly runtime environment with multiple backends and a package manager. Wasm-tools, on the other hand, concentrates on low-level WebAssembly tooling, offering utilities for parsing, validating, and manipulating WebAssembly modules. While Wasmer is better suited for running WebAssembly modules in various environments, Wasm-tools excels in tasks related to WebAssembly development and analysis.
Emscripten: An LLVM-to-WebAssembly Compiler
Pros of Emscripten
- More mature and widely adopted toolchain for compiling C/C++ to WebAssembly
- Provides a comprehensive ecosystem with libraries and APIs for web integration
- Supports a broader range of programming languages beyond just C/C++
Cons of Emscripten
- Larger toolchain with more dependencies, potentially more complex setup
- May produce larger output files compared to more specialized tools
- Can be slower for certain compilation tasks due to its comprehensive nature
Code Comparison
Emscripten example:
#include <emscripten.h>
#include <stdio.h>
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
return a + b;
}
wasm-tools example (using wat2wasm):
(module
(func $add (param $a i32) (param $b i32) (result i32)
local.get $a
local.get $b
i32.add)
(export "add" (func $add)))
While Emscripten provides a full C/C++ compilation environment, wasm-tools offers lower-level WebAssembly manipulation tools. Emscripten is better suited for large-scale projects and existing C/C++ codebases, while wasm-tools is more appropriate for fine-grained WebAssembly module creation and manipulation.
A TypeScript-like language for WebAssembly.
Pros of AssemblyScript
- Higher-level language, similar to TypeScript, making it more accessible for web developers
- Provides a familiar development experience with static typing and object-oriented programming
- Includes a standard library with common data structures and utilities
Cons of AssemblyScript
- Limited ecosystem compared to more established WebAssembly tools
- May produce larger output files compared to lower-level WebAssembly tools
- Performance can be slightly lower than hand-optimized WebAssembly code
Code Comparison
AssemblyScript:
export function add(a: i32, b: i32): i32 {
return a + b;
}
wasm-tools (using WAT format):
(module
(func $add (param $a i32) (param $b i32) (result i32)
local.get $a
local.get $b
i32.add)
(export "add" (func $add)))
AssemblyScript provides a more familiar syntax for developers coming from TypeScript or JavaScript backgrounds, while wasm-tools offers lower-level control and optimization possibilities. The choice between the two depends on the project requirements, developer expertise, and performance needs.
Facilitating high-level interactions between Wasm modules and JavaScript
Pros of wasm-bindgen
- Specifically designed for Rust-to-WebAssembly interoperability
- Provides high-level abstractions for working with JavaScript APIs
- Generates TypeScript definitions for improved type safety in JavaScript
Cons of wasm-bindgen
- Limited to Rust-WebAssembly integration
- May introduce overhead for simple use cases
- Less flexible for general WebAssembly manipulation
Code Comparison
wasm-bindgen:
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
wasm-tools:
use wasmparser::Parser;
let mut parser = Parser::new(0);
for payload in parser.parse_all(wasm_bytes) {
// Process WebAssembly modules
}
wasm-bindgen focuses on creating JavaScript-friendly interfaces for Rust-generated WebAssembly modules, while wasm-tools provides lower-level utilities for working with WebAssembly binary format. wasm-bindgen is ideal for Rust developers targeting web platforms, offering seamless integration with JavaScript ecosystems. In contrast, wasm-tools is more versatile, supporting various WebAssembly-related tasks across different languages and use cases, but requires more manual work for JavaScript interoperability.
A fast and secure runtime for WebAssembly
Pros of Wasmtime
- Full-featured WebAssembly runtime with JIT compilation
- Supports WASI (WebAssembly System Interface) for system-level interactions
- Extensive language support, including Rust, C, and Python bindings
Cons of Wasmtime
- Larger codebase and more complex architecture
- Focused on runtime execution, less suitable for WebAssembly tooling tasks
- Steeper learning curve for contributors due to its comprehensive feature set
Code Comparison
Wasmtime (runtime execution):
let engine = Engine::default();
let module = Module::from_file(&engine, "example.wasm")?;
let instance = Instance::new(&mut store, &module, &[])?;
let run = instance.get_func(&mut store, "run")?;
run.call(&mut store, &[], &mut [])?;
Wasm-tools (WebAssembly manipulation):
let wasm = wat::parse_file("example.wat")?;
let module = Module::decode(&wasm)?;
let validated = validate(&module)?;
let encoded = module.encode()?;
Summary
Wasmtime is a comprehensive WebAssembly runtime, ideal for executing WebAssembly modules with high performance and system-level integration. Wasm-tools, on the other hand, focuses on WebAssembly tooling, providing utilities for parsing, validating, and manipulating WebAssembly code. While Wasmtime excels in runtime execution, Wasm-tools is better suited for tasks involving WebAssembly analysis and transformation.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
wasm-tools
A Bytecode Alliance project
CLI and Rust libraries for low-level manipulation of WebAssembly modules
Installation
Precompiled artifacts built on CI are available for download for each release.
To build from source first install Rust for your platform and then use the included Cargo package manager to install:
$ cargo install wasm-tools
Alternatively if you use cargo binstall
then that can be used
to install the precompiled artifacts instead:
$ cargo binstall wasm-tools
Installation can be confirmed with:
$ wasm-tools --version
Subcommands can be explored with:
$ wasm-tools help
Examples
Basic validation/printing:
# Validate a WebAssembly file
$ wasm-tools validate foo.wasm
# Validate a WebAssembly module in the text format, automatically converting to
# binary.
$ wasm-tools validate foo.wat
# Validate a WebAssembly file enabling an off-by-default feature
$ wasm-tools validate foo.wasm --features=exception-handling
# Validate a WebAssembly file with a default-enabled feature disabled
$ wasm-tools validate foo.wasm --features=-simd
# Print the text format of a module to stdout
$ wasm-tools print foo.wasm
# Convert a binary module to text
$ wasm-tools print foo.wasm -o foo.wat
Simple mutation as well as piping commands together:
# Mutate a WebAssembly module and print its text representation to stdout
$ wasm-tools mutate foo.wasm -t
# Mutate a WebAssembly module with a non-default seed and validate that the
# output is a valid module.
$ wasm-tools mutate foo.wasm --seed 192 | wasm-tools validate
# Demangle Rust/C++ symbol names in the `name` section, strip all other custom
# sections, and then print out what binary sections remain.
$ wasm-tools demangle foo.wasm | wasm-tools strip | wasm-tools objdump
Working with components:
# Print the WIT interface of a component
$ wasm-tools component wit component.wasm
# Convert WIT text files to a binary-encoded WIT package, printing the result to
# stdout
$ wasm-tools component wit ./wit -t
# Convert a WIT document to JSON
$ wasm-tools component wit ./wit --json
# Round trip WIT through the binary-encoded format to stdout.
$ wasm-tools component wit ./wit --wasm | wasm-tools component wit
# Convert a core WebAssembly binary into a component. Note that this requires
# WIT metadata having previously been embedded in the core wasm module.
$ wasm-tools component new my-core.wasm -o my-component.wasm
# Convert a core WebAssembly binary which uses WASI to a component.
$ wasm-tools component new my-core.wasm -o my-component.wasm --adapt wasi_snapshot_preview1.reactor.wasm
CLI Conventions
There are a few conventions that all CLI commands adhere to:
- All subcommands print "short help" with
-h
and "long help" with--help
. - Input is by default read from stdin if no file input is specified (when applicable).
- Output is by default sent to stdout if a
-o
or--output
flag is not provided. Binary WebAssembly is not printed to a tty by default, however. - Commands which output WebAssembly binaries all support a
-t
or--wat
flag to generate the WebAssembly text format instead. - A
-v
or--verbose
flag can be passed to enable log messages throughout the tooling. Verbosity can be turned up by passing the flag multiple times such as-vvv
. - Color in error messages and console output is enabled by default for TTY based
outputs and can be configured with a
--color
argument.
Tools included
The wasm-tools
binary internally contains a number of subcommands for working
with wasm modules and component. Many subcommands also come with Rust crates
that can be use programmatically as well:
CLI | Rust Crate | Playground | Description |
---|---|---|---|
wasm-tools validate | wasmparser | Validate a WebAssembly file | |
wasm-tools parse | wat and wast | parse | Translate the WebAssembly text format to binary |
wasm-tools print | wasmprinter | Translate the WebAssembly binary format to text | |
wasm-tools smith | wasm-smith | Generate a valid WebAssembly module from an input seed | |
wasm-tools mutate | wasm-mutate | Mutate an input wasm file into a new valid wasm file | |
wasm-tools shrink | wasm-shrink | Shrink a wasm file while preserving a predicate | |
wasm-tools dump | Print debugging information about the binary format | ||
wasm-tools objdump | Print debugging information about section headers | ||
wasm-tools strip | Remove custom sections from a WebAssembly file | ||
wasm-tools demangle | Demangle Rust and C++ symbol names in the name section | ||
wasm-tools compose | wasm-compose | Compose wasm components together (deprecated) | |
wasm-tools component new | wit-component | Create a component from a core wasm binary | |
wasm-tools component wit | Extract a *.wit interface from a component | ||
wasm-tools component embed | Embed a component-type custom section in a core wasm binary | ||
wasm-tools metadata show | wasm-metadata | Show name and producer metadata in a component or module | |
wasm-tools metadata add | Add name or producer metadata to a component or module | ||
wasm-tools metadata unbundle | Extract core wasm modules from a component | ||
wasm-tools addr2line | Translate wasm offsets to filename/line numbers with DWARF | ||
wasm-tools completion | Generate shell completion scripts for wasm-tools | ||
wasm-tools json-from-wast | Convert a *.wast file into JSON commands |
The wasm-tools
CLI contains useful tools for debugging WebAssembly modules and
components. The various subcommands all have --help
explainer texts to
describe more about their functionality as well.
Libraries
As mentioned above many of the tools of the wasm-tools
CLI have libraries
implemented in this repository as well. These libraries are:
wasmparser
- a library to parse WebAssembly binarieswat
- a library to parse the WebAssembly text formatwast
- likewat
, except provides an ASTwasmprinter
- prints WebAssembly binaries in their string formwasm-mutate
- a WebAssembly test case mutatorwasm-shrink
- a WebAssembly test case shrinkerwasm-smith
- a WebAssembly test case generatorwasm-encoder
- a crate to generate a binary WebAssembly modulewit-parser
- a crate to parse and manage*.wit
files and interfaces.wit-component
- a crate to create components from core wasm modules.wasm-metadata
- a crate to manipulate name and producer metadata (custom sections) in a wasm module or component.
It's recommended to use the libraries directly rather than the CLI tooling when embedding into a separate project.
C/C++ bindings
Using the CMakeLists.txt
in crates/c-api
, wasm-tools
can be used from the
wasm-tools.h
header. Note that these
bindings do not comprehensively cover all the functionality of this repository
at this time, but please feel free to contribute more if you find functions
useful!
Versioning and Releases
This repository has both a CLI and a suite of crates that is published to crates.io (Rust's package manager). The versioning scheme used by this repository looks like:
wasm-tools
- the CLI follows the versioning pattern of1.X.Y
. FrequentlyY
is 0 andX
is bumped as part of a release for this repository.wat
- this Rust crate is versioned at1.X.Y
as well and matches thewasm-tools
version.wast
- this Rust crate is versioned asX.0.Y
. TheX
here matches theX
in1.X.Y
ofwasm-tools
.- All other crates - all other crates in this repository are versioned at
0.X.Y
whereX
matches the1.X.Y
ofwasm-tools
.
Note that the Y
of all the versions above will also match for any release of
this repository. This versioning scheme is intended to reflect the stable nature
of the CLI and the wat
crate in terms of API stability. Other crates, however,
all receive a major version bump that are not automatically considered API
compatible on all releases. This reflects how WebAssembly itself is an evolving
standard which is not an unchanging foundation. All of the crates in this
repository are suitable for "production use" but be aware that API stability is
not guaranteed over time. If you have difficulty upgrading versions please feel
free to file an issue and we can help out.
Also, this repository does not currently have a strict release cadence. Releases are done on an as-needed basis. If you'd like a release done please feel free to reach out on Zulip, file an issue, leave a comment on a PR, or otherwise contact a maintainer.
For maintainers, the release process looks like:
- Go to this link
- Click on "Run workflow" in the UI.
- Use the default
bump
argument and hit "Run workflow" - Wait for a PR to be created by CI. You can watch the "Actions" tab for if things go wrong.
- When the PR opens, close it then reopen it. Don't ask questions.
- Review the PR, approve it, then queue it for merge.
That should be it, but be sure to keep an eye on CI in case anything goes wrong.
Contributing
See CONTRIBUTING.md for more information about contributing to this repository.
License
This project is triple licenced under the Apache 2/ Apache 2 with LLVM exceptions/ MIT licences. The reasoning for this is:
- Apache 2/ MIT is common in the rust ecosystem.
- Apache 2/ MIT is used in the rust compiler, and some of this code may be migrated there.
- Some of this code may be used in compiler output, and the Apache 2 with LLVM exceptions licence is useful for this.
For more details see
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache 2/ Apache 2 with LLVM exceptions/ MIT licenses, shall be licensed as above, without any additional terms or conditions.
Top Related Projects
The WebAssembly Binary Toolkit
🚀 The leading Wasm Runtime supporting WASIX, WASI and Emscripten
Emscripten: An LLVM-to-WebAssembly Compiler
A TypeScript-like language for WebAssembly.
Facilitating high-level interactions between Wasm modules and JavaScript
A fast and secure runtime for WebAssembly
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot