概要
- Go と Godot でAndroid/iOS向けのバイナリ生成は容易
- Linux ではバイナリ互換性と グラフィックス 周りに大きな課題
- musl と glibc の互換性問題が顕著
- musl 対応のため独自パッチやビルド手法を導入
- 静的バイナリ+グラフィックス実現には dlopen 問題の克服が鍵
Linuxバイナリ互換性の壁
- Go の静的バイナリはLinuxサーバーやCLI向けに広く普及
- グラフィックス 利用時はGPUドライバがC ABI経由で動的ライブラリを要求
- glibc と musl 間の互換性問題
- glibc製バイナリはmusl環境で動作不可、逆も同様
- Void Linux (musl版)での実体験
- Zed editorやgraphics.gdプロジェクトのビルド困難
- Goはmusl向け c-shared / c-archive ビルドに未対応
muslサポートのための工夫
- GOOS=musl という独自ビルドターゲットをgraphics.gdに導入
- musl向け c-shared ビルドを廃止、 c-archive でGodotと直接リンク
- これによりmuslサポートを実現
- Linux向けリリース時は glibc版 と musl版 の2種類を用意する必要
- ユーザーに正しいバイナリ選択を促す課題
静的バイナリ+グラフィックスの挑戦
- muslは 静的リンク に優れるため、単一静的バイナリの実現を模索
- Godotは依存ライブラリを内包、残りは動的ロード(dlopen)で対応
- -static 指定でビルドすると「Dynamic loading not supported」エラー
- muslは静的バイナリでの dlopen 実装を拒否
- glibcとmuslの TLS 実装差異が原因
dlopen問題の突破口
- dlopen は弱シンボルとしてコンパイルされるため、自前実装が可能
- C言語のdetour技法やCosmopolitanのdlopen手法が参考
- 小型Cプログラムを組み込んで実行時にホストのダイナミックリンカを呼び出し
- システムのdlopenを「奪い」、graphics.gdに戻る
- アセンブリトランポリンでlibc TLSを切り替えつつ動的関数をラップ
- cgoに類似したアプローチ
シングル静的バイナリ+グラフィックスの実現
- musl+独自dlopen実装で、 Go製シングル静的バイナリ+グラフィックス がLinuxで実現
- どのLinux(3.2以降)でもハードウェアアクセラレーション付きで動作可能
サンプルとクロスコンパイル手順
- Dodge The Creeps サンプルプロジェクトの静的バイナリ公開
- https://release.graphics.gd/dodge_the_creeps.static
- 任意のプロジェクトをクロスコンパイル可能
GOOS=musl GOARCH=amd64 gd buildコマンドexport_presets.cfgを削除して新しいmuslエクスポートプリセットを追加
今後の展望と課題
- helperバイナリ の埋め込みや配布方法の改善
- glibc/musl 混在環境でのユーザー体験向上
- シングルバイナリ配布の標準化に向けたさらなる工夫