wasi-sdkを利用してさくっとWASMを試す

wasi-sdkを利用してC++のコードWSAMにコンパイルしてみます。
2021.02.24

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、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を作成します。文字列を標準出力に出力する簡単なコードです。

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

コンテナ技術を捨て、 WASIを試す

また、Emscriptenを使わずCのコードをWASMにコンパイルする手順については下記の記事を参考にしています。

Compiling C to WebAssembly and Running It - without Emscripten