PHPからWebAssemblyのバイナリを実行するphp-ext-wasmを試してみる
こんにちは、ナカエです。
今回はPHPからWebAssemblyのバイナリを実行するPHPエクステンションphp-ext-wasm(注: experimental)を見つけたのでそれについての記事です。
今回試した環境
- Mac OS(High Sierra)
- PHP 7.2.7
- Rust 1.32.0-nightly
必要なもの
- Rustツールチェイン
- Just (Rust製のビルド自動化ツール)
PHPエクステンションの元となるライブラリがRustで書かれているのでRustツールチェインが必要です。また、ビルド処理はRust製のビルド自動化ツールによってJustfileに記述されています。
準備1. Rustツールチェインのインストール
rustupを使ってインストールします。
rustupのインストール
curl https://sh.rustup.rs -sSf | sh
.bashrcの設定
source ~/.cargo/env
rustのnightlyを入れる
rustup install nightly
rustup default nightly
rustupが使いやすすぎて人生がつらい。
※ 安定リリース版のstableでもいけるかもしれませんが試してません。
準備2. Justのインストール
Homebrewを使います。
brew install just
ビルド
PHPエクステンションのビルド
git clone https://github.com/Hywan/php-ext-wasm
cd php-ext-wasm
# Rustのライブラリのビルド
just rust
# PHPエクステンションのビルド
just php
テストコードの実行
composer install
php -d extension=wasm tests/toy.php
// int(42)
リポジトリの構成
これだけだと味気ないのでリポジトリの構成を見てみましょう。
src/
Rustのライブラリのコードが入っています。このライブラリはWASMのバイナリをインスタンス化して関数を呼び出すAPIを公開します。Rust製のWasmインタープリタwasmiに依存しています。
extension/
PHPエクステンションのコード(lib.rs)が入っています。前述のRustのライブラリのAPIをCのAPIを通じてZend Engineから利用できるようにします。 wasmreadbinary, wasmnewinstance, wasminvokeargumentsbuilder, wasminvoke_function などの関数が含まれます。
headers/
php-ext-wasm.hがjust rust
によるビルド時に生成されます。 このヘッダファイルはPHPエクステンションのビルド時に利用されます。
lib
PHPエクステンションが公開するローレベルな関数を使いやすくするためのPHPクラス群です。 テストコードで利用されている\WASM\Instanceなどを含みます。
tests
テストコードです。先ほど実行していたtests/toy.phpはこのようになっています。
<?php
require_once dirname(__DIR__) . '/vendor/autoload.php';
$instance = new WASM\Instance(__DIR__ . '/toy.wasm');
$result = $instance->sum(5, 37);
var_dump($result);
WebAssemblyのバイナリであるtests/toy.wasmを読み込み、sumという関数を呼び出しているのがわかります。
tests/toy.wasmファイルの元となっているのはtoy.rsです。
#[no_mangle]
pub extern "C" fn sum(x: i32, y: i32) -> i32 {
x + y
}
justfileの記述を見るに、just compile-wasm
でtests/toy.rsからtests/toy.wasmをビルドしているようですが、wasm-gcなどのツールを別途用意しておく必要があるようです。
まとめ
少し複雑な構成ですが、php-ext-wasmはRustのwasmインタープリタを使って作られたwasmバイナリ用のライブラリをCでラップしたPHPエクステンションということですね。 まだパフォーマンスは計測していないので次回以降試したいと思います。