haskell-jp / random #104 at 2023-10-15 20:56:37 +0900

かりんとう
直接haskellの部分でなくて恐縮ですが、.hsをコンパイルした.wasmファイルをhtmlに組み込む例を知りたいです。
(ghc-wasm-metaからのwasi-jsとか見ましたがNode向けの内容しか見つけられていません)
進み具合として、wasm32-wasi-ghc により.wasmにはできています。
自分なりにwasmの組み込みかたを検索してhtmlはこうなっています。
!DOCTYPE html
<html lang="ja">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script>
const importObject={wasi_snapshot_preview1:{proc_exit:arg=>arg,fd_close:arg=>arg,fd_write:arg=>arg,fd_seek:arg=>arg,environ_sizes_get:arg=>arg,environ_get:arg=>arg,fd_fdstat_get:arg=>arg,path_open:arg=>arg,path_filestat_get:arg=>arg,path_create_directory:arg=>arg,fd_prestat_get:arg=>arg,fd_prestat_dir_name:arg=>arg,clock_time_get:arg=>arg,fd_fdstat_set_flags:arg=>arg,fd_read:arg=>arg,fd_filestat_set_size:arg=>arg,fd_filestat_get:arg=>arg,poll_oneoff:arg=>arg}};
WebAssembly.instantiateStreaming(fetch('Hello.wasm'),importObject).then(obj=>{
obj.instance.exports.hs_init(0,0);
console.log(obj.instance.exports.test(10));
});
</script>
</body>
</html>
ちなみにここでtestは引数の数値を2倍して返す関数です。で、以下のエラーが出ています。
Hello.wasm:0xb42e Uncaught (in promise) RuntimeError: unreachable
at Hello.wasm._Exit (Hello.wasm:0xb42e)
at Hello.wasm.exit (Hello.wasm:0x176db)
at Hello.wasm.stg_exit (Hello.wasm:0xabf3b)
at Hello.wasm.getProcessTimes (Hello.wasm:0xd513)
at Hello.wasm.stat_startInit (Hello.wasm:0xa904a)
at Hello.wasm.hs_init_ghc (Hello.wasm:0xabcb8)
at Hello.wasm.hs_init (Hello.wasm:0xabc44)
違うアプローチも含めて、解決方法があれば知りたいです。
バックトレースから察するに、 hs_init から getProcessTimes という関数を呼ぶ際に何か問題があってエラーで終了する関数を呼ぼうとしたけど、importしている proc_exit 関数の実装が適切でないから unreachable に達したように見えますね。
見たところ import している WASI の実装がどれも適切でない(全て arg => arg としか書いてない)のが原因でしょう。
WASIの実装をブラウザーで動かす場合、パッと検索してヒットしたものだとこちらの pollyfill はいかがでしょうか。 https://github.com/bjorn3/browser_wasi_shim
あと、 https://github.com/wasmerio/wasmer-js も使えたはずです。
ちなみになんでそんなに簡単じゃないかというと、ブラウザーにはWASIが前提としている、ファイルシステムや標準入出力などに対応する機能の実装方法が何通りも考えられるからです。ユースケースに応じて実装を変えなければなりません。
かりんとう
ありがとうございます。
見つかるのがnpmのインストールが前提条件になっているものばかりですが、
npmが必須な感じなのでしょうか?
(レンタルサーバー上への配置を目標としているので、インストールは避けてファイルの配置で済ませたい、もしかしたらインストールもOKなのかもしれませんが未確認)
ユースケースに応じて実装を変えなければなりません。
それはhtml内に書ける表現で可能でしょうか?
可能なら一例を知りたいです。
今時のJavaScriptのライブラリーなんでnpmでのインストールは避けられないでしょうね。
原則として、npmでプロジェクト向けにインストールしたものはプロジェクトディレクトリーの node_modules ディレクトリーに入るので、node_modulesにあるファイルを import してnode_modules ごとコピーすればレンタルサーバーでの配置は難しくないと思います。
ライブラリーによっては(特に古いものは importで読み込めるES Module になってないので) Vite などのバンドラーも必要になるのでちょっと面倒かも知れませんが、その場合でも Vite でビルドしたものをコピーすればでこるはずです。
かりんとう
node_modulesにあるファイルを import してnode_modules ごとコピー
盲点でした、それでできるかもしれませんね。
今は別のことで立て込みそうなので後になるかもしれませんが試してみます。
igrepさんありがとうございました。