This article is the first of a series dealing with CMake and STM32 microcontrollers. In fact, it is more about CMake on MCUs but I had to pick one ...
For further actions, you may consider blocking this person and/or reporting abuse
I have just run into this article. Awesome one, I really like your approach.
But I have a question - why don't you use our STM32CubeMX support? Most of your CMakeLists.txt can be written automatically with that.
Thanks!
The reason is because this serie is dedicated to CMake on MCU and I try to be as agnostic as possible from other tools than CMake itself.
The purpose is for people to understand how to write the CMakeLists.txt. Asking a tool to generate it is not exactly the best approach in my opinion.
Furthermore, CLion is not a free software (even if EAP might be a possible workaround). Even if I talked about it in my second episode, I didn't want it to a central piece of my articles.
Also, I talked about STM32 because I had to choose one MCU to write code examples. Using a tool that is dedicated to these families seemed to be even less agnostic.
To be honest, I haven't tried the STM32CubeMX support since it has been integrated directly in CLion. We used the 3rd party plugin, a long time ago. But I remember we didn't used the generated CMakeLists.txt for our project.
Ok, thanks, I fully understand your reasons.
In fact that generated CMakeLists.txt is quite close to your one, the same ideas behind. And it's possible that "3rd party plugin" was my old hobby project :-).
Some small notes about CMakeLists.txt:
Toolchain file looks a bit overcomplicated thingy, I prefer(ed) to keep toolchain information in the same
CMakeLists.txt
(important note: aboveproject
clause). On the other hand, nowadays we have CMake presets feature, which may make the toolchain file a bit more user-friendlyYou do not need to use
arm-none-eabi-size
utility, the linker can print the same information, CMake clauseadd_link_options(-Wl,--print-memory-usage)
does the trickIf, at some point, you want to make a project with dual-core STM32H7xx, I have a template for CMakeLists.txt for this case, not tied to CLion, but extracting project information directly from STM32CubeMX files.
I like your 3rd episode, that's a great idea to hide all of false-positive compiler warnings coming from libraries, that helps to keep actual project code error-free.
I also like your C++ episodes, embedded software have to move towards stricter and safer languages.
I guess it was! Thanks a lot for this plugin, it was the key to move from Eclipse to CLion. And moving to CMake & CLion was one of the greatest choices we made on this project!
About these small notes :)
Using a tool chain seems to be the CMake way to cross-compile, that's why I show it here. If your project is solely made to generate a firmware for a MCU, then setting the toolchain directly in the CMakeLists.txt seems indeed simpler and as efficient. But once you want to also generate a PC-based software, for instance for unit tests and simulators, the toolchain file seems the obvious way. I wanted to make an episode about PC-executed unit tests but never took the time (for the moment?). I wasn't aware of CMake presets, I am going to check them! Thanks!
You have missed the PS in my article ;) I wasn't aware of this option when I wrote the article. Must simpler indeed! And in the end it's bad for this article: it shows how to call an external software as a post-build step.
Thanks for sharing. I hope I will use such a MCU one day.
Thanks!
Nice to see other people willing for the embedded world to move to C++. I have been using only C++ for the last 5 years. I will never go back to raw C. I have been looking for the Rust a little, but didn't try to run it on MCU for the moment. Maybe one day XD
Feel free to use my prototype for that. It worked 2 yrs ago:)
And I am now thinking about an article about emulator-running unit tests. A prototype works. One day.... You know :)
I will have a look at it, thank you :)
Yes, I know...
I have tried out CMake presets and they are amazing. I still have a problem to load MVSC presets in CLion. I have a configure preset like this one:
From the command-line, I must call
vcvarsall.bat
to configure the compiler before callingcmake --preset=a-preset-that-inherits-from-this-one
.In CLion, do you know how I can call this script when I use the action "Load CMake presets"?
The answer from my colleague:
You actually don't need to run vcvarsall.bat manually. CLion will take care of it. You need to:
configure Visual Studio toolchain in CLion
specify this toolchain in your preset using this JSON fragment:
Here's a more detailed instruction: jetbrains.com/help/clion/cmake-pre...
That's even better than asking the support directly! Thanks 😁
It does work if I add the key to the derived preset, but it does work on the base preset. It seems that the "vendor" map is not inherited.
When I read the documentation, it looks like a bug to me:
Yeah, you are right. Now there is a ticket about it
youtrack.jetbrains.com/issue/CPP-2...
That's perfect :)
I was not expecting to see such a high quality embedded post on dev.to.
Your Cmake is great:
[X] Using the target_* API
[X] Using toolchain file
[X] Almost no set() variable
[X] No glob
[X] Generator expression
[X] Support windows and posix
[X] add_custom_command
I'd like to see more advanced compiler flag configuration. Also how about adding unit tests? Or supporting gdb?
Merci et bonne journée!
Woh! This comment made my day! ❤️
For more advanced compiler flags: have you read other episodes in the series? See the table at the beginning of this article.
I have planned to write another episode about running unit tests on your computer. I don't know when I will do it.
I have not planned to talk about GDB:
Bonne journée :)
thanks for posting this.
we're going to use cmake for SiLabs ARM project
I upgraded Qt to version 6, and have loved that it uses cmakelists.txt as its project file. That has been awesome
Thanks for this, I tried to follow other tutorials, but those were focused on a lot of other things than compiling and linking so this was a very good start to finally get something built.
I use globbing, but that comes down to personal preference (it has its pros and cons).
Not quite sure why that happens, but I got an extension of .elf so I used:
set_target_properties(${EXECUTABLE} PROPERTIES
SUFFIX ".out"
)
To actually get an .out file.
Now I just have to adjust some things, but it's looking much better.
You're welcome :)
Globbing has its advantages, no doubts! My experience proved that you end up excluding some files from the result list and you get back to list your files by hand ^^
Nevertheless, they are good for instance to get a set of generated files when these numbers of files and their names is not known in advance.
I believe *.elf is the default extension for GCC generated software. Nice trick ;)
This post was awesome! I've made many STM32 projects with SCons and with GNU Make, and this shows how easy it could be for me to transition!
CMake is great for me, as it can generate outputs for language servers which can then hook into emacs (or Visual Studio Code if that's your thing). I think this will allow me to have a bit more of a modern feel :D
I'll be reading your follow-ups next!
I get below errors after apply " cmake --build . -- -j 4"( Win and ubuntu )
D:\Dev-Tools\cmakef4\startup_stm32f413xx.s: Assembler messages:
D:\Dev-Tools\cmakef4\startup_stm32f413xx.s:1: Error: junk at end of line, first unrecognized character is
-'
startup_stm32f413xx.s 'D:\Dev-Tools\cmakef4\startup_stm32f413xx.s:2: Error: bad size 0 in type specifier
D:\Dev-Tools\cmakef4\startup_stm32f413xx.s:2: Error: bad instruction
mingw32-make.exe[2]: *** [CMakeFiles/nucleo-f413zh.out.dir/startup_stm32f413xx.s.obj] Error 1
mingw32-make.exe[1]: *** [CMakeFiles/nucleo-f413zh.out.dir/all] Error 2
mingw32-make.exe: *** [all] Error 2
This looks weird.... The errors happen ion lines 1 and 2 of the file.
Is the file correct?
What version of arm-none-eabi-gcc do you use?
Does the Makefile generated by STM32CubeMX work?
You can try the following command
cmake --build . --verbose -- -j 4
to get more details from the build system.->Yes the file is correct and project generated by stm32cubemx
-> arm-none-eabi-gcc version
arm-none-eabi-gcc.exe (GNU Tools for Arm Embedded Processors 8-2019-q3-update) 8.3.1 20190703 (release) [gcc-8-branch revision 273027]
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-> cmake --build . --verbose -- -j 4
[ 4%] Building ASM object CMakeFiles/nucleo-f413zh.out.dir/startup_stm32f413xx.s.obj
D:\Dev-Tools\gcc-arm-8\bin\arm-none-eabi-gcc.exe -DSTM32F413xx -DUSE_HAL_DRIVER -ID:\Dev-Tools\cmakef4\Core\Inc -ID:\Dev-Tools\cmakef4\Drivers\STM32F4xx_HAL_Driver\Inc -ID:\Dev-Tools\cmakef4\Drivers\CMSIS\Device\ST\STM32F4xx\Include -ID:\Dev-Tools\cmakef4\Drivers\CMSIS\Include -g -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fdata-sections -ffunction-sections -Wall -Og -o CMakeFiles\nucleo-f413zh.out.dir\startup_stm32f413xx.s.obj -c D:\Dev-Tools\cmakef4\startup_stm32f413xx.s
D:\Dev-Tools\cmakef4\startup_stm32f413xx.s: Assembler messages:
D:\Dev-Tools\cmakef4\startup_stm32f413xx.s:1: Error: junk at end of line, first unrecognized character is
-'
startup_stm32f413xx.s 'D:\Dev-Tools\cmakef4\startup_stm32f413xx.s:2: Error: bad size 0 in type specifier
D:\Dev-Tools\cmakef4\startup_stm32f413xx.s:2: Error: bad instruction
mingw32-make.exe[2]: *** [CMakeFiles/nucleo-f413zh.out.dir/startup_stm32f413xx.s.obj] Error 1
mingw32-make.exe[2]: Leaving directory
D:/Dev-Tools/cmakef4/cmake-build-debug'
D:/Dev-Tools/cmakef4/cmake-build-debug'mingw32-make.exe[1]: *** [CMakeFiles/nucleo-f413zh.out.dir/all] Error 2
mingw32-make.exe[1]: Leaving directory
This is quite an old version of GCC.
To be clear: the Makefile generated by stm32cubemx does build the project, right?
Not an expert, but stumbled about some errors in my own project to find some workarounds below.
For anyone else having problems with "undefined reference to ... _close, _lseek" etc, remove the "enable_language(C ASM)" line.
This seems to be an issue of libg_nano.a vs liba_nano.a - with the line in it seems to use libg_nano.a and you get the linker errors.
Alternatively, changing "-specs=nano.specs" to "-specs=nosys.specs".
Errors like these are indeed caused by variations in the standard libraries. I am not familiar with specs files, so fixing them is a bit like coin-flipping for me ;)
Hello, great series! I'm a bit confused about the usage of
CMAKE_FIND_ROOT_PATH
inside the toolchain file. It is set to${BINUTILS_PATH}
which points togcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc.exe
. I would expect to find the toolchain library paths instead?Glad you enjoyed the series :)
To be very honnest, I didn't write the toolchain myself. We have been using this file since 2018 and I don't remember how we got it.
Your comment seems pretty legit. I believe the toolchain file is wrong.
After some researches and experiments, I was able to reduce the toolchain file and the projects (both the sample project I am using for this series and the professional projects at my office) keep building successfully.
Here my shrinked file:
Since I never write toolchain files, I may be missing some points. For instance, I know that CMAKE_SYSTEM_VERSION should be set:
But I have no idea of the value I should give it... The official toolchain file samples don't always set it.