build: keep header dependencies through a compiler cache hit on clang-cl (#15875)

For clang-cl, CMake sets the depfile flags to the gcc-style -MD, -MT and -MF,
passed through as -clang: arguments. ccache does not parse those, so a cache
hit writes only the object. Ninja has no depfile to read, so it records zero
header dependencies for that object and does not rebuild it after a header
edit. The stale object is still linked into the library and the DLL. sccache
0.15.0 reproduces the depfile on a hit and is unaffected.

Use /showIncludes instead. CMake already does that for MSVC, and ccache
reproduces it on a hit. A make-rules override sets the flags, because CMake
includes the override after Platform/Windows-Clang.cmake. It is forwarded to
each dependency because every one configures as its own CMake project, and it
is only set when the file exists, because scripts/flatpak/make_deps_tar.sh
packs deps/ alone.

In a build with a warm cache, 678 of 790 objects had no recorded headers.
Object code does not change. One GUI translation unit compiled both ways is
byte-identical apart from the COFF timestamp.
This commit is contained in:
Kris Austin
2026-09-24 14:06:24 -03:00
committed by GitHub
parent 42009cf385
commit 0db1dc6480
3 changed files with 23 additions and 0 deletions
+3
View File
@@ -70,6 +70,9 @@ if (POLICY CMP0092)
cmake_policy(SET CMP0092 NEW)
endif ()
# project() reads this, so set it first.
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_LIST_DIR}/cmake/modules/ClangClShowIncludes.cmake")
project(OrcaSlicer)
# Backward compatibility for old CMake versions
+10
View File
@@ -0,0 +1,10 @@
# ccache does not parse the -clang: arguments CMake uses for clang-cl's gcc-style
# depfile, so a cache hit writes the object and no depfile, and Ninja then records
# no headers for that object. ccache reproduces /showIncludes output on a hit.
foreach (_lang C CXX)
if (CMAKE_${_lang}_COMPILER_ID STREQUAL "Clang" AND
CMAKE_${_lang}_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
set(CMAKE_DEPFILE_FLAGS_${_lang} "/showIncludes")
set(CMAKE_${_lang}_DEPFILE_FORMAT msvc)
endif ()
endforeach ()
+10
View File
@@ -38,6 +38,14 @@ if(POLICY CMP0135) # DOWNLOAD_EXTRACT_TIMESTAMP
cmake_policy(SET CMP0135 NEW)
endif()
# project() reads this, so set it first. scripts/flatpak/make_deps_tar.sh packs deps/
# without cmake/, so the file is missing in a Flatpak build.
set(_rules_override "${CMAKE_CURRENT_LIST_DIR}/../cmake/modules/ClangClShowIncludes.cmake")
if (EXISTS "${_rules_override}")
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_rules_override}")
endif ()
unset(_rules_override)
project(OrcaSlicer-deps)
# Backward compatibility for old CMake versions
@@ -220,6 +228,7 @@ if (NOT IS_CROSS_COMPILE OR NOT APPLE)
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}
-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}
-DCMAKE_USER_MAKE_RULES_OVERRIDE:STRING=${CMAKE_USER_MAKE_RULES_OVERRIDE}
-DCMAKE_TOOLCHAIN_FILE:STRING=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}
-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}
@@ -267,6 +276,7 @@ else()
-DCMAKE_IGNORE_PREFIX_PATH:STRING=${CMAKE_IGNORE_PREFIX_PATH}
-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}
-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}
-DCMAKE_USER_MAKE_RULES_OVERRIDE:STRING=${CMAKE_USER_MAKE_RULES_OVERRIDE}
-DBUILD_SHARED_LIBS:BOOL=OFF
${_cmake_osx_arch}
"${_configs_line}"