Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/articles/toc.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
- name: Introduction to the .NET embedding of Wasmtime
href: intro.md
- name: WASI Preview2 Component Runner (Shim)
href: wasi-preview2-shim.md
87 changes: 87 additions & 0 deletions docs/articles/wasi-preview2-shim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# WASI Preview2 Component Runner (Shim)

This repository includes an optional native shim for running WASI 0.2 components
in-process. It pairs a small Rust `cdylib` with a managed wrapper:

- Rust shim: `native/wasmtime-preview2-shim`
- C# wrapper: `src/Preview2ComponentRunner.cs`

## Build the native shim

The shim uses Wasmtime 35 and requires Rust 1.86+.

```
cd native/wasmtime-preview2-shim
cargo build --release
```

Add the resulting library to the runtime loader path:

- macOS: `libwasmtime_preview2_shim.dylib`
- Linux: `libwasmtime_preview2_shim.so`

## Run a component

```
using Wasmtime;

var exitCode = Preview2ComponentRunner.Run(
componentPath: "dotnet.wasm",
args: new[] { "arg1", "arg2" },
environment: new Dictionary<string, string>
{
["DOTNET_EnableDiagnostics"] = "0"
},
preopens: new[]
{
new PreopenDirectory(".", ".")
},
inheritStdio: true,
inheritEnvironment: true,
inheritNetwork: true
);
```

The runner wires `wasi:cli/run` and returns the component exit code.

## Library components (no `wasi:cli/run`)

Library-style .NET components do not export `wasi:cli/run`. To invoke their
exported C-ABI functions in-process, extract the main core module and use the
existing Wasmtime .NET core APIs:

```
using Wasmtime;

ComponentCoreExtractor.ExtractMainModule(
componentPath: "dotnet.wasm",
outputPath: "core-module.wasm");

using var config = new Config().WithWasmThreads(true);
using var engine = new Engine(config);
using var module = Module.FromFile(engine, "core-module.wasm");
using var store = new Store(engine);

store.SetWasiConfiguration(
new WasiConfiguration()
.WithInheritedStandardOutput()
.WithInheritedStandardError()
.WithPreopenedDirectory(".", "."));

using var linker = new Linker(engine);
linker.DefineWasi();
linker.DefineWasiPreview2Stubs();

using var instance = linker.Instantiate(store, module);
var alloc = instance.GetFunction<int, int>("alloc");
var dealloc = instance.GetAction<int, int>("dealloc");
```

The extracted core module imports `wasi_snapshot_preview1`, so the core WASI
linker (`DefineWasi`) is required. Some extracted modules also import:

- `wasi_snapshot_preview1.adapter_close_badfd`
- `wasi_snapshot_preview1.adapter_open_badfd`
- WASI preview2 `[resource-drop]` functions (no-op stubs are sufficient)

`DefineWasiPreview2Stubs` provides these stubs for common preview2 interfaces.
1 change: 1 addition & 0 deletions native/wasmtime-preview2-shim/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target/
15 changes: 15 additions & 0 deletions native/wasmtime-preview2-shim/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "wasmtime-preview2-shim"
version = "0.1.0"
edition = "2021"
rust-version = "1.86"

[lib]
crate-type = ["cdylib"]

[dependencies]
anyhow = "1.0"
wasmtime = "35.0.0"
wasmtime-wasi = "35.0.0"
wasmtime-wasi-http = "35.0.0"
wasmparser = "0.244.0"
45 changes: 45 additions & 0 deletions native/wasmtime-preview2-shim/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# WASI Preview2 Shim

This crate builds a small native shim that runs WASI 0.2 (preview2) components
in-process using Wasmtime. The shim is invoked from .NET via P/Invoke.

## Requirements

- Rust 1.86+ (Wasmtime 35 requires a newer toolchain)

## Build

```
cd native/wasmtime-preview2-shim
cargo build --release
```

Artifacts:

- macOS: `target/release/libwasmtime_preview2_shim.dylib`
- Linux: `target/release/libwasmtime_preview2_shim.so`

## Loading from .NET

The managed wrapper expects the library name `wasmtime_preview2_shim`.
Ensure the compiled library is on the dynamic loader search path or copied
next to the .NET application.

Example (macOS):

```
export DYLD_LIBRARY_PATH=/path/to/native/wasmtime-preview2-shim/target/release:$DYLD_LIBRARY_PATH
```

Example (Linux):

```
export LD_LIBRARY_PATH=/path/to/native/wasmtime-preview2-shim/target/release:$LD_LIBRARY_PATH
```

## Core module extraction (library components)

Library components that do not export `wasi:cli/run` can be handled by extracting
their main core module and using the existing Wasmtime .NET core APIs.

The shim exposes `wasmtime_preview2_extract_core_module` for this purpose.
Loading
Loading