wasi-sdkを利用してさくっとWASMを試す
こんにちは、CX事業本部のうらわです。
最近、WebAssembly(以下、WASM)を勉強しています。
C/C++の場合、Emscriptenを使ってWASMにコンパイルできます。この手順はMDN Web Docsにも日本語の記事があります。
今回はEmscriptenではなくClangを使用してC++のコードをWASMにコンパイルする方法を試します。すでに2年前ではありますが、LLVM8.0からターゲットとして生成するバイナリにWASMが正式に対応しています。
参考: WebAssemblyに正式対応した「LLVM 8.0」がリリース
また、ブラウザ外で実行するためのWASMランタイムはwasmtimeを使用します。
環境
Macで実施します。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H15
本記事で記載しているコードやコマンドは以下のリポジトリにまとめてあります。
開発環境について
開発環境の構築にはwasi-sdk
を利用します。wasi-sdk
リポジトリにはWASMの開発に必要なClang, LLVM, wasi-libcが一式用意されています。
MacやLinux等の各環境に応じた圧縮ファイルをダウンロードして展開するだけですぐに利用できます。
This repository contains no compiler or library code itself; it uses git submodules to pull in the upstream Clang and LLVM tree, as well as the wasi-libc tree.
以下のコマンドでMac用のwasi-sdk
の圧縮ファイルをダウンロードし展開します。
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz -O wasi-sdk.tar.gz mkdir -p wasi-sdk && tar xvf wasi-sdk.tar.gz -C wasi-sdk --strip-components 1 rm -rf wasi-sdk.tar.gz
clang++
のバージョンを確認します。
$ ./wasi-sdk/bin/clang++ --version clang version 11.0.0 (https://github.com/llvm/llvm-project 176249bd6732a8044d457092ed932768724a6f06) Target: wasm32-unknown-wasi Thread model: posix
実装とコンパイル
src/main.cpp
を作成します。文字列を標準出力に出力する簡単なコードです。
#include <cstdio> #include <iostream> #include <string> int main() { std::string str = "hello wasi-sdk!"; std::cout << str << std::endl; std::printf("%s\n", str.c_str()); return 0; }
このコードを以下のコマンドでWASMにコンパイルします。build
ディレクトリにsample.wasm
が出力されます。
mkdir build ./wasi-sdk/bin/clang++ --sysroot=./wasi-sdk/share/wasi-sysroot src/main.cpp -o build/sample.wasm
wasmtimeで実行
出力されたWASMをブラウザ外で実行するためにwasmtime
をダウンロードします。こちらもwasi-sdk
と同様、圧縮ファイルをダウンロードして展開します。
wget https://github.com/bytecodealliance/wasmtime/releases/download/v0.23.0/wasmtime-v0.23.0-x86_64-macos.tar.xz -O wasmtime.tar.gz mkdir -p wasmtime && tar xvf wasmtime.tar.gz -C wasmtime --strip-components 1 rm -rf wasmtime.tar.gz
wasmtime
のバージョンを確認します。
$ ./wasmtime/wasmtime --version wasmtime 0.23.0
wasmtime
でWASMを実行してみます。C++のコードに書いた文字列が表示されます。
$ ./wasmtime/wasmtime build/sample.wasm hello wasi-sdk! hello wasi-sdk!
おわりに
非常に簡単なコードですがC++のコードをClangでWASMにコンパイルし、ブラウザ外で実行ができました。
本記事で説明をしていないWebAssembly System Interface(WASI)については下記記事をご参照ください。
Standardizing WASI: A system interface to run WebAssembly outside the web
また、Emscriptenを使わずCのコードをWASMにコンパイルする手順については下記の記事を参考にしています。
Compiling C to WebAssembly and Running It - without Emscripten