on 2025-12-05 4:44 AM
This article aims to introduce STM32 developers to the basics of CMake, focusing on practical use cases that simplify the learning curve and help avoid common pitfalls during onboarding.
In the rapidly evolving world of embedded development, efficient and reliable build systems play a crucial role in accelerating product development and ensuring code quality. For STM32 developers, grasping the build process is fundamental to fully leveraging the power of STM32 microcontrollers and their extensive ecosystem.
CMake has emerged as a modern, versatile, and widely adopted build system generator that addresses many challenges faced by embedded developers today. Unlike traditional IDE-specific project formats, CMake provides a unified, flexible, and portable approach to managing builds across different platforms, toolchains, and environments.
STM32CubeIDE and Eclipse/CDT offer excellent GUI-based development solutions. However, to meet the growing demand for automation and modern engineering practices, we are expanding our offering to fully support flexible, CLI-based workflows and robust CI/CD integration.
Our command-line tools (CLT) are the first step in this transition. We are fundamentally embracing CMake because it provides the necessary foundation for true flexibility. CMake enables developers to easily generate project files for a variety of IDEs or compile code directly via the command line, ensuring maximum freedom and tool choice.
CMake uses simple, text-based configuration files (CMakeLists.txt) that are easy to version control, share, and maintain. This is not the case with IDE-specific project files that are often bulky and difficult to manage. As STM32 projects grow in complexity, CMake’s modular approach helps maintain a clean and scalable build system.
CMake’s toolchain abstraction can allow developers to switch seamlessly between toolchains without rewriting build scripts. This flexibility allows STM32 developers to more easily port projects between toolchains.
In modern embedded development, automated builds and testing pipelines are key to maintaining code quality and accelerating delivery. CMake’s command-line driven workflow integrates naturally with continuous integration (CI) systems, enabling STM32 teams to automate builds, run tests, and deploy firmware efficiently.
Many STM32 software components, middleware, and libraries now provide native CMake support or integration examples. Learning CMake empowers developers to take full advantage of these resources, reducing integration effort.
By understanding and adopting CMake, STM32 developers gain a powerful skillset that enhances productivity, fosters collaboration, and future-proofs their projects. This article will guide you step-by-step through essential CMake concepts and practical examples tailored to STM32 development, ensuring a smooth and confident onboarding experience.
This article is not an intended to be full training on all CMake concepts and usage. To learn more, visit the official CMake online documentation link.
To generate a CMake project, follow these steps:
The selected folder must contain only one Project (CMakeLists.txt). If you want to open multiple projects in your workspace, you must add them one by one using “File → Add Folder to Workspace…” menu.
STM32CubeMX is responsible for the generation of two types of CMake files:
You can create or add your own configuration and build preset in the CMakePresets.json file
This is an example of a preset configuration:
For more details about the parameters, visit https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html
After creating the config preset, a build preset must be created in the same file example:
To use this configuration preset you can select it from the “Project Status” tab of the CMake extension interface as following, or via the command line with --preset=example:
You can also use the CMAKE_BUILD_TYPE as a condition to build/include files.
CMakeLists.txt is a one-time generated file. Any user change is kept if STM32CubeMX or other ST tools are regenerating assets.
Two CMakeLists.txt files are available in your project:
We advise using relative paths instead of full path to help share your project across development environments.
To add source files, use the "target_sources" node as shown below:
To add header folders, use the "target_include_directories" node:
To add library files, use the "target_link_libraries" node for the lib name and "target_link_directories" for the lib path:
Toolchain files are for GCC and starm-clang.cmake for llvm. Both files embed the parameters, but the configuration differs from one toolchain to another.
When creating a new project from extension, you have the choice between GCC LLVM or a hybrid environment with both LLVM and GCC. In the hybrid environment, both files are present in the project.
You can change your compiler settings from this batch of parameter
You can change your output settings from this batch of parameter
You can change your cortex settings for the compiler from this batch of flags
The settings depend on the selected context. By default, only release and debug are available. If you have an additional build context, you can add more configurations in this area.
The compiler supports the following optimization levels:
-Og enables optimizations that do not interfere with debugging. It should be the optimization level of choice for the standard edit-compile-debug cycle, offering a reasonable level of optimization while maintaining fast compilation and a good debugging experience.)
-Os enables all -O2 optimizations that do not typically increase code size. It also performs further optimizations designed to reduce code size. -Os disables the following optimization flags: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)
You can change your ASM compiler settings from this batch of parameter
You can change your Linker settings from this batch of parameter
Two types of projects can be generated, single context projects and multicontext projects.
A multicontext project is generated for:
In the figure below you can see the difference between these two types of projects.
For the multicontext projects, you find the same described files before in single projects but with more specificity:
For additional help, visit our VS Code forum board below and ask your question there:
https://community.st.com/t5/stm32cubeide-for-visual-studio/bd-p/stm32-vscode-extension-mcus