Skip to content

Refresher on Cross-Compilation

To maintain some consistentcy, there are a few terms we should know before going forward.

  • Build machine: The computer that executes the build processes
  • Host machine: The computer on which the software will execute
  • Target machine: The machine/device on which the compiled output will run

In short cross compmilation is the process of building and compiling code for a target platform other than the host machine.

For instance, you might want to write an application for an STM32F1 MCU on your 64-bit Windows 10 workstation. In this instance, you would be producing a binary that would run on a 32-bit ARM Cortex M0.

  • Host Machine: Windows 10
  • Build Machine: Windows 10
  • Target Machine: STM32F1 (ARM Cortex M0)

The takeaway is that many embedded projects require the developer to write code that will execute on a processor with a different architecture than the one they are writing firmware with. This might seem like an obvious statement but there is an underlying importance here. Part of generating the correct artifacts is passing the right compiler flags to the cross compiler. You certainly could do this manually, but integrating CMake or another build systems would streamline this process greatly with consistent outputs and configuratble targets. (I.e, quickly chaning target architecture from command line)

Note on Cross Compiling With CMake

The following is directly referenced from the Mastering CMake Guide from Kitware:

Cross-compiling is fully supported by CMake, ranging from cross-compiling from Linux to Windows; cross-compiling for supercomputers, through to cross-compiling for small embedded devices without an operating system (OS).

Cross-compiling has several consequences for CMake:

CMake cannot automatically detect the target platform.

CMake cannot find libraries and headers in the default system directories.

Executables built during cross compiling cannot be executed.

Cross-compiling support doesn’t mean that all CMake-based projects can be magically cross-compiled out-of-the-box (some are), but that CMake separates between information about the build platform and target platform and gives the user mechanisms to solve cross-compiling issues without additional requirements such as running virtual machines, etc.

To support cross-compiling for a specific software project, CMake must to be told about the target platform via a toolchain file. The CMakeLists.txt may have to be adjusted. It is aware that the build platform may have different properties than the target platform, and it has to deal with the instances where a compiled executable tries to execute on the build host

CMake and Toolchain Files

Similar to our typical CMakeLists.txt files which define what (and to varying extents how) build artifacts are produced, we can also dictate the toolchain, compiler, and target system through the use of a Toolchain File. In short, the toolchain file is an additional file or set of files that describe the target platform.

A few things to note here about toolchain files:

  1. They have the ".cmake" file extension
  2. All the same syntax rules established by the base CMakeLists.txt file still apply here
  3. There are a few variables that we need to change in order for our build process to recognize the change in toolchains
  4. When invoking the CMake command, you must set the CMAKE_TOOLCHAIN_FILE cache variable to the respective toolchain file in order for the changes to take affect

Project Structure with Toolchain files

Simple CMake projects will likely have no more than a few folders for source code, global header files, and libraries. Toolchain files shouldn't compromise that efficiency in development environments. In order to keep a good project structure, we have a recommended project folder structure that should be adapted. Create a new folder called cmake. This shall hold all tools, scripts, toolchain files, and any auxiliary items used during the build process. As far as build systems are concerned, you might devise a structure that looks like so:

Target subfolder

native subfolder

Drivers subfolder

cross-compile