diff --git a/cmake/modules/RootCTest.cmake b/cmake/modules/RootCTest.cmake index 54338cd765a18..5db33bbb287d8 100644 --- a/cmake/modules/RootCTest.cmake +++ b/cmake/modules/RootCTest.cmake @@ -51,6 +51,21 @@ foreach(d ${test_list}) endif() endforeach() +# Building a test executable must bring lib/modules.idx and all module +# artifacts (PCMs) up to date. Otherwise, a targeted build that changes a +# dictionary (e.g. `cmake --build . --target testFoo`) leaves the test running +# against a stale global module index and stale dependent PCMs, which +# manifests as modules that fail to load or as spurious segfaults. The +# modules_idx target depends on every ROOT module, so making the test +# executables depend on it ensures any dictionary change is first propagated +# through the dependent PCMs and the index is regenerated. +if(runtime_cxxmodules AND TARGET modules_idx) + get_property(modules_idx_gtests GLOBAL PROPERTY ROOT_MODULES_IDX_GTESTS) + foreach(modules_idx_gtest ${modules_idx_gtests}) + add_dependencies(${modules_idx_gtest} modules_idx) + endforeach() +endif() + # When ninja or the Microsoft generator are in use, tests that compile an executable might try # to rebuild the entire build tree. If multiple of these are invoked in parallel, ninja will # suffer from race conditions. diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 87080dc7a5ba9..5ca11a2d2d679 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -1965,6 +1965,11 @@ function(ROOT_ADD_GTEST test_suite) # against. For example, tests in Core should link only against libCore. This could be tricky # to implement because some ROOT components create more than one library. ROOT_EXECUTABLE(${test_suite} ${source_files} LIBRARIES ${ARG_LIBRARIES}) + if(runtime_cxxmodules) + # Register the test so that the modules_idx dependency can be attached at + # the end of the top-level CMakeLists, where the modules_idx target exists. + set_property(GLOBAL APPEND PROPERTY ROOT_MODULES_IDX_GTESTS ${test_suite}) + endif() target_link_libraries(${test_suite} PRIVATE GTest::gtest GTest::gmock GTest::gtest_main GTest::gmock_main) if(TARGET ROOT::TestSupport) target_link_libraries(${test_suite} PRIVATE ROOT::TestSupport)