From 0db1dc6480e653c9fbc8e4c492a31b5f2235e374 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Thu, 24 Sep 2026 12:06:24 -0500 Subject: [PATCH] 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. --- CMakeLists.txt | 3 +++ cmake/modules/ClangClShowIncludes.cmake | 10 ++++++++++ deps/CMakeLists.txt | 10 ++++++++++ 3 files changed, 23 insertions(+) create mode 100644 cmake/modules/ClangClShowIncludes.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 85e558a18c..6f8e994758 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/cmake/modules/ClangClShowIncludes.cmake b/cmake/modules/ClangClShowIncludes.cmake new file mode 100644 index 0000000000..91b9a18069 --- /dev/null +++ b/cmake/modules/ClangClShowIncludes.cmake @@ -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 () diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index e02186705b..0e7141c12c 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -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}"