lua による imgui 計画の準備として、 libclang
によるバインディング生成器を luajit
に移植してみた。
libclang
に対してはだいだい動くようになって、自身で生成した FFI
で動作するところまでできた。
また、 EmmyLua Annotation
もある程度付与できた。
こいつで、 imgui.h
から luajit FFI を生成する。
libclang
c(c++)ヘッダーを clang_visitChildren
により、カーソルのTree としてパースする。
今回は、 CXChildVisit_Recurse
で全部のカーソルをパースすることにした。
- 同じカーソルが複数個所に現れうる
- 循環しうる(Link List ?)
がありうることを考慮しておく。
clang-c/Index.h
は 6000 カーソルくらいなので問題ないが、 Windows.h
とかは 150000 カーソルとか爆発する。
わりと色んなところで型がネストしていてつらい
- struct の中は namespace なので何でもあり
- anonymous な union や struct のその場定義
- typedef struct などのその場定義
- 関数ポインタのその場定義
要するに、Cのコードの書き方によってどのようなカーソル構造になるかのパターンを知っている必要があって、 パターン毎に分岐して情報を収集する必要がある。 ある型のメンバーの情報を集めていると、ネストした別の型情報が現れる場合があるので切り分ける。
基本的なパターン
FFI では、対象となる関数を起点にその関数が使用するすべての型の定義を取り込む。
カーソルはCのTranslationUnitの木構造をあらわしていて、型をあらわしていない。
カーソルから頑張って型を得る。
型を得られるカーソルは決まっていて、CXCursorType
が宣言Declの系列となる。
TODO
カーソル FunctionDecl
カーソル EnumDecl
カーソル TypedefDecl
カーソル StructDecl
Type Pointer
Type Array
Type Elaborated
Type Record
Type FunctionProto 関数ポインタ pointer => functionproto
union
typedef struct
c++ name mangling
マクロとの戦い
luajit ffi
ffi.cdef
に素直に定義すればいいので、他の言語の FFI に比べて簡単。
はまり。
ffi.load
の返り値が GC されると関数ポインタが死ぬ- pointer は
ffi.new('TYPE[1]')
のようにサイズ1の array で運用する - tostring と ffi.string は違う
- nullptr は nil ?
だいたいよきに計らってくれるので、 rust
の FFI に比べて簡単なのであった。
ひとつだけはまりがあって、 struct
の値渡しができない場合がある。
そういえば、 rust
でも struct
の値渡しではまった記憶が。
rust の場合は、 struct
の値返しが動かなかった。
これ、C の方で pointer 経由で値を返すラッパーを定義する必要があって回避方法はなかった。
ImVec2 ImGui::GetContentRegionAvail()
luajit ffi でもできるか注意が必要だな。
lfs への依存を FFI した Windows API で置き換える
現状、ファイル操作 isExists
, mkDir
のために lfs を使っているのだけど、
FFI で Windows API にアクセスできるようにしたら lfs 無しにできそう。
となれば luarocks も無しにできるので、 必要なのは luajit.exe だけになる。