2012-12-29

Cross Compiling and Pkg-config

My host is Ubuntu 64, and target Win32 using MinGW32, for the examples in this article. Also it is assumed that the mingw32 target is named i686-w64-mingw32, so if it isn't, just substitute with the target on your system.

When running a Makefile targeted for cross compilation, pkg-config is unfortunately not looking in the mingw32-directory by itself by just installing mingw32. You will have to somehow redirect it. One way is to create a shell script and place with your ming32-gcc. Name the script with the same name pattern as your mingw32-gcc, on my system it's i686-w64-mingw32-gcc, so name it i686-w64-mingw32-pkg-config.

The script that I ended up with that works for me looks like this:

#!/bin/bash
MINGW_ROOT=/usr/i686-w64-mingw32
export PKG_CONFIG_LIBDIR=${MINGW_ROOT}/lib/pkgconfig
export PKG_CONFIG_PATH=${MINGW_ROOT}/share/pkgconfig
pkg-config --define-variable=prefix=${MINGW_ROOT} $@

Since I've chosen to use CMake instead of autotools for my projects, this script isn't called because CMake works in a different way. CMake finds the correct pkgconfig path, but often the .pc-files has an erroneous prefix, which is fixed in the script above by calling pkg-config with the flag --define-variable=prefix=${MINGW_ROOT}. Instead we have to edit the .pc-files and correct the prefix. In my lib/pkgconfig directory there are 190 .pc-files, but we can do this with a file search and regex substitution.

$ find /usr/i686-w64-mingw32/lib/pkgconfig -type f -exec sed \
> -i "s/^prefix=.*$/prefix=\/usr\/i686-w64-mingw32/g" {} \;

This will work in some lucky situations, but have a look at this gtk+-2.0.pc and you'll see why it won't work always:

prefix=/usr/i686-w64-mingw32/sys-root/mingw
exec_prefix=/usr/i686-w64-mingw32/sys-root/mingw
libdir=/usr/i686-w64-mingw32/sys-root/mingw/lib
includedir=/usr/i686-w64-mingw32/sys-root/mingw/include
target=win32

gtk_binary_version=2.10.0
gtk_host=i686-w64-mingw32

Name: GTK+
Description: GTK+ Graphical UI Library (${target} target)
Version: 2.24.10
Requires: gdk-${target}-2.0 atk cairo gdk-pixbuf-2.0 gio-2.0
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0 -mms-bitfields

The prefix isn't used by the other variables, so how do we fix this then? If we know the prefix and also knows that it's the same in all .pc-files, then we can replace it with a regex, but if it's not, and we may not be sure and checking 190 files is a bit tiresome, it's not a good solution. We'll have to find the prefix, replace it with the correct prefix and then replace all other instances of the prefix directory with '${prefix}'. This script will do the trick:

#!/usr/bin/perl
my $prefix = shift;
my $dir = "$prefix/lib/pkgconfig";
opendir(DIR, $dir) or die $!;
my @files = grep { /\.pc$/ && -f "$dir/$_" } readdir(DIR); 

closedir(DIR);

foreach my $fn (@files) {
    my ($file,$p,$fp);
    open($fp, "<$dir/$fn") or die $!;
    local $/;
    $file = <$fp>;
    close($fp);

    # Substitute 'prefix=(.*)' with a dummy tag, and store prefix in $p:
    if($file =~ s/\bprefix\=(.*)\b/$p=$1;"\$prefix"/e) {
        $file =~ s/$p/\$\{prefix\}/g; # Substitute $p with '${prefix}'
        $file =~ s/\$prefix/prefix=$prefix/; # Replace dummy tag
        open(OUTFILE,">$dir/$fn") or die $!;
        print OUTFILE $file;
        close(OUTFILE);
    }
}

Save this script as pkg-config-fix.pl and run (for safety's sake, make a backup of the files in /usr/i686-w64-ming32/lib/pkgconfig):

$ sudo chmod +x pkg-config-fix.pl
$ ./pkg-config-fix.pl /usr/i686-w64-mingw32
Have a look at gtk+-2.0.pc, it should look like this:
prefix=/usr/i686-w64-mingw32
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
target=win32

gtk_binary_version=2.10.0
gtk_host=i686-w64-mingw32

Name: GTK+
Description: GTK+ Graphical UI Library (${target} target)
Version: 2.24.10
Requires: gdk-${target}-2.0 atk cairo gdk-pixbuf-2.0 gio-2.0
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0 -mms-bitfields

The script is safe to run several times if you install new packages. Now CMake will work properly and find all libraries and headers.

No comments:

Post a Comment