Skip to content

Commit a3623c0

Browse files
committed
devcontainer and cicd enhancements to enable muti ISA cross compilation
1 parent 34eae88 commit a3623c0

File tree

9 files changed

+434
-138
lines changed

9 files changed

+434
-138
lines changed

.devcontainer/Dockerfile

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# =============================================================================
22
# YABB Development Container
3-
# Nim development environment with multi-arch support (AMD64 + ARM64)
3+
# Nim development environment with Zig cross-compilation support
44
# =============================================================================
55

66
FROM mcr.microsoft.com/devcontainers/base:debian-13
@@ -11,21 +11,26 @@ ENV DEBIAN_FRONTEND=noninteractive
1111
# Build arguments for version management
1212
ARG NIM_VERSION=2.2.6
1313
ARG NIMLANGSERVER_VERSION=1.12.0
14+
ARG ZIG_VERSION=0.15.2
15+
ARG RISCSTAR_VERSION=15.2-r1
1416

1517
# Environment variables
1618
ENV NIM_VERSION=${NIM_VERSION}
17-
ENV PATH="/home/vscode/nim-${NIM_VERSION}/bin:/home/vscode/.nimble/bin:${PATH}"
19+
ENV ZIG_VERSION=${ZIG_VERSION}
20+
ENV RISCSTAR_VERSION=${RISCSTAR_VERSION}
21+
ENV PATH="/home/vscode/riscv64-toolchain/bin:/home/vscode/nim-${NIM_VERSION}/bin:/home/vscode/.nimble/bin:/home/vscode/zig:${PATH}"
1822

