From 370663041dffecde41eb58a8ff9b41e21cb97fe5 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Wed, 17 Jun 2026 20:52:49 +0200 Subject: [PATCH] [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 3ce1d5d5d1162..567aaf8bc3a00 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -623,22 +623,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()