From 253bfb2ab50fbc79f9a19bb0b3eb4a6f613454b9 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 30 Oct 2026 14:54:56 +0000 Subject: [PATCH] [CMake] Only report include dirs known to cling as compiler defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since b304aa59425 ("Drop system headers from cling command line"), rootcling does not promote compiler default include directories to -I, assuming that cling adds them by itself. Cling, however, only adds the C++ standard library directories (queried from the compiler at startup), its own builtin headers and the system directories that the clang driver adds for the sysroot. The CMAKE__IMPLICIT_INCLUDE_DIRECTORIES that ROOT reports to rootcling as compiler defaults can contain more than that: the compiler wrappers of Nix or Spack and environment variables like CPATH inject the include directories of all dependencies into the implicit search path of the compiler. Cling does not search these at runtime, so dropping them from the rootcling command line and from the dictionary payload breaks the dictionary generation and the runtime interpreter for headers that include dependency headers, e.g.: REveElement.hxx:27:10: fatal error: 'nlohmann/json.hpp' file not found Only report the directories that cling knows about as compiler default include directories, so that the other ones are still passed as -I: - the C++ standard library directories, - the builtin header directories of the compiler, - the sysroot directories that the clang driver adds, see AddClangSystemIncludeArgs() in clang/lib/Driver/ToolChains/Linux.cpp and Darwin.cpp. The sysroot is CMAKE_SYSROOT, or on macOS the SDK path that CMake resolves from CMAKE_OSX_SYSROOT (which may be empty or a bare SDK name) and passes to the compiler as -isysroot, - the C library directories that the builtin clang is configured with (C_INCLUDE_DIRS), which may not be under the sysroot, e.g. on Nix. 🤖 Done with the help of AI (cherry picked from commit 98cd7995ac01e547ae65bd13aff90edeec3d1bef) --- cmake/modules/RootMacros.cmake | 41 +++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 0cfeaae9b898c..c0f0dbea2ed64 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -754,9 +754,48 @@ function(ROOT_GENERATE_DICTIONARY dictionary) endforeach() endif() + # rootcling does not promote compiler default include directories to -I, + # assuming that cling adds them by itself. Cling, however, only adds the C++ + # standard library directories, its own builtin headers and the sysroot + # directories added by the clang driver. Directories injected by compiler + # wrappers or environment variables like CPATH are unknown to cling at + # runtime, so only report the former as compiler defaults. + if(CMAKE_SYSROOT) + set(sysroot "${CMAKE_SYSROOT}") + elseif(APPLE AND _CMAKE_OSX_SYSROOT_PATH) + # The SDK path that CMake resolves from CMAKE_OSX_SYSROOT (possibly empty + # or a bare SDK name) and passes to the compiler as -isysroot. + set(sysroot "${_CMAKE_OSX_SYSROOT_PATH}") + elseif(APPLE AND IS_DIRECTORY "${CMAKE_OSX_SYSROOT}") + set(sysroot "${CMAKE_OSX_SYSROOT}") + else() + set(sysroot "") + endif() + # Normalize like the implicit include directories (no trailing slash). + if(sysroot) + get_filename_component(sysroot "${sysroot}" ABSOLUTE) + string(REGEX REPLACE "/+$" "" sysroot "${sysroot}") + endif() + # What the clang driver adds, see AddClangSystemIncludeArgs() in + # clang/lib/Driver/ToolChains/{Linux,Darwin}.cpp. The multiarch directory + # /usr/include/ is matched below. C library directories that + # the builtin clang is configured with (C_INCLUDE_DIRS, colon-separated) are + # reported in addition: a C library directory must never be promoted to -I. + set(sysrootIncDirs "${sysroot}/usr/local/include" "${sysroot}/include" "${sysroot}/usr/include") + set(clingCIncDirs) + if(C_INCLUDE_DIRS AND NOT WIN32) + string(REPLACE ":" ";" clingCIncDirs "${C_INCLUDE_DIRS}") + list(TRANSFORM clingCIncDirs REPLACE "/+$" "") + endif() set(compIncPaths) foreach(implinc IN LISTS CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES) - list(APPEND compIncPaths "-compilerI${implinc}") + get_filename_component(implincParent "${implinc}" DIRECTORY) + get_filename_component(implincName "${implinc}" NAME) + if(implinc MATCHES "/c\\+\\+(/|$)" OR implinc MATCHES "/lib(64)?/(gcc|clang)/" + OR implinc IN_LIST sysrootIncDirs OR implinc IN_LIST clingCIncDirs + OR (implincParent STREQUAL "${sysroot}/usr/include" AND implincName MATCHES "^[^-]+-[^-]+-[^-]+")) + list(APPEND compIncPaths "-compilerI${implinc}") + endif() endforeach() # Keep the byproducts (rdict pcm, rootmap, C++ module) newer than the