From a9829699f30c40dff54c6b44e1d08333b6364e79 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Wed, 17 Jun 2026 20:52:49 +0200 Subject: [PATCH 1/2] [CMake] Make dictionary module dependencies independent of config order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For each entry in DEPENDENCIES, ROOT_GENERATE_DICTIONARY passes rootcling a `-m .pcm` flag and a dependency on the dependency's module file, so that the prebuilt module is loaded instead of being built implicitly. This was wired up by inspecting the target graph while the macro runs (`if(NOT TARGET G__${dep})` / `get_target_property(... ROOT_PCM_FILENAME)`), which only works if is configured before the dictionaries using it. That breaks for core/multiproc: libMultiProc depends on Net (via TSocket), but it lives under core/, configured long before net/. So when G__MultiProc is generated, G__Net does not exist yet, the dependency is silently dropped, and rootcling can build Net implicitly, failing with "Building module 'Net' implicitly ... 'G__MultiProc.cxx' depends on 'Net'". The same shape affects every dictionary depending on a module configured later (Tree -> Net, ...). Decide this at generation time instead, when all targets exist: guard the flag and the module-file dependency with $>. They are emitted whenever provides a dictionary and expand to nothing otherwise (e.g. a plain library such as TBB::tbb), regardless of configuration order. Closes #21673. 🤖 Problem identified by AI, then the human guided the AI to write the solution that the human wanted to apply. --- cmake/modules/RootMacros.cmake | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 6ea436ed24686..01ecc191fd379 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -616,22 +616,17 @@ function(ROOT_GENERATE_DICTIONARY dictionary) #---Get the library and module dependencies----------------- if(ARG_DEPENDENCIES) foreach(dep ${ARG_DEPENDENCIES}) - if(NOT TARGET G__${dep}) - # This is a library that doesn't come with dictionary/pcm - continue() - endif() - + # Whether provides a dictionary/pcm is decided at generation time + # via $>, so the '-m' flag and the module-file + # dependency below are independent of configuration order and expand to + # nothing for a dictionary-less library. + set(dep_has_dict "$") set(dependent_pcm ${libprefix}${dep}_rdict.pcm) if (runtime_cxxmodules AND NOT dep IN_LIST local_no_cxxmodules) set(dependent_pcm ${dep}.pcm) - if(TARGET ${dep}) - get_target_property(_dep_pcm_filename ${dep} ROOT_PCM_FILENAME) - if(_dep_pcm_filename) - list(APPEND pcm_dependencies ${_dep_pcm_filename}) - endif() - endif() + list(APPEND pcm_dependencies "$<${dep_has_dict}:$>") endif() - set(newargs ${newargs} -m ${dependent_pcm}) + set(newargs ${newargs} "$<${dep_has_dict}:-m>" "$<${dep_has_dict}:${dependent_pcm}>") endforeach() endif() From d9557732f75eb1d51e197e0fd20e421a6860de62 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Mon, 31 Aug 2026 17:57:07 +0200 Subject: [PATCH 2/2] [cmake] Make explicit that all dictionaries depends on Core.pcm By pcanal They depend on it implicitly and not expressing leads to missing rebuilds as seen at: root-project#23046 when no ARG_DEPENDENCIES are specified at all Co-author: FerdyMercury --- cmake/modules/RootMacros.cmake | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 01ecc191fd379..f48676f747401 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -614,21 +614,24 @@ function(ROOT_GENERATE_DICTIONARY dictionary) endif() #---Get the library and module dependencies----------------- - if(ARG_DEPENDENCIES) - foreach(dep ${ARG_DEPENDENCIES}) - # Whether provides a dictionary/pcm is decided at generation time - # via $>, so the '-m' flag and the module-file - # dependency below are independent of configuration order and expand to - # nothing for a dictionary-less library. - set(dep_has_dict "$") - set(dependent_pcm ${libprefix}${dep}_rdict.pcm) - if (runtime_cxxmodules AND NOT dep IN_LIST local_no_cxxmodules) - set(dependent_pcm ${dep}.pcm) - list(APPEND pcm_dependencies "$<${dep_has_dict}:$>") - endif() - set(newargs ${newargs} "$<${dep_has_dict}:-m>" "$<${dep_has_dict}:${dependent_pcm}>") - endforeach() - endif() + # Every dictionary implicitly depends on Core's pcm, except the one for Core itself. + if(ARG_MODULE AND NOT ARG_MODULE STREQUAL "Core") + list(INSERT ARG_DEPENDENCIES 0 Core) + list(REMOVE_DUPLICATES ARG_DEPENDENCIES) + endif() + foreach(dep ${ARG_DEPENDENCIES}) + # Whether provides a dictionary/pcm is decided at generation time + # via $>, so the '-m' flag and the module-file + # dependency below are independent of configuration order and expand to + # nothing for a dictionary-less library. + set(dep_has_dict "$") + set(dependent_pcm ${libprefix}${dep}_rdict.pcm) + if (runtime_cxxmodules AND NOT dep IN_LIST local_no_cxxmodules) + set(dependent_pcm ${dep}.pcm) + list(APPEND pcm_dependencies "$<${dep_has_dict}:$>") + endif() + set(newargs ${newargs} "$<${dep_has_dict}:-m>" "$<${dep_has_dict}:${dependent_pcm}>") + endforeach() if(cpp_module_file) set(newargs -cxxmodule ${newargs})