Wasmer 3.0 の WASM からの各プラットフォーム用バイナリ生成機能を試す

| 7 min read
Author: masahiro-kondo masahiro-kondoの画像

これは、豆蔵デベロッパーサイトアドベントカレンダー2022第13日目の記事です。

3月の記事「スタンドアローンおよび言語組み込みの WebAssembly ランタイム Wasmer」で、WASI 対応の WASM ランタイム Wasmer について紹介しました。

先月 Wasmer 3.0 のリリースがアナウンスされました。

Announcing Wasmer 3.0

この記事では Wasmer 3.0 の新機能、特に各プラットフォーム向けバイナリ生成機能について確認していこうと思います。

Wasmer 3.0 へのアップデート

#

さっそく Wasmer を最新版に更新しました。self-update サブコマンドを使用しました。wasmer / wapm はそれぞれ、3.0.2 / 0.5.9 になっていました。

$ wasmer self-update
already installed in /Users/masahiro-kondo/.wasmer with version: 2.2.1
Downloading archive from https://github.com/wasmerio/wasmer/releases/download/v3.0.2/wasmer-darwin-arm64.tar.gz
installing: /Users/masahiro-kondo/.wasmer
Updating bash profile /Users/masahiro-kondo/.zshrc
warning: the profile already has Wasmer and has not been changed
check: wasmer 3.0.2 installed successfully ✓
downloading: wapm-cli-darwin-aarch64
Latest release: 0.5.9
WAPM already installed in /Users/masahiro-kondo/.wasmer with version: 0.5.3
Downloading archive from https://github.com/wasmerio/wapm-cli/releases/download/v0.5.9/wapm-cli-darwin-aarch64.tar.gz
installing: /Users/masahiro-kondo/.wasmer
Information

今回は curl https://get.wasmer.io -sSfL | sh でインストールしていた Wasmer をアップデートしました。このコマンドを再実行することでも更新可能です。また、Wasmer は Homebrew などのパッケージマネージャーでもインストールできます。詳しくはインストーラーのリポジトリの README を参照してください。

GitHub - wasmerio/wasmer-install: Wasmer Binary Installer https://wasmer.io/

WASM パッケージの直接実行(wasmer run)

#

3月の記事では WASM のパッケージを wapm install コマンドでローカルにインストールしてから wapm run で実行していましたが、3.0 からはインストールステップをスキップして wasmer run で直接実行できるようになりました[1]

$ wasmer run cowsay hello wasmer!
_______________
< hello wasmer! >
---------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||

wasmer run でリモートのパッケージを直接実行できるようになったので、docker run と同様な感じでパッケージが手軽に利用できるようになりました。

冒頭のアナウンスの記事では python パッケージをダイレクトに実行する例が紹介されています。実際に、WASM で実装された Python インタープリタが起動してきました。

