原文:Building GTK apps for MS Windows on Linux

原文を翻訳しつつ有りますが、Info/クロスビルド環境の構築で成功した方法を書いていますのでこちらは参考程度にしてください。

はじめに

このページが対象とする読者層は、既に(様々なツールに通じている)Linux上でビルドされるGTKベースのソフトウェアに大変満足しており、その他のOSに通じる必要なしにプログラムのwin32バージョンを準備したい人々です。

私には、十分に首尾一貫したHOWTOを書くための時間がありません。ここで見出せるものは、かなり現場の状態に近いアイディア、Tips及び例です。それは、私のプログラムgretlをWindows向けにクロスコンパイルした経験を基にしています。もし、かなり大規模なクロスビルドの例を見たいなら、sourceforgeからgretlのソースパッケージを取得し、win32というサブディレクトリを調査してください。

いくつかの内容が日付に依存するかもしれないので、2004年10月早期にこの文書を書いたと記しておきます。きっとこれらの記述にさまざまな詳細を見落としています。:誤った記述を見つけたなら、どうか私にお知らせください。そうすれば、このページを更新したいと思います。もし、このページに興味を持ったならば、using some native win32 stuff上のGTKの文脈にある私のページもご覧ください。

クロスコンパイラとbinutils

まず、必要となるのがクロスコンパイラとldの類といったbinutilsの適切なセットです。

ご自身でそれらをアセンブルすることもできますし、libsdl.orgから、クロスコンパイラのパッケージをバイナリやソースで取得する選択肢もあります。

私がした様にご自身でそれを設置する方法を取るなら、mingw.orgで取得を始める事を推奨します。mingwのdownload areaを見て、どのように冒険したいかを決めてください。(様々なビンテージの(?)リリース"候補"か"現在の"リリースを選ぶか。)選択したbinutilsとgccのリリースのソースをダウンロードしてください。私は、現在、gccバージョン3.4.0とbinutilsバージョン2.15.90を使っていてとても良く動いてくれます。

ここでクロス(開発)システムの場所を決める必要があります。私は、/opt/cross-toolsに置きます。ツールをインストールする場所を選択したので以下のスクリプトを使ってそれらに対してconfigureとmakeを実行します。:

(訳注:whateverの部分はバージョンに、/opt/cross-toolsはあなたが決めたディレクトリに変更してください。)

 #!/bin/sh
 cd binutils-whatever
 mkdir build
 cd build
 ../configure --disable-nls --target=mingw32 \
 --prefix=/opt/cross-tools --disable-shared
 make  "CFLAGS=-O2 -fno-exceptions" "LDFLAGS=-s"
 make install
 #!/bin/sh
 cd gcc-whatever
 mkdir build
 cd build
 ../configure --target=mingw32 --prefix=/opt/cross-tools --disable-nls \
  --disable-shared --enable-languages=c,c++,f77 
 make CFLAGS="-O2 -fomit-frame-pointer" LDFLAGS=-s
 make install

既にLinux向けのドキュメントを持っているでしょうから、たぶんこれらのツールのドキュメントを次の様にして削除することもできます。:

 rm -rf /opt/cross-tools/info /opt/cross-tools/man

Win32 API

より早くするためには、Win32 APIをサポートする適切なヘッダとインポートライブラリをインストールする必要があります。ここに書くように必要とするパッケージはw32api-3.1.tar.gz(再び、mingw.orgから)です。適切な場所にパッケージを展開します。例えば、クロスツールのインストール先に /opt/cross-tools を選択し、ターゲットをmingw32としてgccを設定したならば、クロス開発用のgccは /opt/cross-tools/mingw32 にあるので次の様にしてください。 

 cd /opt/cross-tools/mingw32
 tar xvfz w32api-3.1.tar.gz

Win32環境向けGTK API

