Cocoa 使いが wxWidgets を使ってみる (1)

− インストールと Xcode でのビルド −

(2008/10/26 記)

 近々初めての Intel Mac が我が家に来ることになった。Mac/Windows/Linux を1台のマシンで走らせてみようと思っている。もちろん Mac をメインで使うのだが、必要に迫られれば Windows も使える、というのはある意味安心感がある。Linux は…まあオマケみたいなもんですね。あんまり「必要に迫られる」ことはなさそう。

 こういう環境が手に入るのであれば、クロスプラットフォームのソフト開発にぜひ挑戦してみたい。以前から wxWidgets には興味を持っていたので、この機会に本格的に手をつけることにした。まずは、Mac 上で開発環境を整備して、あれこれいじってみている。

1. インストール

 Mac OS 10.4 には wxWidgets 2.5.3 がインストールされている。ターミナルを開いて次のように打ち込めばわかる。

$ /usr/bin/wx-config --version 2.5.3

 現時点 (2008年10月26日) での wxWidgets の最新版は 2.8.9 なので、これはいかにも古い(まあ、Mac OS 10.4 がすでに古いという話もあるが)。また、動作がバージョンに依存しないようにするために、wxWidgets をスタティックリンクする方針で考えたい。バイナリがやたら大きくなるが、まあたかだか 5~6 MB だし、今どきその程度のサイズは誤差範囲だろう。システム添付のライブラリのバージョンが変わるごとに動作が変わる方が怖い。

 そこで、最新版をスタティックライブラリとしてビルドし直すことにする。公式ダウンロードページから wxMac のソースコードアーカイブをダウンロードして、適当なディレクトリ(ここでは $HOME/Development とした)に展開する。

$ cd $HOME/Development $ tar xzvf wxMac-2.8.9.tar.gz $ cd wxMac-2.8.9

 wxWidgets の configure, build は、トップレベルのディレクトリにビルド専用ディレクトリを作り、その中で行うようになっている。トップレベルが散らからないので助かる。

$ mkdir osx-build $ cd osx-build $ ../configure --with-macos-sdk=/Developer/SDKs/MacOSX10.4u.sdk --with-macosx-version-min=10.4 --enable-universal_binary --disable-shared --with-opengl --enable-unicode --with-libjpeg=builtin --with-libpng=builtin --with-regex=builtin --with-libtiff=builtin --with-zlib=builtin --with-expat=builtin $ make

 configure のオプションだが、今回は 10.4 以降で使える Universal Binary を目標とした。--disable-shared がスタティックライブラリを作る指示。これを有効にすると、--enable-monolithic は指定しない方がよいらしい(参照:Getting Started on OSX - WxWiki)。後ろの方の --with-xxxx=builtin は、libjpeg 等々をすでにインストールしていた場合、バイナリがそれに依存することを防ぐためのもの。

上では見やすくするため行を分けてあるが、実際には configure のオプションはすべて1行で入力する。

 make したあと普通に sudo make install すると、/usr/local 以下にインストールされるが、今回は必要ない。アプリケーションをビルドする時に、$HOME/Development/wxMac-2.8.9 以下の適当なディレクトリを指定してやれば済むから。

 アプリケーションのビルドに必要なコンパイルオプションは、wx-config を使えばわかるようになっている。

# C++ ソースのコンパイル $ $HOME/Development/wxMac-2.8.9/osx-build/wx-config --cppflags -I$HOME/Development/wxMac-2.8.9/osx-build/lib/wx/include/mac-unicode-release-static-2.8 -I$HOME/Development/wxMac-2.8.9/include -I$HOME/Development/wxMac-2.8.9/contrib/include -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D__WXMAC__ # リンク $ $HOME/Development/wxMac-2.8.9/osx-build/wx-config --libs -L$HOME/Development/wxMac-2.8.9/osx-build/lib -arch ppc -arch i386 -framework IOKit -framework Carbon -framework Cocoa -framework System -framework QuickTime -framework OpenGL -framework AGL $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_macu_richtext-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_macu_aui-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_macu_xrc-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_macu_qa-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_macu_html-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_macu_adv-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_macu_core-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_base_carbonu_xml-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_base_carbonu_net-2.8.a $HOME/Development/wxMac-2.8.9/osx-build/lib/libwx_base_carbonu-2.8.a -framework WebKit -lwxregexu-2.8 -lwxexpat-2.8 -lwxtiff-2.8 -lwxjpeg-2.8 -lwxpng-2.8 -lwxzlib-2.8 -lpthread -liconv

