Cross-compiler and binutils
GTK API for win32
GTK pkgconfig files
Configuring and building sources for win32
Simple makefile example
GTK runtime files
Creating a self-installing exe
The intended readership for this page is those who are already quite comfortable with building GTK-based software on Linux (who know their way around the various tools), and who wish to prepare win32 versions of their programs without having to mess with that Other OS themselves.
I don't have time at present to write a full, coherent HOWTO. What you'll find here are various ideas, tips and examples in a fairly raw state. They are based on my experience in cross-building for Windows my program gretl. If you want to take a look at a fairly large-scale example of a cross build, grab the gretl source package from sourceforge and poke around in the win32 subdirectory of the source.
Since some elements below may date fairly quickly, I should say that I'm writing this in early October, 2004. I'm sure to have overlooked various details in these notes: if anyone spots missing stuff, please let me know and I'll update this page. If you find this page of interest, you might also want to take a look at my page on using some native win32 stuff in a GTK context.
Your first requirement is a cross-compiler and an appropriate set of binutils (as, ld and friends).
You can assemble these yourself or there is the option of grabbing a cross-compiler package (in binary or source form) from libsdl.org.
If you take the put-it-together-yourself route (as I have done), I recommend starting your shopping at mingw.org. Take a look at the mingw download area and decide how adventurous you want to be ("Candidate" releases of various vintages or the "Current" release). Download the source for selected releases of binutils and gcc. I am currently using gcc version 3.4.0 and binutils version 2.15.90, and they work fine.
Now you need to decide on a location for your cross system. I put it in /opt/cross-tools. Having chosen a place to install the tools, configure and make them. I use these scripts:
#!/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
You can probably throw away the documentation for these tools, since you'll already have it for the Linux versions:
rm -rf /opt/cross-tools/info /opt/cross-tools/man
or something like that.
To get any further you need to install the appropriate headers and import libraries to support the win32 API. As of this writing, the package you want is w32api-3.1.tar.gz (again, from mingw.org). Untar the package in the appropriate place. For example if you've chosen /opt/cross-tools for your cross tools root, and you've configured gcc with a target of mingw32, your cross-gcc will be found in /opt/cross-tools/mingw32 and you'd do, e.g.
cd /opt/cross-tools/mingw32 tar xvfz w32api-3.1.tar.gz
It's a GTK app you're building, so you need all the appropriate headers and import libs. You could (perhaps) build all that stuff yourself, but why bother when Tor Lillqvist has done the job for us? [If you do feel like trying this, check out the documentation for Cross-compiling the GLib package.]
Pick up all the current "dev" zipfiles (atk, glib, gtk, pango) from the GTK download page. Tor also offers links to win32 versions of various GTK dependencies, such as libiconv, libpng, zlib and libxml2. You'll want to grab these too. In all cases you need the "dev" files, containing headers and the "import libraries" (*.a or *.lib) that are needed at compile time. If you want to package and distribute a GTK runtime along with your app (making it self-contained), you'll also need to grab the corresponding "bin" or "runtime" packages. These contain the dlls corresponding to the import libraries, along with various other runtime files (see below for details on this).
I recommend unzipping the GTK and associated "dev" files using the same root as mentioned above for the win32 API. That is, import libs go into /opt/cross-tools/mingw32/lib on my system, and headers are based at /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.
The pkgconfig files supplied with Tor's GTK "dev" packages are designed for use on Windows and have to be modified slightly for a cross build (so that they contain the correct prefix). Here is a script that does the job (to be run in the relevant cross pkgconfig directory) :
#!/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
For cross-building your own app, or for cross-building special dependencies (extra dlls), there are broadly two approaches:
Use the regular mechanism of configure scripts in conjunction with pkg-config, but in cross mode.
Use hand-crafted Makefiles.
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 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
Note: The -mms-bitfields flag is essential if you want your app to actually run on win32 (when using Tor Lillqvist's pre-built GTK runtime at any rate).
In place of plain configure I use this script called 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. [Update October 6, 2004: Making a bit more progress -- details here.]
In the meantime, I tend to resort the following…
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)
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)
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).
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):
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):
"WIMP" support (optional: let the user make the app look more Windows-like):
If your app is internationalized, you'll want to make binary message catalogs (.mo) in win32 format. I do this by using msgfmt.exe (available in the GNU gettext package for win32) under wine.
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.
Last modified: Wed Oct 6, 2004