From ae81fae79bf268dcd6adaf586908dbb675da6899 Mon Sep 17 00:00:00 2001 From: AnzoBenjamin Date: Fri, 7 Aug 2026 11:38:31 +0300 Subject: [PATCH] fix(ci): probe clang via xcrun when selecting Xcode for cargo Prefer xcrun --find clang over a hard-coded usr/bin/clang path when choosing DEVELOPER_DIR for legacy macOS and darwin-x64 ripgrep cargo builds. Fall back through current selection, Xcode apps, and Command Line Tools so CLI Release Prod does not fail when runner images omit the direct clang binary path. --- .github/workflows/cli-release-build.yml | 134 +++++++++++++++------ scripts/__tests__/release-workflow.test.ts | 2 +- 2 files changed, 99 insertions(+), 37 deletions(-) diff --git a/.github/workflows/cli-release-build.yml b/.github/workflows/cli-release-build.yml index 2095173d1b..0d217ffdc4 100644 --- a/.github/workflows/cli-release-build.yml +++ b/.github/workflows/cli-release-build.yml @@ -220,33 +220,64 @@ jobs: tar -xzf "$LEGACY_DIR/ripgrep.tar.gz" \ -C "$LEGACY_DIR/ripgrep" --strip-components=1 - # Select a usable Xcode with clang before cargo needs a C linker. - # Some runner images leave a broken default (e.g. Xcode_15.4 without clang). + # Select a usable developer dir with clang before cargo needs a C linker. + # Prefer xcrun --find clang over checking usr/bin/clang directly: some + # runner images omit that path even when the selected toolchain works. DEVELOPER_DIR="" - CANDIDATES=() - while IFS= read -r app; do - CANDIDATES+=("$app") - done < <(ls -1d /Applications/Xcode_*.app 2>/dev/null | sort -V -r || true) - if [[ -d /Applications/Xcode.app ]]; then - CANDIDATES+=("/Applications/Xcode.app") + if CURRENT_DEVELOPER_DIR="$(xcode-select -p 2>/dev/null || true)" \ + && [[ -n "$CURRENT_DEVELOPER_DIR" ]]; then + export DEVELOPER_DIR="$CURRENT_DEVELOPER_DIR" + if ! xcrun --find clang >/dev/null 2>&1; then + DEVELOPER_DIR="" + fi fi - for app in "${CANDIDATES[@]}"; do - if [[ -x "$app/Contents/Developer/usr/bin/clang" ]]; then - DEVELOPER_DIR="$app/Contents/Developer" - break + if [[ -z "$DEVELOPER_DIR" ]]; then + CANDIDATES=() + while IFS= read -r app; do + CANDIDATES+=("$app") + done < <(ls -1d /Applications/Xcode_*.app 2>/dev/null | sort -V -r || true) + if [[ -d /Applications/Xcode.app ]]; then + CANDIDATES+=("/Applications/Xcode.app") fi - done + for app in "${CANDIDATES[@]}"; do + candidate="$app/Contents/Developer" + export DEVELOPER_DIR="$candidate" + if sudo xcode-select -s "$candidate" \ + && xcrun --find clang >/dev/null 2>&1; then + break + fi + DEVELOPER_DIR="" + done + fi + if [[ -z "$DEVELOPER_DIR" ]] && [[ -d /Library/Developer/CommandLineTools ]]; then + candidate="/Library/Developer/CommandLineTools" + export DEVELOPER_DIR="$candidate" + if sudo xcode-select -s "$candidate" \ + && xcrun --find clang >/dev/null 2>&1; then + : + else + DEVELOPER_DIR="" + fi + fi if [[ -z "$DEVELOPER_DIR" ]]; then - echo "error: no Xcode app with an executable clang under /Applications" >&2 - echo "Available apps:" >&2 + echo "error: no usable Xcode or Command Line Tools with clang" >&2 + echo "xcode-select -p:" >&2 + xcode-select -p 2>&1 || true + echo "Available Xcode apps:" >&2 ls -la /Applications/Xcode*.app 2>/dev/null || echo "(none)" >&2 + echo "which clang:" >&2 + which clang 2>&1 || true + echo "xcrun --find clang:" >&2 + xcrun --find clang 2>&1 || true exit 1 fi - sudo xcode-select -s "$DEVELOPER_DIR" export DEVELOPER_DIR echo "Selected DEVELOPER_DIR=$DEVELOPER_DIR" - xcodebuild -version - clang --version + if command -v xcodebuild >/dev/null 2>&1; then + xcodebuild -version + fi + clang --version 2>/dev/null || true + xcrun clang --version pushd "$LEGACY_DIR/ripgrep" MACOSX_DEPLOYMENT_TARGET=11.0 cargo build --release --locked @@ -269,33 +300,64 @@ jobs: tar -xzf "$RG_DIR/ripgrep.tar.gz" \ -C "$RG_DIR/source" --strip-components=1 - # Select a usable Xcode with clang before cargo needs a C linker. - # Some runner images leave a broken default (e.g. Xcode_15.4 without clang). + # Select a usable developer dir with clang before cargo needs a C linker. + # Prefer xcrun --find clang over checking usr/bin/clang directly: some + # runner images omit that path even when the selected toolchain works. DEVELOPER_DIR="" - CANDIDATES=() - while IFS= read -r app; do - CANDIDATES+=("$app") - done < <(ls -1d /Applications/Xcode_*.app 2>/dev/null | sort -V -r || true) - if [[ -d /Applications/Xcode.app ]]; then - CANDIDATES+=("/Applications/Xcode.app") + if CURRENT_DEVELOPER_DIR="$(xcode-select -p 2>/dev/null || true)" \ + && [[ -n "$CURRENT_DEVELOPER_DIR" ]]; then + export DEVELOPER_DIR="$CURRENT_DEVELOPER_DIR" + if ! xcrun --find clang >/dev/null 2>&1; then + DEVELOPER_DIR="" + fi fi - for app in "${CANDIDATES[@]}"; do - if [[ -x "$app/Contents/Developer/usr/bin/clang" ]]; then - DEVELOPER_DIR="$app/Contents/Developer" - break + if [[ -z "$DEVELOPER_DIR" ]]; then + CANDIDATES=() + while IFS= read -r app; do + CANDIDATES+=("$app") + done < <(ls -1d /Applications/Xcode_*.app 2>/dev/null | sort -V -r || true) + if [[ -d /Applications/Xcode.app ]]; then + CANDIDATES+=("/Applications/Xcode.app") fi - done + for app in "${CANDIDATES[@]}"; do + candidate="$app/Contents/Developer" + export DEVELOPER_DIR="$candidate" + if sudo xcode-select -s "$candidate" \ + && xcrun --find clang >/dev/null 2>&1; then + break + fi + DEVELOPER_DIR="" + done + fi + if [[ -z "$DEVELOPER_DIR" ]] && [[ -d /Library/Developer/CommandLineTools ]]; then + candidate="/Library/Developer/CommandLineTools" + export DEVELOPER_DIR="$candidate" + if sudo xcode-select -s "$candidate" \ + && xcrun --find clang >/dev/null 2>&1; then + : + else + DEVELOPER_DIR="" + fi + fi if [[ -z "$DEVELOPER_DIR" ]]; then - echo "error: no Xcode app with an executable clang under /Applications" >&2 - echo "Available apps:" >&2 + echo "error: no usable Xcode or Command Line Tools with clang" >&2 + echo "xcode-select -p:" >&2 + xcode-select -p 2>&1 || true + echo "Available Xcode apps:" >&2 ls -la /Applications/Xcode*.app 2>/dev/null || echo "(none)" >&2 + echo "which clang:" >&2 + which clang 2>&1 || true + echo "xcrun --find clang:" >&2 + xcrun --find clang 2>&1 || true exit 1 fi - sudo xcode-select -s "$DEVELOPER_DIR" export DEVELOPER_DIR echo "Selected DEVELOPER_DIR=$DEVELOPER_DIR" - xcodebuild -version - clang --version + if command -v xcodebuild >/dev/null 2>&1; then + xcodebuild -version + fi + clang --version 2>/dev/null || true + xcrun clang --version pushd "$RG_DIR/source" MACOSX_DEPLOYMENT_TARGET=13.0 cargo build --release --locked diff --git a/scripts/__tests__/release-workflow.test.ts b/scripts/__tests__/release-workflow.test.ts index 1a93290fa4..5a46868aa8 100644 --- a/scripts/__tests__/release-workflow.test.ts +++ b/scripts/__tests__/release-workflow.test.ts @@ -72,7 +72,7 @@ describe('CLI release build workflow', () => { for (const block of [legacyBlock, intelBlock]) { expect(block).toContain('xcode-select -s') expect(block).toContain('export DEVELOPER_DIR') - expect(block).toContain('/Contents/Developer/usr/bin/clang') + expect(block).toContain('xcrun --find clang') } }) })