Skip to content

Commit ac067b6

Browse files
committed
[ci] Add riscv{32/64}imac-unknown-none-elf cross-compilation images
1 parent 9c9378f commit ac067b6

5 files changed

Lines changed: 369 additions & 0 deletions

File tree

.github/workflows/docker.yml

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
name: Build and Publish Docker Image
2+
3+
on:
4+
pull_request:
5+
6+
workflow_dispatch:
7+
inputs:
8+
target:
9+
type: choice
10+
description: Which image to release
11+
required: true
12+
options:
13+
- riscv-unknown-elf-toolchain
14+
- rust-riscv32imac-cross
15+
- rust-riscv64imac-cross
16+
push:
17+
tags:
18+
# matches tags like `service/v1.0.0`
19+
- "*/v*"
20+
21+
env:
22+
REGISTRY: ghcr.io
23+
REGISTRY_IMAGE: ghcr.io/commonwarexyz/monorepo
24+
GIT_REF_NAME: ${{ github.ref_name }}
25+
26+
jobs:
27+
prepare:
28+
name: Prepare Bake
29+
runs-on: ubuntu-latest
30+
permissions:
31+
packages: write
32+
outputs:
33+
matrix: ${{ steps.platforms.outputs.matrix }}
34+
target: ${{ steps.target-spec.outputs.target }}
35+
steps:
36+
- name: Checkout
37+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
38+
- name: Specify Target
39+
id: target-spec
40+
run: |
41+
export TARGET="${{ inputs.target }}"
42+
if [[ -z $TARGET ]]; then
43+
export TARGET="${GIT_REF_NAME%/*}"
44+
fi
45+
echo "Target: $TARGET"
46+
echo "target=$TARGET" >> $GITHUB_OUTPUT
47+
- name: Create matrix
48+
id: platforms
49+
run: |
50+
echo "matrix=$(docker buildx bake -f docker/docker-bake.hcl ${{ steps.target-spec.outputs.target }} --print | jq -cr '.target."${{ steps.target-spec.outputs.target }}".platforms')" >> ${GITHUB_OUTPUT}
51+
- name: Show matrix
52+
run: |
53+
echo ${{ steps.platforms.outputs.matrix }}
54+
- name: Docker meta
55+
id: meta
56+
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
57+
with:
58+
images: ${{ env.REGISTRY_IMAGE }}/${{ steps.target-spec.outputs.target }}
59+
tags: |
60+
type=ref,event=branch
61+
type=match,pattern=v(.*),group=1,event=tag
62+
type=ref,event=pr
63+
- name: Rename meta bake definition file
64+
run: |
65+
mv "${{ steps.meta.outputs.bake-file }}" "${{ runner.temp }}/bake-meta.json"
66+
- name: Upload meta bake definition
67+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
68+
with:
69+
name: bake-meta
70+
path: ${{ runner.temp }}/bake-meta.json
71+
if-no-files-found: error
72+
retention-days: 1
73+
74+
build:
75+
name: Build Image (${{ needs.prepare.outputs.target }} - ${{ matrix.platform }})
76+
runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || 'ubuntu-22.04-arm' }}
77+
permissions:
78+
packages: write
79+
needs:
80+
- prepare
81+
strategy:
82+
fail-fast: false
83+
matrix:
84+
platform: ${{ fromJson(needs.prepare.outputs.matrix) }}
85+
steps:
86+
- name: Prepare
87+
run: |
88+
platform=${{ matrix.platform }}
89+
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
90+
- name: Download meta bake definition
91+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
92+
with:
93+
name: bake-meta
94+
path: ${{ runner.temp }}
95+
- name: Authenticate with container registry
96+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
97+
with:
98+
registry: ${{ env.REGISTRY }}
99+
username: ${{ github.actor }}
100+
password: ${{ secrets.GITHUB_TOKEN }}
101+
- name: Set up Docker Buildx
102+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
103+
- name: Build
104+
id: bake
105+
uses: docker/bake-action@3acf805d94d93a86cce4ca44798a76464a75b88c # v6.9.0
106+
with:
107+
files: |
108+
./docker/docker-bake.hcl
109+
cwd://${{ runner.temp }}/bake-meta.json
110+
targets: ${{ needs.prepare.outputs.target }}
111+
set: |
112+
*.tags=
113+
*.platform=${{ matrix.platform }}
114+
*.output=type=image,"name=${{ env.REGISTRY_IMAGE }}/${{ needs.prepare.outputs.target }}",push-by-digest=true,name-canonical=true,push=true
115+
- name: Export digest
116+
run: |
117+
mkdir -p ${{ runner.temp }}/digests
118+
digest="${{ fromJSON(steps.bake.outputs.metadata)[needs.prepare.outputs.target]['containerimage.digest'] }}"
119+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
120+
- name: Upload digest
121+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
122+
with:
123+
name: digests-${{ env.PLATFORM_PAIR }}
124+
path: ${{ runner.temp }}/digests/*
125+
if-no-files-found: error
126+
retention-days: 1
127+
128+
merge:
129+
name: Publish Manifest (${{ needs.prepare.outputs.target }})
130+
runs-on: ubuntu-latest
131+
permissions:
132+
packages: write
133+
needs:
134+
- build
135+
- prepare
136+
steps:
137+
- name: Download meta bake definition
138+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
139+
with:
140+
name: bake-meta
141+
path: ${{ runner.temp }}
142+
- name: Download digests
143+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
144+
with:
145+
path: ${{ runner.temp }}/digests
146+
pattern: digests-*
147+
merge-multiple: true
148+
- name: Authenticate with container registry
149+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
150+
with:
151+
registry: ${{ env.REGISTRY }}
152+
username: ${{ github.actor }}
153+
password: ${{ secrets.GITHUB_TOKEN }}
154+
- name: Set up Docker Buildx
155+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
156+
- name: Create manifest list and push
157+
working-directory: ${{ runner.temp }}/digests
158+
run: |
159+
docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map(select(startswith("${{ env.REGISTRY_IMAGE }}/${{ needs.prepare.outputs.target }}")) | "-t " + .) | join(" ")' ${{ runner.temp }}/bake-meta.json) \
160+
$(printf '${{ env.REGISTRY_IMAGE }}/${{ needs.prepare.outputs.target }}@sha256:%s ' *)
161+
- name: Inspect image
162+
run: |
163+
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}/${{ needs.prepare.outputs.target }}:$(jq -r '.target."docker-metadata-action".args.DOCKER_META_VERSION' ${{ runner.temp }}/bake-meta.json)

docker/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# `commonware-docker`
2+
3+
This directory contains all of the repositories' dockerfiles as well as the [bake file](https://docs.docker.com/build/bake/)
4+
used to define this repository's docker build configuration.
5+
6+
## Install Dependencies
7+
8+
* `docker`: https://www.docker.com/get-started/
9+
* `docker-buildx`: https://github.com/docker/buildx?tab=readme-ov-file#installing
10+
11+
## Building Locally
12+
13+
To build any image in the bake file locally, use `docker buildx bake`:
14+
15+
```sh
16+
export TARGET="<target_name>"
17+
18+
# Optional: adjust the tag for the image
19+
# Defaults to `commonware:local`
20+
export DEFAULT_TAG="my-image:local"
21+
22+
# Optional: Override the platforms to build the image for.
23+
# Defaults to `linux/amd64,linux/arm64`
24+
export PLATFORMS="<platforms>"
25+
26+
docker buildx bake \
27+
--progress plain \
28+
-f docker/docker-bake.hcl \
29+
$TARGET
30+
```
31+
32+
#### Troubleshooting
33+
34+
If you receive an error like the following:
35+
36+
```
37+
ERROR: Multi-platform build is not supported for the docker driver.
38+
Switch to a different driver, or turn on the containerd image store, and try again.
39+
Learn more at https://docs.docker.com/go/build-multi-platform/
40+
```
41+
42+
Create and activate a new builder and retry the bake command.
43+
44+
```sh
45+
docker buildx create --name commonware-builder --use
46+
```
47+
48+
## Cutting a Release (for maintainers / forks)
49+
50+
To cut a release of the docker image for any of the targets, cut a new annotated tag for the target like so:
51+
52+
```sh
53+
# Example formats:
54+
# - `rust-riscv-cross/v0.1.0-beta.8`
55+
# - `riscv-unknown-elf-toolchain/v1.2.0`
56+
TAG="<target_name>/<version>"
57+
git tag -a $TAG -m "<tag description>" && git push origin tag $TAG
58+
```
59+
60+
To run the workflow manually, navigate over to the ["Build and Publish Docker Image"](https://github.com/commonwarexyz/monorepo/actions/workflows/docker.yaml)
61+
action. From there, run a `workflow_dispatch` trigger, select the tag you just pushed, and then finally select the image to release.
62+
63+
Or, if you prefer to use the `gh` CLI, you can run:
64+
```sh
65+
gh workflow run "Build and Publish Docker Image" --ref <tag> -f image_to_release=<target>
66+
```
67+

docker/docker-bake.hcl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
variable "REGISTRY" {
2+
default = "ghcr.io"
3+
}
4+
5+
variable "REPOSITORY" {
6+
default = "commonwarexyz/monorepo"
7+
}
8+
9+
variable "DEFAULT_TAG" {
10+
default = "commonware:local"
11+
}
12+
13+
variable "PLATFORMS" {
14+
// Only specify a single platform when `--load` ing into docker.
15+
// Multi-platform is supported when outputting to disk or pushing to a registry.
16+
// Multi-platform builds can be tested locally with: --set="*.output=type=image,push=false"
17+
default = "linux/amd64,linux/arm64"
18+
}
19+
20+
// Special target: https://github.com/docker/metadata-action#bake-definition
21+
target "docker-metadata-action" {
22+
tags = ["${DEFAULT_TAG}"]
23+
}
24+
25+
target "riscv-unknown-elf-toolchain" {
26+
inherits = ["docker-metadata-action"]
27+
context = "."
28+
dockerfile = "docker/riscv-unknown-elf-toolchain.dockerfile"
29+
platforms = split(",", PLATFORMS)
30+
}
31+
32+
target "rust-riscv32imac-cross" {
33+
inherits = ["docker-metadata-action"]
34+
context = "."
35+
dockerfile = "docker/rust-riscv-cross.dockerfile"
36+
args = {
37+
ARCH = "riscv32imac"
38+
}
39+
platforms = split(",", PLATFORMS)
40+
}
41+
42+
target "rust-riscv64imac-cross" {
43+
inherits = ["docker-metadata-action"]
44+
context = "."
45+
dockerfile = "docker/rust-riscv-cross.dockerfile"
46+
args = {
47+
ARCH = "riscv64imac"
48+
}
49+
platforms = split(",", PLATFORMS)
50+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
FROM ubuntu:22.04
2+
3+
# Install core build dependencies
4+
RUN apt-get update && \
5+
apt-get install --assume-yes --no-install-recommends \
6+
ca-certificates \
7+
autoconf \
8+
automake \
9+
autotools-dev \
10+
curl \
11+
python3 \
12+
python3-pip \
13+
python3-tomli \
14+
libmpc-dev \
15+
libmpfr-dev \
16+
libgmp-dev \
17+
gawk \
18+
build-essential \
19+
bison \
20+
flex \
21+
texinfo \
22+
gperf \
23+
libtool \
24+
patchutils \
25+
bc \
26+
zlib1g-dev \
27+
libexpat-dev \
28+
ninja-build \
29+
git \
30+
cmake \
31+
libglib2.0-dev \
32+
libslirp-dev
33+
34+
ENV RISCV=/opt/riscv
35+
ENV PATH=$PATH:$RISCV/bin
36+
37+
RUN git clone --recursive https://github.com/riscv/riscv-gnu-toolchain && \
38+
cd riscv-gnu-toolchain && \
39+
./configure --prefix=$RISCV --enable-multilib && \
40+
make && \
41+
cd .. && \
42+
rm -rf riscv-gnu-toolchain

docker/rust-riscv-cross.dockerfile

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
FROM ghcr.io/commonwarexyz/monorepo/riscv-unknown-elf-toolchain:main AS rv-bare
2+
FROM ubuntu:22.04
3+
4+
ARG ARCH
5+
6+
ENV SHELL=/bin/bash
7+
ENV DEBIAN_FRONTEND=noninteractive
8+
9+
# Install core dependencies
10+
RUN apt-get update && apt-get install --assume-yes --no-install-recommends \
11+
ca-certificates \
12+
build-essential \
13+
autoconf \
14+
automake \
15+
autotools-dev \
16+
git \
17+
curl \
18+
make \
19+
cmake \
20+
xxd \
21+
g++-riscv64-linux-gnu \
22+
libc6-dev-riscv64-cross \
23+
binutils-riscv64-linux-gnu \
24+
llvm \
25+
clang
26+
27+
# Copy the RISC-V GNU toolchain from the previous stage
28+
COPY --from=rv-bare /opt/riscv /opt/riscv
29+
30+
# Install Rustup and Rust
31+
ENV RUST_VERSION=nightly
32+
ENV PATH="/root/.cargo/bin:${PATH}"
33+
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --default-toolchain ${RUST_VERSION} --component rust-src
34+
35+
# Add the RV toolchain to the path
36+
ENV PATH="/opt/riscv/bin:${PATH}"
37+
38+
# Set up the env vars to instruct rustc to use the correct compiler and linker
39+
ENV CC_riscv32_unknown_none_elf=riscv64-linux-gnu-gcc \
40+
CC_riscv64_unknown_none_elf=riscv64-linux-gnu-gcc \
41+
CXX_riscv32_unknown_none_elf=riscv64-linux-gnu-g++ \
42+
CXX_riscv64_unknown_none_elf=riscv64-linux-gnu-g++ \
43+
CARGO_TARGET_RISCV32_UNKNOWN_NONE_ELF_LINKER=riscv64-linux-gnu-gcc \
44+
CARGO_TARGET_RISCV64_UNKNOWN_NONE_ELF_LINKER=riscv64-linux-gnu-gcc \
45+
RUSTFLAGS="-Clink-arg=-e_start" \
46+
CARGO_BUILD_TARGET="$ARCH-unknown-none-elf" \
47+
RUSTUP_TOOLCHAIN=${RUST_VERSION}

0 commit comments

Comments
 (0)