Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/release-auto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,19 @@ jobs:
macos_cross: false
mac_cross_linux: true

# x86_64-apple-darwin shares the mac_cross_linux template
# branch — soldr's apple_sdk fetcher auto-picks
# `darwin-x86_64` (thin-x86_64) when the target triple is
# `x86_64-apple-darwin`, and `cargo zigbuild --target
# x86_64-apple-darwin` resolves the SDKROOT + frameworks
# identically to the arm64 lane. Closes Lane 3 of soldr#1006.
- target: x86_64-apple-darwin
runner: ubuntu-latest
binary_ext: ""
linux_cross: false
macos_cross: false
mac_cross_linux: true

- target: x86_64-pc-windows-msvc
runner: windows-latest
binary_ext: ".exe"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/template_native_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ jobs:
run: |
if [ "${{ inputs.mac_cross_linux }}" = "true" ]; then
# Linux → aarch64-apple-darwin: zigbuild + soldr-managed SDK.
# Identical recipe to ci/docker-mac-arm64-cross/build.sh, which
# Identical recipe to ci/docker-mac-cross/build.sh, which
# validates this same path against a minimal ubuntu:24.04 image.
soldr cargo zigbuild --release --target ${{ inputs.target }} \
-p fbuild-cli \
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
# Simulate the FastLED/fbuild GitHub Actions release runner for the
# `aarch64-apple-darwin` lane on **Linux x86_64**, with no Apple-side
# tooling and no pre-installed Rust toolchain. Soldr bootstraps
# everything else.
# Simulate the FastLED/fbuild GitHub Actions release runners for both
# Apple targets — aarch64-apple-darwin AND x86_64-apple-darwin — on
# **Linux x86_64**, with no Apple-side tooling and no pre-installed
# Rust toolchain. Soldr bootstraps everything else.
#
# This is the "NO CHEATING" proof: we ship a vanilla Debian base + the
# This is the "NO CHEATING" proof: we ship a vanilla Ubuntu base + the
# absolute minimum apt deps, and soldr brings rustup, the pinned
# toolchain, zig, the Apple SDK, and `cargo-zigbuild` — exactly the
# story soldr#997 promised for cross-compile completeness.
#
# Build:
# docker build -f ci/docker-mac-arm64-cross/Dockerfile -t fbuild-mac-arm64-cross .
# docker build -f ci/docker-mac-cross/Dockerfile -t fbuild-mac-cross .
#
# Run (from repo root):
# docker run --rm -v "$PWD:/src" -w /src fbuild-mac-arm64-cross \
# ./ci/docker-mac-arm64-cross/build.sh
# # aarch64 (default):
# docker run --rm -v "$PWD:/src" -w /src fbuild-mac-cross \
# ./ci/docker-mac-cross/build.sh
# # x86_64:
# docker run --rm -v "$PWD:/src" -w /src fbuild-mac-cross \
# ./ci/docker-mac-cross/build.sh x86_64-apple-darwin

# ubuntu:24.04 is exactly what `ubuntu-latest` is on GitHub Actions
# right now (the runners moved off 22.04 in 2025-Q4). Picking it
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
# `ci/docker-mac-arm64-cross/` — Linux → `aarch64-apple-darwin` simulator
# `ci/docker-mac-cross/` — Linux → `(aarch64|x86_64)-apple-darwin` simulator

Reproduces fbuild's `aarch64-apple-darwin` release lane on **Linux x86_64**
with **no Apple-side tooling and no pre-installed Rust toolchain**. Soldr
Reproduces fbuild's Apple release lanes on **Linux x86_64** with **no
Apple-side tooling and no pre-installed Rust toolchain**. Soldr
bootstraps rustup, the pinned 1.94.1 channel, zig, the Apple SDK, and
`cargo-zigbuild` from a vanilla `ubuntu:24.04` base.

This is the proof-of-concept that lets fbuild's release pipeline drop
its `macos-latest` runner for the mac-arm64 lane and replace it with the
its `macos-latest` runners entirely and route both mac arches to the
same `ubuntu-latest` lane every other target already uses.

## Build + run

```bash
# From the fbuild repo root:
docker build -f ci/docker-mac-arm64-cross/Dockerfile -t fbuild-mac-arm64-cross .
docker run --rm -v "$PWD:/src" -w /src fbuild-mac-arm64-cross \
bash ci/docker-mac-arm64-cross/build.sh
# From the fbuild repo root, build the docker image once:
docker build -f ci/docker-mac-cross/Dockerfile -t fbuild-mac-cross .

# Default: aarch64-apple-darwin (Apple Silicon)
docker run --rm -v "$PWD:/src" -w /src fbuild-mac-cross \
bash ci/docker-mac-cross/build.sh

# Intel mac:
docker run --rm -v "$PWD:/src" -w /src fbuild-mac-cross \
bash ci/docker-mac-cross/build.sh x86_64-apple-darwin
```

