From 2ab33a1a4ea736ea7d8233c67a14d184b2fbec6d Mon Sep 17 00:00:00 2001 From: Gin <> Date: Sat, 17 Oct 2026 12:41:44 -0700 Subject: [PATCH 1/5] CI: cache Windows compiles with ccache The two Windows jobs spend 19-27 minutes each compiling, and #1610 left them out of ccache because three things blocked it: - ccache can't wrap the compiler under the Visual Studio generator, so Windows CI now configures with "Ninja Multi-Config". It keeps Visual Studio's output layout (bin/RelWithDebInfo/), so the upload and test steps are unchanged. A new step runs vcvars64.bat from the same Visual Studio and passes its environment to the later steps. For the clang job it puts that Visual Studio's own clang-cl first on PATH, the one the ClangCL toolset used. - ccache can't cache /Zi, which writes debug info to a shared PDB. CI now builds with /Z7 (CMP0141 and CMAKE_MSVC_DEBUG_INFORMATION_FORMAT =Embedded); the linker still writes the PDB that gets uploaded. - ccache can't cache a compile that writes a /FAs assembly listing. The listings are now behind a PA_ASSEMBLY_LISTINGS option, ON by default so local builds keep them, and CI turns it off. CMakeLists.txt and CoreLib.cmake picked the clang-cl flags (-march, -Wno-unused-function) by checking for the ClangCL toolset, which is empty under Ninja. They now check CMAKE_CXX_COMPILER_ID, which is "Clang" for clang-cl under either generator. Ninja runs nproc + 2 compiles at once on Windows instead of 10, close to the one compile per core that Visual Studio's /MP ran, so memory use stays near what the runner handled before. Co-Authored-By: Claude Opus 5.5 --- .../workflows/cpp-ci-serial-programs-base.yml | 64 +++++++++++++++---- SerialPrograms/CMakeLists.txt | 15 ++++- SerialPrograms/cmake/CoreLib.cmake | 12 ++-- 3 files changed, 73 insertions(+), 18 deletions(-) diff --git a/.github/workflows/cpp-ci-serial-programs-base.yml b/.github/workflows/cpp-ci-serial-programs-base.yml index baead1c8d4..667bcf1768 100644 --- a/.github/workflows/cpp-ci-serial-programs-base.yml +++ b/.github/workflows/cpp-ci-serial-programs-base.yml @@ -30,17 +30,29 @@ jobs: - name: Set variables shell: bash run: | - if [[ "${{inputs.compiler}}" == "clang" ]]; then - if [[ "${{inputs.os}}" == windows* ]]; then - CMAKE_ADDITIONAL_FLAGS="-T ClangCL" - elif [[ "${{inputs.os}}" == ubuntu* ]]; then - CMAKE_ADDITIONAL_FLAGS="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo" + BUILD_PARALLEL=10 + if [[ "${{inputs.os}}" == windows* ]]; then + # Build with Ninja: ccache can't wrap the compiler under the Visual Studio generator. + # "Ninja Multi-Config" keeps Visual Studio's output layout (bin/RelWithDebInfo/). + # ccache also can't cache /Zi (debug info written to a shared PDB) or /FAs listings, + # so embed the debug info in each object file with /Z7 (the linker still writes the + # PDB) and turn the listings off. + echo "CMAKE_GENERATOR=Ninja Multi-Config" >> $GITHUB_ENV + CMAKE_ADDITIONAL_FLAGS="-DCMAKE_POLICY_DEFAULT_CMP0141=NEW -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded -DPA_ASSEMBLY_LISTINGS=OFF" + if [[ "${{inputs.compiler}}" == "clang" ]]; then + CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl" + else + CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl" fi + # Visual Studio ran about one compile per core (/MP). Keep Ninja near that instead of + # 10 at once, so memory use stays close to what the runner handled before. + BUILD_PARALLEL=$(( $(nproc) + 2 )) + elif [[ "${{inputs.compiler}}" == "clang" && "${{inputs.os}}" == ubuntu* ]]; then + CMAKE_ADDITIONAL_FLAGS="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo" fi - if [[ "${{inputs.os}}" != windows* ]]; then - CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" - fi + CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" echo "CMAKE_ADDITIONAL_FLAGS=$CMAKE_ADDITIONAL_FLAGS" >> $GITHUB_ENV + echo "BUILD_PARALLEL=$BUILD_PARALLEL" >> $GITHUB_ENV if [[ "${{inputs.os}}" == windows* ]]; then UPLOAD_FOLDER="Arduino-Source/SerialPrograms/bin/RelWithDebInfo" @@ -125,16 +137,44 @@ jobs: # CMake quietly builds without Discord integration when it can't find DPP, so check here. pkg-config --exact-version=10.1.5 dpp + # Ninja needs the MSVC build environment (cl and link on PATH, INCLUDE, LIB, ...), which the + # Visual Studio generator set up by itself. Run vcvars64.bat from the newest Visual Studio, + # the one that generator used, and pass every variable it adds or changes to later steps. + - name: Set up MSVC environment (Windows) + if: startsWith(inputs.os, 'windows') + shell: pwsh + run: | + $vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + $vcvars = cmd /c "`"$vs\VC\Auxiliary\Build\vcvars64.bat`" >nul && set" + if ($LASTEXITCODE -ne 0) { throw "vcvars64.bat failed with exit code $LASTEXITCODE" } + foreach ($line in $vcvars) { + if ($line -notmatch '^([^=]+)=(.*)$') { continue } + $name = $Matches[1] + $value = $Matches[2] + if ($name -eq 'Path' -and '${{inputs.compiler}}' -eq 'clang') { + # Find Visual Studio's own clang-cl, the one its ClangCL toolset used, before any + # other LLVM install on the runner. + $value = "$vs\VC\Tools\Llvm\x64\bin;$value" + } + if ([Environment]::GetEnvironmentVariable($name) -ne $value) { + "$name=$value" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 + [Environment]::SetEnvironmentVariable($name, $value) + } + } + if (-not (Get-Command cl -ErrorAction SilentlyContinue)) { throw "cl.exe isn't on PATH after vcvars64.bat" } + Get-Command cl, link, clang-cl, ninja, cmake -ErrorAction SilentlyContinue | Format-Table Name, Version, Source -AutoSize + # Keep compiler outputs between runs, so a build only recompiles what a change affects. # Only pushes to main save the cache: every PR restores main's latest one, and PR runs don't # fill the repo's 10 GB cache quota with entries that no other run can read. - # Not used on Windows: ccache can't cache MSVC builds that write debug info to a PDB (/Zi). + # max-size is only a cap: evict-old-files drops everything this build didn't use, so each + # saved cache is about one build's worth. Windows has the largest, since /Z7 puts the debug + # info in every object file. - name: Set up ccache - if: ${{!startsWith(inputs.os, 'windows')}} uses: hendrikmuhs/ccache-action@v1.2.24 with: key: ${{inputs.os}}-${{inputs.compiler}} - max-size: 2G + max-size: 5G evict-old-files: job save: ${{github.ref == 'refs/heads/main'}} @@ -144,7 +184,7 @@ jobs: mkdir bin cd bin cmake .. -DQT_MAJOR:STRING=6 ${{env.CMAKE_ADDITIONAL_FLAGS}} - cmake --build . --config RelWithDebInfo --parallel 10 + cmake --build . --config RelWithDebInfo --parallel ${{env.BUILD_PARALLEL}} - name: Prepare upload build if: inputs.upload-build diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index 774d2ae41c..aac02d2b4f 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -68,6 +68,12 @@ option(COMMAND_LINE_EXE "Build the optional executable" ON) # searched for. option(PA_CORE_ONLY "Build only the GUI-free core (basic microcontroller functions, no Qt, OpenCV, etc.)" OFF) +# With MSVC or clang-cl, write an assembly listing (/FAs) of every source file to +# Assembly/ in the build folder, to check the code the compiler generates, e.g. for +# the SIMD kernels. CI turns this off: ccache can't cache a compile that writes a +# listing, so every file would be recompiled on every run. +option(PA_ASSEMBLY_LISTINGS "Write an assembly listing of every source file to Assembly/ (MSVC and clang-cl only)" ON) + if(PA_CORE_ONLY) message(STATUS "PA_CORE_ONLY: building only the GUI-free core") set(CMAKE_AUTOMOC OFF) @@ -388,7 +394,10 @@ if (WIN32) PA_SOCIAL_SDK ) - target_compile_options(SerialProgramsLib PRIVATE /FAs /FaAssembly/ /MP /W4 /WX /external:anglebrackets /external:W0 /utf-8) + if(PA_ASSEMBLY_LISTINGS) + target_compile_options(SerialProgramsLib PRIVATE /FAs /FaAssembly/) + endif() + target_compile_options(SerialProgramsLib PRIVATE /MP /W4 /WX /external:anglebrackets /external:W0 /utf-8) target_compile_options(SerialProgramsLib PRIVATE /wd5054) # Deprecated enum arithemtic target_compile_options(SerialProgramsLib PRIVATE /wd4505) # unreferenced local function has been removed @@ -397,7 +406,9 @@ if (WIN32) set(ARCH_FLAGS_17_Skylake /arch:AVX512) set(ARCH_FLAGS_19_IceLake /arch:AVX512) - if(CMAKE_GENERATOR_TOOLSET MATCHES "ClangCL") + # clang-cl, whether from Visual Studio's ClangCL toolset (-T ClangCL) or from another + # generator such as Ninja, where CMAKE_GENERATOR_TOOLSET is empty. + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") target_compile_options(SerialProgramsLib PRIVATE -Wno-unused-function) target_compile_options(SerialProgramsLib PRIVATE -march=nehalem) set(ARCH_FLAGS_09_Nehalem -march=nehalem) diff --git a/SerialPrograms/cmake/CoreLib.cmake b/SerialPrograms/cmake/CoreLib.cmake index 0494b954f9..9ba29c6706 100644 --- a/SerialPrograms/cmake/CoreLib.cmake +++ b/SerialPrograms/cmake/CoreLib.cmake @@ -59,13 +59,17 @@ add_library(CoreLib STATIC ${CORE_LIBRARY_SOURCES}) pa_apply_gui_free_target_properties(CoreLib) if (WIN32) - # /FaAssembly/CoreLib/ writes assembly listings to Assembly/CoreLib/ in the build folder. - file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Assembly/CoreLib) - target_compile_options(CoreLib PRIVATE /FAs /FaAssembly/CoreLib/ /MP /W4 /WX /external:anglebrackets /external:W0 /utf-8) + if(PA_ASSEMBLY_LISTINGS) # option defined in CMakeLists.txt + # /FaAssembly/CoreLib/ writes assembly listings to Assembly/CoreLib/ in the build folder. + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Assembly/CoreLib) + target_compile_options(CoreLib PRIVATE /FAs /FaAssembly/CoreLib/) + endif() + target_compile_options(CoreLib PRIVATE /MP /W4 /WX /external:anglebrackets /external:W0 /utf-8) target_compile_options(CoreLib PRIVATE /wd5054) # Deprecated enum arithemtic target_compile_options(CoreLib PRIVATE /wd4505) # unreferenced local function has been removed - if(CMAKE_GENERATOR_TOOLSET MATCHES "ClangCL") + # clang-cl, from Visual Studio's ClangCL toolset or from another generator such as Ninja. + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") target_compile_options(CoreLib PRIVATE -Wno-unused-function) target_compile_options(CoreLib PRIVATE -march=nehalem) endif() From 4c3a8696f1f44f8c035fd76d21f9609a39804865 Mon Sep 17 00:00:00 2001 From: Gin <> Date: Sat, 17 Oct 2026 13:34:03 -0700 Subject: [PATCH 2/5] CI: fix the clang-cl Ninja build and make ccache misses cheaper The first Windows runs with ccache turned up three problems: - Windows Clang failed on its first compiles: under Ninja, /MP and /external:anglebrackets reach clang-cl, which ignores them, and /WX turns its unused-argument warning into an error. Visual Studio's ClangCL toolset never passed them on, so they now go to cl only. - ccache-action's default install: detect picked up the ccache 4.9.1 that Strawberry Perl puts on the Windows runner's PATH. Windows now installs the action's own build (4.13.6). - With every file a cache miss, the MSVC build took 34 minutes to compile SerialProgramsLib, against 18 with the Visual Studio generator. On a miss, ccache runs the preprocessor before compiling by default. Depend mode instead hashes the includes the compiler reports (/showIncludes, or -MD on Linux and macOS, which CMake already passes), so it's now on for every build. With the newer ccache and depend mode, the same cold build took 22 minutes. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/cpp-ci-serial-programs-base.yml | 10 ++++++++++ SerialPrograms/CMakeLists.txt | 7 ++++++- SerialPrograms/cmake/CoreLib.cmake | 6 +++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cpp-ci-serial-programs-base.yml b/.github/workflows/cpp-ci-serial-programs-base.yml index 667bcf1768..3495a82c01 100644 --- a/.github/workflows/cpp-ci-serial-programs-base.yml +++ b/.github/workflows/cpp-ci-serial-programs-base.yml @@ -170,6 +170,8 @@ jobs: # max-size is only a cap: evict-old-files drops everything this build didn't use, so each # saved cache is about one build's worth. Windows has the largest, since /Z7 puts the debug # info in every object file. + # On Windows, install the action's own ccache: the runner's Strawberry Perl puts an older + # ccache (4.9.1) on PATH, which the default install: detect would use instead. - name: Set up ccache uses: hendrikmuhs/ccache-action@v1.2.24 with: @@ -177,8 +179,16 @@ jobs: max-size: 5G evict-old-files: job save: ${{github.ref == 'refs/heads/main'}} + install: ${{startsWith(inputs.os, 'windows') && 'binary' || 'detect'}} - name: Generate binaries + env: + # Depend mode: on a cache miss, ccache hashes the include files the compiler reports + # (-MD or /showIncludes) instead of running the preprocessor a second time, which the + # ccache manual says makes a miss much cheaper. In the first runs with ccache, where + # every file missed, compiling took 10-40% longer than before on Linux and macOS, and + # about twice as long on Windows. + CCACHE_DEPEND: 1 run: | cd Arduino-Source/SerialPrograms mkdir bin diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index aac02d2b4f..c36d2f86f5 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -397,7 +397,12 @@ if (WIN32) if(PA_ASSEMBLY_LISTINGS) target_compile_options(SerialProgramsLib PRIVATE /FAs /FaAssembly/) endif() - target_compile_options(SerialProgramsLib PRIVATE /MP /W4 /WX /external:anglebrackets /external:W0 /utf-8) + target_compile_options(SerialProgramsLib PRIVATE /W4 /WX /external:W0 /utf-8) + if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # cl only: clang-cl ignores these, and /WX turns its unused-argument warning into an + # error. (Visual Studio's ClangCL toolset never passed them on to clang-cl.) + target_compile_options(SerialProgramsLib PRIVATE /MP /external:anglebrackets) + endif() target_compile_options(SerialProgramsLib PRIVATE /wd5054) # Deprecated enum arithemtic target_compile_options(SerialProgramsLib PRIVATE /wd4505) # unreferenced local function has been removed diff --git a/SerialPrograms/cmake/CoreLib.cmake b/SerialPrograms/cmake/CoreLib.cmake index 9ba29c6706..e076d91edb 100644 --- a/SerialPrograms/cmake/CoreLib.cmake +++ b/SerialPrograms/cmake/CoreLib.cmake @@ -64,7 +64,11 @@ if (WIN32) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Assembly/CoreLib) target_compile_options(CoreLib PRIVATE /FAs /FaAssembly/CoreLib/) endif() - target_compile_options(CoreLib PRIVATE /MP /W4 /WX /external:anglebrackets /external:W0 /utf-8) + target_compile_options(CoreLib PRIVATE /W4 /WX /external:W0 /utf-8) + if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # cl only: clang-cl ignores these, and /WX turns its unused-argument warning into an error. + target_compile_options(CoreLib PRIVATE /MP /external:anglebrackets) + endif() target_compile_options(CoreLib PRIVATE /wd5054) # Deprecated enum arithemtic target_compile_options(CoreLib PRIVATE /wd4505) # unreferenced local function has been removed From 22feb3a4867cb90d3c96f0aae401b007a3deeef0 Mon Sep 17 00:00:00 2001 From: Gin <> Date: Sat, 17 Oct 2026 14:18:46 -0700 Subject: [PATCH 3/5] CI: leave build-only files out of the Windows artifact The "Serial Programs" artifact uploads the whole bin/RelWithDebInfo folder, which includes the static libraries. SerialProgramsLib.lib was 1.2 GB uncompressed with /Zi and is 2.3 GB with /Z7, since it now holds every object's debug info. Ninja also writes the incremental-link file SerialPrograms.ilk (308 MB) next to the exe, where Visual Studio kept it in its intermediate folder. With both, the MSVC artifact grew from 592 to 972 MB. Neither is needed to run the program, so leave *.lib and *.ilk out of the upload. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/cpp-ci-serial-programs-base.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cpp-ci-serial-programs-base.yml b/.github/workflows/cpp-ci-serial-programs-base.yml index 3495a82c01..7873e56bc5 100644 --- a/.github/workflows/cpp-ci-serial-programs-base.yml +++ b/.github/workflows/cpp-ci-serial-programs-base.yml @@ -205,12 +205,18 @@ jobs: echo "https://github.com/${{github.repository_owner}}/Packages/commit/$(git -C Arduino-Source/Packages rev-parse HEAD)" } > ${{env.UPLOAD_FOLDER}}/version.txt + # Leave out files only the build itself uses: the static libraries (SerialProgramsLib.lib + # alone is over 2 GB with /Z7 debug info) and the incremental-link file (.ilk), which Ninja + # writes next to the exe. - name: Upload Build uses: actions/upload-artifact@v7 if: inputs.upload-build with: name: Serial Programs (os=${{inputs.os}} - compiler=${{inputs.compiler}}) - path: ${{env.UPLOAD_FOLDER}} + path: | + ${{env.UPLOAD_FOLDER}} + !${{env.UPLOAD_FOLDER}}/*.lib + !${{env.UPLOAD_FOLDER}}/*.ilk - name: Upload Executable Only uses: actions/upload-artifact@v7 From aa8260614c48b4c5a8d922cadeddeb65626dbb6f Mon Sep 17 00:00:00 2001 From: Gin <> Date: Sat, 17 Oct 2026 22:08:21 -0700 Subject: [PATCH 4/5] CI: build without debug info Nothing in CI uses debug info. The uploaded Windows builds are for testing; error reports from them stay on the tester's machine, and release builds, which need the PDB to read crash dumps, are made outside CI. Leaving it out makes compiles and links cheaper, the ccache entries smaller, and the artifacts smaller. - Windows: an empty CMAKE_MSVC_DEBUG_INFORMATION_FORMAT (with CMP0141) drops the /Z7 flag, and linking RelWithDebInfo with /INCREMENTAL:NO instead of /debug /INCREMENTAL writes no PDB or .ilk. So the artifact no longer needs the .ilk exclusion. - Ubuntu clang: keep RelWithDebInfo's -O2 -DNDEBUG but drop its -g. Only CI passes these flags, so CMakeLists.txt and its defaults are unchanged: other RelWithDebInfo builds still get full debug info. Co-Authored-By: Claude Opus 5.5 --- .../workflows/cpp-ci-serial-programs-base.yml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/cpp-ci-serial-programs-base.yml b/.github/workflows/cpp-ci-serial-programs-base.yml index 7873e56bc5..bbb9bd37d3 100644 --- a/.github/workflows/cpp-ci-serial-programs-base.yml +++ b/.github/workflows/cpp-ci-serial-programs-base.yml @@ -34,11 +34,13 @@ jobs: if [[ "${{inputs.os}}" == windows* ]]; then # Build with Ninja: ccache can't wrap the compiler under the Visual Studio generator. # "Ninja Multi-Config" keeps Visual Studio's output layout (bin/RelWithDebInfo/). - # ccache also can't cache /Zi (debug info written to a shared PDB) or /FAs listings, - # so embed the debug info in each object file with /Z7 (the linker still writes the - # PDB) and turn the listings off. + # ccache also can't cache /FAs listings, so turn them off. + # CI needs no debug info, so keep RelWithDebInfo's optimization but leave out its + # debug info: with policy CMP0141, an empty CMAKE_MSVC_DEBUG_INFORMATION_FORMAT + # drops /Zi, and linking without /debug writes no PDB. Release builds made outside + # CI keep their debug info. echo "CMAKE_GENERATOR=Ninja Multi-Config" >> $GITHUB_ENV - CMAKE_ADDITIONAL_FLAGS="-DCMAKE_POLICY_DEFAULT_CMP0141=NEW -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded -DPA_ASSEMBLY_LISTINGS=OFF" + CMAKE_ADDITIONAL_FLAGS="-DCMAKE_POLICY_DEFAULT_CMP0141=NEW -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT= -DCMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO=/INCREMENTAL:NO -DPA_ASSEMBLY_LISTINGS=OFF" if [[ "${{inputs.compiler}}" == "clang" ]]; then CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl" else @@ -48,7 +50,8 @@ jobs: # 10 at once, so memory use stays close to what the runner handled before. BUILD_PARALLEL=$(( $(nproc) + 2 )) elif [[ "${{inputs.compiler}}" == "clang" && "${{inputs.os}}" == ubuntu* ]]; then - CMAKE_ADDITIONAL_FLAGS="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo" + # RelWithDebInfo's -O2 without its -g: CI doesn't use the debug info. + CMAKE_ADDITIONAL_FLAGS="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo '-DCMAKE_C_FLAGS_RELWITHDEBINFO=-O2 -DNDEBUG' '-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=-O2 -DNDEBUG'" fi CMAKE_ADDITIONAL_FLAGS="$CMAKE_ADDITIONAL_FLAGS -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" echo "CMAKE_ADDITIONAL_FLAGS=$CMAKE_ADDITIONAL_FLAGS" >> $GITHUB_ENV @@ -168,8 +171,7 @@ jobs: # Only pushes to main save the cache: every PR restores main's latest one, and PR runs don't # fill the repo's 10 GB cache quota with entries that no other run can read. # max-size is only a cap: evict-old-files drops everything this build didn't use, so each - # saved cache is about one build's worth. Windows has the largest, since /Z7 puts the debug - # info in every object file. + # saved cache is about one build's worth. # On Windows, install the action's own ccache: the runner's Strawberry Perl puts an older # ccache (4.9.1) on PATH, which the default install: detect would use instead. - name: Set up ccache @@ -205,9 +207,8 @@ jobs: echo "https://github.com/${{github.repository_owner}}/Packages/commit/$(git -C Arduino-Source/Packages rev-parse HEAD)" } > ${{env.UPLOAD_FOLDER}}/version.txt - # Leave out files only the build itself uses: the static libraries (SerialProgramsLib.lib - # alone is over 2 GB with /Z7 debug info) and the incremental-link file (.ilk), which Ninja - # writes next to the exe. + # Leave out the static libraries, which only the build itself uses. With debug info, + # SerialProgramsLib.lib alone was over 1 GB uncompressed. - name: Upload Build uses: actions/upload-artifact@v7 if: inputs.upload-build @@ -216,7 +217,6 @@ jobs: path: | ${{env.UPLOAD_FOLDER}} !${{env.UPLOAD_FOLDER}}/*.lib - !${{env.UPLOAD_FOLDER}}/*.ilk - name: Upload Executable Only uses: actions/upload-artifact@v7 From 41d5f3241fc83014b9dcb2ccdc19f933e2863a65 Mon Sep 17 00:00:00 2001 From: Gin <> Date: Sun, 18 Oct 2026 11:58:02 -0700 Subject: [PATCH 5/5] CI: write out the one-line ifs in the MSVC environment step Review feedback: one-line if statements are harder to read. Expand the three in the PowerShell step into blocks. No change in behavior. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/cpp-ci-serial-programs-base.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cpp-ci-serial-programs-base.yml b/.github/workflows/cpp-ci-serial-programs-base.yml index bbb9bd37d3..8ad73a7b73 100644 --- a/.github/workflows/cpp-ci-serial-programs-base.yml +++ b/.github/workflows/cpp-ci-serial-programs-base.yml @@ -149,9 +149,14 @@ jobs: run: | $vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath $vcvars = cmd /c "`"$vs\VC\Auxiliary\Build\vcvars64.bat`" >nul && set" - if ($LASTEXITCODE -ne 0) { throw "vcvars64.bat failed with exit code $LASTEXITCODE" } + if ($LASTEXITCODE -ne 0) { + throw "vcvars64.bat failed with exit code $LASTEXITCODE" + } foreach ($line in $vcvars) { - if ($line -notmatch '^([^=]+)=(.*)$') { continue } + # Skip anything that isn't a NAME=value line. + if ($line -notmatch '^([^=]+)=(.*)$') { + continue + } $name = $Matches[1] $value = $Matches[2] if ($name -eq 'Path' -and '${{inputs.compiler}}' -eq 'clang') { @@ -164,7 +169,9 @@ jobs: [Environment]::SetEnvironmentVariable($name, $value) } } - if (-not (Get-Command cl -ErrorAction SilentlyContinue)) { throw "cl.exe isn't on PATH after vcvars64.bat" } + if (-not (Get-Command cl -ErrorAction SilentlyContinue)) { + throw "cl.exe isn't on PATH after vcvars64.bat" + } Get-Command cl, link, clang-cl, ninja, cmake -ErrorAction SilentlyContinue | Format-Table Name, Version, Source -AutoSize # Keep compiler outputs between runs, so a build only recompiles what a change affects.