[MBed CLI Alternative] mbed-cmake

That sounds really good.
I like the Mbed build system because it is really easy to add sourcefiles or libraries. But there are problems when you add headerfiles with names that exist already. Or when you try to reduce the number of included files with .mbedignore entries. There are too many unknown dependencies and this is a tedious work. I hope these issues will be fixed by an improved build system.

Thanks @MultipleMonomials for the positive overview of these complexe topics :slight_smile:

It’s good to hear that investing time in mbed-cmake won’t go to waste and that we’ll be able to move to the new tools easily.

Quick follow-up question (cc @Kojto : with the new cmake tools, will we still have mbed_app.json?

I’m not a big fan of the magic config parsing and json is really hard to edit by humans (the absence of comments is a pain in the neck).

1 Like

I cannot image that mbed_app.json will be dropped, it is something different than the build system. It is the way that librarys announce their settings and to set constant values without changing the library source code.
The config options can be shown with ‘mbed compile --config -v’. With this unified system, it should be possible to add editor extensions for a intellisense for mbed_app.json, that would be cool.

While waiting for the Mbed OS feature-cmake branch to be merged into master, we’ve decided to use mbed-cmake in our project.

Before blindly moving to a new build system, I decided to try it on a smaller project with the same structure to make sure it would suit our needs.

The process is documented in a public repository.

I’ve tried to make the instructions as clear as possible. It’s a work in progress so things may change dramatically in the future.

I’m happy if it can help someone and I’m open to ideas, feedback and suggestions. PR and issues are welcome as well!

I’m happy to announce that after getting rid of some fiddling little details, we have successfully transitioned our whole project to mbed-cmake and it works like a charm!

Our project has the same structure as the template shared before, with:

  • lib directory to store our libs and our vendor libs (such as mbed-os) under lib/_vendor. We followed to Mbed’s cmake-feature directory structure with an include and source directory for each library
  • src directory for the main program (the firmware of our product)
  • spike directory to test features, solutions and investigate bugs

Everything is cmake base, it compiles great and we have near perfect autocompletion with cmake-tools in VSCode.

We also have different targets for different dev boards (internal & external) we’re using and switching is super easy.

We’ve also decided to not have mbed-os under source control yet. We want to be able to keep up with the development and the whole project adds too much clutter to our own. I’ll try to find a way to only keep what we need (in particular regarding targets).

What we don’t have yet:

  • unit tests
  • functional tests (greentea or icetea)
  • separate application and bootloader (we’ll work on that next)
1 Like

I’m not yet using cmake, but it sounds interesting.
My project structure looks like this:

This uses a common mbed-os to avoid wasting to much HD space. The disadvantage is, that an update may not work for some older app, but it can be switched quickly to another mbed-os branch by using git.
I use this also together with VSCode and I start from a workspace within the app folder. The tasks are the same for all apps, so for starting a new project I can copy the app to a new directory in the apps folder. The tasks use ‘mbed compile’ for the build process. A task looks like this:

      {
            "label": "compile debug",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "command": "mbed",
            "args": [
                "compile",
                "--build",
                "../../BUILD/${workspaceFolderBasename}/Debug",
                "--source",
                ".",
                "--source",
                "../../mbed-os",
                "--source",
                "../../libs",
                "--source",
                "../../drivers",
                "--source",
                "../../custom_targets",
                "--source",
                "../../components",
                "--profile",
                "debug"
            ]

Problem is here only intellisense, I have to run a (modified) VScode export to create the c_cpp_properties.json for different targets.

Another caveat with VSCode is that it cannot handle nested git repos, so this structure was necessary. But it is not compatible with the mbed library handling and publishing projects is more difficult.

Now I am interested in what is different to my system.
Is switching between different releases easy as with the mbed build system? The mbed build does always a scan before compiling. But this takes a long time now already. I guess a cmake run has to be started before a make? or does cmake all in one?

In our case, we clone mbed-os with git clone --depth=1 --branch=mbed-os-6.2.1 https://github.com/ARMmbed/mbed-os.

The --depth=1 is important as it clones only the last commit so the directory is not that heavy, only 686,3 MB :wink: The draw back is that you need to re-clone each time so you need a working internet connection.

You structure is not far from the mbed-cmake-template so it should not be that hard.

If you switch, you’ll still need to run the config script to generate the *_config.h and CMake files. Then you can just run CMake with Makefile or Ninja (we use Ninja).

As long as you don’t change any .json files or switch mbed-os version, you’re good.

If you do, you’ll need to config script again. But to be honest it’s pretty fast, you’ll just recompile everything from scratch.

1 Like

thanks for your comments, its getting a little bit clearer now.
So, generating the config and CMake files is the step that the Mbed build system does with the python based scanning?

Is there a difference between the Mbed CMake branch and your work?

The current mbed-cli tools (as far as I understand) are not using CMake, they are parsing the configs and then calling the build commands from the python script (mbed compile).

mbed-cmake uses the mbed-cli to generate the cmake config and then it’s cmake all the way. meaning that you can store your config with git an share them with you team, without the need for those people to use mbed-cli (as long as you don’t change any .json, switch target or mbed-os version).

For an industrial project, those things are usually written in stone, so you won’t change them very often. For personal testing purposes, you might change those regularly. It will scan again, build from scratch but that’s not as bad as it sounds.

I personally love how CMake helps you organize your project.

For quick and dirty, mbed-cli might still be a good choice.

mbed-cmake has been mainly developed by @MultipleMonomials & ProExpertProg. I’ve contributed a little.

mbed-cmake-template is a fork from the current master (6dfe783) but starting from scratch, with a personal reorganization, renaming, some scripts improvements and the removal of mbed-os sources from the git history.

Give it a try! :slight_smile: and let me know if the documentation is good enough.

1 Like

thanks again for your detailed explanation, I’ll give it a try.

Hi all! I’m happy to announce that mbed-cmake has just been updated to version 1.4.0. This version includes a major new feature: the ability to use STM32Cube upload and debug tools with mbed-cmake.

Initially, I started experimenting with this because I was annoyed with pyOCD’s sluggish step-to-next-line command when debugging on my STM32 board, and I wanted to check what other alternatives were available. When I finally got STM32Cube set up, I was blown away: debugging commands run almost instantly! And not only that, but uploading code is at least 5-10 times faster than pyOCD’s upload command! That may not seem like much since it still completes in a few seconds, but if you’re uploading a 128k program tens of times a day, it adds up. And while this is similar to the speed you can get with OpenOCD, OpenOCD requires a lot of configuration to get running for a target while STM32Cube works out of the box.

There is one downside however: to get this to work, you need to install the entire STM32Cube IDE, which takes over 2GB of space. While this software is available freely, ST simply doesn’t distribute their GDB server in any way outside the IDE. And while you can copy the executable out of the IDE, it’s against their EULA to distribute it on its own, so I can’t make you a mini zip file with just the GDB server.

All in all though, this update should be a major productivity boost if you work with STM32 boards. And you can see the docs on configuring the new upload method by scrolling to the bottom of the wiki page (which I also made some updates to).

NOTE: This update fixes the case of certain mbed-cmake file names. On Windows and Mac, if you are copying the new release into your repo (as opposed to using a submodule), you will need to run git config --global core.ignorecase false before committing the changed files to ensure these case changes get picked up.

NOTE 2: Make sure to also update your UploadMethodConfig.cmake in your project to enable the new upload method. The new configs to add can be found in the example project.

2 Likes

as an alternative for debugging I can recommend Black Magic Probe: Home · blackmagic-debug/blackmagic Wiki · GitHub
There you can connect gdb to the probe via a virtual com port. BMP detects the target itself and does not need further configuration. In my launch.json for VSCode, I need to specify only the port for the probe.
And currently I have merged BMP and Mbed. BMP uses libopencm3 and has no ethernet support, I have made the BMP to work over ethernet. So in gdb, a ‘target ext ip:port’ will directly connect to the probe. Its still experimental, but flashing works with 37 kB/s pretty fast and a single step takes about 30 ms. My hardware is a cheap STM32F407VG board + LAN8720 phy, but with Mbed it can run also on other boards with Ethernet.
The USB version on a F103 does flashing with 22 kB/s on the same target.

Flashing seems to be working flawlesly (Win10), but I can’t get debug to work.

I always get

C:/MBED_CMAKE/Target/build/mbed-cmake.gdbinit:3: Error in sourced command file:

[build] localhost:61234: No connection could be made because the target machine actively refused it.

And the offending line in gdbinit:3 is
target remote localhost:61234

And that doesn’t change no matter which port I use. When the default port didn’t work, I used 61234 which is used by STM32CubeIDE by default.

Did you run ninja start-gdbserver in another terminal first?

I didnt know i needed to do that, since the first line of response from “ninja debug-Project” is “starting GDB to debug Project
”

But it is still not working. I want to explore this deeper.

as a first few lines after is start debug with a gdb server started i get

[build] This GDB was configured as "--host=i686-w64-mingw32 --target=arm-none-eabi".
[build] Type "show configuration" for configuration details.
[build] For bug reporting instructions, please see:
[build] <http://www.gnu.org/software/gdb/bugs/>.
[build] Find the GDB manual and other documentation resources online at:
[build]     <http://www.gnu.org/software/gdb/documentation/>.
[build] 
[build] For help, type "help".
[build] Type "apropos word" to search for commands related to "word"...
[build] Reading symbols from D:/Google Drive/VENDING/Project/build/HrVendExec.elf...
[build] Reset_Handler ()
[build]     at ../mbed-cmake/mbed-src/targets/TARGET_STM/TARGET_STM32L4/TARGET_STM32L433xC/device/TOOLCHAIN_GCC_ARM/startup_stm32l433xx.S:63
[build] 63	  ldr   sp, =_estack    /* Atollic update: set stack pointer */
[build] (gdb) Exception condition detected on fd 0
[build] error detected on stdin
[build] A debugging session is active.
[build] 
[build] 	Inferior 1 [Remote target] will be killed.
[build] 
[build] Quit anyway? (y or n) Exception condition detected on fd 0
[build] error detected on stdin
[build] A debugging session is active.
[build] 
[build] 	Inferior 1 [Remote target] will be killed.
[build] 
[build] Exception condition detected on fd 0
[build] error detected on stdin
[build] A debugging session is active.
[build] 
[build] 	Inferior 1 [Remote target] will be killed.
...

And the last message repeats.

Currently, opening the STM32CubeIde and manually pointing the debbuger to .elf file in build directory works just fine, so I am using that.

Hmm, someone else reported this too, but I can’t reproduce on STM32F429ZI. Pretty sure it’s related to config options on the GDB server.

We need to try and figure out what command line arguments the IDE is running ST-LINK_gdbserver.exe with. I think that the easiest way to do this is to first start GDB from the IDE. Then run Process Explorer, find ST-LINK_gdbserver.exe in the list, right click it and selecting Properties, then go to Image > Command line. Can you send me the command line it shows?

Update: turns out I was totally barking up the wrong tree on this! One of the developers at RPL worked with me to diagnose the issue. Turns out that the issue is that Ninja doesn’t run GDB from an interactive terminal, so it freaks out and gives Exception condition detected on fd 0. I feel like “Hey! Please run me from an interactive terminal!” would be a better message, but


Thankfully there is an easy fix for this by adding the CMake option USES_TERMINAL to add_custom_target().

I went ahead and released version 1.4.1 with this fix, plus another fix for ST-LINK_gdbserver failing to execute on Linux and Mac systems with a shared library error.

1 Like

mbed-cmake 1.5.0 has been released!

Changes:

  • Refactor upload method system to make it cleaner and enable you to add upload methods without modifying mbed-cmake
  • Fix CMake dependency errors in unit test configuration (how did it ever work before??)
  • Includes mbed-os 6.5.0 (patched to support unignore rules and to fix a broken mbedignore file (events/tests/.mbedignore) that caused build errors)
  • Rewrote default “ignore all extras” mbedignore file for mbed-os 6.5+ file structure.

Note:

Several upload method variables in this version were renamed for better consistency. These changes have been updated on the wiki page. The renames are:

  • JLINK_JTAG_SPEED → JLINK_CLOCK_SPEED
  • PYOCD_JTAG_SPEED → PYOCD_CLOCK_SPEED

Also, a new STM32CUBE_PROBE_SN variable was added to STM32CUBE to provide better control over which ST-Link is used.

Note 2:

With the pace of official cmake development, this is likely to be the last major release of mbed-cmake. Currently, official CMake is not yet usable for everyone as it’s missing support for many targets as well as upload method support. However, I’m working hard to submit the best features of mbed-cmake as pull requests, and I hope we can get it feature complete within the next few months!

3 Likes

Also, one other announcement: I’m introducing two alternate builds of mbed-cmake: “retro” and “paleo”.

I know that there are lots of you out there who are still using older Mbed OS versions - maybe your target was removed in Mbed 6, or maybe you haven’t updated your code for breaking changes, or maybe you’re just scared to try out this RTOS business (that’s how RPL was until somewhat recently!). Since these versions will never get official CMake support, mbed-cmake is your only way to build them with CMake. However, until now doing that has required copying around a bunch of source files, and even manually patching the Mbed source code in some cases. With these new alternate builds, this becomes a lot easier:

  • mbed-cmake Retro contains the mbed-cmake system together with Mbed OS 5.15.6, for people who need Mbed OS 5.x
  • mbed-cmake Paleo contains the mbed-cmake system together with Mbed 2 r163 for people still using Mbed 2 (I know you’re out there!)

To use these alternate builds, just check out the retro and paleo branches of the mbed-cmake and mbed-cmake-example-project repositories instead of the master branch. I have tested that they compile and run on a few of my boards but I also don’t have the time to test them exhaustively, so let me know if they’re behaving weirdly.

Note: Unit testing is not supported on the retro or paleo configurations.

Note 2: You would not believe how hard it is to find the actual source code for mbed 2! The “most recent” release that mbed-cli downloads is broken and missing most of the source code, and all of the github tags are wrong so I can’t find the old releases on the GitHub repo. I was finally able to find the source code only via a mirror repository.

Just pushed a neat update! Have you ever been annoyed by always having to update the MBED_PATH variable when you plug a new board into your machine? It turns out that all this time, Mbed OS has had an automatic code uploader built in to the mbed-tools python package! It is capable of automatically traversing the list of USB devices to find any and all Mbed dev boards connected to your machine.

I’ve adapted this into a rewrite of the MBED upload method. So, it will automatically search your machine for mbed boards that match your project target and then upload code straight to them – no configuration needed. It will ignore other boards that are a different model, and if you do have multiple of the same board connected, it’s smart enough to handle this case as well (mbed-cli will just blindly flash all of them):
multiple boards

Before I can release it to master, I need a couple people to beta-test this functionality for me. If you’re interested in trying it out, just check out the mbed-pathless branch of the mbed-cmake repository, and report back here whether it works for you. Thanks for your help!

1 Like