Compiling GTK for Win32

31 January 2012
This article details building GTK v2.24.x from source for Windows using MinGW/MSYS. The original motive was the lack of OpenGL support (via GtkGlExt) in the standard Windows binary 'bundle', which is further compounded by there being no official Win32 binary release of GtkGlExt. There is also the secondary motive of having an audited (i.e. tested) binary/source package pair for licencing purposes. There are quite a few HOWTOs kicking around the internet, of which the one by Fragrant Memories and a MinGW/MSYS-orientated one were the most helpful. However even with these information sources it is not a trivial task, so this article will also try to document ways the process goes wrong.

Installing MinGW/MSYS

MinGW/MSYS has improved a lot since I first came across it a few years ago, and although I am not a big fan of download-on-the-fly installers, it has made installing MSYS quite easy. The important component options are MSYS Basic System & MinGW Developer Toolkit, although since I doubt it makes much different to overall download time you may as well simply tick all components. Once installed load up the MinGW Shell (if you did not install the Start menu short-cuts, the start-up batch file is located at C:\MinGW\msys\1.0\msys.bat by default), and run the following commands: Normally I would advocate getting mingw-get to download the latest package list rather than use the built-in one, but I suspect that the repository mingw-get pulls from in this case might be a developmental one rather than a stable-release one. When cross-checking using a fresh install, I used the August 2011 installer, and during installation I selected to use the built-in package list. Apart from the Start Menu short-cuts, MinGW/MSYS installations seem to be self-contained, so I don't foresee any problems in keeping several installed at once. If something breaks for no apparent reason, try a different version of MinGW/MSYS, as I think its development progresses fairly rapidly.

Getting all the packages

You'll need to download: Extract them all into the same place, preserving directory structures.

The build process

I am assuming you are using bash (or a compatible) shell and are reasonably familiar with it. In order to reduce the length of commands that are needed, it is useful to set the following environment variables:

export LIBS=-static-libgcc export PATH=`pwd`/bin/:/build/bin/:$PATH export ZLIB=-L`pwd`/lib export ZINC=-I`pwd`/include export PFIX=/build export PKG_CONFIG_PATH=$PFIX/lib/pkgconfig/

The configuration command-lines for each of the packages is given below, and after each you need to also run make && make install. The packages don't have to be built in this order, but this ordering has taken account of dependencies..

libiconv-1.14, tiff-3.9.5, jpeg-8b, expat-2.0.1, freetype-2.4.2
./configure --prefix=$PFIX
gettext-0.18.1.1
./configure --prefix=$PFIX --enable-threads=win32 --enable-relocatable \ --with-iconv-prefix=$PFIX --without-libintl-prefix --with-included-gettext
fontconfig-2.8.0
./configure --prefix=$PFIX --with-expat=$PFIX --disable-docs
libpng-1.4.8
env CFLAGS=$ZINC LDFLAGS=$ZLIB ./configure --prefix=$PFIX --disable-static --enable-shared
glib-2.28.8
env CFLAGS=$ZINC LDFLAGS=$ZLIB ./configure --prefix=$PFIX --with-threads=win32 --with-pcre=internal
pixman-0.24.0, gdk-pixbuf-2.24.0
env CFLAGS=$ZINC LDFLAGS=$ZLIB ./configure --prefix=$PFIX
cairo-1.10.2
env CFLAGS=$ZINC LDFLAGS=$ZLIB ./configure --prefix=$PFIX --enable-full-testing
atk-1.32.0
./configure --prefix=$PFIX
pango-1.29.4
./configure --prefix=$PFIX --with-included-modules=yes
gtk+-2.24.8
env CFLAGS="$ZINC -I$PFIX/include" LDFLAGS="$ZLIB -L$PFIX/lib" ./configure --prefix=$PFIX \      --with-included-immodules=ime --enable-debug=no --disable-gtk-doc-html

Pitfalls

Wrong libintl causing ld.exe to crash

For some reason MinGW's
tends to be picked up rather than the one built from source. Symptoms are ld.exe crashing:

