diff --git a/.ci/compile.sh b/.ci/compile.sh
index 6789b9817..302972f30 100755
--- a/.ci/compile.sh
+++ b/.ci/compile.sh
@@ -17,9 +17,8 @@
# --dir
sets the name of the build dir, default is "build"
# --cmake-generator sets CMAKE_GENERATOR as used by cmake
# --target-macos-version sets the min os version - only used for macOS builds
-# --profile writes an MSBuild performance summary and binary log, Windows only
-# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE CCACHE_EVICTION_AGE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION MAKE_SANITIZE MAKE_COVERAGE VCPKG_TARGET_MACOS_VERSION BUILD_PARALLEL_LEVEL BUILD_PROFILE
-# (correspond to args: --debug/--release --install --package --suffix --server --test --sanitize --coverage --ccache --dir --profile)
+# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE CCACHE_EVICTION_AGE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION MAKE_SANITIZE MAKE_COVERAGE VCPKG_TARGET_MACOS_VERSION
+# (correspond to args: --debug/--release --install --package --suffix --server --test --sanitize --coverage --ccache --dir )
# exitcode: 1 for failure, 3 for invalid arguments
# Read arguments
@@ -116,10 +115,6 @@ while [[ $# != 0 ]]; do
export CMAKE_GENERATOR=$1
shift
;;
- '--profile')
- BUILD_PROFILE=1
- shift
- ;;
'--target-macos-version')
shift
if [[ $# == 0 ]]; then
@@ -214,22 +209,6 @@ function ccachestatsverbose() {
fi
}
-function cpuinfo() {
- # The number of cores decides how much build parallelism is useful; the hosted
- # runners are not all sized alike, so read it off the machine instead of assuming.
- case "$RUNNER_OS" in
- Windows)
- echo "cores: ${NUMBER_OF_PROCESSORS:-unknown}"
- ;;
- macOS)
- echo "cores: $(sysctl -n hw.ncpu)"
- ;;
- *)
- echo "cores: $(nproc 2>/dev/null || echo unknown)"
- ;;
- esac
-}
-
# Compile
if [[ $RUNNER_OS == macOS ]]; then
# QTDIR is needed for macOS since we actually only use the cached thin Qt binaries instead of the install-qt-action,
@@ -314,34 +293,9 @@ if [[ $RUNNER_OS == macOS ]]; then
fi
elif [[ $RUNNER_OS == Windows ]]; then
- if [[ $CMAKE_GENERATOR == "Visual Studio"* ]]; then
- # cmake only hands MSBuild a job count when one is asked for, and without it
- # MSBuild builds a single node: one project at a time, whatever MTT does inside
- # it. Ask for a node per core.
- if [[ ! $BUILD_PARALLEL_LEVEL ]]; then
- BUILD_PARALLEL_LEVEL="${NUMBER_OF_PROCESSORS:-1}"
- fi
- buildflags+=(--parallel "$BUILD_PARALLEL_LEVEL")
-
- # Enable MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
- # and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt
- # EnforceProcessCountAcrossBuilds makes the CL_MPCount ceiling apply across all
- # the projects the nodes are building, instead of each node running its own
- # cl.exe processes and /m and MTT multiplying into an oversubscribed machine.
- buildflags+=(-- -p:UseMultiToolTask=true -p:EnableClServerMode=true -p:EnforceProcessCountAcrossBuilds=true -p:CL_MPCount="$BUILD_PARALLEL_LEVEL")
- if [[ $BUILD_PROFILE ]]; then
- # A performance summary says which projects and tasks cost what, the binary log
- # keeps the full timeline; both are far too noisy to always produce. The files
- # land next to the solution, i.e. in the build dir the workflow uploads. These
- # join the MTT options above, which already carried the "--" separator.
- buildflags+=("-flp:PerformanceSummary;v=q;LogFile=msbuild-perf.log" -bl:msbuild.binlog)
- fi
- else
- # Ninja runs the compiler itself, so it neither takes the MSBuild switches
- # (it rejects -p: options outright) nor a job count: it sizes its own pool
- # for the cores it finds.
- echo "ninja $(ninja --version)"
- fi
+ # Enable MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
+ # and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt
+ buildflags+=(-- -p:UseMultiToolTask=true -p:EnableClServerMode=true)
fi
if [[ $USE_CCACHE ]]; then
@@ -357,19 +311,10 @@ cmake .. "${flags[@]}"
echo "::endgroup::"
echo "::group::Build project"
-cpuinfo
echo "Running cmake --build with flags: ${buildflags[*]}"
cmake --build . "${buildflags[@]}"
echo "::endgroup::"
-if [[ $BUILD_PROFILE && $RUNNER_OS == Windows && -f msbuild-perf.log ]]; then
- # Repeat the summary in the job log so the numbers are readable without
- # downloading the binary log, which is hundreds of megabytes.
- echo "::group::MSBuild performance summary"
- cat msbuild-perf.log
- echo "::endgroup::"
-fi
-
if [[ $USE_CCACHE ]]; then
if [[ $CCACHE_EVICTION_AGE ]]; then
echo "::group::evict ccache files older than $CCACHE_EVICTION_AGE"
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index a379d1710..2bc0ac11d 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -168,7 +168,7 @@ jobs:
continue-on-error: ${{ matrix.allow-failure == 'yes' }}
timeout-minutes: 70
env:
- CACHE: ${{ github.workspace }}/.cache/${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }} # scratch dir for the container image build and throwaway ccache; nothing below is cached
+ CACHE: ${{ github.workspace }}/.cache/${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }} # directory holding the build image and ccache, only the image subdir is cached below
CCACHE_EVICTION_AGE: 7d
CCACHE_SIZE: 600M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CMAKE_GENERATOR: 'Ninja'
@@ -179,16 +179,29 @@ jobs:
- name: "Checkout"
uses: actions/checkout@v7
- # Nothing on these legs is worth persisting. A compile here runs inside a
- # container, so ccache measures a 0.00 to 1.85 percent hit rate against 49 to
- # 50 percent on the macOS legs: persisting it spent a few hundred MiB per
- # entry buying nothing. The build image is not an alternative: it runs 1.1 to
- # 2.4 GB per leg on disk, about 5 to 6 GB of quota for all nine legs once
- # compressed, so caching it would cost more than dropping the ccache frees.
- # The old ccache- entries are never read again and expire on their own.
+ # Only the image half of this cache is worth keeping. A compile on these legs runs
+ # inside a container, so ccache measures a 0.00 to 1.85 percent hit rate here against
+ # 49 to 50 percent on the macOS legs, and the roughly 420 MiB of ccache each entry
+ # carried was buying nothing. Caching $CACHE/image alone drops that.
+ # The key changes name because the cached content does: the old ccache-
+ # entries hold an image plus a ccache directory, and expire on their own untouched.
+ - name: "Restore build image cache"
+ id: restore_image_cache
+ uses: actions/cache/restore@v6
+ with:
+ key: image-${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }}-${{ hashFiles(format('.ci/{0}{1}/**', matrix.distro, matrix.version)) }}
+ path: ${{ env.CACHE }}/image
+
- name: "Build ${{ matrix.distro }} ${{ matrix.version }} Docker image"
shell: bash
- run: source .ci/docker.sh --build
+ run: |
+ # --get/--save wire the $CACHE/image dir restored/saved above into the
+ # build: without them the image is rebuilt from scratch every run and
+ # the image cache saves nothing. Only persist on master; PR runs just
+ # reuse whatever the restore step found.
+ args=(--get --build)
+ [[ $GITHUB_REF == "refs/heads/master" ]] && args+=(--save)
+ source .ci/docker.sh "${args[@]}"
- name: "Build debug and test"
if: matrix.test != 'skip'
@@ -250,6 +263,25 @@ jobs:
RUN --server --release --package "$package" "${args[@]}"
+ # Delete used cache to emulate a cache update. See https://github.com/actions/cache/issues/342
+ - name: "[Linux] Delete used cache to emulate a cache update"
+ if: github.ref == 'refs/heads/master' && steps.restore_image_cache.outputs.cache-hit
+ continue-on-error: true
+ env:
+ CACHE_PRIMARY_KEY: ${{ steps.restore_image_cache.outputs.cache-primary-key }}
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ if gh cache delete --repo "$GITHUB_REPOSITORY" "$CACHE_PRIMARY_KEY"; then
+ echo "Cache deleted successfully"
+ fi
+
+ - name: "Save updated build image cache"
+ if: github.ref == 'refs/heads/master'
+ uses: actions/cache/save@v6
+ with:
+ key: ${{ steps.restore_image_cache.outputs.cache-primary-key }}
+ path: ${{ env.CACHE }}/image
+
- name: "Upload artifact"
id: upload_artifact
if: matrix.package != 'skip'
@@ -366,20 +398,13 @@ jobs:
target: 10
runner: windows-2025 # https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-VS2026-Readme.md
- # Ninja builds the whole dependency graph at once instead of one
- # MSBuild node at a time, runs the compiler itself, and matches the
- # Linux and macOS legs. Its median build phase measured ~17 min
- # against ~21 for the Visual Studio generator (shared 4-core hosts
- # swing either by minutes, so read medians, not single runs).
- cmake_generator: Ninja
+ cmake_generator: "Visual Studio 18 2026"
+ cmake_generator_platform: x64
make_package: 1
package_suffix: "-Win10"
qt_version: 6.11.*
qt_modules: qtimageformats qtmultimedia qtshadertools qtwebsockets
type: Release
- # Scope is named after the vs2026 toolchain, not the generator: the
- # ABI hash covers cl.exe, which is identical, so this leg keeps
- # restoring the warm archives. Renaming would orphan them.
vcpkg_scope: 'vcpkg/windows10-x64-vs2026/'
vcpkg_upload: 1 # only one leg per vcpkg_scope hands its archives over
@@ -475,13 +500,6 @@ jobs:
shell: bash
run: choco install nsis
- # Ninja invokes cl.exe directly and needs the MSVC environment on PATH.
- - name: "[Windows] Set up MSVC environment"
- if: matrix.os == 'Windows'
- uses: TheMrMilchmann/setup-msvc-dev@368ef7d1ee4d1171b31d4a7f67f4d954f903f5a9 # v4.1.0
- with:
- arch: x64
-
- name: "Setup vcpkg cache"
id: vcpkg-cache
uses: TAServers/vcpkg-cache@v3
@@ -516,6 +534,7 @@ jobs:
BUILDTYPE: '${{ matrix.type }}'
CCACHE_EVICTION_AGE: ${{ matrix.ccache_eviction_age }}
CMAKE_GENERATOR: ${{ matrix.cmake_generator }}
+ CMAKE_GENERATOR_PLATFORM: ${{ matrix.cmake_generator_platform }}
DEVELOPER_DIR: '/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer'
GITHUB_TOKEN: ${{ github.token }} # needed for vcpkg dependency graph updates, see VCPKG_FEATURE_FLAGS
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
@@ -684,8 +703,6 @@ jobs:
if-no-files-found: error
path: ${{ steps.build.outputs.path }}
- # Ninja is single-config: binaries and their PDBs land directly in the
- # target directories instead of a Release subdirectory.
- name: "[Windows] Upload PDBs (Program Databases)"
if: matrix.os == 'Windows' && github.ref_type != 'tag'
uses: actions/upload-artifact@v7
@@ -693,9 +710,9 @@ jobs:
if-no-files-found: error
name: ${{ steps.build.outputs.name }}-PDBs
path: |
- build/cockatrice/*.pdb
- build/oracle/*.pdb
- build/servatrice/*.pdb
+ build/cockatrice/Release/*.pdb
+ build/oracle/Release/*.pdb
+ build/servatrice/Release/*.pdb
- name: "Upload to release"
if: needs.configure.outputs.tag != null && matrix.make_package == '1'