Gtk+3でWindows用のパッケージを作る

313, 2021-08-26

目次

Gtk+3でWindows用のパッケージを作る

MSYS2の環境でMinGWのGCCなどを使ってGtk+3をコンパイルすると、Windowsでも動作するGtk+3製のGUIプログラムを作ることが出来ます。
Windows10環境で動作するプログラムを作った後にやってみたいのは、バイナリのパッケージの作成です。
つまり、作ったプログラムをWindows環境でダブルクリックで動くようにするわけです。

MSYS2環境で作成したGtk+3のプログラムをパッケージングするには色々と関連ファイルを集める必要があります。
ネット上にはあまり情報がありませんが(2021年時点)、今回はこのパッケージングについていろいろと試行錯誤してみました。

Gtk+3のパッケージングで気をつけたいことは↓の通りです。

  • パッケージングの方針

  • プログラムのパッケージング

  • Gladeファイルのパッケージング

  • 関連DLLのパッケージング

  • 関連リソースのパッケージング

  • gdk-pixbuf-2.0の存在

  • 最終的なpackageの構造

  • ライセンスについて

パッケージングの方針

パッケージングで必要になるのが↓3つのファイルです。

  • プログラム本体

  • DLLファイル

  • リソースファイル

プログラム本体はexe形式の実行ファイルです。これはコンパイルされて出力されるファイルになります。
それからGtk+3は沢山の外部ライブラリを使っています。これらはDLLファイルとしてMSYS2の環境に存在します。
そしてGtk+3は色々な外部リソースも参照します。これは画像のアイコンだったりがそうです。これもMSYS2の環境に存在します。

パッケージングではこれらの3つのファイル群をpackage/というディレクトリ以下にまとめます。
package/自体の名前は何でもいいです。
私はMakefileでこのpackage/にパッケージングを自動化しています。

mkdirコマンドで任意のディレクトリ以下にこのpackage/ディレクトリを作成しておきます。

$ mkdir package

プログラムのパッケージング

コンパイルして生成されたプログラム本体は今回はprogram.exeとします。
これはbuild/ディレクトリ以下に生成されているという前提です。
これをpackage/以下にコピーします。

$ cp build/program.exe package/

Gladeファイルのパッケージング

Gtk+3ではGUIの構築にGladeというGUI構築エディタが使えます。
このGladeはデザインを.gladeファイルで保存します。

プログラムがこの.gladeファイルを参照しロードする場合は、パッケージにもこの.gladeファイルを含める必要があります。
今回の例では、design/main.gladeというファイルが実際に使われるGladeファイルとします。
これをpackage/以下にコピーします。

$ cp -r design/ package/

関連DLLのパッケージング

プログラムが使用するDLLを調べるにはlddコマンドを使います。
build/ディレクトリ以下に移動して、プログラムが使っているDLLを調べます。

$ cd build
$ ldd program.exe

すると↓のように紐づけられている外部ライブラリが表示されます。

        ...
        libgobject-2.0-0.dll => /mingw64/bin/libgobject-2.0-0.dll (0x00000000)
        libglib-2.0-0.dll => /mingw64/bin/libglib-2.0-0.dll (0x00000000)
        libgtk-3-0.dll => /mingw64/bin/libgtk-3-0.dll (0x00000000)
        libintl-8.dll => /mingw64/bin/libintl-8.dll (0x00000000)
        ...

プログラムはプログラムの実行時にこれらのDLLを必要とするわけです。
つまりpackage/以下にこれらのDLLを集めます。
DLLの多くはMSYS2の環境の/mingw64/bin/以下にあります。

例外として/c/WINDOWS/System32以下のDLLがありますが、これはパッケージングする必要はありません。
Windows環境でプログラムを動かすわけなので、System32にはパスが通っているからです。
つまりプログラムは実行時にユーザーの環境のSystem32を検索してライブラリを探します。

DLLのコピー処理は骨が折れるので、lddの出力を加工して↓のようなコマンドにしたほうがいいでしょう。

        ...
        cp /mingw64/bin/libgobject-2.0-0.dll package/
        cp /mingw64/bin/libglib-2.0-0.dll package/
        cp /mingw64/bin/libgtk-3-0.dll package/
        cp /mingw64/bin/libintl-8.dll package/
        ...

これらのコマンドはMakefileなどに書いておくと便利です。

関連リソースのパッケージング

Gtk+3はリソースを参照します。
リソースとはアイコン画像などのことです。

これらのリソースはどこにあるのかというと、これもMSYS2の環境にあります。
具体的にはMSYS2の環境の/mingw64/share/以下のファイルのことです。

Gtk+3が参照するリソースは↓のようなものになります。

  • glibのスキーマファイル

  • アイコン画像ファイル

  • 翻訳用のロケールファイル