collect2: ld returned 5 exit status make[3]: *** [gtk-update-icon-cache.exe] Error 1

Only working fix I know is to overwrite, rename, or delete /mingw/lib/libintl.*. Yuk.

Use libpng v1.4.x, not v1.5.x

These two version series are not source-compatible, resulting in these errors:

io-png.c:681:32: warning: passing argument 5 of 'png_get_iCCP' from incompatible pointer type libpng15/png.h:2182:1: note: expected 'png_bytepp' but argument is of type 'char **' io-png.c: In function 'png_error_callback': io-png.c:772:30: error: dereferencing pointer to incomplete type io-png.c: In function 'real_save_png': io-png.c:981:12: error: dereferencing pointer to incomplete type io-png.c:1009:31: warning: pointer targets in passing argument 5 of 'png_set_iCCP' differ in signedness /libpng15/png.h:2189:1: note: expected 'png_const_bytep' but argument is of type 'gchar *'

Error 126 and/or Bad File Number (often gtk-update-icon-cache.exe)

This is UAC kicking in at an unexpected point.

Making all in gtk ./gtk-update-icon-cache --force --ignore-theme-index \ --source builtin_icons stock-icons > gtkbuiltincache.h.tmp && \ mv gtkbuiltincache.h.tmp gtkbuiltincache.h /bin/sh: ./gtk-update-icon-cache: Bad file number make[2]: *** [gtkbuiltincache.h] Error 126

Fastest fix is to run the MSYS Shell as administrator.

Missing libjpeg & libtiff

The JPEG and TIFF libraries are not listed as (sub-)dependencies on the GTK website, but building GDK-Pixbuf without them requires specific overriding using --without-libtiff and --without-libjpeg.

Missing pthread library

This seems to be caused by an absence of the -static-libgcc parameter.

Stuck on C:/Windows/fonts:

If you see the following:

/bin/install -c -m 644 ./fonts.conf /build/etc/fonts/fonts.conf /build/bin/fc-cache -s -f -v C:/Windows/fonts:

It is not stuck. It doing some font-related caching, which might take quite a while. And yes, it does look rather like a prompt for input..

JPEG library build fails

Version 8c of the library does some things that older versions of GCC accepted, but will cause more recent versions to choke:

jcapimin.c:127:1: error: conflicting types for 'jpeg_suppress_tables' jcapimin.c:128:1: note: an argument type that has a default promotion can't match an empty parameter name list declaration jpeglib.h:984:14: note: previous declaration of 'jpeg_suppress_tables' was here make[1]: *** [jcapimin.lo] Error 1 make[1]: Leaving directory `/home/remy/gtk/jpeg-8c'

Version 8b does not seem to have this problem, so try using that version instead.

Unsupported hardware properties

If you get the following, you probably have a broken MSYS:

libtool: link: unsupported hardcode properties libtool: link: See the libtool documentation for more information. libtool: link: Fatal configuration error.

I am not sure of the root cause, but it seems to be the type of error that disappears as easily as it comes.

PKG_CONFIG_PATH not working

While pkg-config will happily use PKG_CONFIG_PATH, the packages themselves install their manifests into $prefix/lib/pkg-config regardless of what PKG_CONFIG_PATH is..

Trojan Horse Generic26 found!

AVG seems to have a history of false positives with MinGW, and it is part of the more general problem of mixing patten-based virus scanners with compiler tool-chains. Configure scripts that compile/run/delete small test programs in quick succession are particularly prone to firing off virus alerts. This seems to happen quite frequently if you use mingw-get to grab (or update to) the latest compiler tools rather than an established snap-shot. Only fix I know, other than the non-option of disabling the virus scanner, is to install a clean copy of MinGW/MSYS and use it built-in package list.

Remarks

Details in this section are not strictly essential to the building process, but are included as they give the reasoning behind some of the process. This section will be most relevant if you are interested in variations such as using different package versions, and is intended to be more general than the errors described in the previous Pitfalls section.

Use of pkg-config