1923
# Install system dependencies
24+
# NOTE: musl-tools and musl-dev REMOVED - Zig provides musl
25+
# NOTE: g++ REMOVED - not needed for C compilation
2026
RUN apt-get update && apt-get install -y --no-install-recommends \
21-
# Build essentials
27+
# Build essentials (still needed for Nim bootstrap)
2228
build-essential \
2329
gcc \
24-
g++ \
30+
# Clang for LLDB debugging compatibility (not for compilation)
2531
clang \
26-
# Static compilation (musl)
27-
musl-tools \
28-
musl-dev \
32+
# LLVM tools (llvm-strip for cross-architecture binary stripping)
33+
llvm \
2934
# Debugging
3035
lldb \
3136
gdb \
@@ -50,10 +55,45 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
5055
&& apt-get clean \
5156
&& rm -rf /var/lib/apt/lists/*
5257

53-
# Switch to vscode user for Nim installation
58+
# Switch to vscode user for Nim/Zig installation
5459
USER vscode
5560
WORKDIR /home/vscode
5661

62+
# Install Zig (cross-compilation toolchain for amd64, arm64, ppc64le)
63+
# URL format: zig-{ARCH}-linux-{VERSION}.tar.xz (architecture before OS)
64+
RUN echo "Installing Zig ${ZIG_VERSION}..." \
65+
&& ARCH=$(uname -m) \
66+
&& if [ "$ARCH" = "x86_64" ]; then ZIG_ARCH="x86_64"; \
67+
elif [ "$ARCH" = "aarch64" ]; then ZIG_ARCH="aarch64"; \
68+
else echo "Unsupported architecture: $ARCH" && exit 1; fi \
69+
&& curl -LO "https://ziglang.org/download/${ZIG_VERSION}/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}.tar.xz" \
70+
&& tar xf "zig-${ZIG_ARCH}-linux-${ZIG_VERSION}.tar.xz" \
71+
&& mv "zig-${ZIG_ARCH}-linux-${ZIG_VERSION}" zig \
72+
&& rm -f "zig-${ZIG_ARCH}-linux-${ZIG_VERSION}.tar.xz" \
73+
&& echo "Zig ${ZIG_VERSION} installed successfully"
74+
75+
# Install RISCstar RISC-V64 musl toolchain (lp64d hard-float ABI)
76+
# Zig's musl uses soft-float which is incompatible with Debian riscv64
77+
# RISCstar provides both x86-64 and ARM64 hosted variants
78+
RUN ARCH=$(uname -m) \
79+
&& echo "Installing RISCstar RISC-V64 toolchain ${RISCSTAR_VERSION} for $ARCH host..." \
80+
&& if [ "$ARCH" = "x86_64" ]; then RISCSTAR_HOST="x86_64"; \
81+
elif [ "$ARCH" = "aarch64" ]; then RISCSTAR_HOST="aarch64"; \
82+
else echo "Unsupported host architecture: $ARCH" && exit 1; fi \
83+
&& curl --tlsv1.2 -LO "https://releases.riscstar.com/toolchain/${RISCSTAR_VERSION}/riscstar-toolchain-${RISCSTAR_VERSION}+qemu-${RISCSTAR_HOST}-riscv64-none-linux-musl.tar.xz" \
84+
&& mkdir -p ~/riscv64-toolchain \
85+
&& tar xf "riscstar-toolchain-${RISCSTAR_VERSION}+qemu-${RISCSTAR_HOST}-riscv64-none-linux-musl.tar.xz" -C ~/riscv64-toolchain --strip-components=1 \
86+
&& rm -f "riscstar-toolchain-${RISCSTAR_VERSION}+qemu-${RISCSTAR_HOST}-riscv64-none-linux-musl.tar.xz" \
87+
&& echo "RISCstar RISC-V64 toolchain ${RISCSTAR_VERSION} installed successfully"
88+
89+
# Create compatibility symlinks for Nim cross-compilation
90+
# Nim expects riscv64-linux-gnu-* but RISCstar provides riscv64-none-linux-musl-*
91+
RUN cd ~/riscv64-toolchain/bin \
92+
&& for tool in gcc g++ ar ld strip objcopy objdump ranlib nm readelf; do \
93+
ln -sf "riscv64-none-linux-musl-$tool" "riscv64-linux-gnu-$tool"; \
94+
done \
95+
&& echo "Created Nim compatibility symlinks for RISC-V64 toolchain"
96+
5797
# Install Nim from source (works on both AMD64 and ARM64)
5898
RUN echo "Installing Nim ${NIM_VERSION} from source..." \
5999
&& curl -LO "https://nim-lang.org/download/nim-${NIM_VERSION}.tar.xz" \
@@ -83,13 +123,17 @@ RUN cd /tmp \
83123
# Create version-agnostic symlink for tooling configs
84124
RUN ln -s ~/nim-${NIM_VERSION} ~/nim
85125

126+
# Install zigcc (Nim wrapper for zig cc)
127+
RUN $HOME/nim-${NIM_VERSION}/bin/nimble install -y zigcc
128+
86129
# Verify installation
87-
RUN nim --version && nimble --version
130+
RUN nim --version && nimble --version && zig version && zigcc --version \
131+
&& riscv64-none-linux-musl-gcc --version
88132

89133
# Reset to root for devcontainer features
90134
USER root
91135

92136
# Labels
93137
LABEL org.opencontainers.image.title="YABB Development Container"
94-
LABEL org.opencontainers.image.description="Nim development environment for YABB (multi-arch)"
95-
LABEL org.opencontainers.image.version="1.1.0"
138+
LABEL org.opencontainers.image.description="Nim + Zig cross-compilation environment for YABB"
139+
LABEL org.opencontainers.image.version="2.0.0"

.devcontainer/devcontainer.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"dockerfile": "Dockerfile",
55
"args": {
66
"NIM_VERSION": "2.2.6",
7-
"NIMLANGSERVER_VERSION": "1.12.0"
7+
"NIMLANGSERVER_VERSION": "1.12.0",
8+
"ZIG_VERSION": "0.15.2",
9+
"RISCSTAR_VERSION": "15.2-r1"
810
}
911
},
1012
"workspaceFolder": "/workspaces/yabb",
@@ -14,7 +16,7 @@
1416
"updateRemoteUserUID": true,
1517
"shutdownAction": "stopContainer",
1618

17-
"initializeCommand": "for vol in yabb-vscode-server yabb-nimble-cache; do docker volume inspect \"$vol\" >/dev/null 2>&1 && docker run --rm -v \"$vol:/data\" alpine chown -R 1000:1000 /data 2>/dev/null; done || true",
19+
"initializeCommand": "for vol in yabb-vscode-server yabb-nimble-cache; do docker volume create \"$vol\" 2>/dev/null || true; docker run --rm -v \"$vol:/data\" alpine chown -R 1000:1000 /data; done",
1820

1921
"features": {
2022
"ghcr.io/devcontainers/features/common-utils:2": {
@@ -60,6 +62,8 @@
6062

6163
"containerEnv": {
6264
"NIM_VERSION": "2.2.6",
65+
"ZIG_VERSION": "0.15.2",
66+
"RISCSTAR_VERSION": "15.2-r1",
6367
"EDITOR": "code --wait",
6468
"VISUAL": "code --wait"
6569
},

.devcontainer/post-create.sh

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ alias jv='just versions'
3333
3434
# Build shortcuts (via just)
3535
alias jb='just build'
36-
alias jbr='just build-release'
37-
alias jbs='just build-static'
38-
alias jbd='just build-debug'
36+
alias jbr='just release'
37+
38+
# Cross-compilation shortcuts (via just)
39+
alias jba='just build-all'
40+
alias jbarm='just build-arm64'
41+
alias jbrv='just build-riscv64'
42+
alias jbppc='just build-ppc64le'
3943
4044
# Test shortcuts (via just)
4145
alias jt='just test'
@@ -80,9 +84,13 @@ yabbhelp() {
8084
echo ""
8185
echo "Build:"
8286
echo " jb - just build (debug)"
83-
echo " jbr - just build-release (optimised)"
84-
echo " jbs - just build-static (musl)"
85-
echo " jbd - just build-debug (with LLDB symbols)"
87+
echo " jbr - just release (optimised static)"
88+
echo ""
89+
echo "Cross-compilation:"
90+
echo " jba - just build-all (all 4 architectures)"
91+
echo " jbarm - just build-arm64"
92+
echo " jbrv - just build-riscv64"
93+
echo " jbppc - just build-ppc64le"
8694
echo ""
8795
echo "Test:"
8896
echo " jt - just test"
@@ -103,7 +111,6 @@ yabbhelp() {
103111
echo "Other:"
104112
echo " jcl - just clean"
105113
echo " jd - just docs"
106-
echo " jrel - just release (full release)"
107114
echo ""
108115
echo "Run 'just --list' for all available commands"
109116
}
@@ -120,28 +127,60 @@ if [ ! -f nimble.lock ]; then
120127
just lock
121128
fi
122129

123-
# Validate versions.env matches installed Nim version
130+
# =============================================================================
131+
# Version Validation - ensures devcontainer matches versions.env
132+
# =============================================================================
124133
echo ""
125134
echo "Validating version configuration..."
126135
if [ -f versions.env ]; then
127136
source versions.env
137+
MISMATCH=0
138+
139+
# Validate Nim
128140
INSTALLED_NIM=$(nim --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
141+
echo "Checking Nim: expected=$NIM_VERSION, installed=$INSTALLED_NIM"
129142
if [ "$NIM_VERSION" != "$INSTALLED_NIM" ]; then
143+
echo " WARNING: Nim version mismatch!"
144+
MISMATCH=1
145+
fi
146+
147+
# Validate Zig
148+
INSTALLED_ZIG=$(zig version 2>/dev/null || echo "unknown")
149+
echo "Checking Zig: expected=$ZIG_VERSION, installed=$INSTALLED_ZIG"
150+
if [ "$ZIG_VERSION" != "$INSTALLED_ZIG" ]; then
151+
echo " WARNING: Zig version mismatch!"
152+
MISMATCH=1
153+
fi
154+
155+
# Validate zigcc is installed
156+
if ! command -v zigcc &> /dev/null; then
157+
echo " WARNING: zigcc not found! Run 'nimble install -y zigcc'"
158+
MISMATCH=1
159+
else
160+
echo "Checking zigcc: installed"
161+
fi
162+
163+
# Validate RISCstar RISC-V64 toolchain
164+
if command -v riscv64-none-linux-musl-gcc &> /dev/null; then
165+
INSTALLED_RISCSTAR=$(riscv64-none-linux-musl-gcc --version 2>/dev/null | head -1 || echo "unknown")
166+
echo "Checking RISCstar RISC-V64: installed ($INSTALLED_RISCSTAR)"
167+
else
168+
echo " WARNING: RISCstar RISC-V64 toolchain not found!"
169+
MISMATCH=1
170+
fi
171+
172+
if [ "$MISMATCH" -eq 1 ]; then
130173
echo ""
131174
echo "========================================"
132175
echo "WARNING: Version mismatch detected!"
133176
echo "========================================"
134-
echo " versions.env: NIM_VERSION=$NIM_VERSION"
135-
echo " Installed Nim: $INSTALLED_NIM"
136-
echo ""
137177
echo "To fix: Update .devcontainer/devcontainer.json"
138-
echo " - build.args.NIM_VERSION"
139-
echo " - containerEnv.NIM_VERSION"
178+
echo " - build.args (NIM_VERSION, ZIG_VERSION)"
179+
echo " - containerEnv (NIM_VERSION, ZIG_VERSION)"
140180
echo "Then rebuild the container."
141181
echo "========================================"
142-
echo ""
143182
else
144-
echo "OK: Nim version matches versions.env ($NIM_VERSION)"
183+
echo "OK: All versions match versions.env"
145184
fi
146185
else
147186
echo "WARNING: versions.env not found"
@@ -157,9 +196,11 @@ echo "YABB Development Environment Ready!"
157196
echo "========================================"
158197
echo ""
159198
echo "Quick start:"
160-
echo " just - Show all available commands"
161-
echo " just build - Build debug binary"
162-
echo " just test - Run tests"
163-
echo " just ci - Run full CI pipeline"
164-
echo " yabbhelp - Show alias shortcuts"
199+
echo " just - Show all available commands"
200+
echo " just build - Build debug binary"
201+
echo " just release - Build optimised static binary"
202+
echo " just build-all - Cross-compile all architectures"
203+
echo " just test - Run tests"
204+
echo " just ci - Run full CI pipeline"
205+
echo " yabbhelp - Show alias shortcuts"
165206
echo ""

.github/workflows/ci.yml

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,44 @@ jobs:
2222

2323
- name: Load versions from versions.env
2424
run: |
25-
# Source versions.env and export to GitHub Actions environment
25+
# Source versions.env - the single source of truth
2626
if [ -f versions.env ]; then
2727
source versions.env
2828
echo "NIM_VERSION=$NIM_VERSION" >> $GITHUB_ENV
2929
echo "NPH_VERSION=$NPH_VERSION" >> $GITHUB_ENV
30-
echo "Loaded versions: NIM=$NIM_VERSION, NPH=$NPH_VERSION"
30+
echo "ZIG_VERSION=$ZIG_VERSION" >> $GITHUB_ENV
31+
echo "Loaded: NIM=$NIM_VERSION, NPH=$NPH_VERSION, ZIG=$ZIG_VERSION"
3132
else
3233
echo "ERROR: versions.env not found"
3334
exit 1
3435
fi
3536
36-
- name: Cache Nim toolchain
37+
- name: Cache Nim + Zig toolchain
3738
uses: actions/cache@v4
38-
id: nim-cache
39+
id: toolchain-cache
3940
with:
4041
path: |
4142
~/nim-${{ env.NIM_VERSION }}
43+
~/zig
4244
~/.nimble/bin
4345
~/.nimble/pkgs2
44-
key: nim-${{ runner.os }}-${{ runner.arch }}-${{ env.NIM_VERSION }}-${{ env.NPH_VERSION }}-${{ hashFiles('*.nimble') }}
46+
key: toolchain-${{ runner.os }}-nim${{ env.NIM_VERSION }}-zig${{ env.ZIG_VERSION }}-${{ env.NPH_VERSION }}-${{ hashFiles('*.nimble') }}
4547
restore-keys: |
46-
nim-${{ runner.os }}-${{ runner.arch }}-${{ env.NIM_VERSION }}-
48+
toolchain-${{ runner.os }}-nim${{ env.NIM_VERSION }}-zig${{ env.ZIG_VERSION }}-
49+
50+
- name: Install Zig
51+
if: steps.toolchain-cache.outputs.cache-hit != 'true'
52+
run: |
53+
cd ~
54+
echo "Installing Zig ${{ env.ZIG_VERSION }}..."
55+
curl -LO "https://ziglang.org/download/${{ env.ZIG_VERSION }}/zig-x86_64-linux-${{ env.ZIG_VERSION }}.tar.xz"
56+
tar xf "zig-x86_64-linux-${{ env.ZIG_VERSION }}.tar.xz"
57+
mv "zig-x86_64-linux-${{ env.ZIG_VERSION }}" zig
58+
rm -f "zig-x86_64-linux-${{ env.ZIG_VERSION }}.tar.xz"
59+
echo "Zig ${{ env.ZIG_VERSION }} installed successfully"
4760
4861
- name: Install Nim from source
49-
if: steps.nim-cache.outputs.cache-hit != 'true'
62+
if: steps.toolchain-cache.outputs.cache-hit != 'true'
5063
run: |
5164
cd ~
5265
echo "Installing Nim ${{ env.NIM_VERSION }} from source..."
@@ -62,34 +75,40 @@ jobs:
6275
rm -f "nim-${{ env.NIM_VERSION }}.tar.xz"
6376
echo "Nim ${{ env.NIM_VERSION }} installed successfully"
6477
65-
- name: Add Nim to PATH
78+
- name: Add tools to PATH
6679
run: |
6780
echo "$HOME/nim-${{ env.NIM_VERSION }}/bin" >> $GITHUB_PATH
6881
echo "$HOME/.nimble/bin" >> $GITHUB_PATH
82+
echo "$HOME/zig" >> $GITHUB_PATH
6983
70-
- name: Verify Nim version
84+
- name: Verify toolchain
7185
run: |
7286
nim --version
7387
nimble --version
88+
zig version
7489
7590
- name: Install just
7691
uses: extractions/setup-just@v2
7792

78-
- name: Install nph formatter
93+
- name: Install zigcc
7994
run: |
80-
if ! command -v nph &> /dev/null; then
81-
# nph requires Nim 2.2.x compiler internals. Build from source using
82-
# choosenim's Nim to avoid nimble resolving to old nim package (2.0.8)
83-
git clone --depth 1 --branch "v${{ env.NPH_VERSION }}" https://github.com/arnetheduck/nph.git /tmp/nph
84-
cd /tmp/nph
85-
nimble setup
86-
nim c -d:release -o:"$HOME/.nimble/bin/nph" src/nph.nim
87-
cd -
88-
rm -rf /tmp/nph
89-
echo "nph installed: $(nph --version)"
90-
else
91-
echo "nph already installed (from cache)"
95+
if ! command -v zigcc &> /dev/null; then
96+
nimble install -y zigcc
9297
fi
98+
zigcc --version
99+
100+
- name: Install nph formatter
101+
if: steps.toolchain-cache.outputs.cache-hit != 'true'
102+
run: |
103+
# nph requires Nim 2.2.x compiler internals. Build from source using
104+
# our Nim to avoid nimble resolving to old nim package (2.0.8)
105+
git clone --depth 1 --branch "v${{ env.NPH_VERSION }}" https://github.com/arnetheduck/nph.git /tmp/nph
106+
cd /tmp/nph
107+
nimble setup
108+
nim c -d:release -o:"$HOME/.nimble/bin/nph" src/nph.nim
109+
cd -
110+
rm -rf /tmp/nph
111+
echo "nph installed: $(nph --version)"
93112
94113
- name: Install project dependencies
95114
run: |
@@ -98,7 +117,6 @@ jobs:
98117
nimble install -d --accept
99118
nimble setup
100119
# Remove again in case nimble reinstalled nim from registry
101-
# (nim should NOT be in nimble.lock, but defense-in-depth)
102120
rm -rf ~/.nimble/pkgs2/nim-*
103121
104122
- name: Check formatting

0 commit comments

Comments
 (0)