Build Systems and CMake
Build systems automate compilation, dependency management, and linking. They track changes and rebuild only what's necessary, making large C++ projects manageable.
Build systems automate compilation, dependency management, and linking. They track changes and rebuild only what's necessary, making large C++ projects manageable.
Choosing a build system for firmware feels like a taste question and is not. The real question underneath it is who owns the generated code, and it has consequences that outlive the project: whether a colleague can build your firmware without installing an IDE, whether CI can build it at all, and whether the day you need to change a pin assignment costs ten minutes or a merge conflict across forty files you did not write.
What are Build Types?
A CUDA project stops being a single nvcc invocation the moment it has more than one translation unit, a library dependency, or a need to target more than one GPU architecture, and hand-rolled build scripts get brittle fast at that point. CMake treats CUDA as a first-class language rather than a special case bolted onto a C++ build, which is what makes multi-file projects, per-architecture code generation, and linking against CUDA libraries manageable without duplicating flags across a Makefile.
Modern CMake Philosophy
CMake's defaults encode one assumption so deeply that it is easy to miss: the machine running the build can also run what the build produces. That is what lets CMake test a compiler by compiling and linking a tiny program, what lets findpackage look in /usr/lib, and what lets checkcsourceruns exist at all. Every one of those assumptions is false for a Cortex-M4 with 128 KB of RAM and no operating system.
CMakePresets.json captures your configure, build, and test settings in a checked-in JSON file, so a
What are Variables?
File Anatomy
What is CTest?
Overview
Core Commands
A target is the unit of modern CMake. Once addexecutable() (or addlibrary()) creates one,
What is ExternalProject?
What is FetchContent?
CMake offers three, in rough order of preference:
Overview
What Are Generator Expressions?
fmt can be dropped into a project as header-only, with no build step at all, or built and linked as
There isn't one right way to add nlohmann/json to a project — there's a spectrum from "copy one
The header-only default is what makes spdlog trivial to adopt — copy a directory, add an include
Installation Methods
This page covers creating libraries and attaching their usage requirements (include dirs,
Understanding Library Linking
This page is about how to structure a project across directories. It leans on
CMake is a build-system generator: you describe your project once in CMakeLists.txt, and CMake
Understanding Target Properties
Overview
CMake is how most projects consume Boost today. Instead of hand-rolling include paths and -lboost_*
Overview
This page is the mechanics of add_subdirectory() — scope, ordering, and how targets and
What Are Find Modules?
Blinking an LED from an Arduino sketch takes two lines and teaches nothing about the machine. Blinking one with no HAL, no IDE and no library takes about ninety lines spread over five files, and by the end you know where every byte of the image came from, what the processor did before your first instruction, and which two writes in the whole program actually made the light change.
Project Structure