If you remember the olden days when packages came with configuration programs such as sdl-config, the odds are you first came across pkg-config when a configuration script broke in some way. As a result it is very tempting to simply bypass pkg-config, but in this case it actually greatly simplifies you task once you get it working. The huge majority of the packages that make up GTK install pkg-config manifests as standard, negating the need for loads of --with-XXX-path=PATH and --enable-XXX parameters.

Why not Cygwin?

I had originally looked into using Cygwin, but given how much MinGW/MSYS has improved since I first used it, Cygwin is an even more complicated process. Main problem Cygwin has is that you will have two build systems installed, and it is the non-default one you want to use for compiling GTK. If the build cannot find the MinGW-specific dependency, it will often include the Cygwin-based one instead, with inevitably bad results. A lot of the HOWTOs I've seen were based on the (now out of date) premise that MSYS was not mature enough to host the build system, so a hybrid of Cygwin and MinGW was needed.

Why not cross-compile

Although I believe it would be a lot faster, it would have its own set of problems, the main one being difficulty in testing the compiled binaries. Wine is a great piece of software, but I don't think it is quite good enough for developmental work. Maybe a future work item..

zlib annoyances

Compared to all the other packages, zlib is a nightmare. When compiled under Windows the resultant library is not only broken, but you also have to mess around with CFLAGS & LDFLAGS variables to get it to work. I suspect that zlib is mostly used as a sub-dependency of PNG support, but given how ubiquitous PNG is these days, leaving it out is no small trade-off.

How much from scratch

One of the original aims was to have everything built from scratch so that I had an audited set of DLLs and associated source code. However there are two components where this is difficult to achieve:
pkg-config
Building this is a chicken-and-egg problem because it requires G-Lib, so it is easiest to simply grab the pre-built one from the GTK web-site. Since pkg-config is used as a tool within the build process rather than forming part of GTK, there are no licensing issues with this one.
zlib
Don't bother building zlib from source. Under Windows, the resulting headers are broken in subtle ways, and to make thing even more confusing the result is linker errors.
Mercifully zlib is not GPL/LGPL licenced, so it is fine to just ship the DLL without worrying about the corresponding source code. Not the purist ideal, admittedly..

No static build?

My original plan was to make static builds as much as possible, allowing both GTK and all its dependencies to be consolidated into a small set of DLL files. Needless to say this is not a well-worn path for GTK. The configure scripts of GDK-Pixbuf and Pango specifically disallow it, the generated makefile for Fontconfig tries to install the DLL import library even though it has not been built, and even if the static libraries build/install properly you sometimes still need manual intervention to get them linked to. Concluded that the obtainable reductions (still over a dozen DLLs) were simply not worth the effort.

libPNG versions

GTK v2.16.x specifically looks for libPNG v1.2, but if it fails to find it the way it then tries to fall back to a non-specific version of libPNG often breaks. To make matters worse the later versions of some of the dependencies do not compile properly with libPNG v1.2, so you have to use v1.4 anyway. There is a PDF HOWTO that details the problem & solution, which amounts to copying libpng14 library files so that -lpng (rather than -lpng14) will pick it up.

Don't use libPNG v1.5.x, as that version seems to be incompatible. Tried it myself, and ended up with build errors. For some reason libPNG treats minor version numbers as an indication of API changes.

GtkGlExt & fossilisation of GTK v2.16.x

Unlike on Linux, the Windows GTK binaries do not include OpenGL support, and since the last 'release' tarball was back in 2006, building it means contending with all the bit-rot GTK v2.16 has accumulated. Considering the effort it takes to get any version of GTK built, I am disinclined to build a version that I suspect has (possibly recently) been discontinued.

I'm always a bit iffy about building developmental versions of (L)GPL software destined for Windows, but in the case of GtkGlExt, there is no choice. As is typical for repository-sourced versions, you need to generate the configuration scripts yourself, which apart from the README file being wrong (you actually run the bootstrap script, not autoconf.sh), does not actually work under MSYS. Mercifully the generated configure script itself is platform-independent, so I did the generation process under Linux then copied the resulting script across to Windows.