Skip to content

Commit 695a10f

Browse files
authored
[ci] Add riscv{32/64}imac-unknown-none-elf cross-compilation images (#1827)
1 parent 227ebb6 commit 695a10f

8 files changed

Lines changed: 383 additions & 8 deletions

File tree

.github/scripts/check_no_std.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@ no_std_packages=(
88
commonware-storage
99
)
1010

11-
target="thumbv7em-none-eabihf"
11+
target="riscv32imac-unknown-none-elf"
12+
image="ghcr.io/commonwarexyz/monorepo/rust-riscv32imac-cross@sha256:652f5ff21c943935bc1caf7cf0c65b38127381c66b423f70f86dc7785d93ce85"
1213
base_rustflags="${RUSTFLAGS:-}"
1314

1415
for package in "${no_std_packages[@]}"; do
15-
build_cmd=(cargo build -p "$package" --no-default-features --target "$target" --release)
16+
build_cmd=(docker run \
17+
--rm \
18+
-v `pwd`:/workdir \
19+
-w="/workdir" \
20+
"$image" cargo +nightly build -p "$package" -Zbuild-std=core,alloc --no-default-features --target "$target" --release)
1621
pretty_cmd="${build_cmd[*]}"
1722
if [ -n "$CI" ]; then
1823
echo "::group::${pretty_cmd}"

.github/workflows/docker.yml

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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: Free Disk Space (Ubuntu)
85+
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
86+
with:
87+
large-packages: false
88+
- name: Prepare
89+
run: |
90+
platform=${{ matrix.platform }}
91+
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
92+
- name: Download meta bake definition
93+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
94+
with:
95+
name: bake-meta
96+
path: ${{ runner.temp }}
97+
- name: Authenticate with container registry
98+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
99+
with:
100+
registry: ${{ env.REGISTRY }}
101+
username: ${{ github.actor }}
102+
password: ${{ secrets.GITHUB_TOKEN }}
103+
- name: Set up Docker Buildx
104+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
105+
- name: Build
106+
id: bake
107+
uses: docker/bake-action@3acf805d94d93a86cce4ca44798a76464a75b88c # v6.9.0
108+
with:
109+
files: |
110+
./docker/docker-bake.hcl
111+
cwd://${{ runner.temp }}/bake-meta.json
112+
targets: ${{ needs.prepare.outputs.target }}
113+
set: |
114+
*.tags=
115+
*.platform=${{ matrix.platform }}
116+
*.output=type=image,"name=${{ env.REGISTRY_IMAGE }}/${{ needs.prepare.outputs.target }}",push-by-digest=true,name-canonical=true,push=true
117+
- name: Export digest
118+
run: |
119+
mkdir -p ${{ runner.temp }}/digests
120+
digest="${{ fromJSON(steps.bake.outputs.metadata)[needs.prepare.outputs.target]['containerimage.digest'] }}"
121+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
122+
- name: Upload digest
123+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
124+
with:
125+
name: digests-${{ env.PLATFORM_PAIR }}
126+
path: ${{ runner.temp }}/digests/*
127+
if-no-files-found: error
128+
retention-days: 1
129+
130+
merge:
131+
name: Publish Manifest (${{ needs.prepare.outputs.target }})
132+
runs-on: ubuntu-latest
133+
permissions:
134+
packages: write
135+
needs:
136+
- build
137+
- prepare
138+
steps:
139+
- name: Download meta bake definition
140+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
141+
with:
142+
name: bake-meta
143+
path: ${{ runner.temp }}
144+
- name: Download digests
145+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
146+
with:
147+
path: ${{ runner.temp }}/digests
148+
pattern: digests-*
149+
merge-multiple: true
150+
- name: Authenticate with container registry
151+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
152+
with:
153+
registry: ${{ env.REGISTRY }}
154+
username: ${{ github.actor }}
155+
password: ${{ secrets.GITHUB_TOKEN }}
156+
- name: Set up Docker Buildx
157+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
158+
- name: Create manifest list and push
159+
working-directory: ${{ runner.temp }}/digests
160+
run: |
161+
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) \
162+
$(printf '${{ env.REGISTRY_IMAGE }}/${{ needs.prepare.outputs.target }}@sha256:%s ' *)
163+
- name: Inspect image
164+
run: |
165+
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)

.github/workflows/fast.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,6 @@ jobs:
176176
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
177177
- name: Run setup
178178
uses: ./.github/actions/setup
179-
- name: Add minimal no_std target
180-
run: rustup target add thumbv7em-none-eabihf
181-
- name: Install ARM bare-metal toolchain (required to compile C from x86 worker)
182-
run: |
183-
sudo apt-get update
184-
sudo apt-get install -y gcc-arm-none-eabi
185179
- name: Check no_std compatibility
186180
run: ./.github/scripts/check_no_std.sh
187181

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ _Examples may include insecure code (i.e. deriving keypairs from an integer argu
4343
_Sometimes, we opt to maintain software that is neither a primitive nor an example to make it easier to interact with the Commonware Library. Unless otherwise indicated, code in this section is intended to be used in production. Please refer to our [security policy](./SECURITY.md) before disclosing an exploit publicly._
4444

4545
* [docs](./docs): Access information about Commonware at https://commonware.xyz.
46+
* [docker](./docker): Dockerfiles used for cross-compilation and CI.
4647
* [macros](./macros/README.md): Augment the development of primitives with procedural macros.
4748
* [pipeline](./pipeline): Mechanisms under development.
4849
* [utils](./utils/README.md): Leverage common functionality across multiple primitives.

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 target=<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: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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 RISCV_TAG=2025.09.28
36+
ENV PATH=$PATH:$RISCV/bin
37+
38+
# https://github.com/riscv-collab/riscv-gnu-toolchain/issues/1669#issuecomment-2682013720
39+
RUN git clone https://github.com/riscv/riscv-gnu-toolchain --branch $RISCV_TAG && \
40+
cd riscv-gnu-toolchain && \
41+
sed -i '/shallow = true/d' .gitmodules && \
42+
sed -i 's/--depth 1//g' Makefile.in && \
43+
./configure --prefix=$RISCV --enable-multilib && \
44+
make && \
45+
cd .. && \
46+
rm -rf riscv-gnu-toolchain

0 commit comments

Comments
 (0)