This is a bit of a broad topic, but I’m trying to find a way to manage a C++17 project with PlatformIO which can deal with lots of “moving parts”: number of µC architectures, target boards, selected features, and test-driven / debug / release builds.
I found the Marlin project, which does appear to cover a huge variety of build variants. There’s also Tasmota, which is more ESP8266-/ESP32-centric.
My main targets are STM32 series µCs, but RasPi Pico and Teensy should preferably also fit in. These are all ARM Cortex, but again, I don’t want to rule out the possibility to handle other architectures, such as Espressif and RiscV. PlatformIO is clearly up to it, so on the build and toolchain side, there appear to be no roadblocks.
Before bringing in existing real code, I have now created a new small setup which lets pio test
work on native and a few different STM32 families. The native build is important because it allows much faster development cycles for those parts of the project which don’t deal directly with hardware.
The main puzzle is how to structure the code. Make the source files and directory structure too fine-grained, and you end up with tons of header file dependencies. Make it too coarse, and you get into piles of #ifdef lines all over the place. A useful middle road seems to be to structure the libraries in lib/
in per-architecture groups, with a library.json
file in each containing a { "platforms": "..." }
line to limit its auto-inclusion by PIO. This hinges on having the following lines in platformio.ini
:
[env]
lib_compat_mode = strict
To complicate matters further, I’m hell-bent on using a test-driven approach as much as possible. Because anything as varied as this will break down at some point in time if development progresses without automated testing. I’m using PIO’s “Unity” support for embedded builds and DocTest for native (which is absolutely brilliant, but not compatible with cross-compilation, alas).
And if that’s not enough, let me add that the project uses code-generation to simplify maintenance and avoid writing boilerplate code (scripted in Python). So there are steps in the build process which must go through the source code and generate other parts of the source code before the compilation can run to completion.
All the code for this project is open source, with a very early design on GitHub, but I don’t like the way it’s evolving and slowly starting to grind to a halt. In the current design, I use PyInvoke as a wrapper around PlatformIO, but while it does simplify some things, it’s not that good a fit to really warrant its use. Might as well extend PIO itself using its extra_script
feature and advanced scripting in Python.
Development of this project takes place on MacOS and Linux (incl. RasPi).
The Marlin project appears to manage most of its variability through a features.ini
file, which specifies which source files to add to a build using src_filter
. This is done via fairly elaborate Python scripts, digging deep into the innards of PIO, as far as I can tell. I find it hard to wrap my mind around it all, and haven’t found documentation for most of the env
and projenv
objects available in PIO’s advanced scripting. My current thinking is that this aspect could be simplified by generating a header with #include’s to define which features and code are to be included in each build.
So my first question is: are there other maintained OSS projects I could look at for insight, which handle a large variety of build targets and use PlatformIO?
My second question is: do you have suggestions on how to set things up for such a wide-ranging & open-ended system? This project has very few dependencies (later extensions will most probably change that). Where would you put say LwIP
, if some of the builds were to use networking? Or TinyUSB
, if a build needs to support device- or host-USB, for example? Along what dimensions would you structure the variability in lib/
: per architecture? per target board? per feature?
Oops, that’s a bit more than a single question
And of course there is no single “right” answer to all of the above.
But any tips and pointers would help me a lot - and be much appreciated.
Also, collecting a few relevant URLs in this thread could be of use to others.
-jcw