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..5dcc9eeae2a579 --- /dev/null +++ b/eng/native/sccache-xarch-wrapper.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Wrapper around sccache for macOS builds. +# sccache cannot parse -Xarch_ flags that CMake generates for PCH +# includes, and also drops plain -include flags during compilation. +# We rewrite "-Xarch_ -include" to "-Xclang -include -Xclang " +# which sccache passes through correctly to the clang frontend. + +args=() +skip_xarch=false + +for arg in "$@"; do + if $skip_xarch; then + skip_xarch=false + if [[ "$arg" == -include* ]]; then + # Rewrite -include to -Xclang -include -Xclang + local_path="${arg#-include}" + args+=("-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..fd04d5bb9f0d5f 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,26 @@ 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. + # + # All supported platforms build on x64 hosts, including macOS arm64 + # cross-builds. The unsuffixed package contains the linux-musl-x64 binary; + # macOS uses the osx-x64 package. - 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" + sccacheSource=() + + if [[ "$osGroup" == "osx" ]]; then + sccachePackage="sccache.osx-x64" + sccacheSource=(--source https://api.nuget.org/v3/index.json) + fi + + "$(Build.SourcesDirectory)/eng/common/dotnet.sh" package download "${sccachePackage}@${sccacheVersion}" -o "$(Build.SourcesDirectory)/.packages" -v quiet ${sccacheSource[@]+"${sccacheSource[@]}"} + 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 bd7fba69fce50c..613932bccd2fdd 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -368,7 +368,10 @@ extends: nameSuffix: CoreCLR_Libraries buildArgs: -s clr+libs -c $(_BuildConfig) timeoutInMinutes: 120 + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/common/upload-artifact-step.yml parameters: rootFolder: $(Build.SourcesDirectory)/artifacts/bin @@ -513,7 +516,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: @@ -809,7 +815,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 @@ -847,8 +856,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 @@ -1502,6 +1514,7 @@ extends: - nameSuffix: CoreCLR_Libraries buildConfig: release preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml - template: /eng/pipelines/common/download-artifact-step.yml parameters: artifactName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_Release @@ -1510,6 +1523,7 @@ extends: displayName: 'unified artifacts' timeoutInMinutes: 150 postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/installer/helix.yml parameters: creator: dotnet-bot @@ -1565,6 +1579,7 @@ extends: - nameSuffix: CoreCLR_Libraries buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml - template: /eng/pipelines/common/download-artifact-step.yml parameters: artifactName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(debugOnPrReleaseOnRolling) @@ -1573,6 +1588,7 @@ extends: displayName: 'unified artifacts' timeoutInMinutes: 150 postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/installer/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"