Skip to content

Instantly share code, notes, and snippets.

@elmot
Created June 28, 2024 16:23
Show Gist options
  • Save elmot/c1691c56d8241b17dcaa690acc170264 to your computer and use it in GitHub Desktop.
Save elmot/c1691c56d8241b17dcaa690acc170264 to your computer and use it in GitHub Desktop.
CMake project for STM32H7Sxx with multiple subprojects
# CMakeLists.txt for multi-project STM32H7Sxx MCUs and CLion IDE
#
# DISCLAIMER: Experimental version, based on undocumented assumptions how STM32CubeMX works
# DISCLAIMER: THIS FILE IS PROVIDED UNDER "The Unlicense" LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND
#
# Requirements:
# Toolchain binaries have to be in system path
# STM32CubeMX field "Project Manager | Code Generator | Target IDE" must be set to "STM32CubeIDE"
#
# Tested under environment:
# Windows 10
# GCC toolchain for ARM Cortex-M V2019q4
# STM32CubeMX V6.11.1
# STM32CubeH7 Firmware Package V1.0.0
# CLion 2024.2
#
# How To Use:
# 1. Set up CLion according to https://www.jetbrains.com/help/clion/embedded-overview.html#build-system
# 2. Create a project using STM32CubeMX STM32H7Sxx MCU, set "Target IDE" as STM32CubeIDE, and click GENERATE CODE
# 3. Place this file into the project root folder
# 4. Open the project root folder as CLion project "File | Open..."
#
# Written by ilia.motornyi[%]jetbrains.com
#
cmake_minimum_required(VERSION 3.21)
# Cross compilers and tools
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)
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_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
# Project settings.
get_filename_component(ProjectId ${CMAKE_CURRENT_LIST_DIR} NAME)
string(REGEX REPLACE "[^-_a-zA-Z0-9]" "_" ProjectId ${ProjectId})
project(${ProjectId} C CXX ASM)
# Common compile settings
# Language standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
set(CMAKE_EXECUTABLE_SUFFIX .elf)
# Build types
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
message(STATUS "Maximum optimization for speed")
add_compile_options(-Ofast)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
message(STATUS "Maximum optimization for speed, debug info included")
add_compile_options(-Ofast -g)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
message(STATUS "Maximum optimization for size")
add_compile_options(-Os)
else ()
message(STATUS "Minimal optimization, debug info included")
add_compile_definitions(DEBUG)
add_compile_options(-Og -g3)
endif ()
# Generic compiler settings
add_compile_options(-mcpu=cortex-m7)
add_compile_options(-mthumb -mthumb-interwork)
add_compile_options(-ffunction-sections -fdata-sections -fno-common -fmessage-length=0)
add_link_options(-mcpu=cortex-m7)
add_link_options(-mthumb -mthumb-interwork)
add_link_options(-Wl,-gc-sections,--print-memory-usage)
# Enable hardware FPU
add_compile_options(-mfloat-abi=hard -mfpu=fpv5-sp-d16)
add_link_options(-mfloat-abi=hard -mfpu=fpv5-sp-d16)
add_compile_definitions(ARM_MATH_CM7;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
# Enable assembler files preprocessing
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-x$<SEMICOLON>assembler-with-cpp>)
# Uncomment to mitigate c++17 register variable warnings
#add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-register>)
# End of common part
function(ModuleProject PART_NAME)
if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/${PART_NAME}")
# Detect linker scripts. Priorities: *_USER.ld, if not found *_FLASH.ld, if not found first *.ld
file(GLOB LINKER_SCRIPTS "${PART_NAME}/*_USER.ld")
if (NOT LINKER_SCRIPTS)
file(GLOB LINKER_SCRIPTS "${PART_NAME}/*_FLASH.ld")
if (NOT LINKER_SCRIPTS)
file(GLOB LINKER_SCRIPTS "${PART_NAME}/*.ld")
endif ()
endif ()
list(GET LINKER_SCRIPTS 0 LINKER_SCRIPT_${PART_NAME})
message(STATUS "Detected Linker Script for ${PART_NAME}: ${LINKER_SCRIPT_${PART_NAME}}")
# Part-specific sources
file(GLOB_RECURSE SRC "${PART_NAME}/*.*" "Drivers/*.*")
add_executable(${PROJECT_NAME}_${PART_NAME} ${LINKER_SCRIPT_${PART_NAME}} ${SRC})
target_link_options(${PROJECT_NAME}_${PART_NAME} PRIVATE -Wl,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}_${PART_NAME}.map -T ${LINKER_SCRIPT_${PART_NAME}})
target_include_directories(${PROJECT_NAME}_${PART_NAME} PRIVATE ${PART_NAME}/Core/Inc)
set(HEX_NAME ${PROJECT_NAME}_${PART_NAME}.hex)
set(HEX_FILE ${PROJECT_BINARY_DIR}/${HEX_NAME})
# Custom command to build .hex files
add_custom_command(TARGET ${PROJECT_NAME}_${PART_NAME} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}_${PART_NAME}> ${HEX_FILE}
BYPRODUCTS ${HEX_FILE}
COMMENT "Building ${HEX_NAME}")
# Read kernel-specific header paths, defines, and sources from ".mxproject"
file(STRINGS .mxproject LINES)
foreach (LINE ${LINES})
if (LINE MATCHES "\\[${PART_NAME}:(PreviousUsedCubeIDEFiles|PreviousLibFiles)\\]") #Detect relevant group
set(CUBE_PRJ_GROUP "${PART_NAME}")
elseif (LINE MATCHES "^\\[.*\\]$") #Detect non-relevant groups
unset(CUBE_PRJ_GROUP)
elseif (CUBE_PRJ_GROUP)
if (LINE MATCHES "^\\s*CDefines=\\s*(.*)") #Detect defines
target_compile_definitions(${PROJECT_NAME}_${CUBE_PRJ_GROUP} PRIVATE ${CMAKE_MATCH_1})
elseif (LINE MATCHES "^\\s*HeaderPath=\\s*(.*)\\s*") #Detect header paths
string(REGEX MATCHALL "[^;]+" INCL_LIST "${CMAKE_MATCH_1}")
target_include_directories(${PROJECT_NAME}_${CUBE_PRJ_GROUP} PRIVATE ${INCL_LIST})
elseif (LINE MATCHES "^\\s*LibFiles=\\s*(.*)\\s*") #Detect library sources
string(REGEX MATCHALL "[^;]+" SRC_LIST "${CMAKE_MATCH_1}")
foreach (SRC_FILE ${SRC_LIST})
if (EXISTS "${CMAKE_SOURCE_DIR}/${SRC_FILE}")
target_sources(${PROJECT_NAME}_${CUBE_PRJ_GROUP} PRIVATE ${SRC_FILE})
endif ()
endforeach ()
endif ()
endif ()
endforeach ()
endif ()
endfunction()
ModuleProject(Appli)
ModuleProject(Boot)
ModuleProject(ExtMemLoader)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment