[MBed CLI Alternative] mbed-cmake

thanks. I have not worked with cmake yet, I want to wait until some new release is using it. Its already hard to follow all the API changes and I’m happy that I have a reliable way now for building the projects :slight_smile:
Before, I used also some exporters, but it is a nightmare to keep them up to date. The mbed-cli without changes is much more easy to use, and integration to VSCode is simple with its tasks.json.

Goal for me with dependency and package managment is 100% reproducability, fat finger prevention, and very fast onboarding of new coders and or employees.

Not looking for NPM like ease of adding broken packages.

Because of Mbed’s test infrastructure I would not be hopping on to the latest of anything until it passes all automated tests. (Rocket included)

@MultipleMonomials I’ve spent yesterday setting up mbed-cmake with my project and I really like it so far. Had to tweak it a little bit to make it work.

Are you open to questions, suggestions, improvements, etc., in your project via issues or PR? Do you have a public roadmap of where you want to go?

Glad to hear! For sure, feel free to submit issues on the repository. And I’m interested to hear any suggestions you have!

At the moment, mbed-cmake is basically in maintenance mode – We’re just trying to maintain it as an alternative build system for projects that aren’t a good fit for the MBed CLI build system. We’re not planning to submit it as a PR to mbed-os, since it’s not (and isn’t trying to be) a build system that works for all mbed os users.

The only large feature I’m thinking about adding is support for IAR and/or Arm Compiler, but I’d have to figure out how to get them installed first. Does anyone know how I can get a license? I have a university student email if that helps.

So I got access to a machine with Arm Compiler on it, and I’m happy to report that mbed-cmake now supports Arm Compiler 6 in addition to GCC Arm! Just pass the -t ARMC6 argument to configure_for_target.py to select Arm Compiler. I’ve tested it and it seems to be working fine for a couple different programs, though it isn’t as well tested with mbed-cmake as GCC Arm. Also note that mbedignore files for GCC Arm don’t necessarily work with Arm Compiler… that was a fun issue to figure out.

1 Like

We just started using this on MIT Rocket Team and it’s really incredible! Especially helps with IDE (CLion) integration.

So I had a chance to speak with Martin at ARM yesterday, and I’m happy to report that I have some updates regarding the state of mbed-cmake and Mbed’s own move to CMake.

Many of you have probably heard that ARM is working on its own first-party CMake build system for Mbed OS, and that at some point it will become the new official build system. While ARM’s build system isn’t quite ready yet, clearly this is duplicating the functionality provided by mbed-cmake, and one wonders if there is a good reason to keep both projects around in the long term.

Well, the good news I have today is that the ARM CMake build system will provide functionality extremely similar to mbed-cmake’s current feature set. While buildfiles will be auto-generated for existing apps by the Python mbed-tools program, the build system also allows you to create your own top-level buildscript to handle building your own code in the way you need. What this means is that switching from mbed-cmake to ARM’s build system, once it’s stable, will be extremely easy – you just need to copy some files around and replace the boilerplate code in the top-level CMakeLists.txt with different boilerplate.

Currently, besides the limited set of supported processors, ARM’s build system is missing two key features: .mbedignore support (or another way to prevent unneeded parts of the OS from building), and automatic uploading (and debugging!) of code. In my opinion, these omissions make ARM’s CMake build system less usable than mbed-cmake at present – however this will change! To address the first issue, Martin explained that the long term plan is to attempt to split Mbed OS up into several smaller libraries (e.g. core functionality, USB, RTOS, Ethernet, etc.) which you can choose to link with or not in your code. This actually sounds way better than the mbedignore system as you can remove specific parts of the OS without worrying about accidentally breaking dependencies. And for the uploading, ARM agrees that it would be useful and is actually considering adopting mbed-cmake’s UploadMethods.cmake script to provide this feature.

So what does this mean for mbed-cmake? Well the plan is that once ARM’s CMake system is feature complete and matches mbed-cmake’s functionality (which is likely to be some time 6-12 months from now), I’ll stop actively maintaining mbed-cmake and encourage users to switch to the official system. But as I said, this should be an extremely easy migration and likely all you’ll need to do is change a few lines in the top-level CMakeLists.txt. And mbed-cmake will keep working fine for people who want to use it, it just won’t work for newer Mbed OS releases once the old build system is eventually removed. So, bottom line: you should definitely switch to ARM’s build system once it comes out, but there’s no reason to wait – you can start using CMake right now and switch over easily later!

4 Likes

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: https://github.com/blacksphere/blackmagic/wiki
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.