🧱

WadoでコンパイルしたWasmをWasmtimeで動かす

に公開

前回のあらすじ

https://github.com/wado-lang/wado
https://zenn.dev/tkithrta/articles/79f4a3360be0e1
https://zenn.dev/tkithrta/articles/afe8938a617d1e

Wadoに入門してmusl libcでビルドされた小さなWadoランタイムを作りました。

今回はこのWadoランタイムでコンパイルしたWasmをWasmtimeで動かしてみたいと思います。

$ wado --version   
wado 0.1.0
$ wado compile --help
Usage: wado compile [options] <file.wado>

Compile a Wado source file to WebAssembly.

Options:
  -o <file>            Output file path (default: <input>.wasm)
  --format <fmt>       Output format: wasm, wat (default: guessed from -o extension)
  --wat-to-stdout      Output WAT to stdout (shorthand for --format wat -o /dev/stdout)
  --world <name>       Target world (default: wasi:cli/command)
                       Use 'test' to export test functions only
  -O <n>               Optimization level: -O0, -O1, -O2, -O3, -Os
  --log-level <level>  Log level: debug, info, warn, error, off (default: info)
  --no-validate        Skip Wasm validation (output raw bytes even if invalid)
  --help               Show this help message

Wasmtime

https://github.com/bytecodealliance/wasmtime

cargo install wasmtime-cliでもインストールできますが、インストールスクリプトを使ったほうが早いので下記コマンドでインストールします。

curl https://wasmtime.dev/install.sh -sSf | bash
$ wasmtime -V
wasmtime 41.0.3 (db1c043b5 2026-02-04)

https://github.com/wado-lang/wado/blob/0a2e13e3669b50862b549a1cf718358fd412b723/wado-cli/src/runtime.rs#L56-L87

wado runwado serveで使用しているWasmtimeの設定を参考にしてオプションフラグをコマンドに渡したいところですが、コマンドがめちゃくちゃ長くなってしまうのでconfig.tomlに書いて--configフラグに渡します。

config.toml
[wasm]
simd = true
threads = true
component-model = true
component-model-async = true
component-model-async-builtins = true
component-model-async-stackful = true
component-model-gc = true
function-references = true
# stack-switching = true
gc = true
wide-arithmetic = true

[wasi]
p3 = true

asyncのstack-switchingが現状linux-x64でしか動かないらしいのでコメントアウトしておきます。[1]

config.tomlチートシート (wasmtime 41.0.3 (db1c043b5 2026-02-04))
$ wasmtime -O help-long
$ wasmtime -C help-long
$ wasmtime -D help-long
$ wasmtime -W help-long
  -W simd[=y|n] --

        Configure support for the simd proposal.
  -W threads[=y|n] --

        Configure support for the threads proposal.
  -W component-model[=y|n] --

        Configure support for the component-model proposal.
  -W component-model-async[=y|n] --

        Component model support for async lifting/lowering.
  -W component-model-async-builtins[=y|n] --

        Component model support for async lifting/lowering: this corresponds
        to the 🚝 emoji in the component model specification.
  -W component-model-async-stackful[=y|n] --

        Component model support for async lifting/lowering: this corresponds
        to the 🚟 emoji in the component model specification.
  -W component-model-gc[=y|n] --

        GC support in the component model: this corresponds to the 🛸 emoji
        in the component model specification.
  -W function-references[=y|n] --

        Configure support for the function-references proposal.
  -W stack-switching[=y|n] --

        Configure support for the stack-switching proposal.
  -W gc[=y|n] --

        Configure support for the GC proposal.
  -W wide-arithmetic[=y|n] --

        Configure support for the wide-arithmetic proposal.
