Build System Overview
Firmware is built with CMake and the ARM GNU toolchain from STM32CubeCLT. STM32CubeMX generates
the hardware initialization code, but never builds anything. scripts/build.sh is the only
entry point you normally need.
Workflow
Section titled “Workflow”Each project under src/ is a standalone CMake project root. It has its own
CMakeLists.txt, CMakePresets.json and cmake/ toolchain files, and it pulls in the shared
firmware library tree with a single line:
add_subdirectory(../../lib fwlib)lib/ then builds the shared libraries and, critically, defines the stm32cubemx target that
CubeMX would otherwise have generated separately inside every project. One shared definition
replaces thirteen copies.
What Happens on a Build
Section titled “What Happens on a Build”Running ./scripts/build.sh --src src/bmc --preset Debug sets off the following chain:
-
build.shrunscmake --preset Debug. No-Dflags are passed, since the preset carries everything CMake needs. -
CMakePresets.jsonselects the build. It picks the Ninja generator, thebuild/Debugoutput directory, and the toolchain file. -
cmake/gcc-arm-none-eabi.cmakeselects the compiler. It resolvesarm-none-eabi-gccfromPATH, applies the Cortex-M4 flags, and points the linker atSTM32G431XX_FLASH.ld. -
src/bmc/CMakeLists.txtdeclares the project. It setsMX_SRC_DIR,MX_INC_DIRandMX_STARTUP_S, then pulls in the shared tree withadd_subdirectory(../../lib fwlib). -
lib/CMakeLists.txtbuilds the libraries. In order:tools/creates theuvvirtual environment and provides thepython_env_readytarget that both code generators depend on.lib/dbc/generatesMRoverCAN.hppfromdbc/MRoverCAN.dbc.lib/config/generates<project>_config.hppfromconfig/<project>.yaml.lib/stm32g4/definesstm32cubemxandSTM32_Driversover the vendored CubeG4 submodule.lib/stm32/andlib/util/provide the hand-written driver and utility headers.
-
The linker produces
src/bmc/build/Debug/bmc.elf, alongside a.mapfile you can inspect withanalyze_flash.py.
Steps 2 and 3 happen only on the first build. Afterwards Ninja re-runs CMake itself when a
CMakeLists.txt changes, so subsequent builds start at step 5. See
Build Script Internals.
The Library Tree
Section titled “The Library Tree”| Target | Source | What it gives you |
|---|---|---|
stm32cubemx | lib/stm32g4/CMakeLists.txt | HAL include paths and -D defines |
STM32_Drivers | lib/stm32g4/CMakeLists.txt | the compiled STM32G4 HAL |
stm32 | lib/stm32/ | board hardware drivers (hw/, serial/, adc.hpp, timer.hpp) |
util | lib/util/ | logger.hpp, pidf.hpp, filtering.hpp, util.hpp |
dbc | generated | CAN message classes from dbc/MRoverCAN.dbc |
config | generated | the board’s register struct from config/<project>.yaml |
A project selects which of these it links through --lib flags on scripts/new.sh. See
Project Anatomy.
Where to Go Next
Section titled “Where to Go Next”- Project Anatomy: what is in a project directory, and what you may edit
- Toolchain and Presets: compiler selection,
DebugvsRelease - Generated Libraries: how the DBC and config headers get built
- Build Script Internals: what
build.shactually runs - Continuous Integration: what CI builds, and in what container