Dec 16, 2007

Jhbuild Anything on Windows - In 12 Steps

Part 1: The Complete Gtk+ Stack from Source

Its been a long week spent watching things compile [0], but I'm happy to report that Jhbuild is now able to build the complete [1] stable Gtk+ stack on windows using the msys/mingw tool chain. That literally means that you can now build you Gtk app, or Gtk itself, for windows, in 12 steps. You still getting all the normal benefits that Jhbuild allows. So, the steps are;

  1. Install MinGW combined installer (MinGW-5.1.3) to C:\mingw

  2. Untar msysCORE-1.0.11-2007.01.11 to C:\msys

  3. Run C:\msys\postinstall\pi.bat, answer yes when it asks whether mingw is already installed and point it to C:\ming

  4. Install Python 2.5.1 to default location (C:\Python25)

  5. Install ActivePerl to C:\Perl. You can probably also install a MingW-provided perl package, but the latest version of this was some 5.6 at the time of this writing, while ActivePerl is 5.8.

  6. Install bzr for windows to C:\Bazaar

OK thats all the preparation steps. Launch C:\msys\msys.bat now to start a minimal unix-like shell. Now onto the meaty part;

  1. bzr branch

  2. cp jhbuild-win32/win32-hacks/* . && mv profile .profile && mv /bin/perl

  3. edit to reflect the prefix you are going to install (or have installed) pkg-config to

  4. edit jhbuild-win32/configs/gtk-win32.jhbuild so that full unix paths reflect the correct location of Make sure /bin/perl and are executable

  5. Close the shell and restart it so that it picks up your new .profile. Check that you can run all needed executables perl --version && python --version && jhbuild --help && ./ --version

Oh, I seem to be forgetting one more thing.... The following command will build gtk+,atk,cairo,pango,zlib,libpng, and glib from source. No really, that is it [0].

  1. jhbuild -f jhbuild-win32/configs/gtk-win32.jhbuild build

Built Gtk+ On Windows

The Hacks (aka things I don't really understand)

There are a few parts of this setup that still confuse me.

  • /bin/perl is a thin wrapper around perl that quotes args and escapes path slashes. Its necessity is based around the interaction of the msys path escaping and what happens when autotools invokes glib-mkenums. It was based upon what I read here. It also writes a debug log to ~/perllog

  • ~/ is a wrapper around that quotes args. It is as described here but with a full prefix to pkg-config (so that you may use one that is installed in your jhbuild prefix). It also writes a debug log to ~/pkglog

Jhbuild Core Modifications

I am currently hosting a bzr branch with my modifications to Jhbuild. I'm still cleaning some things up, but I hope that this is suitable for committing to SVN in the future. My modifications to Jhbuild are basically;

  • Cleaning up all path handling code. That means using os.path.abspath and os.path.join internally. The msys does shell does some shiny things to convert unix paths to windows paths but it works best if the path it is passed is coherent and not a mix of both systems path separators.

  • Some path and environment variable fudging that checks all paths that get passed out to a shell, and converts them to unix format. Python on windows calls the windows CreateProcess function (that expects a windows executable). Therefor we starts a new msys/bin/sh.exe with the first arg the script we originally wished to start, followed by all the inferior args.

  • Added a binary module type. This is basically like a tarball but instead of executing configure, make, make install you can define arbitary shell commands to execute post download and unpack. This is used to provide glib-bin and gtk-bin metapackages (which get binaries from Tor's gtk win32 site). You can depend on the metapackages if you dont feel like compiling the gtk+/glib stack yourself and just want to build your app. You can also insert these binary modules in the dependency chain and use them to execute arbitrary scripts to fix (read: hack) some aspects of packages.

  • New Gtk+ and Glib modules files for binary installation, and source installation.

  • Use pythons build in functions to download files (instead of wget) and to untar/unzip archives (instead of tar and unzip command line programs). Note that this is not strictly necessary as there are builds of tar/unzip and wget for msy - but its easier from a developer perspective.

Remaining Work, Caveats (aka the full story)

  • libjpeg builds ok but doesn't seem able to generate a shared library. Hence libtiff fails and gtk builds without jpeg support.

  • glib-mkenums seems to insert arbiraty data (a directory listing) at the end of .h files. This results in many compiler warning about data after #endif.

  • Read the gtk-win32.jhbuildrc file.

  • Gtk doesn't set the correct paths to the pixbuf loaders and input modules. You will need to run (from the prefix to which Jhbuild installed everything)

    • $JHBUILDPREFIX/bin/gtk-query-immodules-2.0.exe > $JHBUILDPREFIX/etc/gtk-2.0/gtk.immodules

    • $JHBUILDPREFIX/bin/gdk-pixbuf-query-loaders.exe > $JHBUILDPREFIX/etc/gtk-2.0/gdk-pixbuf.loaders

  • You can change gtk to use the default theme by doing

    • echo 'gtk-theme-name = "MS-Windows"' > $JHBUILDPREFIX/etc/gtk-2.0/gtkrc
  • I have not tested this with SVN modules on windows, only tarball releases. I wasn't prepared to discover the compatibility of the msys provided autotools stack (yet).

  • --disable-docs on which/all modules?

  • Hookup to, and submit build reports to JhAutobuild

  • Python or msys or something buffers all the shell output. This means that there can be long periods (minutes) of nothing getting printed to the shell. If it looks like something has failed to build (no CPU/disk activity) the push 1,3 or 4 to retry, cancel, or drop into a shell respectively (i.e. the normal Jhbuild menu presented upon failure).

Part 2: I Just Want to Build my Application (not Gtk)

It should be noted that it is not necessary to build Gtk (from source) if you just want to build a single application. Using the new binary module type, I have prepared a gtk-binary metamodule that downloads all the needed files from Tor's site, and installs them for you. That sounds confusing, so lets take a randomly chosen example program [2]. Lets install medit, from source, using Jhbuild.

Starting with the example configs/gtk-win32.jhbuild file change the module and modulesets lines to

moduleset = [
modules = ['meddit']

Add a module_autogen line for meddit

#Module specific configure arguments passed in addition to autogenargs
module_autogenargs['meddit'] =  ' --without-xml --disable-help --with-python=no'

And the final step....

jhbuild -f jhbuild-win32/configs/gtk-win32.jhbuild build

Meddit running on windows


I got into this because I wanted to be able to build pygoocanvas on windows, so I could hack on Conduit there. I still have not done that, instead I have;

  • gotten royally distracted from the original goal,

  • hacked on Jhbuild,

  • learned a lot about msys/mingw and autotools on windows,

  • hopefully been able to contribute something useful back to the community that makes it easy for joe normal and jane developer to test their app on windows

  • Oh and its not yet finished (but I have tested it a few times on fresh installs, and it should just work) yet

  • Pretty normal summary for a FOSS hackers week, correct?

I would really like help from some people in testing this further, so go ahead, test it today. Ive made it 12 easy steps for you to follow.......

References (thanks)

[0] A full Gtk+ build from source takes about 6 hours on Windows XP (running in VMware getting both 2.4Ghz Pentium 4 cores)

[1] Ok, not the complete stack. To get around some circular dependency issues I start with binary versions of pkg-config iconv and gettext. With pkg-config present I then build Glib from source. I also use a binary version of poppler because it depends on Gdk while Gtk depends on poppler.

[2] Well not entirely random. It was already advertised as being able to builad on windows. Also it failed during make install, complaining about missing share/mime/packages/ and bin/update-mime-database. I created both as empty files and it was successfully installed.