$ wasmtime -S help-long
  -S p3[=y|n] --

        Enable support for WASIp3 APIs.
{
  "optimize": ["opt-level", "regalloc-algorithm", "memory-may-move", "memory-reservation", "memory-reservation-for-growth", "memory-guard-size", "guard-before-linear-memory", "table-lazy-init", "pooling-allocator", "pooling-decommit-batch-size", "pooling-memory-keep-resident", "pooling-table-keep-resident", "pooling-memory-protection-keys", "pooling-max-memory-protection-keys", "memory-init-cow", "memory-guaranteed-dense-image-size", "pooling-total-core-instances", "pooling-total-component-instances", "pooling-total-memories", "pooling-total-tables", "pooling-total-stacks", "pooling-max-memory-size", "pooling-table-elements", "pooling-max-core-instance-size", "pooling-max-unused-warm-slots", "pooling-async-stack-keep-resident", "pooling-max-component-instance-size", "pooling-max-core-instances-per-component", "pooling-max-memories-per-component", "pooling-max-tables-per-component", "pooling-max-tables-per-module", "pooling-max-memories-per-module", "pooling-total-gc-heaps", "signals-based-traps", "dynamic-memory-guard-size", "static-memory-guard-size", "static-memory-forced", "static-memory-maximum-size", "dynamic-memory-reserved-for-growth", "pooling-pagemap-scan"],
  "codegen": ["compiler", "collector", "cranelift-debug-verifier", "cache", "cache-config", "parallel-compilation", "pcc", "native-unwind-info", "inlining", "cranelift"],
  "debug": ["debug-info", "guest-debug", "address-map", "logging", "log-to-files", "coredump"],
  "wasm": ["nan-canonicalization", "fuel", "epoch-interruption", "max-wasm-stack", "async-stack-size", "async-stack-zeroing", "unknown-exports-allow", "unknown-imports-trap", "unknown-imports-default", "wmemcheck", "max-memory-size", "max-table-elements", "max-instances", "max-tables", "max-memories", "trap-on-grow-failure", "timeout", "all-proposals", "bulk-memory", "multi-memory", "multi-value", "reference-types", "simd", "relaxed-simd", "relaxed-simd-deterministic", "tail-call", "threads", "shared-memory", "shared-everything-threads", "memory64", "component-model", "component-model-async", "component-model-async-builtins", "component-model-async-stackful", "component-model-threading", "component-model-error-context", "component-model-gc", "function-references", "stack-switching", "gc", "custom-page-sizes", "wide-arithmetic", "extended-const", "exceptions", "gc-support"],
  "wasi": ["cli", "cli-exit-with-code", "common", "nn", "threads", "http", "http-outgoing-body-buffer-chunks", "http-outgoing-body-chunk-size", "config", "keyvalue", "listenfd", "tcplisten", "tls", "preview2", "inherit-network", "allow-ip-name-lookup", "tcp", "udp", "network-error-code", "preview0", "inherit-env", "p3"]
}

Run

hello.wadoをhello.wasmにコンパイルしてHello, World!を表示してみます。

touch hello.wado
hello.wado
#!/usr/bin/env -S wado run
use { println, Stdout } from "core:cli";

export fn run() with Stdout {
    println("Hello, World!");
}
$ wado compile hello.wado
Generated: hello.wasm
$ wasmtime run --config=config.toml --invoke='run()' hello.wasm
Hello, World!
ok

Wasmtimeで表示できました。

Serve

ok.wadoをok.wasmにコンパイルしてHTTPサーバーを動かしてみたいと思います。

touch ok.wado
ok.wado
#!/usr/bin/env -S wado serve
use { Request, Response, ErrorCode, Fields, Trailers } from "wasi:http";

export async fn handle(request: Request) -> Result<Response, ErrorCode> {
    let [trailers_future, trailers_tx] = Future::<Result<Option<Trailers>, ErrorCode>>::new();
    let headers = Fields::new();
    let [response, _tx_future] = Response::new(headers, null, trailers_future);
    task return Result::<Response, ErrorCode>::Ok(response);
    trailers_tx.write(Result::<Option<Trailers>, ErrorCode>::Ok(null));
}
$ wado compile --world=wasi:http/service ok.wado
Generated: ok.wasm
$ wasmtime serve --config=config.toml ok.wasm
Serving HTTP on http://0.0.0.0:8080/
$ curl -i http://localhost:8080/
HTTP/1.1 200 OK
transfer-encoding: chunked
date: Sun, 22 Feb 2026 14:00:00 GMT

Wasmtimeで起動して200 OKが返ってくることがわかりました。

脚注
  1. https://x.com/mizchi/status/2020041294295527451 ↩︎

Discussion