Sunday, July 1, 2012

Building DBus for Windows XP with MinGW

Background

I was trying to contribute to Meld, a great diff/merge tool. On Linux, Meld has great version control (VC) integration, which is convenient, because if you run git difftool from the terminal, git locks the terminal until you are done. Great for merges.

So I cloned the meld repository, but the master branch no uses dbus, so that if you do a diff and Meld is already open, it will just add a new tab to the current instance of Meld, instead of starting a new one. Unfortunately there is no nicely packaged windows installer for dbus or dbus-python, so I started on the murky compile and build quest. Obviously without the module, import dbus fails.

Building DBus using MinGW32 (aka MinGW)

This was nearly an exercise in futility. Unfortunately (or fortunately) I didn't read the fine print on the DBus [link] page on Windows porting, that says that it has been successfully ported using MinGW-w64 which, who knew?, is different from MinGW. How is it different? Who knows? I haven't tried MinGW-w64 yet, so I'll let you know when I do. Familiar always seems better, but I will reserve judgement until some later date. One thing I like about MinGW is `mingw-get` which is kind of like `apt-get` or `yum` and makes is super easy to add packages from either MSYS or MinGW.

Step 1: MinGW

Download and install mingw-get-inst. Then install the basic packages: make, msys-make, gcc, g++. Then make sure you download  expat, msys-expat, libexpat, msys-libexpat, which are used during the build process. You'll probably also want the mingw-developers-toolkit which has autoconf/make, libtools, etc.

Step 1.5: GTK

download and install either pyGTK, GTK-2.0 all-in-one installers for windows, or get the glib tarball and see this to bootstrap glib.
http://www.mingw.org/wiki/Bootstrapping_GLIB_with_MinGW

Step 1.75: Doxygen

For kicks install doxygen for really nice help documents.

Step 2: DBus

Download the latest dbus tarball and extract it to your c:\ folder. This is important because in general spaces cause issues, and if you need to add it to your path, it will have the shortest possible length, which is nice.

Step 2.5: add MemoryBarrier macro

Patch the "dbus/dbus-sysdeps-win.c" file at the top right after the "#includes" and "#defines" with the following snippet:

__CRT_INLINE VOID MemoryBarrier(VOID)
{
  LONG Barrier = 0;
  __asm__ __volatile__("xchgl %%eax,%0 "
    :"=r" (Barrier));
}

Step 3: configure, make and install

Read the INSTALL text file in the extracted folder. The build, make & installation process is the same for almost all Linux/Unix packages packaged using GNU autotools. There is a copy of pkg-config.exe in your GTK distribution. Otherwise you can try to build it, but it depends on glib, which depends on it - sort of a catch-22.

    $ ./configure PKG_CONFIG=/c/Python27/Lib/site-packages/gtk-2.0/runtime/bin/pkg-config.exe PYTHON=/c/Python27/python
    $ make
    $ make install

Step 4: check that it works

This test is the same as for building dbus with cmake, except that you don't need to copy the libexpat.dll to dbus bin folder, because mingw/msys/autotools does a better job of helping dbus find this file.
Open two msys shells, and start a dbus-daemon in the first shell using the default session configuration, but output the address to a file. Unfortunately, unless you enabled verbose output during the build with the flag -DDBUS_VERBOSE, you can't add it now. You could try make uninstall, make clean, make distclean and start over again, if you really need to debug dbus.

msys shell #1

$ dbus-daemon --session --print-address > /home/dbus.txt

msys shell #2

$ export DBUS_SESSION_BUS_ADDRESS="<paste from dbus.txt, don't forget quotes>"
$ dbus-monitor --address $DBUS_SESSION_BUS_ADDRESS

signal sender=org.freedesktop.DBus -> dest=:1.0 serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired   string ":1.0"
method call sender=:1.0 -> dest=org.freedesktop.DBus serial=3 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch   string "eavesdrop=true,type='method_call'"
method call sender=:1.0 -> dest=org.freedesktop.DBus serial=4 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch   string "eavesdrop=true,type='method_return'"
method call sender=:1.0 -> dest=org.freedesktop.DBus serial=5 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch   string "eavesdrop=true,type='error'"
If you see this, "yay!" it works, I think...
Fork me on GitHub