自分は、GTKのプログラミングをする際には主にPythonを使っているのですが、たまにC言語で書いてみようか、と思う時があるのですよ。
まぁそれも仕事ではなく私事だし、その上気分転換的な感じなので、惰性的にビルド環境にcmakeを使っていたのですが、GTK的にはmeson推しのようなので、この度mesonを使ってみようかと思います。
あと、リソースを使うことを前提とします。
GTKのリソースについては、以前書いた記事を参考にしてください。
以下、ubuntu23.10での作業を前提としています。
ソースコードの作成
まずは、ソースコードを用意します。
適当なディレクトリに、以下のファイルを用意します。
main.c
main.ui
app.gresource.xml
#include <gtk/gtk.h>
static void on_activate(GApplication *app, gpointer cb_data)
{
GtkBuilder *builder;
GtkWidget *window;
builder = gtk_builder_new();
gtk_builder_add_from_resource(builder, "/com/example/example01/main.ui", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
gtk_window_set_application(GTK_WINDOW(window), GTK_APPLICATION(app));
gtk_widget_set_visible(window, TRUE);
g_object_unref(G_OBJECT(builder));
}
int main(int argc, char *argv[])
{
GtkApplication *app;
app = gtk_application_new(NULL, 0);
g_signal_connect(G_OBJECT(app), "activate", G_CALLBACK(on_activate), NULL);
return g_application_run(G_APPLICATION(app), argc, argv);
}
<?xml version="1.0" encoding="utf-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="default-width">300</property>
<child>
<object class="GtkLabel">
<property name="label">Hello, world!</property>
</object>
</child>
</object>
</interface>
<?xml version="1.0" encoding="utf-8"?>
<gresources>
<gresource prefix="/com/example/example01">
<file preprocess="xml-stripblanks">main.ui</file>
</gresource>
</gresources>
まずは、これらをmesonもcmakeも使わずにビルドしてみます。
ubuntuであれば、以下のコマンドで必要なパッケージをインストールします。
sudo apt install -y build-essential libgtk-4-dev libxml2-utils
以下のコマンドでビルドします。
glib-compile-resources app.gresource.xml --target resource.c --generate-source && \
gcc main.c resource.c $(pkg-config --cflags --libs gtk4)
ビルドが成功すると、「a.out
」という実行ファイルが作成されるので、実行してみます。
./a.out
とりあえず確認が取れたら、今回のビルドで作られた「resource.c
」と「a.out
」は削除しておきましょう。
mesonでビルドする。
mesonでビルドしてみます。
まずは、mesonをインストールしなければなりません。
「aptを使ってインストールする」方法と「pipを使ってインストールする」方法がありますが、今回はaptを使います。
sudo apt install -y meson
mesonでビルドするには、「meson.build
」というファイルを作成します。
以下の内容にします。
# 「プロジェクト名」と「言語」を指定します。
# 「プロジェクト名」はご自由に。
project('example01', 'c')
# 依存しているライブラリを指定します。
# ライブラリ名は、pkg-configで指定するライブラリ名です。
# また、複数ある場合には、「`gtk4 gmodule-2.0`」というように、文字列でスペース区切りで指定します。
libs = dependency('gtk4')
# リソースをビルドするための指定をします。
# 「dependencies」に、「app.gresource.xml」で含まれているファイルを指定します。
gnome = import('gnome')
resources = gnome.compile_resources('resources', 'app.gresource.xml',
dependencies: [files('main.ui')],
source_dir: [meson.source_root()])
# ビルドする実行ファイルを指定します。
# 実行ファイル名は、今回は先に指定したプロジェクト名と同じ「example01」にしていますが、
# 必ず同じにする必要はありません。
executable('example01', ['main.c', resources],
dependencies: [libs])
リソースをビルドするためのgnome.compile_resources
については、ここに詳細が書かれています。
最初に一回、ビルド環境を構築します。
meson setup build
このコマンドにより、「build」というディレクトリが作成されます。
このディレクトリの名前は、別に何でも構いません。
このディレクトリに、ビルドの際に作成されるファイルが出力されます。
(一般的に、gitなどのバージョン管理をしないファイルです)
次に、ビルドを行います。
meson compile -C build
正常にビルドが行われれば、buildディレクトリに実行ファイル(今回はexecutable
にexample01
と指定したので、example01
というファイル)が作成されます。
これを実行して、動作を確認します。
./build/example01
ソースファイルを変更した際には、「meson compile
」コマンドを実行してビルドすればよいです。
ついでに、cmakeでビルドする。
ついでなんで、今までやっていたcmakeでのビルドもしてみましょうか。
先のmesonでのビルドを行った場合は、一旦buildディレクトリを削除しておいてください。
cmakeでビルドするための、「CMakeLists.txt
」ファイルを作成します。
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
PROJECT(example01)
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(LIBS REQUIRED gtk4)
INCLUDE_DIRECTORIES(${LIBS_INCLUDE_DIRS})
ADD_CUSTOM_COMMAND(
OUTPUT resource.c
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && glib-compile-resources app.gresource.xml --target ${CMAKE_CURRENT_BINARY_DIR}/resource.c --generate-source
DEPENDS
app.gresource.xml
main.ui
)
ADD_EXECUTABLE(example01
main.c
resource.c
)
TARGET_LINK_LIBRARIES(example01 ${LIBS_LIBRARIES})
cmakeのパッケージをインストールします。
sudo apt install cmake
cmakeでビルドするためのセットアップを行います。
mesonと同様に、build
というディレクトリを作り、そこにビルドの際に作成されるファイルが出力されるようにします。
mkdir build && pushd build && cmake .. && popd
ビルドを行います。
make -C build
mesonと同じように実行ファイルは「example01
」にしてありますので、実行します。
./build/example01
ハマりポイント
冒頭でも書いたとおり、GTKのリソースを使う点が今回の話のポイントなのですが、特に問題なのが glib-compile-resources
コマンドを実行するにはapp.gresource.xml
があるディレクトリで実行しなければならない点。
というのも、中に書かれているファイルパス(今回の例では、main.ui
など)は、app.gresource.xml
からの相対パスではなく、実行時のカレントディレクトリからの相対パスとして処理されてしまうのです。
なので、mesonもcmakeも、ソースディレクトリで実行するようにしています。