nccc: SDL2のABI抽出実験

POSIXやLinux kernel(のioctlやsysctl類)を試す前にSDL2で実験してみる。SDL2はドキュメントがヘッダ毎に分割されていて好都合なため。

抽出ルールの構築
APIの抽出は ヘッダ単位 に行う。つまり、各ヘッダを #include
するだけのソースコードをそれぞれ生成し、 そのヘッダ自体で定義される 各オブジェクトをABIと見做すことにする。POSIX等ではこれは成立しないので、命名規則や基準型(Window 構造体を取るAPIだったら <window.h>
と見做す みたいな)によるフィルタリングも今後実装が必要になると考えられる。
抽出するのは:
- C関数
- Cマクロ
- C型(typedef)
- struct
- union
- enum
いわゆるグローバル変数は不要と言える。POSIXであっても非常に限られた数しかない。

抽出
ASTのダンプとプリプロセスは適当なソースコードを生成してそれを処理する必要がある。Clangのextract APIは特に必要はない。
file(WRITE apigen.c "#include<SDL.h>\n")
sysroot等の情報は変数に追い出しておく。
set(clang "e:/yunibuild/llvm/bin/clang.exe")
set(headerpaths
e:/repos/em2native-tests/_build/Android@armeabi-v7a/_yfrm_headers/SDL2
)
set(rootheader
SDL.h)
set(headers
# Basics
SDL.h
SDL_hints.h
SDL_error.h
....)
set(includes)
foreach(e ${headerpaths})
list(APPEND includes -I${e})
endforeach()
set(apiheaders)
foreach(e ${headers})
list(APPEND apiheaders ${headerpaths}/${e})
endforeach()
set(sysroot
--sysroot=e:/repos/warpsdk/sysroot
)
ASTダンプ
JSON形式のASTダンプは -Xclang -ast-dump=json
で得られる。JSONは標準出力に出力され、50MiBとかヤベぇサイズになる。
execute_process(COMMAND
${clang} --target=wasm32 ${includes}
${sysroot}
-Xclang -ast-dump=json -c apigen.c
OUTPUT_FILE out.json
)
プリプロセス
ASTダンプはプリプロセス後のソースのASTとなるため、マクロの情報は得られない。マクロの情報を得るためには -E
を -dD
付きで実施する。 #include
が展開されて #define
が残る。
execute_process(COMMAND
${clang} --target=wasm32 ${includes}
${sysroot}
-dD -E apigen.c
OUTPUT_FILE out.i.c
)
Clangには pp-trace
というツールもあるが今回は #define
以降の構文は自前でパースする方向にした。単にマクロになっているシンボルさえ列挙できれば充分だが、いわゆる #line
が解釈できる必要はある(定義位置を抽出する必要があるため)。
extract API
最近のClangでは (主にObjective-CやSwift想定で) API情報JSONを出力できる。
execute_process(COMMAND
${clang} --target=wasm32 ${includes}
${sysroot}
-x c-header ${apiheaders}
-extract-api -o out.apiinfo.json
)
extract-api
はASTのjsonと異なりCマクロを抽出できる。 -x c-header
は抽出対象のヘッダ全てを列挙する必要がある。例えば、ここで SDL.h
のみを書くと SDL.h
で 直接 定義されているAPIやマクロのみが対象となってしまいJSONは殆ど空になる。