ADR 0004: Docker for Cross-Compilation
Status
Accepted
Context
Primary development is on macOS (Apple Silicon), but the target device runs Linux aarch64. macOS cannot cross-compile SDL2 apps directly because macOS SDL2 libraries (.dylib, Mach-O format) are incompatible with the Linux aarch64 cross-compiler (needs .so, ELF format).
Options considered:
| Approach | Pros | Cons |
|---|---|---|
| Docker | Same environment every time, works on any host, reproducible | Slower first build (image creation) |
| WSL2 | Native Linux on Windows, can share files | Windows only, setup complexity |
| Virtual Machine | Full Linux environment | Heavy, slow, manual maintenance |
| Remote Linux server | Fast, always-on | Requires server, network dependency |
| Build on device | No cross-compilation at all | Slow compilation on H700, needs dev tools on device |
| nix-shell | Reproducible, declarative | Steep learning curve, nix adoption |
Decision
Use Docker as the primary cross-compilation method. Provide build-on-device as fallback.
Consequences
Positive
- Works on macOS, Linux, and Windows (with Docker Desktop)
- Container has exact SDL2 version we need (2.26.2)
- No host dependency contamination
- Reproducible builds
- Apple Silicon Macs run aarch64 Linux containers natively (no emulation)
Negative
- Docker image is ~2.5 GB (Ubuntu 20.04 + SDL2 build + Rust toolchain)
- First build takes ~2 minutes to create the image
- Container startup adds ~5 seconds per build
- Requires Docker Desktop installed
Implementation
scripts/Dockerfile.build creates the image:
FROM ubuntu:20.04
# Install build dependencies
RUN apt-get install -y build-essential libsdl2-dev libsdl2-ttf-dev ...
# Build SDL2 2.26.2 from source (avoids macOS Metal symbol issues)
RUN wget https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.26.2.tar.gz
...
# Build SDL2_ttf 2.20.2 from source
RUN wget https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.20.2.tar.gz
...
# Install Rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
RUN rustup target add aarch64-unknown-linux-gnu
scripts/docker-build.sh runs the build:
docker build -t cardagain-build -f scripts/Dockerfile.build .
docker run --rm -v $(pwd):/workspace -w /workspace cardagain-build \
bash -c 'cargo build --release --target aarch64-unknown-linux-gnu'
Future work
- Multi-stage Dockerfile to reduce image size
- Cache Rust dependencies between builds
- Publish pre-built image to Docker Hub or GHCR