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
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:
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
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
| 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.
Note
lib/stm32 and lib/util link each other. That cycle is legal only because both currently
resolve to INTERFACE libraries (neither has any .cpp files yet). Adding a source file to
either one will break the configure step until the cycle is removed.
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