diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh index 5e94540ee12b4e..fdf156b16fec2e 100755 --- a/eng/native/build-commons.sh +++ b/eng/native/build-commons.sh @@ -60,6 +60,18 @@ build_native() cmakeArgs="$6" message="$7" + # When sccache is enabled, use it as the compiler launcher. + # On macOS, CMake wraps PCH includes with -Xarch_ which sccache + # cannot parse. Use a thin wrapper that strips -Xarch_ flags + # (safe in single-architecture builds) before forwarding to sccache. + if [[ "${USE_SCCACHE:-}" == "true" ]]; then + local __sccacheLauncher="sccache" + if [[ "$targetOS" == osx || "$targetOS" == maccatalyst ]]; then + __sccacheLauncher="$__RepoRootDir/eng/native/sccache-xarch-wrapper.sh" + fi + cmakeArgs="-DCMAKE_C_COMPILER_LAUNCHER=$__sccacheLauncher -DCMAKE_CXX_COMPILER_LAUNCHER=$__sccacheLauncher $cmakeArgs" + fi + # All set to commence the build echo "Commencing build of \"$target\" target in \"$message\" for $__TargetOS.$__TargetArch.$__BuildType in $intermediatesDir" diff --git a/eng/native/sccache-xarch-wrapper.sh b/eng/native/sccache-xarch-wrapper.sh new file mode 100755 index 00000000000000..fd92766ad3bf9a --- /dev/null +++ b/eng/native/sccache-xarch-wrapper.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Wrapper around sccache for macOS builds. +# sccache cannot parse -Xarch_ flags that CMake generates for PCH +# includes. Rewrite them to explicit Clang frontend options that preserve +# use of the generated PCH while remaining parseable by sccache. + +for arg in "$@"; do + if [[ "$arg" == "-emit-pch" ]]; then + exec "$@" + fi +done + +args=() +skip_xarch=false + +for arg in "$@"; do + if $skip_xarch; then + skip_xarch=false + if [[ "$arg" == -include?* ]]; then + local_path="${arg#-include}" + args+=( + "-Xclang" "-include-pch" "-Xclang" "${local_path}.pch" + "-Xclang" "-include" "-Xclang" "$local_path" + ) + else + args+=("$arg") + fi + continue + fi + if [[ "$arg" == -Xarch_* ]]; then + skip_xarch=true + continue + fi + args+=("$arg") +done + +exec sccache "${args[@]}" diff --git a/eng/pipelines/coreclr/templates/sccache-stats.yml b/eng/pipelines/coreclr/templates/sccache-stats.yml index d881dad08e179a..3f7f000ced1ae3 100644 --- a/eng/pipelines/coreclr/templates/sccache-stats.yml +++ b/eng/pipelines/coreclr/templates/sccache-stats.yml @@ -12,7 +12,7 @@ parameters: osSubgroup: '' steps: - - ${{ if and(or(eq(parameters.osGroup, 'linux'), eq(parameters.osGroup, 'freebsd'), eq(parameters.osGroup, 'openbsd')), or(eq(parameters.archType, 'x64'), eq(parameters.archType, 'arm64'))) }}: + - ${{ if and(or(eq(parameters.osGroup, 'linux'), eq(parameters.osGroup, 'freebsd'), eq(parameters.osGroup, 'openbsd'), eq(parameters.osGroup, 'osx')), or(eq(parameters.archType, 'x64'), eq(parameters.archType, 'arm64'))) }}: - script: sccache --show-stats || true displayName: Sccache stats condition: always() diff --git a/eng/pipelines/coreclr/templates/setup-sccache.yml b/eng/pipelines/coreclr/templates/setup-sccache.yml index d15e1953bdb984..d133175afb5901 100644 --- a/eng/pipelines/coreclr/templates/setup-sccache.yml +++ b/eng/pipelines/coreclr/templates/setup-sccache.yml @@ -11,11 +11,12 @@ parameters: shouldContinueOnError: false osSubgroup: '' - # sccache NuGet package version + # sccache version. Keep the version in sync across platforms so all jobs + # cache against the same compiler-launcher behavior. sccacheVersion: '0.15.0' steps: - - ${{ if and(or(eq(parameters.osGroup, 'linux'), eq(parameters.osGroup, 'freebsd'), eq(parameters.osGroup, 'openbsd')), or(eq(parameters.archType, 'x64'), eq(parameters.archType, 'arm64'))) }}: + - ${{ if and(or(eq(parameters.osGroup, 'linux'), eq(parameters.osGroup, 'freebsd'), eq(parameters.osGroup, 'openbsd'), eq(parameters.osGroup, 'osx')), or(eq(parameters.archType, 'x64'), eq(parameters.archType, 'arm64'))) }}: # Set up the Azure Pipeline Cache for sccache's local cache directory. # Use a rolling key so each build can update the cache; restoreKeys # falls back to the most recent saved entry. @@ -26,6 +27,10 @@ steps: # flags are controlled by RuntimeConfiguration (-rc), which is # constant per leg regardless of buildConfig. Omitting it lets PR # builds warm-start from rolling-build caches saved in the main scope. + # + # osGroup/osSubgroup/archType keep each platform's cache isolated so + # Mac jobs don't poison the Linux entries (different compiler, different + # cache contents). - task: Cache@2 displayName: Sccache cache continueOnError: true @@ -35,11 +40,34 @@ steps: restoreKeys: | sccache | ${{ parameters.osGroup }}${{ parameters.osSubgroup }} | ${{ parameters.archType }} | ${{ parameters.nameSuffix }} - # Download the sccache NuGet package and configure the environment. + # Download sccache and configure the environment. + # + # The unsuffixed package contains the linux-musl-x64 binary. On macOS, + # select the package matching the agent host architecture. - script: | + set -euo pipefail sccacheVersion="${{ parameters.sccacheVersion }}" - sccacheDir="$(Build.SourcesDirectory)/.packages/sccache/${sccacheVersion}/tools" - "$(Build.SourcesDirectory)/eng/common/dotnet.sh" package download "sccache@${sccacheVersion}" -o "$(Build.SourcesDirectory)/.packages" -v quiet + osGroup="${{ parameters.osGroup }}" + sccachePackage="sccache" + + if [[ "$osGroup" == "osx" ]]; then + case "$(uname -m)" in + arm64) + sccachePackage="sccache.osx-arm64" + ;; + x86_64) + sccachePackage="sccache.osx-x64" + ;; + *) + echo "Unsupported macOS host architecture: $(uname -m)" >&2 + exit 1 + ;; + esac + fi + + "$(Build.SourcesDirectory)/eng/common/dotnet.sh" package download "${sccachePackage}@${sccacheVersion}" -o "$(Build.SourcesDirectory)/.packages" -v quiet + sccacheDir="$(Build.SourcesDirectory)/.packages/${sccachePackage}/${sccacheVersion}/tools" + chmod +x "$sccacheDir/sccache" echo "##vso[task.prependpath]$sccacheDir" echo "##vso[task.setvariable variable=SCCACHE_DIR]$(Pipeline.Workspace)/.sccache" diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index a6c1949f76a318..af2fc6e3392cf5 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -404,7 +404,10 @@ extends: nameSuffix: CoreCLR_AllSubsets buildArgs: -s clr+libs+host+packs -c $(_BuildConfig) timeoutInMinutes: 180 + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/installer/helix-queues-setup.yml parameters: creator: dotnet-bot @@ -567,7 +570,10 @@ extends: nameSuffix: Libraries_CheckedCoreCLR buildArgs: -s clr+libs -c $(_BuildConfig) -rc Checked timeoutInMinutes: 120 + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/coreclr/templates/build-native-test-assets-step.yml - template: /eng/pipelines/common/upload-artifact-step.yml parameters: @@ -866,7 +872,10 @@ extends: timeoutInMinutes: 180 nameSuffix: NativeAOT buildArgs: -s clr.aot+libs+tools.illink -c $(_BuildConfig) -rc $(_BuildConfig) -lc Release /p:RunAnalyzers=false + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml parameters: creator: dotnet-bot @@ -905,8 +914,11 @@ extends: nameSuffix: NativeAOT_Libraries buildArgs: -s clr.aot+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:RunSmokeTestsOnly=true /p:ArchiveTests=true /p:RunAnalyzers=false timeoutInMinutes: 240 # Doesn't actually take long, but we've seen the ARM64 Helix queue often get backlogged for 2+ hours + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml # extra steps, run tests postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/libraries/helix.yml parameters: creator: dotnet-bot diff --git a/src/coreclr/build-runtime.sh b/src/coreclr/build-runtime.sh index 6147564b20c11b..6809330b216d33 100755 --- a/src/coreclr/build-runtime.sh +++ b/src/coreclr/build-runtime.sh @@ -173,10 +173,6 @@ if [[ "$__TargetArch" != "$__HostArch" ]]; then __CMakeArgs="-DCLR_CMAKE_TARGET_ARCH=$__TargetArch $__CMakeArgs" fi -if [[ "$USE_SCCACHE" == "true" ]]; then - __CMakeArgs="-DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache $__CMakeArgs" -fi - eval "$__RepoRootDir/eng/native/version/copy_version_files.sh" build_native "$__HostOS" "$__HostArch" "$__ProjectRoot" "$__IntermediatesDir" "$__CMakeTarget" "$__CMakeArgs" "CoreCLR component"