C言語からNimを呼び出す調査
謎ポイント
- サイズは小さくできないのか
-
NimMain
の呼び出しは必須なのか
別に容量がカツカツの環境で使う気は無いので問題は無いのだがNimで生成した.lib
ファイルのサイズが大きい。
具体的にはCで書いてビルドしたものは2kb程度でNimだと120kb程度ある。
GCを切り替えてサイズ重視の最適化をすると44kbまで小さくなるが、比較すると大きい。
参考としてZig言語で最適化有でビルドすると2kbとCと同程度まで小さくなる。
nim c --gc:arc --define:release --opt:size --app:staticLib --noMain --nimcache:nim-cache --header fib.nim
ドキュメントを見るとNimMain
はGC周りの処理のために初期化が必要とあるが--gc:arc
を指定しても必要なんだろうか?
適当にオブジェクトをnew
してみたところNimMain
の呼び出し無しではデフォルトのGCは呼び出した瞬間に落ちたが、Arcを指定していた場合は特に呼び出さなくても機能した。
生成された.c
ファイルを見ても大したことは書かれていないのだがIO関連とか初期化しているっぽいので呼ばないのはマズそうな雰囲気。
でもArcのテスト時にstrformat
を呼んだ状態でIOへの出力(echo)をしてるんだよなぁ。少なくともArcは機能していたのでリーク関連は心配無さそうだし、中で何やってるんだろうか?
何でNimMain
の呼び出しが必要か気になるかというと
- ライブラリとして使うときに初期化を挟むのが面倒
- マルチスレッド環境で問題が無いか気になる(後述するエンジンとの兼ね合い
マルチスレッドで呼ぶ前に初期化すればいい気もするけど意識したくない。適当に呼び出して機能してほしい。
スタティックライブラリにビルドするのは前座で本命はDLLを生成してHotReloadして最終的にはDLLをプラグインの単位として動的に読み込むゲームエンジン(OurMachinery)と組み合わせる。
その際にDLLのリロード自体はエンジン側で管理されて呼び出しされるので、独自の初期化が必須だと面倒なことになりそうだなと。
直で呼び出した場合に問題が有るとCを1枚間に挟む事になるけど、そうなるとHotReloadのイベントをエンジン側が取得できない気がするぞ...。
スタティックライブラリにしてCのプロジェクト側に埋め込んでCプロジェクトのリビルドでDLLを再生成すれば取れるか。
別にNimで直接DLLを生成してHotReloadを試す必要が無いな。
もう一つの謎ポイントとしては複数のライブラリをNimで書いて1つのプロジェクトでC側から呼び出す場合にNimMain
はどういう扱いになるんだろうか。
NimMain
については呼び出し必須。
関数単位で完結している場合は大丈夫だと思うがNimはトップレベルに書かれているコードが実行できる言語で、モジュールにそういったコードが有る場合はモジュールをimportした場合に動作するがNimMain
を呼ばないとそれらが呼び出されない。
自分で書く分には担保できるが外部のコードが使っていない保証は出来ないので呼び出す必要がある。
Nim製ライブラリの複数呼び出しについてはシンボルが重複するとアウトなのでダメなのでは。
static
を付けてリンケージを内部に限定すれば問題ないがヘッダに書かれているという事は公開された関数なわけで、そうなるとシンボルの重複でアウト。
試してみたけど普通に衝突するなこれ。
NimとCの連携について
Cを呼び出す例は割と有るけどCからNimを呼び出す例は公式ドキュメント以外の記述が見つからない。
公式のドキュメントも積極的に更新されている感じも無い。
まあ、Cをメイン開発言語として新規で開発することはほぼ無いだろうし、前から動いているところにNimを導入することも無いだろうからしょうがない。
既存のCライブラリを呼び出せれば十分な場合がほとんどだろう。
単純に呼び出すのは楽なんだけどビルドシステムを構築するのが面倒くさそう。
当たり前だけどNimbleはCコードの面倒を見てくれないし、メイン言語側のCはビルドシステムが死んでいるのでNimの面倒を見るのはキツイ。
が、メイン言語がサブ側の言語の面倒を見るのが筋だと思うのでシステムコマンドでnimbleを呼び出しつつ連携する運用になるか?
今回はZigをコンパイラ兼ビルドシステムとして運用。
ZigがおかしいんだけどZigならCコードと相互運用できるんだよなぁ。
Cを呼び出すことに関しては問題ないんだけどCから呼び出すのは結構つらい。
特に関数名の衝突はコチラでハンドリングできないところでのお話なので面倒くさい。
呼び出しが簡単だったのでCからもイケるでしょと思ったら割ときつかった。
Nimをメイン言語にすれば問題ない話ではあるんだけどね。
RustもそうだがCは隔絶された世界のものとして基本触れない方針なんだろう。
そもそも他言語と積極的に相互運用するケースとか想定してないだろうし(ライブラリのバックエンドとして呼び出すのは別として)
他言語ageをしたいわけじゃないけどZigの良さというかZigの異端さを実感できた。Zigの開発者が「Cは怖い兄だけど仲良く接する」みたいな事をどこかで書いていた気がするが、大体の言語は怖いモノとして触れたがってないからなぁ(だからこそのReplace-Cなんだろうけど)
とりあえずNimでDLL吐き出しても扱うのは面倒くさそうなのでスタティックライブラリ出すところまでで止めておこう。
単純にNimの中で生きていく方が色々と平穏に過ごせそう。