I'm working on porting FreeGLUT for Android, and FreeGLUT is switching to CMake.
I'm more familiar with the GNU Autotools myself, and I'm used to cross-compile with a simple:
./configure --host=arm-linux-androideabi
Can we do that with CMake? Well, it's not well-documented, but yes :)
Let's see how to do that for Android (smartphones) and MinGW (.exe for windows).
The principle is:
- write a "toolchain" CMake script that defines the cross-compiler,
- mention you're using a "GNU" compiler (a.k.a. GCC) so CMake automatically looks for prefixed cross-compilers tools such as
arm-linux-androideabi-cpp or arm-linux-androideabi-ld.
- pass the toolchain script to CMake using the predefined
CMAKE_TOOLCHAIN_FILE variable.
- REMOVE all the CMake-generated files when you change anything, CMake does not rebuild its cache when the toolchain script or PATH is modified, this creates misleading errors. Hence, building in a subdirectory is crucial.
Here's a simple toolchain script:
SET(CMAKE_SYSTEM_NAME Linux) # Tell CMake we're cross-compiling
include(CMakeForceCompiler)
# Prefix detection only works with compiler id "GNU"
# CMake will look for prefixed g++, cpp, ld, etc. automatically
CMAKE_FORCE_C_COMPILER(arm-linux-androideabi-gcc GNU)
SET(ANDROID TRUE)
Note:
SET(ANDROID TRUE) is not mandatory for CMake, it's just used to detect an Android build in the particular case of FreeGLUT development.
Here's how to invoke it:
PATH=/usr/src/ndk-standalone-9/bin:$PATH
cd /usr/src/freeglut-3.0.0/
mkdir cross-android/ && cd cross-android/
cmake \
-D CMAKE_TOOLCHAIN_FILE=../android_toolchain.cmake \
-D CMAKE_INSTALL_PREFIX=/freeglut \
..
make -j4
make install DESTDIR=$(pwd)
Now here's a slightly more complex toolchain for MinGW.
The main issue with MinGW is that there are at least 4 possible prefixes depending on which version and which distro you're using. So I ask the user to specify it with
GNU_HOST:
SET(CMAKE_SYSTEM_NAME Windows)
include(CMakeForceCompiler)
IF("$ GNU_HOST " STREQUAL "")
SET(GNU_HOST i586-mingw32msvc)
ENDIF()
# Prefix detection only works with compiler id "GNU"
CMAKE_FORCE_C_COMPILER($ GNU_HOST -gcc GNU)
# CMake doesn't automatically look for prefixed 'windres', do it manually:
SET(CMAKE_RC_COMPILER $ GNU_HOST -windres)
I wanted to print an error when
GNU_HOST is not specified, but the toolchain script is loaded multiple times, and the command-line variables are not always set (CMake is not super-clean in that regard). So I defined a default, that works.
Sample invocation:
apt-get install mingw-w64
mkdir cross-woe/ && cd cross-woe/
cmake \
-D GNU_HOST=x86_64-w64-mingw32 \
-D CMAKE_TOOLCHAIN_FILE=../mingw_cross_toolchain.cmake \
-D CMAKE_INSTALL_PREFIX=/freeglut \
..
make -j4
make install DESTDIR=$(pwd)
I used this technique to cross-compile my projects, or other projects that use CMake.
mingw-cross-env uses this technique (abeilt with explicit definition of all compiler tools) to provide pre-built windows libraries without altering the existing CMake scripts.
Do you people have tips or a better technique to cross-compile with CMake?