$ wasmer run python/python
Python 3.6.7 (default, Feb 14 2020, 03:17:48)
[Wasm WASI vClang 9.0.0 (https://github.com/llvm/llvm-project 0399d5a9682b3cef7 on generic
Type "help", "copyright", "credits" or "license" for more information.
>>>
Information

wapm.io にはまだ数は少ないですが、このような言語処理系も WASM パッケージとして公開されています。Ruby の irb や JavaScript Engine の SpiderMonkey なども利用可能になっています。

Explore WAPM Packages

各プラットフォーム向けバイナリ生成(wasmer create-exe)

#

create-exe サブコマンドで、各プラットフォーム向けネイティブ実行形式ファイルをクロスコンパイルで生成できるようになっています。

ネイティブコード生成対象として、標準入力からの入力を出力するだけの簡単な WASM を作成して検証してみます。

WASM プロジェクトの準備

#

まず Rust を最新化して WASI 対応 WASM をビルドターゲットに追加します。

rustup update
rustup target add wasm32-wasi

cargo でプロジェクトを作成。

cargo new simple_echo

main.rs を以下のようにしました。

  • main.rs
fn main() {
let mut s = String::new();
std::io::stdin().read_line(&mut s)
.expect("input error at read_line()");
println!("input: {}", s);
}

プロジェクトをビルドすると、target/wasm32-wasi/debug に WASM ファイルが生成されます。

cargo build --target wasm32-wasi

Apple シリコン Mac 用バイナリ生成

#

WASM ファイルが生成されたディレクトリに移動します。

cd target/wasm32-wasi/debug

WASM ファイルを引数にして create-exe でバイナリを生成します。

まず作業している Apple シリコン MacBook 用のバイナリです。ターゲットアーキテクチャのディレクトリ arm64-darwin を事前に作成し、ターゲットプラットフォームを指定せずに create-exe を実行するとバイナリが作成されました。

$ mkdir arm64-darwin
$ wasmer create-exe simple_echo.wasm -o arm64-darwin/simple_echo
Compiler: cranelift
Target: aarch64-apple-darwin
Format: Symbols
Using path `/Users/masahiro-kondo/.wasmer/lib/libwasmer.a` as libwasmer path.
✔ Native executable compiled successfully to `arm64-darwin/simple_echo`.

file コマンドで生成されたバイナリの形式を確認すると Mach-O 64-bit executable arm64 になっています。

$ file arm64-darwin/simple_echo
arm64-darwin/simple_echo: Mach-O 64-bit executable arm64

普通に実行できます。

$ arm64-darwin/simple_echo
hoge
input: hoge

クロスコンパイルで Intel Mac 用バイナリ生成

#

次にクロスコンパイルです。クロスコンパイルにはプログラミング言語 Zig が必要です。筆者は brew でインストールしました。

breww install zig

Intel Mac 用のディレクトリ x86_64-darwin を事前に作成して、--target=x86_64-darwin を指定して create-exe を実行します。かなり時間がかかりますが、うまくいくとバイナリが生成されます。

$ mkidir x84_64-darwin
$ wasmer create-exe simple_echo.wasm --target x86_64-darwin -o x86_64-darwin/simple_echo
Cached tarball to cache path `/Users/masahiro-kondo/.wasmer/cache/wasmer-darwin-amd64.tar.gz`.
Compiler: cranelift
Target: x86_64-unknown-darwin
Format: Symbols
Library Path: /Users/masahiro-kondo/.wasmer/cache/wasmer-darwin-amd64/lib/libwasmer.a
Using zig binary: /opt/homebrew/bin/zig
Using zig target triple: x86_64-macos-none
✔ Cross-compiled executable for `x86_64-unknown-darwin` target compiled successfully to `x86_64-darwin/simple_echo`.

file コマンドで形式を確認。64-bit executable x86_64 になっています。

$ file x86_64-darwin/simple_echo
x86_64-darwin/simple_echo: Mach-O 64-bit executable x86_64

このように、1つの WASM ファイルから、複数のプラットフォーム用のネイティブバイナリをクロスコンパイルで生成できます[2]

WASM ファイルからネイティブコードを生成するメリット

#

これは、各プラットフォーム用のネイティブコードコンパイラや、各言語のクロスコンパイル機能を使用するのとどう違うのでしょうか? Wasmer の公式ブログを見てみます。

WebAssembly as a Universal Binary Format (Part I: Native executables)

以下は Google 翻訳によるものです。

CLI ツールが最終ターゲットとして WebAssembly をターゲットにし始めると、Wasmer に各プラットフォームとチップセットのネイティブ実行可能ファイルを自動的に生成させることができるため、新しいチップと OSS が登場したときに、ソフトウェアを再コンパイルすることを心配する必要はありません。それらは単に機能します。

ネイティブ バイナリは自動的にサンドボックス化され、明示的に決定されない限り、基盤となる OS へのアクセス許可を持たないため、日常的に使用する通常のバイナリよりもはるかに安全です。

Wasmer が「各プラットフォームとチップセットのネイティブ実行可能ファイルを自動的に生成」するため、対象のプラットフォームのネイティブコードコンパイラやツールチェインの整備を待たずに実行可能ファイルの生成が可能ということになります。
さらに、Wasmer から生成されるネイティブコードは Wasmer のサンドボックスモデルを引き継いでいるため、サンドボックスで動作する安全なバイナリであるということができます。

以下のブログでは、このような「ユニバーサル」バイナリ形式が CI やバイナリの配布の手間を軽減してくれることが書かれています。CI でいうと、クロスコンパイルのおかげで、全プラットフォームの仮想マシンやツールチェインを準備する必要がなくなります。

WebAssembly as a Universal Binary Format (Part II: WAPM)

Information

wapm.io の各パッケージも、Exectables リンクからネイティブ実行形式のファイルがダウンロードできるようになっています。

wapm の exectables リンク

プラットフォームの選択

最後に

#

以上、Wasmer 3.0 の新機能を見てみました。フロントエンドのエコシステムでもかなり WASM が使用されるようになっていますが、ブラウザ外でも着々と WASM のエコシステムが整備されて行っているのがわかります。クロスコンパイルに Zig が使用されているのも興味深いですね。


  1. ローカルにパッケージがインストールされていない場合、初回実行時に自動でインストールされます。 ↩︎

  2. Windows の実行形式へのクロスコンパイルも試みましたが、エラーが出てうまくいきませんでした。 ↩︎

豆蔵デベロッパーサイト - 先週のアクセスランキング
  1. 基本から理解するJWTとJWT認証の仕組み (2022-12-08)
  2. Docker+Wasm で WASM をコンテナとして実行する (2023-01-25)
  3. 自然言語処理初心者が「GPT2-japanese」で遊んでみた (2022-07-08)
  4. 直感が理性に大反抗!「モンティ・ホール問題」 (2022-07-04)
  5. Nuxt3入門(第4回) - Nuxtのルーティングを理解する (2022-10-09)
  6. AWS認定資格を12個すべて取得したので勉強したことなどをまとめます (2022-12-12)
  7. Jest再入門 - 関数・モジュールモック編 (2022-07-03)
  8. ORマッパーのTypeORMをTypeScriptで使う (2022-07-27)
  9. Nuxt3入門(第8回) - Nuxt3のuseStateでコンポーネント間で状態を共有する (2022-10-28)
  10. Nuxt3入門(第1回) - Nuxtがサポートするレンダリングモードを理解する (2022-09-25)