MacOS対応 / C++ APIのバインディング


GUIアプリってこんなにパッケージング面倒だっけ。。
0.2.8のリリースに向けてWindowsだけでなくOSXでもGUIビルドを用意したい。昔のMacOSのスクラップブック( http://en.wikipedia.org/wiki/Scrapbook_%28Mac_OS%29 )みたいなイメージでScheme式をコピペして保存できるアプリをイメージしてます(まだ出来てないけど)。
MacOSGUIアプリを作るのは地味に面倒で:

  • 通常のコマンドラインアプリケーションのままでもWindowを開いたりできるが、そのままだとMenubar等が与えられない。
    • Classic MacOSの"デスクアクセサリ"みたいな状態になる
  • Resource等を適当なディレクトリに配置する必要がある
  • Info.plist(XML)を書いてアプリケーションの情報を記述しておく

まぁWin32のようにバイナリのリソースにコンパイルするよりは多少楽だけど。。CMakeは組み込みのサポートが有るので、多少のオプション追加でこれらを自動でやってくれる。
ただ、Win32やXと違って、単一バイナリで両対応できない。(不可能ではないと思うけど推奨されていない)

C++ APIバインディング

nmoshにとっては、wxWidgetsが初めての(大規模な)C++ FFIバインディングになる。C APIはかなりstraight forwardにバインディングを書けるけど、C++は色々と難しいポイントが有る:

  • ストレージの確保と開放

今はBoehm GCなのでそんなに熱心に考えていないが、ストレージの確保と開放のタイミングがかなり見づらい。wxWidgetsは、オブジェクトの所有権を常に移譲するスタイルになっている。つまり、AddとかAppendのようなAPIを使ってMenuBarにMenuを追加したりすると、MenuBarを削除したときにMenuも一緒に削除される。これを防ぐためには明示的にRetain(参照カウントの追加)する必要がある。
C++ APIをwrapするときは、ストレージ管理のためにC++の機能を活用したほうがいいかもしれない。つまり、対象ライブラリが使用しているスマートポインタ等の仕組みに乗れるように、VM側も参照カウント方式のオブジェクト管理機構のための準備しておく方が良いように見える。
MessagePackはC++のクラスをシリアライズする機能を簡単に追加できるようなテクニックを提供している( http://wiki.msgpack.org/pages/viewpage.action?pageId=1081387#QuickStartforC%2B%2B-Userdefinedclasses ) 。同様のフレームワークFFI機構側で整備すると、FFIバインディングをより効率的にできるかもしれない。

  • クラスの継承

wxWidgetsのようなC++で書かれたGUIフレームワークは、システムの提供するC++クラスを継承して自分のアプリケーションを書くことが想定されている。nmoshの場合は、FFIのためのクラスを定義して、Schemeアプリケーションはそのクラスの機能の範囲内で書かれることを期待している(= nmoshのバインディングwxWidgetsの全機能を提供することは想定していない)。
悪いことに、GUIフレームワークでは、GUIオブジェクトは殆ど何らかの規定イベントハンドラクラスからの派生という形でつくられている。FFIバインディングで基底クラスのバインディングを作ることで上位のクラスのバインディングを行おうとすると、絶対に多重継承が発生する。事実上、wxWidgets側では基底イベントハンドラは1種類で、すべてのGUIオブジェクトはそれを継承しているので、バインディング側でも1種類しか持てない。
今のところ末端のクラスでイベントハンドラを書くスタイルにしている。これは、イベントハンドラが値を返すケースを懸念しているためで、例えば、Windowに対するCloseイベントはveto(却下)できるが、その時にC++側からクラスのメンバを参照したいようなケースを処理できない。(Scheme側からの参照はScheme側で解決できるので特に問題にならない)
このようなケースが無いなら、単一の基底イベントハンドラに集中させるほうが設計上は簡単に見えるので、試してみたいところ。
この部分は他のwxWidgetsバインディングでも直面しているはずなので、比較してみるといいかもしれない。(定期的に出る議論: フラットなC APIを共通で持って、それに対するバインディングを個々の言語が持つ)