CMake + STM32 Cross-Compile: A Practical Starter

CMake + STM32 Cross-Compile: A Practical Starter

Jasper

When I moved STM32 projects to CMake, the biggest win was repeatable builds.
No IDE magic, just files and commands.

This is a practical starter for STM32 cross-compilation.

1) What you need

Install ARM GNU Toolchain (arm-none-eabi-gcc) and make sure these are in PATH:

  • arm-none-eabi-gcc
  • arm-none-eabi-g++
  • arm-none-eabi-objcopy
  • arm-none-eabi-size

Check:

1
arm-none-eabi-gcc --version

2) Example project layout

1
2
3
4
5
6
7
8
9
10
11
stm32-blink/
CMakeLists.txt
cmake/
toolchain-stm32f103.cmake
linker/
STM32F103C8TX_FLASH.ld
startup/
startup_stm32f103xb.s
src/
main.c
system_stm32f1xx.c

3) Toolchain file

cmake/toolchain-stm32f103.cmake:

1
2
3
4
5
6
7
8
9
10
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_SIZE arm-none-eabi-size)

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

4) CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cmake_minimum_required(VERSION 3.20)
project(stm32_blink C ASM)

set(MCU_FLAGS "-mcpu=cortex-m3 -mthumb")
set(COMMON_FLAGS "-ffunction-sections -fdata-sections -Wall -Wextra")

add_executable(${PROJECT_NAME}
startup/startup_stm32f103xb.s
src/system_stm32f1xx.c
src/main.c
)

target_compile_options(${PROJECT_NAME} PRIVATE
${MCU_FLAGS}
${COMMON_FLAGS}
)

target_link_options(${PROJECT_NAME} PRIVATE
${MCU_FLAGS}
-T${CMAKE_SOURCE_DIR}/linker/STM32F103C8TX_FLASH.ld
-Wl,--gc-sections
-Wl,-Map=${PROJECT_NAME}.map
)

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:${PROJECT_NAME}> ${PROJECT_NAME}.hex
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${PROJECT_NAME}> ${PROJECT_NAME}.bin
COMMAND ${CMAKE_SIZE} $<TARGET_FILE:${PROJECT_NAME}>
)

5) Minimal main.c

1
2
3
4
5
int main(void) {
while (1) {
// toggle GPIO here
}
}

6) Build command

1
2
3
4
5
cmake -S . -B build \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-stm32f103.cmake \
-DCMAKE_BUILD_TYPE=Release

cmake --build build

After build, you should get:

  • stm32_blink (ELF)
  • stm32_blink.hex
  • stm32_blink.bin
  • stm32_blink.map

7) Flash to board (example)

If you use ST-LINK:

1
st-flash write build/stm32_blink.bin 0x8000000

This setup is small, predictable, and easy to version-control.
Once this baseline works, you can add HAL, FreeRTOS, and board-specific modules step by step.

  • Title: CMake + STM32 Cross-Compile: A Practical Starter
  • Author: Jasper
  • Created at : 2026-03-06 17:35:40
  • Updated at : 2026-03-06 17:35:40
  • Link: https://jasperzpzhang.github.io/stm32-cmake-cross-compile-guide/
  • License: This work is licensed under CC BY-NC-SA 4.0.