Skip to content

Commit eba078d

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

5 files changed

Lines changed: 367 additions & 0 deletions

File tree

.github/workflows/docker.yml

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