Mon, 24 Mar 2008

Cross Compiling with pkg-config.

I'm currently playing with the MinGW cross compiler versions of the GNU C and C++ compilers available via apt-get on Debian and Ubuntu systems. These cross compilers generate windows binaries from a Linux host system which is potentially a much less painful way turning FOSS code into binaries for that particularly odious legacy platform.

Most of the software I'm compiling uses the GNU tools; autoconf, automake, libtool and pkg-config for configuring the software before compiling. Autoconf already has good support for cross compiling and automake and libtool just do what autoconf tells them to do. Pkg-config however is the odd one out.

Pkg-config's job is to retrieve information about installed libraries so that the compiler can find the required header files for inclusion and libraries for linking. For instance, if you wanted compile a program that uses the gconf-2.0 library you could find out the required CFLAGS to be passed to the C compiler and required libraries for linking, by doing something like the following in the Makefile.


  GCONF_CFLAGS = $(shell pkg-config --cflags gconf-2.0)
  GCONF_LIBS = $(shell pkg-config --libs gconf-2.0)

In the above example, when pkg-config is run, it looks in the directory /usr/lib/pkg-config/ and reads information from the file gconf-2.0.pc (each installed library should have one or more of these pkg-config files) which then gets printed out. While the information given by pkg-config would be correct for a native build, it is unlikely to be correct for the cross compiling case.

This issue came up as early as 2003 and there is even a wiki page which suggests some quite extensive changes to pkg-config. Unfortunately I think these suggestions are somewhat fragile and pkg-config itself (I'm using version 0.22) already has features for a better solution.

Like many Unix programs, pkg-config's behaviour can be modified by manipulating certain environment variables. The pkg-config man page explains these variables very well. The first one is PKG_CONFIG_LIBDIR which modifies the default location where pkg-config looks for its per installed library config file. Secondly, the PKG_CONFIG_PATH variable can be set to allow additional pkg-config search paths.

Overriding these two variables results in a MinGW cross pkg-config bash script which I have named i586-mingw32msvc-pkg-config and which looks like this:


  #!/bin/bash

  # This file has no copyright assigned and is placed in the Public Domain.
  # No warranty is given.

  # When using the mingw32msvc cross compiler tools, the native Linux
  # pkg-config executable works fine as long as the default PKG_CONFIG_LIBDIR
  # is overridden.
  export PKG_CONFIG_LIBDIR=/usr/i586-mingw32msvc/lib/pkgconfig

  # Also want to override the standard user defined PKG_CONFIG_PATH with
  # a mingw32msvc specific one.
  export PKG_CONFIG_PATH=$PKG_CONFIG_PATH_MINGW32MSVC

  # Now just execute pkg-config with the given command line args.
  pkg-config $@

Now autoconf generated configure scripts that realise that the i586-mingw32msvc-gcc cross compiler is being used will run the above script and get suitable information for the cross compiler rather than the native compiler.

The only downside to this solution is that a separate script is required for each cross compiler which uses pkg-config. This however is a minor price to pay and it is unlikely that people will end up with huge numbers of XXXX-pkg-config scripts like was common before the widespread use of pkg-config.

Until a better solution becomes available, this is what I will be using.

Posted at: 13:24 | Category: CodeHacking/MinGWCross | Permalink