Open3

nccc: SDL2のABI抽出実験

okuokuokuoku

抽出ルールの構築

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

抽出するのは:

  • C関数
  • Cマクロ
  • C型(typedef)
  • struct
  • union
  • enum

いわゆるグローバル変数は不要と言える。POSIXであっても非常に限られた数しかない。

okuokuokuoku

抽出

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は殆ど空になる。