🍉

WasmtimeでZigのプログラムを動かしてみる

2023/06/02に公開

WASIでWASMを動かすのが気になってきたので。

Wasmtimeのインストール

こちらのページを見ながら
https://wasmtime.dev/

curl https://wasmtime.dev/install.sh -sSf | bash
source ~/.bashrc 
$ which wasmtime
/home/koba/.wasmtime/bin/wasmtime
$ wasmtime
wasmtime-cli 9.0.3
Wasmtime WebAssembly Runtime

USAGE:
    wasmtime <SUBCOMMAND>

OPTIONS:
    -h, --help       Print help information
    -V, --version    Print version information

SUBCOMMANDS:
    compile     Compiles a WebAssembly module
    config      Controls Wasmtime configuration settings
    explore     Explore the compilation of a WebAssembly module to native code
    help        Print this message or the help of the given subcommand(s)
    run         Runs a WebAssembly module
    settings    Displays available Cranelift settings for a target
    wast        Runs a WebAssembly test script file

If a subcommand is not provided, the `run` subcommand will be used.

Usage examples:

Running a WebAssembly module with a start function:

  wasmtime example.wasm

Passing command line arguments to a WebAssembly module:

  wasmtime example.wasm arg1 arg2 arg3

Invoking a specific function (e.g. `add`) in a WebAssembly module:

  wasmtime example.wasm --invoke add 1 2

まずは、RustでHelloWorld

このページに書いてある通りに進めてみる。

hello.rs
fn main() {
    println!("Hello, world!");
}
$ rustup target add wasm32-wasi
info: downloading component 'rust-std' for 'wasm32-wasi'
info: installing component 'rust-std' for 'wasm32-wasi'
 18.9 MiB /  18.9 MiB (100 %)  13.5 MiB/s in  1s ETA:  0s
$ rustc hello.rs --target wasm32-wasi
$ wasmtime hello.wasm
Hello, world!

動いた。

$ ls -lth
total 2.1M
-rwxrwxr-x 1 koba koba 2.1M  6月  2 10:12 hello.wasm
-rw-rw-r-- 1 koba koba   46  6月  2 10:11 hello.rs

wasmファイルのサイズが2.1MBもある。

$ rustc hello.rs -O --target wasm32-wasi
$ wasmtime hello.wasm
Hello, world!
$ ls -lth
total 2.1M
-rwxrwxr-x 1 koba koba 2.0M  6月  2 10:20 hello.wasm
-rw-rw-r-- 1 koba koba   46  6月  2 10:11 hello.rs

-Oをつけてもサイズは2.0MB。

** 2023/06/03 追記
以下のようにstripするオプションをつけたら64KBくらいまで小さくなりました。

$ rustc --version
rustc 1.70.0 (90c541806 2023-05-31)
$ rustc hello.rs -O -C strip=symbols --target wasm32-wasi
$ wasmtime hello.wasm 
Hello, world!
$ ls -lt *.wasm
-rwxrwxr-x 1 koba koba 63602  6月  3 09:29 hello.wasm
-rwxr--r-- 1 koba koba  5116  6月  2 12:27 hello_c.wasm
-rwxr--r-- 1 koba koba 15698  6月  2 10:49 hello_zig_release_fast.wasm
-rwxr--r-- 1 koba koba 23581  6月  2 10:49 hello_zig_release_safe.wasm
-rwxr--r-- 1 koba koba   335  6月  2 10:49 hello_zig_release_small.wasm
-rwxr--r-- 1 koba koba 79290  6月  2 10:48 hello_zig_debug.wasm
-rwxr--r-- 1 koba koba 79260  6月  2 10:42 hello_zig.wasm

** 2023/06/03 追記ここまで

同じことをZigでやってみる。

hello_zig.zig
const std = @import("std");

pub fn main() void {
    std.debug.print("Hello, world!\n", .{});
}

まずはネイティブ向けにビルドして実行。

$ zig build-exe hello_zig.zig 
$ ./hello_zig 
Hello, world!
$ zig targets |grep wasi
  "wasi",
  "wasm32-wasi-musl",

ターゲットを指定してビルド。

