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'