Install wxWidgets 2.8.12 from source on Cygwin with MinGW-w64
自由ソフトとシミュレーションを極めるためにはC++の勉強が必要だ。しかし,モチベーションが上がらない。Pythonで簡単にできることをわざわざC++で倍くらいの行数をかけて作れるようになっても意味がない。それなら,最初からPythonでやったほうがいい。しかし,長期的に考えてC++を勉強しないといけない。C++を勉強する動機付けが必要だった。
簡単なプログラムを作れても今までは全てCUIベースだった。つまり,標準入力から入力を受け付けたりファイルを指定して実行するとかだった。利便性を考えるとGUIがほしいと前から思っていた。単純なプログラムでも標準入力の受付をGUIのダイアログからクリックで選べるようになるだけでかなり違うと思う。GUIプログラムの作成にC++を使えば頑強で便利なものができるはずだ。これで自分のC++の勉強の動機付けとしようと思っ た。
PythonでもGUI作れるが,環境に依存したものになりがちであったりで問題がある。Pythonで作れるものも結局内部でC++を使っていたりするので,それなら最初からC++でやったほうがいいだろう。マルチプラットホームでC++でGUIプログラムを作るにはPythonと同じでQtかwxWidgetsが順当だろう。ライセンスの関係からwxWidgetsがベストだ。
普段の業務では嫌でもWindowsを使うしかないので,Windowsでの開発環境の整備が最大の懸念事項だった。今回はうまくWindowsのCygwin上でMinGW-w64をコンパイラとして使いwxWidgetsをインストールできたのでメモしておく。これによりWindowsで動作するGUI開発環境が手に入る。
Ubuntu 14.04でのインストール
Ubuntu 14.04でのインストールはaptを使えば非常に簡単である。参考として掲載しておく。
以下のコマンドでインストールが終わる。
sudo apt install wx3.0-i18n
ビルド環境
Windows でインストールするにはCygwinを使う。ビルド環境は以下の通り。
Windowsでネイティブに動作させるためにMInGW-w64のコンパイラを使う。
事前にCygwinのsetup-x86.exeでi686-mingw-32-gcc
などを
インストールしておく。なくても大丈夫とは思うが,以下のグラフィック系などの関連ライブラリもインストールしておく。
- png
- tif
- jpge
- zlib
- expat
stowでローカルパッケージを管理している。そのため,インストール先は~/.local/stow/wxWidgets-2.8.12
とした。インストール後にstowコマンドにより~/.local/{bin,lib}
などにリンクを貼っている。
インストール
wxWidgetsの最新版は3.0.1だが,これはうまくmakeできなかったので安定版の2.8.12をインストールした。以下の配布元からファイルをダウンロード・展開してインストールする。
配布元:wxWidgets: Cross-Platform GUI Library http://www.wxwidgets.org/
以下のコマンドを入力(全体をコピーペースト)するとインストールが完了する。
VER=2.8.12
LOCAL=~/.local/
mkdir -p $LOCAL/src
cd $LOCAL/src
wget -nc https://sourceforge.net/projects/wxwindows/files/$VER/wxWidgets-$VER.tar.gz
tar xf wxWidgets-$VER.tar.gz
cd wxWidgets-$VER
./configure --prefix=$LOCAL/stow/wxWidgets-$VER --build=i686-pc-cygwin --host=i686-w64-mingw32 --disable-precomp-headers --enable-unicode --with-sdl --disable-shared --enable-stl
make && make install
cd $LOCAL/stow; stow wxWidgets-$VER
インストールにはだいたい2時間かかった。
configure
によるインストール設定は以下のとおりとなった。
Configured wxWidgets 2.8.12 for `i686-w64-mingw32'
Which GUI toolkit should wxWidgets use? msw Should wxWidgets be compiled into single library? no Should wxWidgets be compiled in debug mode? no Should wxWidgets be linked as a shared library? no Should wxWidgets be compiled in Unicode mode? yes What level of wxWidgets compatibility should be enabled? wxWidgets 2.4 no wxWidgets 2.6 yes Which libraries should wxWidgets use? jpeg builtin png builtin regex builtin tiff builtin zlib builtin odbc no expat sys libmspack no sdl yes
wxWidgets プログラムコンパイル時の注意
wxWidgetsを使ったプログラムをコンパイルするときにはいくつか注意が必要なのでここでまとめておく。
- コンパイラには
i686-mingw32-g++
を使う(Windowsのみ) - コンパイルオプションに
$(wx-config --cppflags --libs)
をつける。 - 単独で動作させるためにオプション
"-static-libgcc -static-libstdc++"
をつけてライブラリを埋め込む 。 - コンパイルの引数にはソースコードを必ず
$(wx-config --cppflabs --libs)
の前に持ってくる。
各項目について以下で説明する。
コンパイラにはi686-mingw32-g++を使う(Windowsのみ)
Windows でコンパイルする際には,MinGW-w64のコンパイラi686-mingw32-g++
を使う。これを使わないと,コンパイルできなかったり,できたとして もcygwin1.dllに依存してしまう。毎回i686-mingw32-g++
と入力するのが面倒ならば以前書いた記事(My Future Sight for Past: CygwinでMinGW-w64を使いWindowsネイティブなバイナリを作成)のようにローカルに別名でリンクを貼っておく。
for compiler in gcc gfortran g++
do
ln -sf /usr/bin/i686-w64-mingw32-$compiler.exe ~/.local/bin/$compiler.exe
done
さらに,g₊₊と入力するのも面倒なので,.bashrcで以下のようにaliasを作っておくと楽だ。
alias gpp="g++"
コンパイルオプションに$(wx-config –cppflags –libs)をつける
wxWidgets をインストールするとヘッダーファイルとライブラリの他にwx-config
というコマンドもインストールされる。このコマンドはオプションをつ けて実行するとwxWidgetsのコンパイルに必要なヘッダファイルやライブラリの場所を返してくれる。そのため,以下のようにコンパイル時に引数として渡して,C++のヘッダファイルとライブラリの場所を返すようにする。なお,--cppflags
は--cxxflags
でもよい。
i686-mingw32-g++ hoge.cpp $(wx-config --cppflags --libs)
単独で動作させるためにオプション”- static-libgcc -static-libstdc++”をつけてライブラリを埋め込む
コ ンパイルしたプログラムが単独で動作するようにするために,g++ のオプ ション"-static-libgcc -static-libstdc++"
をつける。これを付けないとlibgccとlibstdc++の入っていない環境では動作しなくなる。具体的には以下のエラーが出る。
error while loading shared libraries: libgcc_s_sjlj-1.dll: cannot open shared object file: No such file or directory
コンパイルの引数にはソースコードを必ず$(wx-config –cppflabs –libs)の前に持ってくる。
コンパイルするときは引数の順番が大事だ。必ず$(wx-config --cppflags --libs)
の前にソースコードを持ってくる。そうしないとエラーが出る。例えば,hello.cpp を以下のように後ろの方に持ってくるとエラーが出る。
gpp $(wx-config --cppflags --libs) -static-libgcc -static-libstdc++ hello.cpp -o b.exe
/tmp/ccmnAftP.o:hello.cpp:(.text+0x4c): undefined reference to `wxAppConsole::CheckBuildOptions(char const*, char const*)'
/tmp/ccmnAftP.o:hello.cpp:(.text+0xdd): undefined reference to `wxEntry(HINSTANCE__*, HINSTANCE__*, char*, int)' /tmp/ccmnAftP.o:hello.cpp:(.text+0x189): undefined reference to `wxMessageBox(wxString const&, wxString const&, long, wxWindow*, int, int)' /usr/lib/gcc/i686-w64-mingw32/4.8.3/../../../../i686-w64-mingw32/bin/ld: /tmp/ccmnAftP.o: bad reloc address 0xf in section `.text$_ZN12wxStringData6UnlockEv[__ZN12wxStringData6UnlockEv]' /usr/lib/gcc/i686-w64-mingw32/4.8.3/../../../../i686-w64-mingw32/bin/ld: final link failed: Invalid operation collect2: error: ld returned 1 exit status
このエラーの原因がわからなくて時間を浪費してしまった。
正しくコンパイルするには以下のようにソースコードhello.cppをwx-config
の前に持ってくる。
gpp -o b.exe hello.cpp $(wx-config --cppflags --libs) -static-libgcc -static-libstdc++
動作確認
インストールがうまくできているか,動作確認を行う。
付属のサンプルのビルド
wxWidgets に付属してくるサンプルを試しにコンパイルしてみる。
cd ~/.local/src/wxWidgets-2.8.12/sample/minimal
Makefile を修正する。EXTRALIBSに-static-libgcc -static-libstc++
を追加。これはg++のオプションで,ライブラリを埋め込むようにする。
vim Makefile
EXTRALIBS = -lz -lrpcrt4 -loleaut32 -lole32 -luuid -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -lctl3d32 -ladvapi32 -lwsock32 -lgdi32 -static-libgcc -static-libstdc++
この修正をしないと,コンパイル後実行すると以下のようにライブラリがないというエラーが出る。
/cygdrive/d/cygwin/home/senooken/.local/src/wxWidgets-2.8.12/samples/minimal/minimal.exe: error while loading shared libraries: libgcc_s_sjlj-1.dll: cannot open shared object file: No such file or directory
修正後以下のコマンドを実行してコンパイル。
make
mininal.exe ができるのでこれを実行する。
./minimal.exe
以下のようにウィンドウ(Windowsでの実行結果)が表示されればOK。コマンドからでなくダブルクリックしても実行できる。
これで確認が完了。
Hello World
Ubuntuのようにインストーラー?でインストールした場合のために,簡単なサンプルでコンパイルできるか試す。サンプルは以下のサイトのものを少し修正したものだ。
参考:wxWidgetshttp://kodamail.sakura.ne.jp/leisure/wiki/wiki.cgi/wxWidgets?lang=jp#9
// hello.cpp
#include <wx/wxprec.h>
#include <wx/wx.h>
class helloApp: public wxApp{
public:
virtual bool OnInit();
};
IMPLEMENT_APP(helloApp)
bool helloApp::OnInit(){
wxMessageBox(wxT("Hello wxWidgets"), wxT("Message Box"), wxOK);
return false;
}
以下のコマンドでコンパイルする。
g++ -o hello.{exe,cpp} $(wx-config --cppflags --libs) -static
./hello.exe
実行結果は以下の通り。
まとめ
CygwinとMinGW-64を使い,WindowsでwxWidgetsをインストールし,GUIプログラムの開発環境を整備した。これでWindowsでも動作するバイナリを作れる。ただし、コンパイルはそれぞれのOSごとに行う必要がある。
あまりwxWidgetsに関する日本語の情報はないので,英語のマニュアルを読むしかない。簡単なものを作りながら,モチベーションを保ちつつC++の勉強をしていきたい。