Project Anatomy
Every firmware project has the same shape, whether it lives in src/, src/tests/ or
starter-projects/. This page uses src/bmc as the example. For what each board actually
does, see Boards.
What You Should Edit
Section titled “What You Should Edit”Almost everything in a project directory is generated and will be overwritten. The files that are genuinely yours:
Src/*.cpp: your firmware. Picked up by a glob, so new files need no CMake change.Inc/*.hpp: your headers, other than the generated<project>_config.hpp.USER CODE BEGIN/USER CODE ENDblocks inside CubeMX’smain.candmain.h.- The
.iocfile, edited through the CubeMX GUI.
Everything else regenerates.
File Breakdown
Section titled “File Breakdown”src/bmc/ CMakeLists.txt generated by update_cmake_cfg.py CMakePresets.json generated by update_cmake_cfg.py bmc.ioc CubeMX, edited through the GUI startup_stm32g431xx.s CubeMX STM32G431XX_FLASH.ld CubeMX, referenced by the toolchain file cmake/ gcc-arm-none-eabi.cmake CubeMX, used by every preset starm-clang.cmake CubeMX, unused Inc/ main.h CubeMX, USER CODE blocks are yours stm32g4xx_hal_conf.h CubeMX stm32g4xx_it.h CubeMX bmc_config.hpp generated by config_gen.py motor.hpp yours err.hpp yours type.hpp yours Src/ main.c CubeMX, USER CODE blocks are yours stm32g4xx_hal_msp.c CubeMX stm32g4xx_it.c CubeMX syscalls.c CubeMX sysmem.c CubeMX system_stm32g4xx.c CubeMX controller.cpp yoursThe five CubeMX .c files plus the startup assembly are compiled by lib/stm32g4, not by the
project itself. The project’s own target_sources globs Src/*.cpp only.
Two Directory Layouts
Section titled “Two Directory Layouts”Most projects keep sources at Src/ and Inc/. Some CubeMX versions emit Core/Src and
Core/Inc instead, and src/tests/serial is the one project in this tree that does. The generator
probes for both, so either works, but do not mix them within a project.
The Interface with lib/
Section titled “The Interface with lib/”A project must set three variables before pulling in the library tree:
set(MX_SRC_DIR "${CMAKE_SOURCE_DIR}/Src")set(MX_INC_DIR "${CMAKE_SOURCE_DIR}/Inc")set(MX_STARTUP_S "${CMAKE_SOURCE_DIR}/startup_stm32g431xx.s")
add_subdirectory(../../lib fwlib)lib/stm32g4 fails the configure step if any is missing, and lib/CMakeLists.txt uses their
presence to decide whether this is an MCU build at all. lib/stm32g4 then reaches back up and adds
sources to the project’s own executable target by name, which is why the ordering matters.
Linked Libraries
Section titled “Linked Libraries”The bottom of a generated CMakeLists.txt looks like this:
# Add linked librariestarget_link_libraries(${CMAKE_PROJECT_NAME} stm32cubemx
# Add user defined libraries stm32 dbc util)stm32cubemx is always present. The rest come from the --lib flags passed to scripts/new.sh:
./scripts/new.sh --board NUCLEO-G431RB --src src/example --lib stm32 --lib dbc --lib utilLibrary names are not validated. A typo becomes a missing-target error at build time.
Regenerating a Project
Section titled “Regenerating a Project”There is no shell wrapper for this. Run the tool directly:
uv run --project tools python tools/scripts/update_cmake_cfg.py \ --src src/bmc --root . --ctx lib/stm32g4 \ --lib stm32 --lib dbc --lib util