GTKアプリケーションをビルドするには、適切なヘッダとインポートライブラリの全てが必要です。(おそらく)ご自身で全てをビルドすることも可能ですが、我々のためにTor Lillqvist氏が行った仕事の様に苦労する理由がありますか?(atk, glib, gtk, pango)の現在の"dev" zipファイルをTor氏のdownload pageから、取得してください。Tor氏もまたlibiconv、libpng、zlibやlibxml2といったGTKが依存する物の様々なWin32版へのリンクを提供しています。それらも取得してください。全ての場合においてコンパイル時に必要なヘッダやインポートライブラリ(*.aあるいは*.lib)を含んだ"dev"ファイルを必要とします。アプリケーション自身に含めてGTKランタイムを配布したい場合は、対応する"bin"あるいは"runtime"パッケージも取得する必要があります。それらは、インポートライブラリに対応するdllを他の様々なランタイムファイルとともに含んでいます(詳細については、belowを参照してください)。

私は、上記のWin32の場合と同様のルートにGTKと関連する"dev"ファイルを展開するよう提案します。こうするとインポートライブラリは/opt/cross-tools/mingw32/libに、ヘッダファイルは/opt/cross-tools/mingw32/includeに展開されます。

Note on import libraries: You're likely to run across more than one variety of import library. There are *.a libs, which work nicely with a cross gcc. Tor's packages include these. But some packages don't include *.a libraries, only Microsoft-style *.lib files. These can be used OK with the utility mingw32-dllwrap, but not (so far as I can tell) directly with cross gcc. On the other hand, you may find that if the .lib files don't work (linker errors) you can substitute the corresponding dlls and get linking to work.

インポートライブラリに関する注意:複数のインポートライブラリの派生に出くわすかもしれません。クロスgccでうまく動作する*.aというライブラリがあります。Tor氏のパッケージは、これらを含んでいます。しかし、いくつかのパッケージは*.aというライブラリではなく、Microsoftスタイルの*.libというファイルのみを含んでいます。これらは、(未訳:so far as I can tell)クロスgccから直接利用することはできませんが、ユーティリティmingw32-dllwrapを介して利用可能です。別の手段として、動かない(リンカエラーを起こす).libファイルに出くわしたら、対応するdllファイルを介してリンクが可能となります。表現再考

GTKのpkgconfig用ファイル

Tor氏のGTK "dev"パッケージにより提供されるpkgconfig用ファイルは、Windows上で利用する様に設計されているため、クロスビルド環境向けにはわずかに修正する必要があります(それらが正しい接頭辞を含む様に)。この作業を行うためのスクリプトを用意しました(クロス開発環境のpkgconfigディレクトリ内で実行します)。

 #!/bin/sh
 
 TARGET=/opt/cross-tools/mingw32
 
 for f in *.pc ; do
    if grep 'prefix=/target' $f >/dev/null 2>&1 ; then
      cat $f | sed s+^prefix=/target+prefix=$TARGET+ > $f.tmp
      mv $f.tmp $f
    fi
 done  

Win32環境向けにソースを設定(configure)とビルドする

アプリケーション自身や特別に依存する物(特別なdll)をクロスビルドするためには、2つのアプローチがあります。:

  1. クロス開発モードでですが、pkg-configに関連したconfigureスクリプトの通常のメカニズムを利用する。
  2. 手製のMakefileを利用する

The first option is preferable if it works OK. Obviously you're going to need some environment variable magic to get anything working. Having experimented a bit, I now start by sourcing the following (source cross.env).

それが可能ならば、最初の選択肢は望ましいです。動かすためには、明示的にいくつかの環境変数を工夫する必要があるでしょう。少し実験して、次の様な出だしではじめました。(ソースcross.env)

 # cross.env
 PREFIX=/opt/cross-tools
 TARGET=mingw32
 export CC="mingw32-gcc -mms-bitfields"
 export CXX="mingw32-g++ -mms-bitfields"
 export CFLAGS="-O2 -march=i586 -mms-bitfields"
 export CXXFLAGS="-O2 -march=i586 -mms-bitfields"
 export PKG_CONFIG_PATH=$PREFIX/$TARGET/lib/pkgconfig
 export PATH=$PREFIX/bin:$PREFIX/$TARGET/bin:/bin:/usr/bin
 export LD_LIBRARY_PATH=$PREFIX/$TARGET/lib
 export LDFLAGS=-L$PREFIX/$TARGET/lib
 export OBJDUMP=$PREFIX/bin/mingw32-objdump
 export HOST_CC=/usr/bin/gcc

注意: アプリケーションをWin32環境で実行させるためには、-mms-bitfieldsフラグは不可欠です。(Tor Lillqvist氏がビルド済みのGTKランタイムを利用する場合も同様)。

素のconfigureの代わりにcross-configureと呼ばれるスクリプトを使用します。:

 #!/bin/sh
 
 TARGET=mingw32
 cache=win32.cache
 sh configure --cache-file="$cache" \
         --target=$TARGET --host=$TARGET --build=i686-linux \
         --prefix=/opt/cross-tools/mingw32 $*
 status=$?
 rm -f "$cache"
 exit $status

With the environment set up correctly, make can be used as is (no fancy stuff required).

Note: An alternative to the above approach is to load all the required environment settings into your cross-configure script, and write a corresponding cross-make script that invokes make with the appropriate environment. Advantage of this alternative: you don't need to "pollute" your working environment with all the cross-compilation settings, as happens when you source cross.env. Disadvantage: it's easy to forget what you're doing and type make when you mean cross-make, which results in a big mess.

Whichever variant of the "cross-configure" approach you employ, you may run into problems building dlls. For some reason libtool (I'm currently using version 1.5.10) does not seem to want to make Windows dlls on Linux (I can get static libraries OK). There are several "issues" here -- I'm gradually coming to understand them, but I don't have a sure fix at this point. October 6, 2004: Making a bit more progress -- details [http://ricardo.ecn.wfu.edu/~cottrell/cross-gtk/libtool.html here.]

In the meantime, I tend to resort the following…

DLL-building magic

Here's a sample of a Makefile that "works for me" for cross-building dlls (this one makes a dll out of the Cephes library code for figuring probability-values). If I get stuck using other methods I copy-n-paste from this and modify as needed.

 CC = mingw32-gcc -Wall -O2 -mms-bitfields
 AS = mingw32-as
 DLLWRAP = mingw32-dllwrap
 
 CFLAGS = -I.
 
 PROBSRC = bdtr.c btdtr.c chdtr.c drand.c expx2.c fdtr.c gamma.c gdtr.c \
 	igam.c igami.c incbet.c incbi.c mtherr.c nbdtr.c ndtr.c ndtri.c \
         pdtr.c stdtr.c unity.c polevl.c const.c
 
 PROBOBJ = $(PROBSRC:.c=.o)
 
 %.o: %.c
 	$(CC) -c $(CFLAGS) $<
 
 DLLWRAP_FLAGS = --as=$(AS) --export-all --driver-name $(CC) -s
 
 # build libprob.dll, and create a corresponding import library
 # libprob.a
 
 libprob.dll: $(PROBOBJ) 
 	$(DLLWRAP) $(DLLWRAP_FLAGS) \
 	--output-def libprob.def --implib libprob.a \
 	-o $@ $^ 

The routine is: make all the object files as usual, then package them into a dll using mingw32-dllwrap. If you need additional libraries linked in, stick them onto the end of the dllwrap command, as in:

 libgretl.dll: $(LIBOBJ) $(MINOBJ) 
         $(DLLWRAP) $(DLLWRAP_FLAGS) \
         --output-def libgretl.def --implib libgretl.a \
         -o $@ $^ -lf2c -lm -L$(imports) -lxml2 -lz -lintl -lprob -lgmp \
         -lmingwex $(GLIBLIB) $(LAPACK_LIBS)

Simple makefile example

Here's an example of a complete cross-Makefile for a trivial GTK program. Note the compiler flag -mwindows: this is required to produce a windows application as opposed to a win32 console application (which automatically spawns a console when invoked via a menu or icon).

 CC = mingw32-gcc -O2 -Wall -mms-bitfields -mwindows
 PKG_CONFIG_PATH = /opt/cross-tools/mingw32/lib/pkgconfig
 
 CFLAGS := $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) \
           pkg-config --cflags gtk+-win32-2.0)
 LIBS := $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) \
           pkg-config --libs gtk+-win32-2.0)
 
 foo.exe: foo.c
         $(CC) -o $@ $(CFLAGS) $< $(LIBS)

GTK runtime files

By "GTK runtime files" I mean the set of DLLs, modules, configuration files and message catalogs that support the actual execution of a GTK program.

When you distribute a GTK application for Linux, it's natural to assume that the GTK runtime will already be in place -- or if it's not, that the user will be able to install it easily from packages such as rpms or debs. It's not your responsibility as an application developer to provide the basic runtime.

