diff --git a/scripts/bootstrap_local_tests.sh b/scripts/bootstrap_local_tests.sh index f3770c6..4082f24 100755 --- a/scripts/bootstrap_local_tests.sh +++ b/scripts/bootstrap_local_tests.sh @@ -14,6 +14,14 @@ VENV_DIR="${MLX_METALLIB_VENV:-/tmp/swiftlm_mlx_venv}" echo "=> Building test harness (swift build --build-tests)..." swift build --build-tests +if [ -d .build/out ]; then + # Swift 6.4+ layout: the metallib is embedded in each test bundle (see + # scripts/install-test-metallib.sh); copying one in breaks the next incremental build. + bash scripts/check-metal-toolchain.sh + echo "=> Done. Run tests with: swift test --skip-build" + exit 0 +fi + echo "=> Installing MLX Metal library..." if [ ! -d "$VENV_DIR" ]; then python3 -m venv "$VENV_DIR" diff --git a/scripts/check-metal-toolchain.sh b/scripts/check-metal-toolchain.sh new file mode 100755 index 0000000..74a851c --- /dev/null +++ b/scripts/check-metal-toolchain.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# check-metal-toolchain.sh — fail early, with the fix, when the Metal compiler is missing. +# +# SwiftPM compiles the Cmlx kernels itself and embeds `default.metallib` in +# mlx-swift_Cmlx.bundle inside every .xctest, so `swift build --build-tests` followed by +# `swift test --skip-build` needs no hand-copied metallib. Copying one into +# .xctest/Contents/MacOS invalidates the bundle signature and the next incremental +# build then fails at CodeSign. The one thing the build does need is the Metal compiler, +# which Xcode 26+ ships as a separate download. See #128 Tier 3. +set -euo pipefail + +if xcrun -find metal >/dev/null 2>&1; then + exit 0 +fi + +cat >&2 <<'MSG' +error: the Metal Toolchain is not installed, so the MLX kernels cannot be compiled. +Install it with: + + xcodebuild -downloadComponent MetalToolchain +MSG +exit 1 diff --git a/scripts/install-test-metallib.sh b/scripts/install-test-metallib.sh index 10d1ed6..8bd2a40 100755 --- a/scripts/install-test-metallib.sh +++ b/scripts/install-test-metallib.sh @@ -11,11 +11,22 @@ set -euo pipefail cd "$(dirname "$0")/.." +# Swift 6.4+ (Xcode 27) builds into .build/out/ and embeds default.metallib in +# mlx-swift_Cmlx.bundle inside every .xctest, so there is nothing to install. Copying a +# metallib into .xctest/Contents/MacOS there invalidates the bundle signature and +# the next incremental build fails at CodeSign. Older toolchains (Swift 6.2 / Xcode 26, the +# layout CI uses: .build/arm64-apple-macosx/) do not embed one and still need the copy below. +if [ -d .build/out ]; then + bash scripts/check-metal-toolchain.sh + echo "Swift 6.4+ build layout: metallib is embedded in the test bundles, nothing to install." + exit 0 +fi + CONFIGS=("${1:-debug release}") find_metallib() { # 1. Already built by build.sh - for candidate in .build/*/release/mlx.metallib .build/*/release/default.metallib default.metallib; do + for candidate in .build/release/mlx.metallib .build/*/release/mlx.metallib .build/*/release/default.metallib default.metallib; do [ -f "$candidate" ] && { echo "$candidate"; return 0; } done # 2. From the mlx Python wheel, as CI does