From 2b85541e39bdd1e0ca9e050790fe898ce1852e8e Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 11 Sep 2025 13:51:54 -0400 Subject: [PATCH 1/5] cxximportstd: support setting the `import std` metadata location Some deployments may not be able to discover the metadata file reliably (e.g., custom `clang` builds on macOS while using the SDK's stdlib or distribution bugs). Allow users to force the location so that compiler-driven detection doesn't have to bend over backwards for unforeseen bugs. --- Help/manual/cmake-variables.7.rst | 1 + ...odules-custom-import-std-metadata-file.rst | 7 ++++ .../CMAKE_CXX_STDLIB_MODULES_JSON.rst | 11 ++++++ Modules/Compiler/Clang-CXX-CXXImportStd.cmake | 34 +++++++++-------- Modules/Compiler/GNU-CXX-CXXImportStd.cmake | 34 +++++++++-------- Modules/Compiler/MSVC-CXX-CXXImportStd.cmake | 38 ++++++++++--------- Source/cmCoreTryCompile.cxx | 1 + 7 files changed, 79 insertions(+), 47 deletions(-) create mode 100644 Help/release/dev/cxxmodules-custom-import-std-metadata-file.rst create mode 100644 Help/variable/CMAKE_CXX_STDLIB_MODULES_JSON.rst diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index aabf61365f..989246e956 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -45,6 +45,7 @@ Variables that Provide Information /variable/CMAKE_CURRENT_LIST_FILE /variable/CMAKE_CURRENT_LIST_LINE /variable/CMAKE_CURRENT_SOURCE_DIR + /variable/CMAKE_CXX_STDLIB_MODULES_JSON /variable/CMAKE_DEBUG_TARGET_PROPERTIES /variable/CMAKE_DIRECTORY_LABELS /variable/CMAKE_DL_LIBS diff --git a/Help/release/dev/cxxmodules-custom-import-std-metadata-file.rst b/Help/release/dev/cxxmodules-custom-import-std-metadata-file.rst new file mode 100644 index 0000000000..104f9178ad --- /dev/null +++ b/Help/release/dev/cxxmodules-custom-import-std-metadata-file.rst @@ -0,0 +1,7 @@ +cxxmodules-custom-import-std-metadata-file +------------------------------------------ + +* The ``import std`` support learned to use the + :variable:`CMAKE_CXX_STDLIB_MODULES_JSON` variable to set the path to the + metadata file for the standard library rather than using the compiler to + discover its location. diff --git a/Help/variable/CMAKE_CXX_STDLIB_MODULES_JSON.rst b/Help/variable/CMAKE_CXX_STDLIB_MODULES_JSON.rst new file mode 100644 index 0000000000..134e8d60bc --- /dev/null +++ b/Help/variable/CMAKE_CXX_STDLIB_MODULES_JSON.rst @@ -0,0 +1,11 @@ +CMAKE_CXX_STDLIB_MODULES_JSON +----------------------------- + +.. versionadded:: 4.2 + +This variable may be used to set the path to a metadata file for CMake to +understand how the ``import std`` target for the active CXX compiler should be +constructed. + +This should only be used when the compiler does not know how to discover the +relevant module metadata file without such assistance. diff --git a/Modules/Compiler/Clang-CXX-CXXImportStd.cmake b/Modules/Compiler/Clang-CXX-CXXImportStd.cmake index 5330eb1a3a..9061e006f7 100644 --- a/Modules/Compiler/Clang-CXX-CXXImportStd.cmake +++ b/Modules/Compiler/Clang-CXX-CXXImportStd.cmake @@ -10,21 +10,25 @@ function (_cmake_cxx_import_std std variable) return () endif () - execute_process( - COMMAND - "${CMAKE_CXX_COMPILER}" - ${CMAKE_CXX_COMPILER_ID_ARG1} - "-print-file-name=${_clang_modules_json_impl}.modules.json" - OUTPUT_VARIABLE _clang_libcxx_modules_json_file - ERROR_VARIABLE _clang_libcxx_modules_json_file_err - RESULT_VARIABLE _clang_libcxx_modules_json_file_res - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_STRIP_TRAILING_WHITESPACE) - if (_clang_libcxx_modules_json_file_res) - set("${variable}" - "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `${_clang_modules_json_impl}.modules.json` resource\")\n" - PARENT_SCOPE) - return () + if (CMAKE_CXX_STDLIB_MODULES_JSON) + set(_clang_libcxx_modules_json_file "${CMAKE_CXX_STDLIB_MODULES_JSON}") + else () + execute_process( + COMMAND + "${CMAKE_CXX_COMPILER}" + ${CMAKE_CXX_COMPILER_ID_ARG1} + "-print-file-name=${_clang_modules_json_impl}.modules.json" + OUTPUT_VARIABLE _clang_libcxx_modules_json_file + ERROR_VARIABLE _clang_libcxx_modules_json_file_err + RESULT_VARIABLE _clang_libcxx_modules_json_file_res + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + if (_clang_libcxx_modules_json_file_res) + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `${_clang_modules_json_impl}.modules.json` resource\")\n" + PARENT_SCOPE) + return () + endif () endif () # Without this file, we do not have modules installed. diff --git a/Modules/Compiler/GNU-CXX-CXXImportStd.cmake b/Modules/Compiler/GNU-CXX-CXXImportStd.cmake index 965e25a929..834e99912e 100644 --- a/Modules/Compiler/GNU-CXX-CXXImportStd.cmake +++ b/Modules/Compiler/GNU-CXX-CXXImportStd.cmake @@ -6,21 +6,25 @@ function (_cmake_cxx_import_std std variable) return () endif () - execute_process( - COMMAND - "${CMAKE_CXX_COMPILER}" - ${CMAKE_CXX_COMPILER_ID_ARG1} - -print-file-name=libstdc++.modules.json - OUTPUT_VARIABLE _gnu_libstdcxx_modules_json_file - ERROR_VARIABLE _gnu_libstdcxx_modules_json_file_err - RESULT_VARIABLE _gnu_libstdcxx_modules_json_file_res - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_STRIP_TRAILING_WHITESPACE) - if (_gnu_libstdcxx_modules_json_file_res) - set("${variable}" - "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `libstdc++.modules.json` resource\")\n" - PARENT_SCOPE) - return () + if (CMAKE_CXX_STDLIB_MODULES_JSON) + set(_gnu_libstdcxx_modules_json_file "${CMAKE_CXX_STDLIB_MODULES_JSON}") + else () + execute_process( + COMMAND + "${CMAKE_CXX_COMPILER}" + ${CMAKE_CXX_COMPILER_ID_ARG1} + -print-file-name=libstdc++.modules.json + OUTPUT_VARIABLE _gnu_libstdcxx_modules_json_file + ERROR_VARIABLE _gnu_libstdcxx_modules_json_file_err + RESULT_VARIABLE _gnu_libstdcxx_modules_json_file_res + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + if (_gnu_libstdcxx_modules_json_file_res) + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `libstdc++.modules.json` resource\")\n" + PARENT_SCOPE) + return () + endif () endif () # Without this file, we do not have modules installed. diff --git a/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake b/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake index 08199f7e6c..ff01263246 100644 --- a/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake +++ b/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake @@ -1,21 +1,25 @@ function (_cmake_cxx_import_std std variable) - find_file(_msvc_modules_json_file - NAME modules.json - HINTS - "$ENV{VCToolsInstallDir}/modules" - PATHS - "$ENV{INCLUDE}" - "${CMAKE_CXX_COMPILER}/../../.." - "${CMAKE_CXX_COMPILER}/../.." # msvc-wine layout - PATH_SUFFIXES - ../modules - NO_CACHE) - # Without this file, we do not have modules installed. - if (NOT EXISTS "${_msvc_modules_json_file}") - set("${variable}" - "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `modules.json` resource\")\n" - PARENT_SCOPE) - return () + if (CMAKE_CXX_STDLIB_MODULES_JSON) + set(_msvc_modules_json_file "${CMAKE_CXX_STDLIB_MODULES_JSON}") + else () + find_file(_msvc_modules_json_file + NAME modules.json + HINTS + "$ENV{VCToolsInstallDir}/modules" + PATHS + "$ENV{INCLUDE}" + "${CMAKE_CXX_COMPILER}/../../.." + "${CMAKE_CXX_COMPILER}/../.." # msvc-wine layout + PATH_SUFFIXES + ../modules + NO_CACHE) + # Without this file, we do not have modules installed. + if (NOT EXISTS "${_msvc_modules_json_file}") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `modules.json` resource\")\n" + PARENT_SCOPE) + return () + endif () endif () file(READ "${_msvc_modules_json_file}" _msvc_modules_json) diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 721f29ff81..eab2ad340d 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -1095,6 +1095,7 @@ cm::optional cmCoreTryCompile::TryCompileCode( vars.emplace("CMAKE_MSVC_RUNTIME_CHECKS"_s); vars.emplace("CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS"_s); vars.emplace("CMAKE_VS_USE_DEBUG_LIBRARIES"_s); + vars.emplace("CMAKE_CXX_STDLIB_MODULES_JSON"_s); if (cmValue varListStr = this->Makefile->GetDefinition( kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) { From 6c178a4ae36f2b951f6b405821a312278ec11376 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 11 Sep 2025 15:39:37 -0400 Subject: [PATCH 2/5] Tests/RunCMake: add newlines in CXXModules options Better readability for upcoming changes. --- Tests/RunCMake/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index cb2a6717fb..dfe93123a8 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -824,7 +824,10 @@ add_RunCMake_test(DependencyGraph) set_property(TEST RunCMake.DependencyGraph APPEND PROPERTY LABELS "Fortran") # Add C++ Module tests. -add_RunCMake_test(CXXModules -DCMake_TEST_MODULE_COMPILATION=${CMake_TEST_MODULE_COMPILATION} -DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES}) +add_RunCMake_test(CXXModules + -DCMake_TEST_MODULE_COMPILATION=${CMake_TEST_MODULE_COMPILATION} + -DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES} +) # ctresalloc links against CMakeLib and CTestLib, which means it can't be built # if CMake_TEST_EXTERNAL_CMAKE is activated (the compiler might be different.) From 2f101b2c8ccbf5d068131b4b47aff00b41add220 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 11 Sep 2025 15:44:51 -0400 Subject: [PATCH 3/5] Tests/CXXModules: support testing with custom stdlib json locations --- Tests/RunCMake/CMakeLists.txt | 1 + Tests/RunCMake/CXXModules/RunCMakeTest.cmake | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index dfe93123a8..6bb5aaebed 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -827,6 +827,7 @@ set_property(TEST RunCMake.DependencyGraph APPEND PROPERTY LABELS "Fortran") add_RunCMake_test(CXXModules -DCMake_TEST_MODULE_COMPILATION=${CMake_TEST_MODULE_COMPILATION} -DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES} + -DCMake_TEST_CXX_STDLIB_MODULES_JSON=${CMake_TEST_CXX_STDLIB_MODULES_JSON} ) # ctresalloc links against CMakeLib and CTestLib, which means it can't be built diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake index 8ed2f97f20..9a8e6987b5 100644 --- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake +++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake @@ -1,6 +1,12 @@ include(RunCMake) -run_cmake(Inspect) +set(stdlib_custom_json) +if (CMake_TEST_CXX_STDLIB_MODULES_JSON) + list(APPEND stdlib_custom_json + -DCMAKE_CXX_STDLIB_MODULES_JSON=${CMake_TEST_CXX_STDLIB_MODULES_JSON}) +endif () + +run_cmake(Inspect ${stdlib_custom_json}) include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake") # Test negative cases where C++20 modules do not work. @@ -149,6 +155,10 @@ function (run_cxx_module_test directory) else () set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug) endif () + if (directory MATCHES "import-std") + list(APPEND RunCMake_TEST_OPTIONS + ${stdlib_custom_json}) + endif () if (RunCMake_CXXModules_INSTALL) set(prefix "${RunCMake_BINARY_DIR}/examples/${test_name}-install") From 42621a232be760cd07bab5a161149b20757e3b58 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 11 Sep 2025 18:05:08 -0400 Subject: [PATCH 4/5] Tests/CXXModules: add a label So that CI can target the test where necessary. --- Tests/RunCMake/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 6bb5aaebed..07f47a155a 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -829,6 +829,8 @@ add_RunCMake_test(CXXModules -DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES} -DCMake_TEST_CXX_STDLIB_MODULES_JSON=${CMake_TEST_CXX_STDLIB_MODULES_JSON} ) +set_property(TEST RunCMake.CXXModules APPEND + PROPERTY LABELS "CXXModules") # ctresalloc links against CMakeLib and CTestLib, which means it can't be built # if CMake_TEST_EXTERNAL_CMAKE is activated (the compiler might be different.) From 85e536b5ebe2856cbde5e27e4d67d75217adb362 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 11 Sep 2025 16:13:35 -0400 Subject: [PATCH 5/5] gitlab-ci: test `CMAKE_CXX_STDLIB_MODULES_JSON` in CI Do this by relocating the file to a sibling directory so that its `../` contents continue to find the correct module interface files, but it won't be found by default. --- .gitlab-ci.yml | 10 ++++++++++ ...onfigure_linux_gcc_cxx_modules_reloc_ninja.cmake | 13 +++++++++++++ .gitlab/os-linux.yml | 7 +++++++ 3 files changed, 30 insertions(+) create mode 100644 .gitlab/ci/configure_linux_gcc_cxx_modules_reloc_ninja.cmake diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4e240785ff..3c7758df2c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -478,6 +478,16 @@ t:hip6.3-radeon: variables: CMAKE_CI_JOB_NIGHTLY: "true" +t:linux-gcc-cxx-modules-reloc-ninja: + extends: + - .gcc_cxx_modules_reloc_ninja + - .cmake_test_linux_release + - .linux_x86_64_tags + - .run_dependent + - .needs_centos7_x86_64 + variables: + CMAKE_CI_JOB_NIGHTLY: "true" + t:linux-gcc-cxx-modules-ninja: extends: - .gcc_cxx_modules_ninja diff --git a/.gitlab/ci/configure_linux_gcc_cxx_modules_reloc_ninja.cmake b/.gitlab/ci/configure_linux_gcc_cxx_modules_reloc_ninja.cmake new file mode 100644 index 0000000000..75e94df868 --- /dev/null +++ b/.gitlab/ci/configure_linux_gcc_cxx_modules_reloc_ninja.cmake @@ -0,0 +1,13 @@ +# "Misplace" the `libstdc++.modules.json` file so that +# `CMAKE_CXX_STDLIB_MODULES_JSON` is needed to use `import std`. +set(gcc_prefix "/opt/gcc-importstd") +set(CMake_TEST_CXX_STDLIB_MODULES_JSON + "${gcc_prefix}/lib64/libstdc++.modules.json" + CACHE FILEPATH "") +file(MAKE_DIRECTORY + "${gcc_prefix}/lib64.reloc") +file(RENAME + "${gcc_prefix}/lib64/libstdc++.modules.json" + "${CMake_TEST_CXX_STDLIB_MODULES_JSON}") + +include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml index c262945da9..a076df3d04 100644 --- a/.gitlab/os-linux.yml +++ b/.gitlab/os-linux.yml @@ -524,6 +524,13 @@ variables: CMAKE_CONFIGURATION: linux_gcc_cxx_modules_ninja +.gcc_cxx_modules_reloc_ninja: + extends: .gcc_cxx_modules_x86_64 + + variables: + CMAKE_CONFIGURATION: linux_gcc_cxx_modules_reloc_ninja + CTEST_LABELS: "CXXModules" + .gcc_cxx_modules_ninja_multi: extends: .gcc_cxx_modules_x86_64