The automated build process is based on a combination of nant and premake scripts (we use premake to generate code::blocks project files for our development machines and makefiles for the build machine). The scripts use gcc/g++ to build the Linux version of the library (.so) for our kiosks and they use MinGW to cross-compile the library for Windows x86.
MinGW is just the standard version installed from the repositories and is not currently capable of producing 64-bit binaries, so we needed to switch that section of our toolchain.
The rest of this post documents how we configured a new toolchain capable of 64-bit builds and makes use of the MinGW-w64 project.
The MinGW-w64 project provides two toolchains, one targetting Win32 builds and one targetting Win64 builds.
Download the Win32 toolchain and extract to /opt/mw32
Download the Win64 toolchain and extract to /opt/mw64
In /usr/local/bin create the following helper scripts (this is optional but we found them useful):
#!/bin/bash PATH="/opt/mw32/bin/:$PATH" i686-w64-mingw32-ar $@
#!/bin/bash PATH="/opt/mw32/bin/:$PATH" i686-w64-mingw32-gcc -m32 $@
#!/bin/bash PATH="/opt/mw32/bin/:$PATH" i686-w64-mingw32-g++ -m32 $@
#!/bin/bash PATH="/opt/mw64/bin/:$PATH" x86_64-w64-mingw32-ar $@
#!/bin/bash PATH="/opt/mw64/bin/:$PATH" x86_64-w64-mingw32-gcc -m64 $@
#!/bin/bash PATH="/opt/mw64/bin/:$PATH" x86_64-w64-mingw32-g++ -m64 $@
Our library is built using wxWidgets since it is fast, easy to use and provides cross-platform access to string functions, file handling, XML parsing, image loading/saving and so on. We statically link wxWidgets and so the following describes how to build 32-bit and 64-bit static versions of wxWidgets.
Download wxWidgets >= 2.9 since 2.8.x does not seem to build to 64-bit successfully. As of writing there is also a problem with legacy references that break the build and the simplest way to fix this is to hack the "configure" and "configure.in" scripts removing "-lwctl3d32".
Open a shell in the wxWidgets root folder (having extracted it somewhere) and run the following. I recommend going away and having a nice cup of tea while the make is running since it will take a while.
$ PATH=/opt/mw32/bin/:$PATH ./configure prefix=/opt/mw32/mingw --host=i686-w64-mingw32 --enable-unicode --disable-monolithic --disable-shared --build=`./config.guess` $ PATH=/opt/mw32/bin/:$PATH make $ sudo make install $ make clean $ PATH=/opt/mw64/bin/:$PATH ./configure prefix=/opt/mw64/mingw --host=x86_64-w64-mingw32 --enable-unicode --disable-monolithic --disable-shared --build=`./config.guess` $ PATH=/opt/mw64/bin/:$PATH make $ sudo make install
As of writing the make install does not copy the headers to a nice "wx" folder and so the simplest solution is to symlink them:
$ cd /opt/mw32/mingw/include $ sudo ln -s wx-2.9/wx ./ $ cd /opt/mw64/mingw/include $ sudo ln -s wx-2.9/wx ./
Since our server is also used to build Linux versions of the library, it has the wxWidgets developmental packages installed from the repositories and therefore also has the "wx-config" tool available. To make this tool aware of our cross-compilation configurations we simply need to symlink the scripts to the appropriate location:
$ cd /usr/lib/wx/config $ sudo ln -s /opt/mw32/mingw/lib/wx/config/i686-w64-mingw32-msw-unicode-static-2.9 ./ $ sudo ln -s /opt/mw64/mingw/lib/wx/config/x86_64-w64-mingw32-msw-unicode-static-2.9 ./
Building something using the appropriate wxWidgets libraries is now a case of passing the appropriate wx-config command to the compiler:
32-bit build options:
|`wx-config --host=i686-w64-mingw32 --version=2.9 --cxxflags`|
32-bit link options:
|-static-libstdc++ -static-libgcc `wx-config --host=i686-w64-mingw32 --version=2.9 --libs`|
64-bit build options:
|`wx-config --host=x86_64-w64-mingw32 --version=2.9 --cxxflags`|
64-bit link options:
|-static-libstdc++ -static-libgcc `wx-config --host=x86_64-w64-mingw32 --version=2.9 --libs`|
If this is configured in a makefile then the helper scripts can be used to tell make which toolchain to use, e.g.:
$ make config=cross CC=mw32-gcc CXX=mw32-g++ AR=mw32-ar
Congratulations, you should now have a Linux system capable of cross-compiling to both 32-bit and 64-bit Windows binaries.
I have since found that when setting up a build (using tools such as premake) it is simpler if the helper scripts act in the same way as the native build tools and handle the -m32 and -m64 flags appropriately. The following is an example of the mw-g++ script I am now using to replace the previously defined mw32-g++ and mw64-g++ :
#!/bin/bash target="x32" for arg in $*; do if [ "$arg" = "-m64" ]; then target="x64" break fi done if [ "$target" = "x64" ]; then PATH="/opt/mw64/bin/:$PATH" x86_64-w64-mingw32-g++ $@ else PATH="/opt/mw32/bin/:$PATH" i686-w64-mingw32-g++ $@ fi