MSYS2 MinGW GCC 環境をつくる (その 3) です。今回は、 GTK+アプリケーションの作成に必要なライブラリのインストールと構成をして、 実際に簡単な GTK+アプリケーションを作成します。
MSYS2 環境を構築して MinGW gcc コンパイラをインストールする方法、 Eclipse CDT をインストールして MinGW gcc コンパイラを使用する方法については前回および前々回の記事を参照してください。
GTK+とは
GTK+ (The GIMP Toolkit) は GUI を作成するためのマルチプラットフォーム ・ ツールキットです。小さなアプリケーションにも、 大規模なシステムにも適合します。どのようなアプリケーションを作ることができるのかは、 公式サイトで公開されているスクリーンショットを見ると分かりやすいと思います。
GTK+の末尾には +
が付いていますが、 この +
は C++の +
とは関係がありません。GTK+は (C++ではなく) C 言語でも使える C API となっています。もちろん、 C++からも C API を呼び出すことはできるので、 C++から GTK+を使うことはできます。
gtkmmとは
C++から GTK+の API を使うこともできますが、 どうせならオブジェクト指向のクラスライブラリのほうが嬉しいですよね。
そこで登場するのが gtkmm です。gtkmm は GTK+の公式な C++インターフェースです。C++を使うのであれば、 GTK+を直接使うよりも gtkmm を使ったほうが絶対に便利です。
- 元々は
gtk--
という名前でしたが、--
(minus minus) をmm
として、 現在の gtkmm という名前になりました。
2018 年 1 月時点で、 主に使われている GTK+バージョンには 2.4
系と 3.0
系の 2 系統があります。今回は gtkmm 3.0
を使って GTK+アプリケーションを作っていきます。
必要なライブラリをインストールする
まずは必要なライブラリのインストールです。これまでに gcc をインストールしたのと同様、 MSYS2 なら簡単に GTK+アプリケーション開発に必要なライブラリをインストールすることができます。
C:\msys64\mingw64.exe
を起動して、 gtkmm
パッケージを検索します。
gtkmmを含むパッケージを検索するコマンド$ pacman -Ssq gtkmm
4 つのパッケージが見つかりました。
mingw-w64-i686-gtkmm
gtkmm 2.4 系 (32 ビット版)mingw-w64-i686-gtkmm3
gtkmm 3.0 系 (32 ビット版)mingw-w64-x86_64-gtkmm
gtkmm 2.4 系 (64 ビット版)mingw-w64-x86_64-gtkmm3
gtkmm 3.0 系 (64 ビット版)
今回使用するのは、 mingw-w64-x86_64-gtkmm3
gtkmm 3.0 系 (64 ビット版) になります。さっそく、 インストールしていきましょう。
gtkmm3(64ビット版)をインストールするコマンド$ pacman -S mingw-w64-x86_64-gtkmm3
mingw-w64-x86_64-gtkmm3
が依存するパッケージが自動的に表示されます。中には mingw-w64-x86_64-gtk3-3.22.26-1
なども見えますね。
「インストールを行いますか?」 の確認メッセージで Y を押してから、 Enter キーを押すと、 gtkmm と必要なパッケージがまとめてインストールされます。
パッケージ数が多いのでインストール完了まで少し時間がかかります。ゆっくりと待ちましょう。
pkg-configをインストールする
pkg-config も一緒にインストールしておきます。
pkg-configを含むパッケージを検索するコマンド$ pacman -Ssq pkg-config
5 つのパッケージが見つかりました。もう慣れてきましたよね。MinGW 64 ビット版ということで mingw-w64-x86_64-pkg-config
パッケージをインストールします。
mingw-w64-x86_64-pkg-configパッケージをインストールするコマンド$ pacman -S mingw-w64-x86_64-pkg-config
「インストールを行いますか?」 の確認メッセージが表示されるので、 Y を押してから、 Enter キーを押します。
これで pkg-config
コマンドが使えるようになりました。
pkg-configとは
GTK+アプリケーションをビルドするには数多くのライブラリをリンクする必要があります。ヘッダーファイルやライブラリのパスが分散しているため、 コンパイルおよびリンク時にヘッダーファイルやライブラリを指定するのが非常に煩雑です。
本来は GTK+アプリケーションのコンパイル時に以下のような指定が必要になります。
g++ myapp.cpp -IC:/msys64/mingw64/include/gtkmm-3.0 -IC:/msys64/mingw64/include/gtk-3.0 ¥
-LC:/msys64/mingw64/lib -lgtkmm-3.0 -lgtk-3 -lgdk-3 -lgdi32 -lole32
実際にはもっと多くのヘッダーファイル、 ライブラリが必要でもっと引数は長くなります。
大変ですよね。このコンパイル時の引数指定を簡略化してくるのが、 pkg-config
です。
gtkmm-3.0のコンパイルに必要な引数を表示するコマンド$ pkg-config gtkmm-3.0 --cflags --libs
このように引数に gtkmm-3.0
を指定して pkg-config
を実行するとコンパイル時に必要な引数を出力してくれます。
pkg-config
のオプション --cflags
はコンパイル時に必要となるヘッダーファイルなどを出力します。オプション --libs
はリンク時に必要となるライブラリなどを出力します。
pkg-config
はたくさんの引数を手書きしなくて済むだけでなく、 プラットフォーム依存を解決する役割も持っています。たとえば、 MinGW (Windows) で pkg-config gtkmm-3.0 --libs
を実行した場合の出力には -lgdi32
や -lole32
など Windows 固有のライブラリも出力されますが、 Ubuntu (Linux) で pkg-config gtkmm-3.0 --libs
を実行してもこれらのライブラリは出力されず、 代わりに Ubuntu (Linux) 固有の出力がされます。
つまり、 pkg-config gtkmm-3.0
を使うと、 プラットフォームごとに適切なコンパイル引数が指定できるわけです。
具体的な使い方は Makefile
を書くときに説明していきます。
簡単なGTK+アプリケーションを作る
さて、 簡単な GTK+アプリケーションを作っていきましょう。
Eclipse CDT を起動して、 C++プロジェクト sample-gtkmm
を作ります。C++プロジェクトの作り方や構成方法が分からなくなってしまった場合は前回の記事を読み返してみてください。
MyWindowクラスの作成
最初にウィンドウ ・ クラスを作ります。クラスは src
フォルダーを選択して、 右クリック、 New → Class で作成することができます。
クラス作成ダイアログが表示されるので、 Class name に MyWindow
と入力して Finish をクリックします。(Namespace のチェックは外しておきます。)
これで MyWindow
クラスを構成するソースコード MyWindow.cpp
とヘッダーファイル MyWindow.h
の雛形が自動的に作成されます。
それぞれのファイルは以下のようになっています。
MyWindow.h#ifndef MYWINDOW_H_
#define MYWINDOW_H_
class MyWindow {
public:
MyWindow();
virtual ~MyWindow();
};
#endif /* MYWINDOW_H_ */
MyWindow.cpp#include "MyWindow.h"
MyWindow::MyWindow() {
// TODO Auto-generated constructor stub
}
MyWindow::~MyWindow() {
// TODO Auto-generated destructor stub
}
これらのファイルを以下の内容に変更します。
MyWindow.h(変更後)#ifndef MYWINDOW_H_
#define MYWINDOW_H_
#include <gtkmm.h>
class MyWindow : public Gtk::Window {
public:
MyWindow();
virtual ~MyWindow();
protected:
Gtk::Button btn1;
};
#endif /* MYWINDOW_H_ */
MyWindow.cpp(変更後)#include "MyWindow.h"
MyWindow::MyWindow()
: btn1("Hello, World!!")
{
set_default_size(320, 240);
add(btn1);
show_all();
}
MyWindow::~MyWindow() {
}
- まだコードの意味が分からないかもしれませんが、 まずは、 GTK+アプリケーションのビルドの仕方を説明させてください。GTK+アプリケーションの作り方やソースコードの解説は別の機会に。
ソースコードを変更した後は各所に赤い波線が表示されたり、 エラーを示すマークが表示されます。これは Eclipse CDT が gtkmm を参照できていないために起こっています。後で解決方法を説明していきます。今はこのまま作業を続けて問題ありません。
main.cppの作成
次に、 プログラムのエントリーポイントとなる main.cpp
を作成します。src
フォルダーを選択して、 右クリック、 New → Source File です。
ファイル名 main.cpp
を入力して Finish をクリックします。
main.cpp
ファイルを編集して以下の内容にします。
main.cpp#include <gtkmm.h>
#include "MyWindow.h"
int main(int argc, char* argv[]) {
auto app = Gtk::Application::create(argc, argv);
MyWindow myWindow;
return app->run(myWindow);
}
main.cpp
もエラー表示が出てしまいますが、 今はこのままで問題ありません。
Makefileの作成
Project Explorer でプロジェクト名 sample-gtkmm
を選択して、 右クリック、 New → File を選択します。
File name に Makefile
をと入力して Finish をクリックします。
Makefile
を編集して以下の内容にしてください。
MakefileTARGET=sample-gtkmm
SRC_DIR=./src
OBJ_DIR=./obj
BIN_DIR=./bin
CC = gcc
CXX = g++
CPPFLAGS =
CXXFLAGS = $(shell pkg-config gtkmm-3.0 --cflags)
LDFLAGS =
LOADLIBES =
LDLIBS = $(shell pkg-config gtkmm-3.0 --libs) -lstdc++
EXTENSION:=.cpp
SRC:=$(wildcard $(SRC_DIR)/**/*$(EXTENSION)) $(wildcard $(SRC_DIR)/*$(EXTENSION))
SRC_WITHOUT_PREFIX:=$(patsubst $(SRC_DIR)%,%,$(SRC))
OBJ:=$(addprefix $(OBJ_DIR),$(SRC_WITHOUT_PREFIX:$(EXTENSION)=.o))
$(BIN_DIR)/$(TARGET) : $(OBJ)
@if [ ! -d $(BIN_DIR) ]; then mkdir $(BIN_DIR); fi
$(CC) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(OBJ_DIR)/%.o : $(SRC_DIR)/%$(EXTENSION)
@if [ ! -d $(OBJ_DIR) ]; then mkdir $(OBJ_DIR); fi
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
.PHONY: all clean
all: $(BIN_DIR)/$(TARGET)
clean:
@if [ -d $(OBJ_DIR) ]; then rm -fr $(OBJ_DIR); fi
@if [ -d $(BIN_DIR) ]; then rm -fr $(BIN_DIR); fi
Makefile
の 10 行目と 13 行目に注目してください。
CXXFLAGS = $(shell pkg-config gtkmm-3.0 --cflags)
LDLIBS = $(shell pkg-config gtkmm-3.0 --libs) -lstdc++
pkg-config
が出てきました。$(shell …)
というのは make のコマンドで、 シェルでコマンドを実行してその出力が値になります。つまり、 pkg-config gtkmm-3.0 --cflags
を実行して出力を CXXFLAGS
変数に設定している、 pkg-config gtkmm-3.0 --libs
を実行してその出力に -lstdc++
を加えて LDLIBS
変数に設定している、 ということになります。
Makefile
の後半で、 CXXFLAGS
はコンパイル時の引数に指定されています。同様に LDLIBS
はリンク時の引数に指定されています。
ビルド
Makefile
を作成したら、 プロジェクトをビルドしてみましょう。Eclipse のメニューから Project → Build Project を選択します。
ビルド状況は Console
ビューに表示されます。
pkg-config
の出力が g++
(コンパイル)、 gcc
(リンク) の引数に指定されていることが分かります。
ビルドが成功すると sample-gtkmm
プロジェクトの Binaries
に sample-gtkmm.exe
が表示されます。
実行
sample-gtkmm.exe
を実行してみましょう。sample-gtkmm
プロジェクトを選択して、 右クリック、 Run As → Local C/C++ Application を選択するか、 もしくは Ctrl + F11 を押します。
起動しました!成功です!
Eclipseでgtkmmを参照できるようにする
main.cpp
、 MyWindow.cpp
、 MyWindow.h
にエラー表示が残っているのに、 アプリケーションがビルドできて実行もできました。なんだか不思議ですね。
Makefile
には gtkmm-3.0
に必要なヘッダーファイル、 ライブラリを指定する記述を追加していたのでビルドできました。ですが、 Eclipse は (Makefile
の中に書かれている内容を検出できないため) gtkmm のヘッダーファイルを見つけられずにエラー表示を出してしまします。
Eclipse にも gtkmm に必要なヘッダーファイルの場所を教えてあげる必要があります。
プロジェクト名 sample-gtkmm
を選択して、 右クリック、 Properties を選択するか、 もしくは Alt + Enter を押してプロジェクトのプロパティを表示します。
プロジェクトのプロパティが表示されたら、 C/C++ General
→ Path and Symbols
を開いて、 Includes
タブを表示します。
ここで Add... ボタンをクリックして必要なヘッダーファイルを追加していくと、 Eclipse が gtkmm を参照できない問題が解決するのですが…。必要なヘッダーファイルが多く 1 つずつ追加していくのはとても大変です。
そこで、 pkg-config
の出力を利用して Eclipse にヘッダーファイルを認識させる方法を使いたいと思います。
プロジェクトのプロパティで、 C/C++ Build
→ Environment
を開きます。
この画面は出したままにしておいて、 一度、 pkg-config
コマンドを実行します。
C:\msys64\mingw64.exe
を起動して、 次のコマンドを実行します。
CPLUS_INCLUDE_PATHを取得するコマンド$ pkg-config --cflags-only-I gtkmm-3.0 | sed -e "s/^-I//" | sed -e "s/ -I/;/g"
このコマンドは pkg-config
の出力を sed
で加工して、 ヘッダーファイルのパスを ;
セミコロン区切りで返します。
pkg-config
のオプションは --cflags-only-I
としています。--cflags
とは異なり -mms-bitfields
や -pthread
などの引数は含まれず、 純粋にヘッダーファイルのパスのみが出力されます。
この出力部分をマウスクリック→ドラッグで範囲選択、 右クリックして Copy を選択します。
これで出力内容がクリップボードにコピーされました。Eclipse に戻ります。sample-gtkmm
プロジェクトのプロパティを開いて C/C++ Build
→ Environment
を開いてるはずです。
Add... ボタンをクリックします。
新しい環境変数を設定するダイアログが表示されます。Name には CPLUS_INCLUDE_PATH
と入力します。Value にはクリップボードにコピーした内容 (pkg-config を sed で加工して出力した内容) をペーストします。(Value 欄にフォーカスして Ctrl + v を押せばペーストできます。)
Add to all configurations
にも一応チェックを入れておきましょう。(いまは構成が 1 つしかないのでチェックしなくても同じなのですが一応。)
最後に OK をクリックします。
新しい環境変数 CPLUS_INCLUDE_PATH
が追加され、 値として gtkmm 関連のヘッダーファイルのパスが入っています。
Apply をクリックします。
もう一度、 sample-gtk
プロジェクトのプロパティ、 C/C++ General
→ Path and Symbols
に切り替えて、 Includes
タブを表示します。
なんと! 先程まで空っぽだった Include directories
にたくさんのディレクトリが並んでいます。Eclipse CDT には環境変数 CPLUS_INCLUDE_PATH
を自動的に参照して構成してくれる機能があるのです。
Apply and Close をクリックしてプロパティを閉じます。
これで、 Eclipse も gtkmm に関連するヘッダーファイルを見つけられるようになったので、 main.cpp
、 MyWindow.cpp
、 MyWindow.h
に表示されていたエラーも消えます。
- エラーが消えないときはファイル名をダブルクリックしてみてください。ファイルへのアクセスが発生しないと再チェックされないようです。
コード補完
Eclipse CDT がヘッダーファイルを認識するとエラーが消えるだけではありません。コード補完という嬉しい機能も使えるようになります。
たとえば、 変数 btn1
の後ろに .
(ドット) を入力すると、 メソッドの一覧が表示されて選択できるようになります。これは Eclipse CDT が変数 btn1
の型が Gtk::Button
であることを認識して、 さらに Gtk::Button
の定義をヘッダーファイルから参照してクラスのメンバーを自動的に表示してくれているわけです。
これで開発が捗りそうですね。
簡単な GTK+アプリケーション開発手順の紹介は以上です。