これらのリソースをpackage/以下にコピーするわけですが、最初にpackage/以下にshare/ディレクトリとshare/icons/ディレクトリを作っておきます。

$ mkdir package/share
$ mkdir package/share/icons

そして必要なリソースを環境からpackage/にコピーします。

$ cp -r /mingw64/share/glib-2.0/ package/share/
$ cp -r /mingw64/share/icons/Adwaita/ package/share/icons/
$ cp -r /mingw64/share/icons/hicolor/ package/share/icons/
$ cp -r /mingw64/share/locale/ package/share/

ちなみにこのコピー方法には無駄があります。
このコピーでは実際のプログラムの動作で使われない画像ファイルやロケールもコピーしてしまっています。
このようなコピーだとパッケージファイルの容量が肥大化するため、アイコン画像の選別などを行ったほうが良いと思われます。
ロケールも日本限定であれば/jaディレクトリのみで十分と言えます。

gdk-pixbuf-2.0の存在

ここまでパッケージングをしていざプログラムをWindows環境下でダブルクリックで実行すると、いろいろエラーが出ます。
エラーの多くはgdk-pixbuf-2.0のものです。
gdk-pixbuf-2.0はGtk+3が使用する外部ライブラリで、画像の読み込みを行うライブラリです。
ソースコードレベルでは確認していませんが、gdk-pixbuf-2.0は動的に外部ライブラリを読み込むようで、gdk-pixbuf-2.0が使用する外部ライブラリや関連ファイルもパッケージに含める必要があります。

gdk-pixbuf-2.0が使用するファイルや外部ライブラリは/mingw64/lib/gdk-pixbuf-2.0/以下にあります。

これをpackage/以下にコピーします。

$ mkdir package/lib/
$ cp -r /mingw64/lib/gdk-pixbuf-2.0/ package/lib/

さらにgdk-pixbuf-2.0/mingw64/bin/以下のDLLもいくつか必要とします。
これらもpackage/以下にコピーしておきます。

$ cp /mingw64/bin/librsvg-2-2.dll package/
$ cp /mingw64/bin/libxml2-2.dll package/
$ cp /mingw64/bin/liblzma-5.dll package/

筆者の環境では作ったプログラムがsvg画像を参照していました。
そのため↑のようにlibrsvgなどのDLLが必要になりました。
gdk-pixbuf-2.0が参照するファイルによってはさらに別のDLLが必要になる可能性があります。

その場合、/mingw64/bin/以下のDLLをすべてpackage/以下に放り込んで、起動に必要ないDLLを選別するというブルートフォース的なアプローチも考えられます。
ただ、この方法はちょっと危険です。後述の「ライセンスについて」をご覧ください。

最終的なpackageの構造

最終的なpackage/の構造は↓のようになります。

package/
    design/
        main.glade
    share/
        glib-2.0/
        icons/
        locale/
    lib/
        gdk-pixbuf-2.0/
    program.exe
    librsvg-2-2.dll
    ... (以下DLLたくさん)

このパッケージングには色々無駄が多いです。
プログラムに使用されていない画像ファイルや、ロケール、それからDLLなども含まれています。
実際のパッケージングではこれらのファイルをブラッシュアップして容量を削減する必要があると思われます。

ライセンスについて

パッケージングで気をつけたいのがDLLや画像などのライセンスです。
パッケージを他人に頒布した場合で、仮にGPLなどのライセンスが含まれるファイルがその頒布に含まれていた場合、そのプログラムのソースコードの公開義務などが生まれる可能性もあります。
またDLLなどのライブラリのライセンスがそもそも頒布を認めていない場合もあります。
Gtk+3のライセンスはLGPLなので、パッケージもそのライセンスの範囲で使う必要があります。
ライセンスについてはこの記事では解説しません。

つまり/mingw64/bin以下のDLLをブルートフォース的に全部package/に突っ込んだりすると、ライセンスの問題が生まれる可能性があるわけです。
知らずにパッケージングしていたライブラリのライセンスが自分の意図しないライセンスで、頒布したあとにユーザーから突っ込まれたり問題になったりする可能性があるわけです。
そういうわけで、ブルートフォース的なアプローチは危険です。必ずライブラリやリソースのライセンスは確認するようにしましょう。

ちなみに筆者はこの記事でパッケージングしているファイルのライセンスをすべて確認していません。
そのためパッケージに意図しないライセンスが含まれている可能性もあります。
ですので頒布はしないでください。
仮に頒布して何か問題が起きても筆者は責任が取れません。

おわりに

今回はGtk+3のWindows用のパッケージを作ってみました。
Gtk+3はいろいろ必要なファイルが多いです。

次はLGPLとGPLについて学ぼう

ライセンスは確認しよう