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.

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.