Metric Panda Games

One pixel at a time.

Cross compiling for Three Platforms

Rival Fortress Update #11

I’ve moved permanently to Linux as my development platform. I’m in love! Linux is giving me even more freedom from clutter and OS annoyances than what OSX was giving me. How did I ever get by without a tiling window manager!

Fanboyism aside, this week I finally finished the cross compiling setup that I started working on a while back.

Whenever I push commits to the Github repository, an automated build triggers for the three platforms that Rival Fortress will ship on: Windows (32/64bits), Linux (32/64bits) and OSX(64bits).

The build “server” is Mac Mini running a bare bones installation of Arch Linux.

Cross compilation process

The cross compilation process is handled by a simple bash script. The setup step, that is run only once after a clean git clone, initializes Cmake for the 5 “platforms” like so:

# 64 bit builds
if [ ! -d build/linux64 ]; then
  cmake -H. -Bbuild/linux64 -G Ninja -DCMAKE_BUILD_TYPE=Debug
fi

if [ ! -d build/osx ]; then
  cmake -H. -Bbuild/osx -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/x86_64-osx.cmake
fi

if [ ! -d build/win64 ]; then
  cmake -H. -Bbuild/win64 -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/x86_64-w64-mingw32.cmake
fi


# 32 bit builds
if [ ! -d build/linux32 ]; then
  CFLAGS=-m32 CXXFLAGS=-m32 cmake -H. -Bbuild/linux32 -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/i686-linux.cmake
fi

if [ ! -d build/win32 ]; then
  cmake -H. -Bbuild/win32 -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/i686-w64-mingw32.cmake
fi

Each build, a part from the 64 bit Linux, has a toolchain file associated with it that specifies the compiler to use and the path to libraries and headers.

The 64 bit Linux build doesn’t need a toolchain file since the system is 64 bit and is configured to build by default using Clang 3.8.

The 64 bit Linux also runs first as it is the only build that will run the reflection preprocessor and other build time custom tools that generate code.

Toolchains

I’m using mingw-w64 to build Windows binaries and OSX Cross to build for OSX.

This is the toolchain file I use to compile Windows 64bit binaries:

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)

set(CMAKE_C_COMPILER     "${TOOLCHAIN_PREFIX}-gcc")
set(CMAKE_CXX_COMPILER   "${TOOLCHAIN_PREFIX}-g++")

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(CMAKE_CROSS_COMPILING TRUE)

Other toolchain files are similar, the only change is x86_64 to i686 and the TOOLCHAIN_PREFIX. You can read more about cross-compiling with Cmake on the docs.

The variable CMAKE_CROSS_COMPILING is used throughout the CMakeLists.txt files to disable running of preprocessing tools I mentioned earlier.

Building

The actual build process is rather simple: the same bash script I mentioned above serially runs Ninja on each folder like so:

  ninja -C build/<platform>

If the build fails the stderr is redirected to a BUILD_ERRORS.txt file that I can later review. Whenever a build breaks for a platform I run the same toolchain on my main development workstation and fix the bugs.

I’m currently building only in debug mode, but when I’ll integrate automated testing for I’ll enable Release mode to. Cross-platform automated testing will be tricky as I’ll probably have to use some form of OS virtualization.

Obviously a successful build doesn’t mean the actual game will run on the target platform, but that will be (hopefully) handled when I implement automated testing.