Docker Container for STM32 CMake & Ninja Compiling

Visit GitHub for source code.

-+- TL;DR -+-

This docker image auto clone an online git repo and compile the CMake & Ninja supported STM32 project locally on your computer with mounted volume.

docker run -v "{Local_Full_Path}":"/home" jasonyangee/stm32-builder:ubuntu-latest -r {Git_Repo_URL}

Example Project

For CMake setup, refer to the below STM32 project template.

https://github.com/jasonyang-ee/STM32-CMAKE-TEMPLATE.git

Help Menu

docker run jasonyangee/stm32-builder:ubuntu-latest --help                              
Usage: build.sh [OPTIONS]
Options:
 -h, --help                            Print this help message
 -t, --type <build type>               Set CMake build type
                                       Default: Release
 -v, --volume <volume mount path>      Path to mount project inside of container and cmake will build in this path
                                       Default: /home
 -r, --repo <repository url>           Clone repository from url into volume path and build

Commands:

docker run -v {HostPath}:/home {IMAGE:VERSION} -r {Git_Repo_URL} -t {Build_Type}
docker run -v {HostPath}:{ContainerPath} {IMAGE:VERSION} -r {Git_Repo_URL} -t {Build_Type} -v {ContainerPath}

Basics of This Image

This image is intended for building STM32 Microcontroller C/C++ Project Configured with CMake and Ninja.

The entrypoint bash script executes basically those commands in default:

git clone $REPO $VOLUME
cmake -DCMAKE_BUILD_TYPE=$TYPE -S $VOLUME -B $VOLUME/build/ -G Ninja
cmake --build $VOLUME/build/ -j$CORES

Docker Image Compiler Environment

Public Registry:

ghcr.io/jasonyang-ee/stm32-builder:ubuntu-latest

ghcr.io/jasonyang-ee/stm32-builder:debian-latest

ghcr.io/jasonyang-ee/stm32-builder:alpine-latest

ghcr.io/jasonyang-ee/stm32-builder:arch-latest

jasonyangee/stm32-builder:ubuntu-latest

jasonyangee/stm32-builder:debian-latest

jasonyangee/stm32-builder:alpine-latest

jasonyangee/stm32-builder:arch-latest

Help Menu

Example usage format can be viewed with --help command.

docker run jasonyangee/stm32-builder:ubuntu-latest --help

Use With Git Link

Mechanism

Container will mount to local folder as working directory. Then it will clone the supplied git repo source file into /home and compile it in /home/build.

  • HostPath is any empty folder path on local host machine. If no folder existed, one will be created.

  • ContainerPath is the path inside of container. Default is /home.

Command

  • Format:

    docker run -v "{HostPath}":"/home" {IMAGE:VERSION} -r {Git_Repo_URL}
    docker run -v "{HostPath}":"/home" {IMAGE:VERSION} -r {Git_Repo_URL} -t {Build_Type}
    docker run -v "{HostPath}":"{ContainerPath}" {IMAGE:VERSION} -r {Git_Repo_URL} -t {Build_Type} -v {ContainerPath}
    
  • Example:

    docker run -v "F:\test_compile":"/home" jasonyangee/stm32-builder:ubuntu-latest -r https://github.com/jasonyang-ee/STM32-CMAKE-TEMPLATE.git
    docker run -v "F:\test_compile":"/home" jasonyangee/stm32-builder:ubuntu-latest -r https://github.com/jasonyang-ee/STM32-CMAKE-TEMPLATE.git -t MinSizeRel
    docker run -v "F:\test_compile":"/custom" jasonyangee/stm32-builder:ubuntu-latest -r https://github.com/jasonyang-ee/STM32-CMAKE-TEMPLATE.git -t Debug -v /custom
    

Output

Binary Output .bin .elf .hex .map are located in HostPath/build.

Use With Mount Volume

Mechanism

Container will mount your existing project folder into /home and compile it in /home/build.

  • HostPath is the existing project folder path on your local host machine. This folder must contain your source code.

  • ContainerPath is the folder in docker container. Default is /home.

Command

  • Format:

    docker run -v "{HostPath}":"/home" {IMAGE:VERSION} 
    docker run -v "{HostPath}":"/home" {IMAGE:VERSION} -t {Build_Type}
    docker run -v "{HostPath}":"/custom" {IMAGE:VERSION} -v /custom
    
  • Example:

    docker run -v "F:\Project\STM32-CMAKE-TEMPLATE":"/home" jasonyangee/stm32-builder:ubuntu-latest
    docker run -v "F:\Project\STM32-CMAKE-TEMPLATE":"/home" jasonyangee/stm32-builder:ubuntu-latest -t Debug
    docker run -v "F:\Project\STM32-CMAKE-TEMPLATE":"/custom" jasonyangee/stm32-builder:ubuntu-latest -v /custom
    

Output

Binary Output .bin .elf .hex .map are located in HostPath/build.

Use Online With Github Action

Mechanism

Using Github Action to load this docker image as base environment. Then run the build.sh script.

build.sh accpets the the same arguments: -r -t -v.

Default HostPath is /github/workspace and ContainerPath is /home.

Only -t is recommended to be used with Github Action.

How To Use

In the source root, create file .github\workflows\build.yml with the following script.

  • Short Example:

    - uses: actions/checkout@v3
    - name: BUILD
      run: build.sh -t MinSizeRel
    
  • Full Script:

    name: 'Build with Ubuntu Container'
    on:
    push:
    	branches:
    	- 'main'
    
    jobs:
      BUILD and RELEASE:
    	runs-on: ubuntu-latest
    	container:
    	  image: 'jasonyangee/stm32-builder:ubuntu-latest'
    	
    	steps:
    	- uses: actions/checkout@v3
    	- name: BUILD
    	  run: build.sh -t MinSizeRel
    
    	- name: Upload Binary .elf
    	  uses: actions/upload-artifact@v2
    	  with:
    	    name: BINARY.elf
    	    path: ${{ github.workspace }}/build/*.elf
    
    	- name: Upload Binary .bin
    	  uses: actions/upload-artifact@v2
    	  with:
    	    name: BINARY.bin
    	    path: ${{ github.workspace }}/build/*.bin
    

Use As Dev Container

Mechanism

In case of team usage, it is possible to distribute a fine tuned docker image to standardize an oranization wide compile environment.

In your project source root, define a .devcontainer/devcontainer.json to configure needed VS Code extensions.

Once reopend in container, you will be operating in this container OS and be able to consistantly compile binary files while using VS Code to continue the development.

How To Use

  1. In VS Code, install extensions:

  2. Turn on dev container setting: Execute In WSL

setting

  1. Attach your hardware usb port as describe below in section WSL USB Passthrough.

  2. Creat folder .devcontainer and add the example devcontainer.json file in project root.

  3. Ctrl + Shift + p select Dev Containers: Reopen in Container.

  4. Build using bash script build.sh -v $PWD or using VS Code Extension.

  5. Flash the device as described in section WSL ST-LINK.

Example

  • devcontainer.json
    {
    	"name": "STM32",
    	"image": "jasonyang-ee/stm32-builder:ubuntu-latest",
    	"privileged": true,
    	"customizations": {
    		"vscode": {
    			"extensions": [
    				"dan-c-underwood.arm",
    				"jeff-hykin.better-cpp-syntax",
    				"ms-vscode.cpptools",
    				"akiramiyakoda.cppincludeguard",
    				"xaver.clang-format",
    				"twxs.cmake",
    				"ms-vscode.cmake-tools",
    				"adpyke.codesnap",
    				"mcu-debug.debug-tracker-vscode",
    				"marus25.cortex-debug",
    				"ms-vscode-remote.remote-containers",
    				"ms-azuretools.vscode-docker",
    				"cschlosser.doxdocgen",
    				"mhutchie.git-graph",
    				"donjayamanne.githistory",
    				"eamodio.gitlens",
    				"zixuanwang.linkerscript",
    				"bierner.markdown-preview-github-styles",
    				"mcu-debug.memory-view",
    				"mcu-debug.rtos-views",
    				"albert.tabout",
    				"ms-vscode-remote.remote-wsl"
    			]
    		}
    	}
    }
    

Manual Image Usage

  • Docker using volume mount and override ENTRYPOINT to keep interactive mode live

    docker run -v "F:\Project\STM32-CMAKE-TEMPLATE":"/home" -it --entrypoint /bin/bash jasonyangee/stm32-builder:ubuntu-latest
    
  • Run build script to invoke auto compiling process.

    build.sh
    
  • build.sh accpets the the same arguments: -r -t -v.

    build.sh -t MinSizeRel
    

The Windows Subsystem for Linux (WSL)

Follow this guide to setup WSL on Windows Environment.

https://learn.microsoft.com/en-us/windows/wsl/install

WSL USB Passthrough to WSL2

Using Windows machine is difficault to expose USB device to container.

Using WSL maybe the only option for now.

Follow this: https://learn.microsoft.com/en-us/windows/wsl/connect-usb

  • Run cmd (admin mode) on Windows:

    winget install --interactive --exact dorssel.usbipd-win
    wsl --update
    wsl --shutdown
    
  • Run (restart) WSL Ubuntu:

    sudo apt update
    sudo apt install linux-tools-5.4.0-77-generic hwdata
    sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/5.4.0-77-generic/usbip 20
    
  • Run cmd (admin mode) on Windows:

    usbipd list
    

  • Note the ST-Link ID and bind it on Windows CMD:
    usbipd bind --busid 3-5
    usbipd wsl attach --busid 3-5
    usbipd wsl list
    

  • Onced a device has been binded, for all future connection, you will only need to attach.
    usbipd list
    usbipd wsl attach --busid 3-5
    

ST-Link

ST Link Programmer has not yet been automated.

Mechanism

Once completed USB Pass Through, you will be able to use st-link to flash the device.

How To Use

Tool Details: https://github.com/stlink-org/stlink

  • Confirm Connnection:

    st-info --probe
    
  • Manual Flash:

    st-flash write {TARGET.bin} 0x8000000
    
  • Manual Reset:

    st-flash reset
    

Flash Device with Command Line

  1. Attach USB device into WSL from Windows CMD (Admin).
  2. Start WSL.
  3. Check for ST Link Connection.
  4. Overwrite entrypoint and volume mount an existing project on WSL.
  5. Invoke docker auto build with the mounted volume.
  6. Flash STM32
  • List of Commands:
    usbipd list
    usbipd wsl attach --busid 3-5
    usbipd wsl list
    wsl
    cd {WSL_USER_PATH}
    ls
    sudo st-info --probe
    docker run -v {WSL_PROJECT_PATH}:{CONTAINER_PROJECT_PATH} -it --privileged --entrypoint /bin/bash jasonyangee/stm32-builder:ubuntu-latest
    build.sh {CONTAINER_PROJECT_PATH}
    st-flash write {PATH_TO_TARGET.BIN} 0x8000000
    

Flash Device in Dev Container

In project root, create file .vscode/tasks.json with the following script.

  • .vscode/tasks.json
    {
    	"version": "2.0.0",
    	"tasks": [
    		{
    			"type": "shell",
    			"label": "Linux: Flash Firmware",
    			"command": "st-flash",
    			"args": [
    				"--reset",
    				"write",
    				"${command:cmake.launchTargetDirectory}/${command:cmake.buildTargetName}.bin",
    				"0x08000000"
    			],
    			"options": {
    				"cwd": "${workspaceFolder}"
    			},
    			"problemMatcher": []
    		},
    		{
    			"type": "shell",
    			"label": "Linux: Reset Device",
    			"command": "st-flash",
    			"args": [
    				"reset"
    			],
    			"options": {
    				"cwd": "${workspaceFolder}"
    			},
    			"problemMatcher": []
    		},
    	]
    }
    

Example

Build This Dockerfile

If you choose to build your own image from Dockerfile.

Manual Build Bash Command Example

  • Format

    docker build -t {image_name}:{image_tag} -f Dockerfile.ubuntu .
    docker build -t {image_name}:{image_tag} -f Dockerfile.alpine .
    docker build -t {image_name}:{image_tag} -f Dockerfile.arch .
    docker build -t {image_name}:{image_tag} -f Dockerfile.debian .
    
  • Example

    docker build -t jasonyangee/stm32-builder:ubuntu-latest -f Dockerfile.ubuntu .
    

Auto Build Using VS Code Tasks

  • Ctrl + Shift + p and enter run task and choose the build options: Build Ubuntu.
  • Modify the build arguments in .vscode/tasks.json if you wish to have different image name.
    stm32-builder:ubuntu-latest",
    

User Modifications

Check ARM releases at here:

https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads/

  • Modify ARM_VERSION=12.2.rel1 for enforcing compiler version.

  • If pulling latest version is desired, insert this line before curl command in dockerfile.

    && ARM_VERSION=$(curl -s https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads | grep -Po '<h4>Version \K.+(?=</h4>)') \
    

Github Action Variables

For those who want to setup your own github action to auto publish variation of this dockerfile to your own docker registry. You may copy my action yml file setup and define the following github variables.

vars.REGISTRY			// Github package link (private: "ghcr.io"   organization: "ghcr.io/Org_Name")
secrete.DOCKERHUB_TOKEN		// Docker Hub login token
secrete.DOCKERHUB_USERNAME	// Docker Hub username
secrete.TOKEN_GITHUB_PERSONAL	// Github package token
secrete.USER_GITHUB_PERSONAL	// Github package username

Visit My Main Page for More Projects

https://doc.jasony.org