"$HOME" と書いたところは、実際にはホームディレクトリへのフルパスが表示されている。また、見やすくするため改行を入れたが、実際には1行で続けて表示される。

 $HOME/Development/wxMac-2.8.9/.../libwx_(ほげほげ).a が並んでいるところは、-lwx_(ほげほげ) と書いても通るような気がするのだが、wx-config の出力は上の通りになる。何か理由があるのだろう。あと、なぜか --cppflags の出力の方には -arch i386 -arch ppc がないので、忘れずに補ってやらないといけない。このへんは、Xcode の設定や Makefile の記述で対応することになる。

2. サンプルプログラムを Xcode でビルドする

 $HOME/Development/wxMac-2.8.9/ の中にサンプルプログラムがたくさん用意されている。これをビルドするには、osx-build/samples または osx-build/demos の中の適当なディレクトリを選び、その中で make すればよい。これだけでちゃんと OS X のアプリケーションバンドルまで作ってくれるあたり、なかなか完成度が高い。ただ、これまで Cocoa で開発してきたプログラムを移植することを考えると、やはり Xcode でビルドできるようにしたいところ。demos/life を例にとると、次のようになる。Xcode は 2.4.1 だが、他のバージョンでも本質的には同じはず。

(1) Xcode の "File / New Project..." で新規の "Carbon Application" を作成する。仮に "wxLife" という名前とする。

(2) プロジェクトディレクトリ (wxLife) の中に "Sources" というディレクトリを作る。

(3) "Sources" ディレクトリに、wxMac-2.8.9/demos/life の中にあるファイルをコピーする。ただし、次のファイルは不要。

(4) Xcode プロジェクトに最初から入っている *_Prefix.pch, main.c, main.nib を削除する。プロジェクトから削除して、"Delete Reference and Files" でファイルごと消してしまって構わない。

(5) Xcode の "Project / Add to Project..." で "Sources" の中のファイルをプロジェクトに加える。"Sources" グループに入れておくと見やすい。なお、"Bitmap" ディレクトリの中のファイルは、加えても加えなくてもどちらでもよい。

dialog.cpplife.cpp から Bitmap/*.xpm ファイルが #include されているのでファイル自体は必要だが、ビルドの際に直接触れる訳ではないので、Xcode が認識している必要はない。

(6) Xcode のプロジェクトウィンドウで、"Targets" の中にある "wxLife" を選び、command-I または "I" アイコンで情報ウィンドウを開く。

(7) "Build" タブを選び、"Configuration" を "All Configurations" にする。

(8) 以下の設定を変更する。

 なお、"Header Search Paths", "Library Search Paths", "Other Linker Flags", "Other C Flags" に並べた値は、"$HOME/Developmenet/wxMac-2.8.9/osx-build/wx-config --cppflags" または ""$HOME/Developmenet/wxMac-2.8.9/osx-build/wx-config --libs core,base" で表示されるものを編集して(不要なものを削って)使う。後者の "core,base" とは、wxWidgets のライブラリ群の中で必要なものだけを選択する指定。

(9) Xcode の "Project / Add to Project..." で以下のフレームワークをプロジェクトに加える。フレームワークは /System/Library/Frameworks の中にある。

IOKit, Carbon, Cocoa, System, QuickTime, OpenGL, AGL, WebKit

 これらのフレームワークも、""$HOME/Developmenet/wxMac-2.8.9/osx-build/wx-config --libs core,base" で表示されるオプションで -framework XXXX という記述から見つければよい。また、"Other Linker Flags" の項に -framework XXXX のまま書き加えてももちろん構わない。

OpenGL なんか使ってないのに -framework OpenGL が必要になっているのは解せんが…

 たぶんこれで普通にビルドできると思う(何か忘れてるかも…)。Debug ビルドで 5.9 MB、Release ビルドで 7.7 MB("Linking" の "Dead Code Stripping" をオンにすると 5.8 MB)だった。一昔前だったら「ええっ、この程度のアプリケーションで 6 MB? こんな重いフレームワーク使えるかっ」と怒ったところだけど、今ならサイズについてはみんなもっと寛容だよね。

 ところで、wxWidgets 2.8.9 付属の Life は wxMac 上では重大な不具合があって、このままだとスタートボタンを押しても盤面が変化しません。下の "Generation" とか "Population" は更新されるので、盤面の更新が正しく行われていないらしい。ライフゲームの基本ができとらんやないか。次のパッチを当てれば直ります。life.cppLifeCanvas::DrawChanged() の最後のあたり。

--- life_original.cpp 2008-10-26 23:39:40.000000000 +0900 +++ life.cpp 2008-10-26 23:00:44.000000000 +0900 @@ -826,6 +826,10 @@ for (size_t m = 0; m < ncells; m++) DrawCell(cells[m].i, cells[m].j, dc); } + +#if __WXMAC__ + Refresh(); +#endif } // event handlers

 画面描画に関しては、プラットフォーム間の動作の違いが一番顕著に現れるところなので、よく注意してテストしないとこういうことが頻繁に起きる。要注意、とメモしておこう。