Rust/PyO3拡張のwasm wheelを作る
前回はC拡張をwasmにビルドしてPyodideで使う方法をまとめました。今回はRustで書いたPyO3拡張をwasmにビルドしてPyodideで使う方法をまとめます。今回のコードも前回と同じく以下のリポジトリにあります。
環境構築
今回直接使うことになるツールは通常のRust/PyO3プロジェクトと同様 maturin
です
これが pyodide-build
とほぼ同等の作業、つまりPyO3のプロジェクトをビルドしてpyodide用のwheelを作ってくれます。pyodide-build
は裏でEmscriptenのCコンパイラemcc
を呼び出していましたが、 maturin
はRustコンパイラのwasm32-unknown-emscripten
ターゲットを使います。なので rustup
でこのターゲットをインストールしておきます。このターゲットはRustのnightlyビルドでのみ利用可能です(stableにもインストールできますが、実行するとNightlyの機能を使っているので失敗します)。
rustup toolchain install nightly
rustup target add --toolchain nightly wasm32-unknown-emscripten
RustコンパイラはさらにリンカとしてEmscriptenのコンパイラ emcc
を使います。なので前回と同様emsdkをインストールします。
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install 3.1.45
./emsdk activate 3.1.45
source emsdk_env.sh
emsdkのバージョンは前回とあわせておきました。別バージョンだとどうなるのかは検証していません。
Rust/PyO3拡張のビルド
まずは maturin
をインストールします。pip
で用意するのが簡単でしょう
pip install maturin
PyO3プロジェクトを作るには maturin new
を使います。
maturin new -b pyo3 rust-extension
これで rust-extension
というディレクトリが作られます。このディレクトリで maturin build
とすると通常のwheelがビルドされますが、今回はwasm用にビルドします。まずはnightly
コンパイラを使うので rust-toolchain
を書き換えます。
echo "nightly" > rust-extension/rust-toolchain
toolchainファイルについてはrustupのドキュメントを見てください。これでwasm wheelがビルドできます。
cd rust-extension
maturin build --release -o dist --target wasm32-unknown-emscripten -i python3.11
この時インタプリタを -i python3.11
のように指定する必要があることに注意してください。これはおそらく普段はPythonのランタイムがあるのでそこから自動的に取得していますが、今回はpyodideのランタイムはこの段階で存在していないので明示的に指定する必要があるのでしょう。-o dist
はwheelの出力先です。ここにwheelが出来上がります。
dist
└── rust_extension-0.1.0-cp311-cp311-emscripten_3_1_45_wasm32.whl
Node.jsでテストする
出来上がったwheelをGitHub Pages等にアップロードすることで前回みたようにJupyterLiteから使うことができますが、今回は別の方法でテストしましょう。PyodideはブラウザだけでなくNode.jsでも使うことができるので、これを使ってみましょう。
まず適当に npm
環境を用意しておき、 pyodide
をインストールします。
npm install pyodide
これで node_modules
に pyodide
がインストールされて次のように使うことができます
const { loadPyodide } = require("pyodide");
async function hello_python() {
let pyodide = await loadPyodide();
return pyodide.runPythonAsync("1+1");
}
hello_python().then((result) => {
console.log("Python says that 1+1 =", result);
});
node ./test.js # => Python says that 1+1 = 2
このJavaScriptのAPIのリファレンスは以下にあります
これはローカルのファイルシステムにあるwheelも読み込むことができます。
これはCIでテストするのに便利です。
Discussion