$ zig build-exe -target wasm32-wasi-musl hello_zig.zig
$ wasmtime hello_zig.wasm
Hello, world!
$ ls -lt
total 3992
-rwxr--r-- 1 koba koba   79260  6月  2 10:33 hello_zig.wasm
-rw-rw-r-- 1 koba koba  108122  6月  2 10:33 hello_zig.wasm.o
-rwxrwxr-x 1 koba koba  730952  6月  2 10:28 hello_zig
-rw-rw-r-- 1 koba koba 1053072  6月  2 10:28 hello_zig.o
-rw-rw-r-- 1 koba koba      98  6月  2 10:24 hello_zig.zig
-rwxrwxr-x 1 koba koba 2094117  6月  2 10:20 hello.wasm
-rw-rw-r-- 1 koba koba      46  6月  2 10:11 hello.rs

optimizeレベルを変えて、wasmファイルのサイズを比べる。

zig build-exe には -o オプションが無くて、出力するファイル名はソースファイル名で決まってしまいます。なので、シンボリックリンクを作りました。

$ ln -s hello_zig.zig hello_zig_debug.zig
$ ln -s hello_zig.zig hello_zig_release_safe.zig
$ ln -s hello_zig.zig hello_zig_release_small.zig
$ ln -s hello_zig.zig hello_zig_release_fast.zig

4種類のモードでビルド。

$ zig build-exe -O Debug -target wasm32-wasi-musl hello_zig_debug.zig
$ zig build-exe -O ReleaseSmall -target wasm32-wasi-musl hello_zig_release_small.zig
$ zig build-exe -O ReleaseSafe -target wasm32-wasi-musl hello_zig_release_safe.zig
$ zig build-exe -O ReleaseFast -target wasm32-wasi-musl hello_zig_release_fast.zig

ファイルサイズを見てみる。

$ ls -l *.wasm
-rwxrwxr-x 1 koba koba 2094117  6月  2 10:20 hello.wasm
-rwxr--r-- 1 koba koba   79290  6月  2 10:48 hello_zig_debug.wasm
-rwxr--r-- 1 koba koba   15698  6月  2 10:49 hello_zig_release_fast.wasm
-rwxr--r-- 1 koba koba   23581  6月  2 10:49 hello_zig_release_safe.wasm
-rwxr--r-- 1 koba koba     335  6月  2 10:49 hello_zig_release_small.wasm
-rwxr--r-- 1 koba koba   79260  6月  2 10:42 hello_zig.wasm

ZigでReleaseSmallでビルドしたものは、すごく小さいですね。335バイト。

ついでにzig cc でwasm出力 (2023/06/02追記)

hello.c
#include <stdio.h>

int main() {
    puts("Hello, world!");
}

-Os(サイズが小さくなるように最適化)をつけてwasmにコンパイル

$ zig cc -o hello_c.wasm -Os -target wasm32-wasi-musl hello.c
$ wasmtime hello_c.wasm 
Hello, world!
$ ls -l *.wasm
-rwxr--r-- 1 koba koba    5116  6月  2 12:27 hello_c.wasm
-rwxrwxr-x 1 koba koba 2094117  6月  2 10:20 hello.wasm
-rwxr--r-- 1 koba koba   79290  6月  2 10:48 hello_zig_debug.wasm
-rwxr--r-- 1 koba koba   15698  6月  2 10:49 hello_zig_release_fast.wasm
-rwxr--r-- 1 koba koba   23581  6月  2 10:49 hello_zig_release_safe.wasm
-rwxr--r-- 1 koba koba     335  6月  2 10:49 hello_zig_release_small.wasm
-rwxr--r-- 1 koba koba   79260  6月  2 10:42 hello_zig.wasm

Cと比べても、Zigのrelease_smallはサイズが小さい。

使用したzigのバージョン

$ zig version
0.11.0-dev.3336+6c2f37455
$ zig cc --version
clang version 16.0.1 (https://github.com/ziglang/zig-bootstrap 710c5d12660235bc4eac103a8c6677c61f0a9ded)
Target: aarch64-unknown-linux-musl
Thread model: posix
InstalledDir: /usr/bin

Discussion