On MS Windows, of course, GTK is not part of the basic kit and you face a choice:

  • Tell users that your package depends on the GTK runtime, and point them towards a third-party package containing that runtime.
  • Package with your app that portion of the GTK runtime that the app requires, thereby making your package self-contained.

If you decide on the first option you may want to take a look at the GTK installers offered by Alex Shaduri and Jernej Simoncic.

I have gone for the second option: I prefer to give users the simplest possible one-step installation. If you take this approach you will probably want to find out what is the minimal subset of GTK runtime files required to support your application. You will surely need all the basic DLLs for atk, glib, gtk and pango, plus their essential dependencies such as zlib, libxml2, libiconv and libintl. You'll need some of the dynamically-loadable modules for gtk and pango, but probably not all of them. You may or may not need message catalogs for gtk and friends. It may take a bit of trial and error to figure out the essential subset.

For reference, I show below a listing of the GTK runtime files that I distribute with my application. The path to these files is relative to the installation directory chosen by the user at install time (see Creating a self-installing exe below).

The GPL:

 COPYING

Core GTK DLLs:

 libatk-1.0-0.dll
 libgdk_pixbuf-2.0-0.dll
 libgdk-win32-2.0-0.dll
 libglib-2.0-0.dll
 libgmodule-2.0-0.dll
 libgobject-2.0-0.dll
 libgthread-2.0-0.dll
 libgtk-win32-2.0-0.dll
 libpango-1.0-0.dll
 libpangoft2-1.0-0.dll
 libpangowin32-1.0-0.dll

Basic dependency DLLs:

 iconv.dll
 intl.dll
 libpng12.dll
 libxml2.dll
 zlib1.dll

Basic config files:

 etc/pango/pango.modules
 etc/pango/pango.aliases
 etc/gtk-2.0/gdk-pixbuf.loaders
 etc/gtk-2.0/gtkrc

Image-file loaders (subset for the image formats used by my app):

 lib/gtk-2.0/2.4.0/loaders/libpixbufloader-png.dll
 lib/gtk-2.0/2.4.0/loaders/libpixbufloader-xpm.dll

Message catalogs (subset for the languages supported by my app):

 lib/locale/es/LC_MESSAGES/atk10.mo
 lib/locale/es/LC_MESSAGES/glib20.mo
 lib/locale/es/LC_MESSAGES/gtk20.mo
 lib/locale/fr/LC_MESSAGES/atk10.mo
 lib/locale/fr/LC_MESSAGES/glib20.mo
 lib/locale/fr/LC_MESSAGES/gtk20.mo
 lib/locale/it/LC_MESSAGES/atk10.mo
 lib/locale/it/LC_MESSAGES/glib20.mo
 lib/locale/it/LC_MESSAGES/gtk20.mo
 lib/locale/ja/LC_MESSAGES/glib20.mo
 lib/locale/ja/LC_MESSAGES/gtk20.mo
 lib/locale/pl/LC_MESSAGES/glib20.mo
 lib/locale/pl/LC_MESSAGES/gtk20.mo

Pango modules (subset: my app only supports European languages):

 lib/pango/1.4.0/modules/pango-basic-win32.dll
 lib/pango/1.4.0/modules/pango-basic-fc.dll

"WIMP" support (optional: let the user make the app look more Windows-like):

 etc/gtk-2.0/gtkrc.wimp
 lib/gtk-2.0/2.4.0/engines/libwimp.dll

アプリケーション用のメッセージカタログ

もし、アプリケーションを国際化しているなら、Win32フォーマットでバイナリメッセージカタログ(.mo)を作成したいでしょう。私は、wine環境下でmsgfmt.exe(win32向けのGNU gettextパッケージ内の物が利用可能)を使ってこれを行っています。

インストーラの作成

Yes, you can even do this without leaving Linux -- with a little help from wine. Jordan Russell makes available a nice free installer-builder, Inno Setup. It's a Windows program, but it runs fine on Linux under wine (its own self-installer works fine under wine too.) It is fully scriptable and its compiler can be run non-interactively.

In case you're interested, here is a sample script, gretl.iss, for use with Inno Setup.

      • -

原著:Allin Cottrell <cottrell at wfu.edu> 翻訳:Yasumichi Akahoshi