はじめに
WebAssembly というのは、WebAP のフロントエンド開発において高速さと堅牢さを実現するために生み出された技術です。
これを利用して、WebAP 以外でも WebAssembly を利用してポータビリティを向上させるための技術が WASI (WebAssembly System Interface) です。
WASI はまだ発展途上ではありますが、wasmtime という WASI の参照実装が開発されています。
これを利用して Python から WebAssembly の呼び出しを行います。
Python から WebAssembly 呼び出し
動作環境
- Windows 11
- WSL Ubuntu 20.04
- Python 3.8.10
- wasmtime 0.40.0
事前準備
WSL ディストリビューションの複製(非必須)
お試しで実行する場合は WSL Ubuntu イメージを複製しておくのがお勧めです。
本手順は必須ではありません。
各種インストール
初めに、Ubuntu パッケージを最新化しておきます。
$ sudo apt update
$ sudo apt upgrade
python パッケージをインストールするための pip をインストールします。
$ sudo apt install python3-pip
次に、pip から wasmtime をインストールします。
$ pip install wasmtime
WebAssembly コード
今回使用する WebAssembly のサンプルコードです。
(module
(func (export "add_int")
(param $value_1 i32) (param $value_2 i32)
(result i32)
local.get $value_1
local.get $value_2
i32.add
)
)
2つの整数を足し合わせる add_int メソッドを定義しています。
3行目の param
句が引数を定義しています。
4行目の result
で戻り値の型を指定しています。
5~6行目の local.get
では、それぞれの引数の値をスタックに積んでいます。
7行目の i32.add
でスタックから整数を2つポップして足し算し、この結果を再度スタックに積んでいます。
最終的にスタックに残った整数値が result として返却されます。
Python コード
シンプルに呼び出し
Python コードから WebAssembly を呼び出すには2つ手法があります。
まずはシンプルな呼び出し方法です。
import wasmtime.loader # noqa
import sample # type: ignore
print(sample.add_int(3, 5))
1行目で wasmtime.loader
をインポートしています。
これをインポートすることで、WebAssembly の呼び出しを簡略化することができます。
flake8 より未使用 import の警告が発生するため # noqa
のコメントを挿入しています。
2行目では WebAssembly をインポートしています。
今回は sample.wat としてファイルを保存しましたので、ここから拡張子を除いた sample をインポートします。
Pylance からインポートの解決失敗の警告が発生するため、これを無視する目的で # type: ignore
のコメントを挿入しています。
メインのコードは4行目のみです。sample.add_int
を呼び出し、3 + 5 の演算をさせます。
$ python3 main_simple.py
8
冗長に呼び出し
次に冗長な呼び出し方法です。
カスタマイズが必要なケースでは、こちらの手法を用いることになります。
なお、下記のページに公式ドキュメントがありますが、記事執筆時点(2022/09/18)ではドキュメントが古いようで、各種仕様が正しくありません。
wasmtime 0.40.0 で動作するよう、適宜見直しをしています。
import wasmtime
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, "sample.wat")
instance = wasmtime.Instance(store, module, [])
add_int = instance.exports(store)["add_int"]
print(add_int(store, 3, 5))
実行結果はシンプルな呼び出し方法と同じです。
3 + 5 の結果が返却されます。
$ python3 main_verbose.py
8