CMake Cross-Compiling Template

Most of the C/C++ developers are running into it: The need to cross-compile your C/C++ code for multiple targets (e.g. ARM, x86, …). Anyhow, you may know that this might be very frustrating. Therefore, I want to explain you short and easy how to cross-compile your program e.g. for ARM with CMake, short: A CMake Cross-Compiling Template ;-).

CMake Cross-Compiling – Short Version

1. RPI-Tool: Clone RaspberryPI Tools

git clone https://github.com/raspberrypi/tools.git /home/<yourusername>/rpi-tools

2. Clone CMake Cross-Compiling Template

git clone https://github.com/Rodiii/cmake_crosscompiling_template

3. Toolchain: Modify Path to RPI Tools in toolchain-arm.cmake

In cmake_crosscompiling_template/toolchain-arm.cmake replace <path-to-raspberrypi-tools> with the path where you cloned the rpi-tools to. Please don’t use ~ here.

4. Build it for PI

mkdir build_arm
cd build_arm
cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm.cmake ..
make -j 8

CMake Cross-Compiling – Long Version

1. RPI-Tools: Clone RaspberryPI Tools

The RaspberryPI tools are needed in order to get the ARM compiler suitable for compiling for your PI. Additionally, you’ll receive the PI sysroot.

Therefore, execute the following commands in your shell:

git clone https://github.com/raspberrypi/tools.git /home/<yourusername>/rpi-tools

2. Toolchain: Create a Toolchain to Compile for PI

CMake needs to know where the ARM compiler is located on your machine. Therefore, create a file toolchain-arm.cmake on the root of your project directory. This will be used in your cmake command later to compile your program for ARM.

Important: Replace <path-to-raspberrypi-tools> with the path where you cloned the rpi-tools to. Please don’t use ~ here.

set(CMAKE_TOOLCHAIN_FILE "toolchain-arm.cmake")
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)

# Specify the cross compiler
# clone rpi tools from https://github.com/raspberrypi/tools.git
set(tools <path-to-raspberrypi-tools>/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf)
SET(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)

# Where is the target environment
SET(CMAKE_FIND_ROOT_PATH ${tools}/arm-linux-gnueabihf/sysroot/)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=${CMAKE_FIND_ROOT_PATH}")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --sysroot=${CMAKE_FIND_ROOT_PATH}")
SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --sysroot=${CMAKE_FIND_ROOT_PATH}")

# Search for programs only in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# Search for libraries and headers only in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

SET(CMAKE_ARM_COMPILATION 1)

3. Dependencies: Adapt your CMakeList.txt to use ARM libs for ARM compilation

Probably, you are using dependencies in your project. These dependencies must be compiled for your target platform that your program can use them within your cross-compiling. Luckily, most of the projects out there have tutorials how to cross-compile these.

In your project directory, create a directory thirdparty which will contain the headers of your dependencies as well as the compiled libraries. E.g. for curl:

thirdparty/curl/x86/ ==> will include x86 libraries
thirdparty/curl/arm/ ==> will contain arm libraries
thirdparty/curl/include/ ==> will contain all headers of CURL

Afterwards, you have to link those libraries depending of the target system in your CMakeList.txt.

cmake_minimum_required(VERSION 3.0)

project(cmake_crosscompiling_template)

if(CMAKE_VERSION VERSION_LESS "3.7.0")
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()

set(WORKSPACE_PATH "${CMAKE_SOURCE_DIR}/../") 

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")

add_definitions(-Wall -Wno-psabi)

aux_source_directory(src SOURCES)
aux_source_directory(include INCLUDES)

if(CMAKE_ARM_COMPILATION)
    link_directories(thirdparty/curl/arm)
else()
    link_directories(thirdparty/curl/x86)
endif()

add_executable(cmake_crosscompiling_template main.cc ${SOURCES} ${INCLUDES})
target_include_directories(cmake_crosscompiling_template PRIVATE include thirdparty/curl/include)
target_link_libraries(cmake_crosscompiling_template curl)

4. CMake: Run CMake and Make to Cross-Compile

Finally, it’s time to check if cross-compiling works for you know. Therefore, execute the following commands:

mkdir build_arm
cd build_arm
cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm.cmake ..
make -j 8

That’s it. Feel free to leave a comment if you have feedback or questions.

You can find the code linked in this tutorial here: https://github.com/Rodiii/cmake_crosscompiling_template
You can use this repository as template repository for your CMake cross-compile project.