Skip to content

refactor(ci): use Homebrew LLVM for macOS validation #4

refactor(ci): use Homebrew LLVM for macOS validation

refactor(ci): use Homebrew LLVM for macOS validation #4

Workflow file for this run

name: ci-macos
# macOS validation CI for mcpp.
# Phase 1: Validate that upstream LLVM/Clang can compile C++23 modules on macOS ARM64.
# Phase 2 (future): Full mcpp self-host once xlings macOS binary is compatible.
on:
push:
branches: [ feat/macos-support ]
pull_request:
branches: [ main ]
paths:
- 'src/toolchain/**'
- 'src/build/**'
- 'install.sh'
- '.github/workflows/ci-macos.yml'
workflow_dispatch:
concurrency:
group: ci-macos-${{ github.ref }}
cancel-in-progress: true
jobs:
macos-llvm-validation:
name: macOS ARM64 — LLVM toolchain validation
runs-on: macos-14
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: System info
run: |
uname -a
sw_vers
xcrun --show-sdk-path
echo "SDK version: $(xcrun --show-sdk-version)"
- name: Install LLVM 20 via Homebrew
run: |
# Use Homebrew LLVM as a stand-in for xlings LLVM package.
# This validates the same compilation model (upstream clang + libc++).
brew install llvm
LLVM_PREFIX=$(brew --prefix llvm)
echo "LLVM_PREFIX=$LLVM_PREFIX" >> "$GITHUB_ENV"
echo "PATH=$LLVM_PREFIX/bin:$PATH" >> "$GITHUB_ENV"
"$LLVM_PREFIX/bin/clang++" --version
- name: Validate clang++ can compile C++23 with import std
run: |
WORK=$(mktemp -d)
cd "$WORK"
SDKROOT=$(xcrun --show-sdk-path)
CXX="$LLVM_PREFIX/bin/clang++"
LIBCXX_MOD="$LLVM_PREFIX/share/libc++/v1"
echo "=== Checking libc++ module sources ==="
ls "$LIBCXX_MOD/" 2>/dev/null || {
echo "::warning::libc++ module sources not found at $LIBCXX_MOD"
# Try alternate location
LIBCXX_MOD=$(find "$LLVM_PREFIX" -name "std.cppm" -path "*/libc++/*" -exec dirname {} \; | head -1)
echo "Found at: $LIBCXX_MOD"
}
if [ -f "$LIBCXX_MOD/std.cppm" ]; then
echo "=== Pre-compiling std module ==="
mkdir -p pcm.cache
"$CXX" -std=c++23 --sysroot="$SDKROOT" \
-Wno-reserved-module-identifier \
--precompile "$LIBCXX_MOD/std.cppm" -o pcm.cache/std.pcm
echo "=== Compiling std.pcm → std.o ==="
"$CXX" -std=c++23 --sysroot="$SDKROOT" \
-Wno-reserved-module-identifier \
pcm.cache/std.pcm -c -o std.o
echo "=== Compiling main.cpp with import std ==="
cat > main.cpp << 'SRC'
import std;
int main() {
std::println("C++23 import std works on macOS ARM64!");
return 0;
}
SRC
"$CXX" -std=c++23 --sysroot="$SDKROOT" \
-fmodule-file=std=pcm.cache/std.pcm \
-c main.cpp -o main.o
echo "=== Linking ==="
"$CXX" --sysroot="$SDKROOT" main.o std.o -o hello_modules \
-L"$LLVM_PREFIX/lib/c++" -lc++ 2>/dev/null || \
"$CXX" --sysroot="$SDKROOT" main.o std.o -o hello_modules
echo "=== Running ==="
./hello_modules
else
echo "::warning::std.cppm not found, testing non-module compilation only"
fi
- name: Validate non-module C++23 compilation
run: |
WORK=$(mktemp -d)
cd "$WORK"
SDKROOT=$(xcrun --show-sdk-path)
CXX="$LLVM_PREFIX/bin/clang++"
cat > main.cpp << 'SRC'
#include <iostream>
#include <format>
#include <print>
int main() {
std::cout << std::format("Hello from clang {} on macOS!", __clang_version__) << std::endl;
std::println("std::println works!");
return 0;
}
SRC
echo "=== Compile + Link ==="
"$CXX" -std=c++23 --sysroot="$SDKROOT" -o hello main.cpp
echo "=== Run ==="
./hello
- name: Validate target triple and sysroot probing
run: |
CXX="$LLVM_PREFIX/bin/clang++"
echo "=== Target triple ==="
"$CXX" -dumpmachine
echo "=== Sysroot (compiler) ==="
"$CXX" -print-sysroot 2>/dev/null || echo "(empty - expected on macOS)"
echo "=== xcrun SDK ==="
xcrun --show-sdk-path
echo "=== Module manifest ==="
"$CXX" -print-library-module-manifest-path 2>/dev/null || echo "(not available)"
- name: Validate install.sh platform detection
run: |
# Just test the platform detection logic, not actual download
uname_s=$(uname -s)
uname_m=$(uname -m)
echo "Platform: ${uname_s}-${uname_m}"
case "${uname_s}-${uname_m}" in
Darwin-arm64) echo "PASS: would select darwin-arm64" ;;
Darwin-x86_64) echo "PASS: would select darwin-x86_64" ;;
*) echo "FAIL: unexpected platform"; exit 1 ;;
esac
macos-xlings-compat:
name: macOS ARM64 — xlings binary compatibility check
runs-on: macos-14
timeout-minutes: 10
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Test xlings macOS binary
env:
XLINGS_VERSION: '0.4.30'
run: |
WORK=$(mktemp -d)
tarball="xlings-${XLINGS_VERSION}-macosx-arm64.tar.gz"
curl -fsSL -o "${WORK}/${tarball}" \
"https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${tarball}"
tar -xzf "${WORK}/${tarball}" -C "${WORK}"
XLINGS_DIR="${WORK}/xlings-${XLINGS_VERSION}-macosx-arm64"
echo "=== Testing xlings binary ==="
file "$XLINGS_DIR/subos/default/bin/xlings"
otool -L "$XLINGS_DIR/subos/default/bin/xlings" 2>/dev/null || true
# Try running — may fail with dyld errors on current runner
"$XLINGS_DIR/subos/default/bin/xlings" --version || {
echo "::warning::xlings macOS binary is not compatible with this runner."
echo "This is an upstream xlings issue — the binary was built against a"
echo "newer macOS SDK than the runner provides."
echo "macOS runner info:"
sw_vers
exit 0 # Don't fail the job — this is expected for now
}