WASM 使うの難しい
- カテゴリ:
- ソフトウェア/ツール/OSS
- コメント数:
- Comments: 0
◆ wasmer のパッケージをブラウザで使おうとするとうまく動かない
こういうの見つけました
https://github.com/wapm-packages/python
WebAssembly で動く Python のようです
WebAssembly ということはブラウザで動くんでしょうか
ブラウザ上で Python 動かせるというのは面白そうなので試してみることにしました
wasmer なのでブラウザで動かすにはこういうことをすればできるようです
https://docs.wasmer.io/integrations/js/wasi/browser/examples/hello-world
こういうパッケージをインストールして
wasi のセットアップ
コンパイルとインスタンス化して実行
コンパクトにするためにコメントは除去してます
そのへんも見るならリンク先で
パッケージは npm のものなのでブラウザで動かすには import の依存解決が必要です
この例では parcel を使うようです
とりあえずこの通りやってみたのですが 動きません
実行以前の Parcel の依存解決でエラーです
ドキュメントに書かれてるバージョンと最新のバージョンで色々変わってそうなので @wasmer/wasi パッケージのリポジトリを直接見ることにしました
https://github.com/wasmerio/wasmer-js
けっこう違ってます
ブラウザ用の binding とかはいらないみたいで wasmfs もデフォルトで wasi に含まれてるみたいです
wasi.fs で MemFS 型のオブジェクトを取得できて ここの readDir とか rename とか open メソッドを使ってメモリ内ファイルシステムの読み書きをするみたいです
とりあえず @wasmer/wasi だけを残して
という感じで実行しました
ロードするところまでは動いてるのですが instantiate でエラーです
ランタイムエラーとしか出てなくて何が悪いのかわかりません
そもそもブラウザで本当に動くのかってところも怪しかったので 例にもあった helloworld.wasm を試します
https://github.com/wasmerio/docs.wasmer.io/blob/master/integrations/shared/wat/wasi/helloworld.wasm
すると 問題なく動きました
エラーもなく 標準出力に hello world が出てます
なんで Python だと謎のエラーなんでしょう
wasmer-js のリポジトリ内の例はブラウザではなく Node.js だったので同じパッケージをそのまま使って Node.js で試してみます
.js ファイルは基本同じですが fetch で wasm ファイルを取得する部分を Node.js 用に変更します
これで試すと Node.js でもエラーでしたが場所が違って instantiate は成功していました
その後の start の中でランタイムエラーのようです
start はできている以上 標準エラー出力になにか出てないかと見てみると
と Python のエラーが出ていました
エラーは出ているものの一応 Python は動いてそうです
なぜブラウザだとここまで行かないのか不明ですが そもそもこの Python の wasm が動くのかもわからないので 本来の cli で wasmer コマンドを使うことにしました
公式ドキュメントのとおりインストールします
https://docs.wasmer.io/ecosystem/wasmer/getting-started
パッケージマネージャはなくて shell script でのインストールみたいです
fedora35 だと依存ファイルがなくてエラーになったので libxkbcommon-x11 と ncurses-compat-libs を dnf で入れると正常にインストールできました
これで helloworld.wasm は動きます
python.wasm を試してみると PYTHONHOME などの環境変数が無いことのエラーが出ていますが Node.js のときよりも動いています
ただ最終的に locale がどうこうで encodings モジュールをロードしようとして見つからないとエラーになっていました
標準ライブラリは wasm に含まれるわけではなく 別の方法でライブラリの py ファイルにアクセスできるようにしないといけないみたいです
wasmer コマンドだとフォルダのマッピングがありますが ブラウザで動作させることを考えると難しそうです
標準ライブラリの全部のファイルをブラウザがダウンロードして メモリ内ファイルシステムに配置するとかやろうとは思わないです
Node.js 版でのみ出るエラーやブラウザ版でなぜかインスタンス化できないなどの問題もありますし それらを解決できても標準ライブラリの問題もあると考えると 簡単にできるものじゃなさそうです
最初からブラウザを想定されてない WebAssembly パッケージはブラウザで使うのは難しそうです
https://github.com/wapm-packages/python
WebAssembly で動く Python のようです
WebAssembly ということはブラウザで動くんでしょうか
ブラウザ上で Python 動かせるというのは面白そうなので試してみることにしました
wasmer なのでブラウザで動かすにはこういうことをすればできるようです
https://docs.wasmer.io/integrations/js/wasi/browser/examples/hello-world
こういうパッケージをインストールして
import { WASI } from '@wasmer/wasi'
import browserBindings from '@wasmer/wasi/lib/bindings/browser'
import { WasmFs } from '@wasmer/wasmfs'
wasi のセットアップ
const wasmFs = new WasmFs()
let wasi = new WASI({
args: [wasmFilePath, echoStr],
env: {},
bindings: {
...browserBindings,
fs: wasmFs.fs
}
})
コンパイルとインスタンス化して実行
let response = await fetch(pathToWasmFile)
let wasmBytes = new Uint8Array(await response.arrayBuffer())
let wasmModule = await WebAssembly.compile(wasmBytes);
let instance = await WebAssembly.instantiate(wasmModule, {
...wasi.getImports(wasmModule)
});
wasi.start(instance)
コンパクトにするためにコメントは除去してます
そのへんも見るならリンク先で
パッケージは npm のものなのでブラウザで動かすには import の依存解決が必要です
この例では parcel を使うようです
とりあえずこの通りやってみたのですが 動きません
実行以前の Parcel の依存解決でエラーです
ドキュメントに書かれてるバージョンと最新のバージョンで色々変わってそうなので @wasmer/wasi パッケージのリポジトリを直接見ることにしました
https://github.com/wasmerio/wasmer-js
けっこう違ってます
ブラウザ用の binding とかはいらないみたいで wasmfs もデフォルトで wasi に含まれてるみたいです
wasi.fs で MemFS 型のオブジェクトを取得できて ここの readDir とか rename とか open メソッドを使ってメモリ内ファイルシステムの読み書きをするみたいです
とりあえず @wasmer/wasi だけを残して
import { init, WASI } from "@wasmer/wasi"
const main = async () => {
await init()
const wasm_file = "/python.wasm"
const wasi = new WASI({
args,
env: {},
})
const module = await WebAssembly.compileStreaming(fetch(wasm_file))
await wasi.instantiate(module, {})
const exit_code = wasi.start()
const stdout = wasi.getStdoutString()
console.log({ exit_code, stdout })
}
main()
という感じで実行しました
ロードするところまでは動いてるのですが instantiate でエラーです
ランタイムエラーとしか出てなくて何が悪いのかわかりません
そもそもブラウザで本当に動くのかってところも怪しかったので 例にもあった helloworld.wasm を試します
https://github.com/wasmerio/docs.wasmer.io/blob/master/integrations/shared/wat/wasi/helloworld.wasm
すると 問題なく動きました
{exit_code: 0, stdout: 'hello world\n'}
エラーもなく 標準出力に hello world が出てます
なんで Python だと謎のエラーなんでしょう
wasmer-js のリポジトリ内の例はブラウザではなく Node.js だったので同じパッケージをそのまま使って Node.js で試してみます
.js ファイルは基本同じですが fetch で wasm ファイルを取得する部分を Node.js 用に変更します
const buf = fs.readFileSync("./python.wasm")
const module = await WebAssembly.compile(new Uint8Array(buf))
await wasi.instantiate(module, {})
これで試すと Node.js でもエラーでしたが場所が違って instantiate は成功していました
その後の start の中でランタイムエラーのようです
start はできている以上 標準エラー出力になにか出てないかと見てみると
{
stdout: '',
stderr: 'Fatal Python error: failed to get random numbers to initialize Python\n\n'
}
と Python のエラーが出ていました
エラーは出ているものの一応 Python は動いてそうです
なぜブラウザだとここまで行かないのか不明ですが そもそもこの Python の wasm が動くのかもわからないので 本来の cli で wasmer コマンドを使うことにしました
公式ドキュメントのとおりインストールします
https://docs.wasmer.io/ecosystem/wasmer/getting-started
パッケージマネージャはなくて shell script でのインストールみたいです
curl https://get.wasmer.io -sSfL | sh
fedora35 だと依存ファイルがなくてエラーになったので libxkbcommon-x11 と ncurses-compat-libs を dnf で入れると正常にインストールできました
これで helloworld.wasm は動きます
python.wasm を試してみると PYTHONHOME などの環境変数が無いことのエラーが出ていますが Node.js のときよりも動いています
ただ最終的に locale がどうこうで encodings モジュールをロードしようとして見つからないとエラーになっていました
標準ライブラリは wasm に含まれるわけではなく 別の方法でライブラリの py ファイルにアクセスできるようにしないといけないみたいです
wasmer コマンドだとフォルダのマッピングがありますが ブラウザで動作させることを考えると難しそうです
標準ライブラリの全部のファイルをブラウザがダウンロードして メモリ内ファイルシステムに配置するとかやろうとは思わないです
Node.js 版でのみ出るエラーやブラウザ版でなぜかインスタンス化できないなどの問題もありますし それらを解決できても標準ライブラリの問題もあると考えると 簡単にできるものじゃなさそうです
最初からブラウザを想定されてない WebAssembly パッケージはブラウザで使うのは難しそうです