やったことだけ書く備忘録

[続] LuaをWebAssemblyにコンパイルして実行する話

(続き) LuaでもWebAssemblyがしたかった(した)



前回に続いて一通り動かせるようになったの書きます。できるようになったのは以下の通り:



複数の型付き引数、戻り値の型指定ができるようになった



これができないと全く実用性がないのでサポートしました。

方法については色々悩んだ結果、JSのpackage.jsonっぽくdefinition.ymlという設定ファイルに定義して、それを元にコンパイルすることで実現しました。

例えば、




# エントリーファイル。webpackとかrollupでいうinput的なもの
entry_file: hello_world.lua

# 関数の型定義。ここに書いたものだけが実際にWASMにエクスポートされる
functions:
hello_world:
args:
- int
- string
return: string

# 依存モジュール定義。luarocksで入る
dependencies:
- xxx
- yyy


というような定義を書くと、引数がint, stringで2つ、戻り値がstringのhello_worldという関数がWASMで定義されるようになります。複数の関数もフィールド追加で可能です。

Lua側では、エクスポートする関数をグローバル空間に定義する必要があります。つまり、通常は local キーワードでローカル関数にしますが、あえてキーワードをつけずに定義します。
グローバル関数どうなのよとは思いますが、Cから関数呼ぶのが簡単だったので。




function hello_world(numstr)
    return (
'Hello World!, args: %d and %s'):format(numstr)
end
 


とすることで定義と一致させます。関数の存在チェックは実行時に行うので、コンパイルは通っても実行時に関数が未定義のエラーになる可能性はあります。
この辺はコンパイル時に検証しても良かったですが、後述の通り生成スクリプトをPythonにしてしまったので、Luaランタイムを触らなくなりました。とりあえずは定義を信頼するということで。



依存モジュールをバンドルできるようになった



上の定義ファイルで dependencies の配列に記述したLuarocksのモジュール(インストール時にコンパイルするCライブラリも含めて)をWASMにバンドルできるようにしました。これもできないと実用性低いなと思ったので。
やってることは、luarocksコマンドに --tree=[dir] というオプションを渡すと、そのディレクトリ内にモジュールを配置してくれる(パスは通ってない)ので、一時的にここにインストールして、ツリー構造に従って再帰的にライブラリを探索、Luaファイルは中身をバンドルし、Cライブラリはemccのコンパイル時にLinkさせるようにしています。とりあえずCライブラリを使う luaposix というLua向けのPOSIXライブラリをバンドルできたので、他のでも同じく行けるはず。他、自作モジュールは src/ 以下に配置するとバンドルします。



生成手法



必要なファイルを集めてきて、WASMにコンパイル可能なCファイルを生成、ライブラリをリンクしつつemccでコンパイルする、という手順を取っています。コンパイル可能なCファイルの生成はかなり辛い感じでした。
他、Luaにはpakcage.searcherに自作関数を定義できて、require(module)とした時にtableに入れておいてたスクリプト文字列をload(いわゆるeval)して解決させることができたり、色々やっています。
初めはこれもLuaで書いていたんですが、結局便利じゃんってことで生成スクリプトはPythonにしました。Luaでもできそうなので機会があれば書き直すかも。

これにより、必要なランタイムやライブラリが多岐にわたってしまったので、やはりdocker image上で生成してもらうのが良いかと思います。



実行速度



体感として遅いです。というのは、各関数の起動時にLuaのC APIである lua_Stateを生成して、ライブラリをロードして、関数を呼び出して結果を返し、lua_Stateを閉じるようなことをやっているからだと思います。
WASMでもmain()関数は実行されるので、そこでlua_Stateを開いて、それを使いまわした方がいいのかな、とも思いますが、じゃあどこでstateをcloseするんだってことで、今は逐一Lua VMを起動している感じになっています。この辺詳しい人にアドバイスもらいたい、、、



とりあえず



LuaでもWebAssemblyができるようになりました。ホントはtable -> JSON string みたいなものやりたかったけど、大体できて満足したので、とりあえずこれで。
また時間見つけたら実装追加していきたいなーと思います。

ysugimoto/webassembly-luaでやっているので、こうした方が良いとかあればPR/Issueお待ちしております :-)

現場からは以上です。

« 前の記事 次の記事 »