Cross compile Windows Applications

Posted on 2012-04-09

There is a nice repository on build.opensuse.org which provides some useful packages to cross compile from linux, and I’m going to describe a simple setup using cmake and Qt:

First install openSUSE 12.1 into a virtual machine (unless you want to do it on a real machine).

Then add the extra repositories and install the needed packages (as root):

1
2
3
4
zypper ar http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_12.1/windows:mingw:win32.repo
zypper install mingw32-cross-gcc mingw32-cross-gcc-c++ mingw32-libjpeg-devel mingw32-libpng-devel mingw32-libqt4 mingw32-libqt4-devel mingw32-libtiff-devel mingw32-zlib-devel
zypper ar http://download.opensuse.org/repositories/devel:/tools:/building/openSUSE_12.1/devel:tools:building.repo
zypper install cmake-2.8.7 binutils git

  • The second repository is needed for an updated cmake-2.8.7 which includes http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6ddb1e5b9a3eff941ad12d29609839871fe518ed
  • binutils includes “strings” which is needed in one of the scripts below.

Then login with your normal user, and prepare the cmake toolchain file:

~/toolchain-windows.cmake:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
SET(CMAKE_SYSTEM_NAME Windows)

SET(CMAKE_C_COMPILER   i686-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
SET(CMAKE_RC_COMPILER  i686-w64-mingw32-windres)

SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32/sys-root/mingw)

SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

SET(QT_QMAKE_EXECUTABLE /usr/i686-w64-mingw32/bin/qmake CACHE INTERNAL "" FORCE)
SET(QT_MOC_EXECUTABLE /usr/i686-w64-mingw32/bin/moc CACHE INTERNAL "" FORCE)
SET(QT_RCC_EXECUTABLE /usr/i686-w64-mingw32/bin/rcc CACHE INTERNAL "" FORCE)
SET(QT_UIC_EXECUTABLE /usr/i686-w64-mingw32/bin/uic CACHE INTERNAL "" FORCE)

Now checkout your favorite project which uses cmake+qt and build it with cmake in a subdirectory:

1
2
3
4
5
6
git clone -b stefan-wip git://stbuehler.de/qcross.git
cd qcross
mkdir winbuild
cd winbuild
cmake -DCMAKE_TOOLCHAIN_FILE=~/toolchain-windows.cmake ..
make

The resulting binaries will need some DLLs; with the two scripts below (chmod +x) they should be easy to install into a directory:

1
$ installapp ~/qcross/winbuild ~/app/qcross

Now all the needed files should be in ~/app/qcross.

bin/installexe:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/bin/bash

if [ -z "$1" -o -z "$2" ]; then
    echo "Syntax: $0 <source> <targetdir> [optionall dll dirs]" 1>&2
    exit 1
fi

SOURCE=$1
shift
TARGET=$1
shift

DLLSOURCE=/usr/i686-w64-mingw32/sys-root/mingw/

if [ ! -f "$SOURCE" ]; then
    echo "source '$SOURCE' doesn't exist"
fi

mkdir -p "$TARGET"

walk() {
    b="$(basename $1)"
    d="$TARGET/$b"
    if [ -f "$d" -a ! "$d" -ot "$1" ]; then
        echo "Skipping   '$b' [current version already present]"
    else
        echo "Installing '$b'"
        cp -a "$1" "$TARGET/"

        # Hack to find dependencies
        strings "$1" | grep '\.dll' | while read dll
        do
            DLL=`find "$DLLSOURCE" "$@" -name "$dll" -print -quit`
            if [ ! -z "$DLL" -a -f "$DLL" ]; then
                walk "$DLL"
            fi
        done
    fi
}

walk "$SOURCE"
exit 0

bin/installapp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/bin/bash

if [ -z "$1" -o -z "$2" ]; then
    echo "Syntax: $0 <sourcedir> <targetdir>" 1>&2
    exit 1
fi

SOURCE=$1
shift
TARGET=$1
shift

for exe in $(find "$SOURCE" -name '*.exe' | grep -v CMakeFiles); do
    echo "Installing executable $exe -> $TARGET"
    installexe "$exe" "$TARGET" "$TARGET" "$@"
done

Generated using nanoc and bootstrap - Last content change: 2013-08-16 14:47