`build.sh` produces three artifacts under `$PWD/staging/` and asserts via
`file(1)` that each is a `Mach-O 64-bit arm64` binary — the
`build.sh` produces three artifacts under `$PWD/staging/` and asserts
via `file(1)` that each is a `Mach-O 64-bit <arch>` binary — the
`NO CHEATING` gate. If anything regressed and we accidentally produced
the host Linux binary, `file` reports `ELF 64-bit LSB pie executable,
x86-64` and the script fails loudly.

The arch check is per-target (`arm64|aarch64` for the Apple Silicon
lane, `x86_64` for the Intel lane), so neither lane can silently
fall back to the host triple.

## Why `ubuntu:24.04` (not `debian:bookworm-slim`)

Soldr's published Linux-gnu binary requires `glibc 2.39`. Debian
Expand Down
38 changes: 26 additions & 12 deletions ci/docker-mac-arm64-cross/build.sh → ci/docker-mac-cross/build.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
#!/usr/bin/env bash
# Run inside the `fbuild-mac-arm64-cross` docker image (see Dockerfile).
# Cross-compiles fbuild + fbuild-daemon + the PyO3 extension to
# aarch64-apple-darwin using soldr + cargo-zigbuild + soldr's Apple SDK.
# Run inside the `fbuild-mac-cross` docker image (see Dockerfile).
# Cross-compiles fbuild + fbuild-daemon + the PyO3 extension to one of
# the Apple targets using soldr + cargo-zigbuild + soldr's Apple SDK.
#
# Usage:
# ./build.sh # default aarch64-apple-darwin
# TARGET=x86_64-apple-darwin ./build.sh # mac intel
# ./build.sh aarch64-apple-darwin # explicit positional arg
#
# Output layout (in $PWD/staging):
# fbuild ← Mach-O 64-bit executable arm64
# fbuild-daemon ← Mach-O 64-bit executable arm64
# _native.abi3.so ← Mach-O 64-bit dylib arm64 (PyO3 extension)
# fbuild ← Mach-O 64-bit executable <arch>
# fbuild-daemon ← Mach-O 64-bit executable <arch>
# _native.abi3.so ← Mach-O 64-bit dylib <arch> (PyO3 extension)

set -euo pipefail

TARGET="aarch64-apple-darwin"
TARGET="${1:-${TARGET:-aarch64-apple-darwin}}"
case "$TARGET" in
aarch64-apple-darwin) MACHO_ARCH_PATTERN="arm64|aarch64" ;;
x86_64-apple-darwin) MACHO_ARCH_PATTERN="x86_64" ;;
*)
echo "ERROR: unsupported TARGET=$TARGET (expected aarch64-apple-darwin or x86_64-apple-darwin)" >&2
exit 2
;;
esac
echo "::notice::TARGET=$TARGET (expect Mach-O $MACHO_ARCH_PATTERN)"
STAGING="${STAGING:-$PWD/staging}"
mkdir -p "$STAGING"

Expand Down Expand Up @@ -56,19 +70,19 @@ if [ ! -f "$EXT_SRC" ]; then
fi
cp "$EXT_SRC" "$STAGING/_native.abi3.so"

# Verify the output is actually a Mach-O ARM64 binary — this is the
# Verify the output is actually a Mach-O <arch> binary — this is the
# `NO CHEATING` gate. If file(1) reports anything other than
# `Mach-O 64-bit ... arm64` for all three artifacts, the cross-compile
# `Mach-O 64-bit ... <arch>` for all three artifacts, the cross-compile
# silently produced the host binary instead and we must fail loudly.
for f in fbuild fbuild-daemon _native.abi3.so; do
desc="$(file "$STAGING/$f")"
echo " $desc"
if ! echo "$desc" | grep -qE "Mach-O.*(arm64|aarch64)"; then
echo "ERROR: $f is not Mach-O arm64 — got: $desc" >&2
if ! echo "$desc" | grep -qE "Mach-O.*($MACHO_ARCH_PATTERN)"; then
echo "ERROR: $f is not Mach-O matching '$MACHO_ARCH_PATTERN' — got: $desc" >&2
exit 1
fi
done
echo "::endgroup::"

echo "All three artifacts are valid Mach-O arm64. Staging dir: $STAGING"
echo "All three artifacts are valid Mach-O for $TARGET. Staging dir: $STAGING"
ls -lh "$STAGING"
Loading