In this article, I’ll show you how to create a Docker image for Continuous Integration of embedded software projects. I’ll use Silicon Labs Simplicity Studio and Circle CI as an example. However the basic principle could be applied to many embedded software tools and many CI tools.
In recent years there’s been a big move towards continuous integration in the cloud with the rise of tools like Travis CI, CircleCI, Bitbucket Pipelines and more. CI/CD in the cloud is challenging for many embedded software projects because of our arcane tools and ancient licensing models. Putting together a cloud build environment is non-trivial. And it’s not like CircleCI are going to offer a standard Keil uVision Docker image any time soon.
Silicon Labs’ Simplicity Studio is a YACE. Yet Another Customized Eclipse. Like Atollic TrueSTUDIO, like NXP MCUXpresso and many more.
Simplicity Studio has some characteristics that make it difficult to wrangle it into a CI build environment. As at version 220.127.116.11811151901-172 of Simplicity Studio ARM IDE:
- The base installation, which can be done headlessly, does not include any SDKs or build tools. For example, the Bluetooth SDK and the GNU ARM Toolchain.
- To install the SDKs and build tools, it’s necessary to first login to your Silicon Labs account. It’s currently only possible to login via the Simplicity Studio GUI. Headless login is not possible.
- Once logged in, it’s presently only possible to install the desired SDKs and build tools using the GUI. Headless installation is not possible. However, having contacted Silicon Labs support, I can tell you that headless installation is coming soon.
- Simplicity Studio very much intends for your projects to be managed make IDE projects. Unlike stock Eclipse CDT, there’s no out-of-the-box support for Makefile projects. Code generation is strongly encouraged through the AppBuilder Bluetooth Configurator. “Install New Software” is removed from the Help menu – they really don’t want you to install non-Silabs plugins.
The bottom line is that it’s presently impossible to fully automate creation of a build environment through something like a Dockerfile. You are forced to at least partially handcraft the environment. This situation will be sadly true of many embedded IDEs, and certainly true of the likes of Keil uVision.
Mercifully, Simplicity Studio at least does not suffer any licensing complication. No node locked license, no floating license, no worries.
The summary is this: hand-install the IDE and tools, then build a Docker image by copying the installation tree.
Here are my repositories:
My development host is an Ubuntu 18.04 64-bit VM. If you insist on maximizing your suffering by working under Windows, you’ll have to adapt the steps accordingly.
Of course, I assume you have Docker installed, and you know how to use it.
OK, now here’s the detailed recipe of how to create the Docker image.
Handcraft Your IDE Installation
In my case, I did a fresh install of Simplicity Studio to /opt. I then logged in and installed my desired SDKs and tools:
- Bluetooth SDK 18.104.22.168 (with Gecko Platform 22.214.171.124811021046-152)
- GNU ARM Toolchain v7.2.2017.q4
- and a few other bits
Before a Dockerfile can be used to build the Docker image, it’s first necessary to copy the Simplicity Studio to the Docker context. To automate that, I’ve wrapped the Docker build command in a shell script (docker-build.sh). The shell script does the copy, but also prunes out some stuff that isn’t needed for the CI environment, and retains only one version of the SDK. This trims the resultant Docker image size.
With this automation, it’s easy to generate an updated Docker image when Silicon Labs release updated SDKs.
#!/bin/bash # Check that the Gecko SDK Suite version has been passed as an argument if [ $# -ne 1 ]; then echo "Usage: $0 [Gecko SDK Suite Version Number. e.g. 2.4]" exit 1 fi # Confirm that the Gecko SDK Suite version actually exists if [ ! -d "/opt/SimplicityStudio_v4/developer/sdks/gecko_sdk_suite/v$1" ]; then echo "Gecko SDK Suite $1 not found in your Simplicity Studio installation" exit 1 fi # Simplicity Studio does not support headless install of SDKs, so we # copy our installation into the Docker context so we can build a # Docker image with the necessary build tools echo Copying Simplicity Studio installation to the Docker context ... mkdir -p SimplicityStudio_v4 cp -R /opt/SimplicityStudio_v4 . # Get rid of all SDKs except the one we currently need to build the Thunderboard projects mv SimplicityStudio_v4/developer/sdks/gecko_sdk_suite/v$1 v$1 rm -r SimplicityStudio_v4/developer/sdks/gecko_sdk_suite/* mv v$1 SimplicityStudio_v4/developer/sdks/gecko_sdk_suite/v$1 # Clean out other big things we don't need for CI of Thunderboard projects rm -r SimplicityStudio_v4/developer/sdks/gecko_sdk_suite/v$1/app rm -r SimplicityStudio_v4/developer/sdks/gecko_sdk_suite/v$1/hardware rm -r SimplicityStudio_v4/developer/sdks/gecko_sdk_suite/v$1/platform/hwconf_data rm -r SimplicityStudio_v4/developer/sdks/gecko_sdk_suite/v$1/util/third_party/emwin echo Running Docker build ... docker build --tag uncannier-thunderboard:gecko-sdk-suite-v$1 . echo Cleaning up ... rm -r SimplicityStudio_v4 echo Push as "docker push gregbreen/uncannier-thunderboard:gecko-sdk-suite-v$1"
After setting up the context, the wrapper script triggers the build of the Docker image. The only real trick with the Dockerfile is that it should use the same OS base image as your host. This ensures that the copied Simplicity Studio installation will be able to execute in the Docker container.
FROM amd64/ubuntu:18.04 LABEL maintainer "Greg Breen <email@example.com>" LABEL description "Simplicity Studio in a container for CI of Thunderboard projects" # To the best of my knowledge, Silicon Labs do not support headless install of # Simplicity Studio. We can do the base install headlessly, but we can't install # the SDKs (Gecko and Bluetooth for example) without running the GUI. Thus we # build this Docker image by copying a Simplicity Studio installation that already # has the SDKs installed. Therefore this Dockerfile should be executed in a Linux distro # that is the same as the Linux distro used as the base image here. Ubuntu 18.04 amd64 # in my case. RUN mkdir -p /opt/SimplicityStudio_v4 COPY SimplicityStudio_v4 /opt/SimplicityStudio_v4 # Need to install Simplicity Studio's prerequisites - we use its setup script to do # this. As a consequence, we need to setup udev rules even though this image is only # used for building. RUN dpkg --add-architecture i386 RUN apt-get update RUN mkdir -p /etc/udev/rules.d RUN sed -i "s/sudo apt-get install/apt-get install -y/" "/opt/SimplicityStudio_v4/setup.sh" RUN /opt/SimplicityStudio_v4/setup.sh # Need 64-bit edition of Qt5 for Simplicity Commander to run RUN apt-get install libqt5gui5 # Need to install the following package to avoid warnings during builds RUN apt-get install -y libcanberra-gtk-module # Put Simplicity Commander in the path - our build calls Commander ENV PATH="/opt/SimplicityStudio_v4/developer/adapter_packs/commander:$PATH"
With thanks to Daniel Meer for the sed trick: https://github.com/meerdan/docker-simplicity-studio
Even with the trimming, the resultant image is a tad hefty. A Docker push will get it to Docker Hub, or your private repository, but you’ll need some patience.
If you consult Dr Google, you’ll find lots of self-styled Docker gurus saying that image sizes should never be in the GB. These people haven’t suffered with embedded software tools.
At last, we get to the payoff.
I won’t go to detail on how to setup your projects in CircleCI. Let’s just pick the eyes out.
Here’s the config.yml as added to the Uncannier Thunderboard Sense 2 project.
I elected to not use Silicon Labs’ Python scripts for headless builds: https://www.silabs.com/documents/public/application-notes/an1121-headless-builds.pdf. I think they offer no material advantage over using the vanilla Eclipse command-line approach.
version: 2 jobs: build: docker: - image: gregbreen/uncannier-thunderboard:gecko-sdk-suite-v2.4 steps: - checkout - run: name: Build the Uncannier Thunderboard Sense 2 bootloader command: /opt/SimplicityStudio_v4/studio -nosplash -application org.eclipse.cdt.managedbuilder.core.headlessbuild --launcher.suppressErrors -import uts-bootloader -cleanBuild uts-bootloader/Release - run: name: Build the Uncannier Thunderboard Sense 2 application command: /opt/SimplicityStudio_v4/studio -nosplash -application org.eclipse.cdt.managedbuilder.core.headlessbuild --launcher.suppressErrors -import uts-application -cleanBuild uts-application/Release - run: name: Package the build artifacts command: | cd uts-application/Release mv uts-image.hex uts-image-$CIRCLE_BUILD_NUM.hex mv uts-application.gbl uts-application-$CIRCLE_BUILD_NUM.gbl mv uts-apploader.gbl uts-apploader-$CIRCLE_BUILD_NUM.gbl tar -cvzf uncannier-thunderboard-sense2.tar.gz uts-image-$CIRCLE_BUILD_NUM.hex uts-application-$CIRCLE_BUILD_NUM.gbl uts-apploader-$CIRCLE_BUILD_NUM.gbl - store_artifacts: path: ./uts-application/Release/uncannier-thunderboard-sense2.tar.gz destination: uncannier-thunderboard-sense2.tar.gz
Build History & Logs
Here are the Uncannier Thunderboard projects on CircleCI:
Click through to see the build logs.
I have many CI battle scars, and most of them are with Atlassian Bamboo and various AWS EC2 build agents or locally-hosted VM build agents. Docker and cloud CI, in my view, has a lower barrier to entry. If you can get the lasso onto your embedded development tools, there’s no real excuse to not have CI on your embedded software project.
Uncannier Pull Requests