こんにちは、高木です。

今年に入ってから作り始めたC++によるTcl/Tkのラッパーライブラリには、設計上検討しないといけないことが山のようにあります。
大まかな方針は最初に決めたとおりですが、細かいところは都度決めていかなければなりません。

今回は、ラッパーライブラリでTk_Main関数を使えるかどうかについてです。

Tk_Main関数というのはTk APIの関数で、Tcl/Tkアプリケーションのメイン処理です。
この関数に、Cのmain関数の引数argcとargv、それからユーザー定義のTcl_AppInit関数を渡すことでアプリケーションが動く仕組みです。

Tk_Main関数の中で定型的な処理をやってくれているので、便利といえば便利です。
Tcl_FindExecutable関数を呼び出し、インタープリタを作成し、メモリを初期化し、……、Tk_MainLoop関数を呼び出し、最後はTcl_Exit関数でプロセスを終了させます。

大体は悪くないんです。
というか、ぜひ使いたいんです。
けれども、最後の最後、Tcl_Exit関数の呼び出しだけが余計なんです。

今回のラッパーライブラリでは、Tcl/Tkは専用のスレッドの中に閉じ込める方針にしています。
一応、Tcl_SetExitProc関数でTcl_ExitThreadを呼び出すだけの関数を登録しておけば、Tcl_Exit関数の中でTcl_ExitThread関数が呼び出されますので、プロセスごと落ちることは回避できます。
あるいは同じように、Tcl_SetExitProc関数でlongjmp関数で脱出する関数を登録するという方法もないわけではありません。
ただ、どちらもトリッキーですし、何とも不健全な感が否めません。

Tkのさまざまな言語バインディングを見ても、Tk_MainLoop関数に相当する機能を自分で呼び出すようにしています。
なので、今回のラッパーライブラリでも同じようにしてもいいのかもしれません。

いろいろ考えた結果、Tk_Main関数相当の機能は別途実装することにしました。
そして、内部でTcl_Exit関数やTcl_ExitThread関数を呼び出すのではなく、Tcl_Finalize関数を呼び出してそのまま呼び出し元に戻るようにしたいと思います。

最近はTcl/Tkのバージョンアップの速度も緩やかですので、将来的な互換性の懸念もそう大きくないでしょう。