From 9cad48c6cbdc0c64f0695c474223acdccbf3211d Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 21 Nov 2024 04:56:41 -0500 Subject: gcc: support `import std` (cherry picked from commit a980dab9b1 (gcc: support `import std`, 2024-11-21)) --- Modules/CMakeDetermineCompilerId.cmake | 5 +- Modules/Compiler/GNU-CXX-CXXImportStd.cmake | 134 +++++++++++++++++++++ .../import-std-no-std-property-build-stdout.txt | 2 +- 3 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 Modules/Compiler/GNU-CXX-CXXImportStd.cmake diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index 5e88076..e5dc8ea 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -315,8 +315,9 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src) set(CMAKE_${lang}_STANDARD_LIBRARY "") if ("x${lang}" STREQUAL "xCXX" AND EXISTS "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${lang}-DetectStdlib.h" AND - "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang" AND - "x${CMAKE_${lang}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU") + ("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang" AND + "x${CMAKE_${lang}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU") OR + ("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xGNU")) # See #20851 for a proper abstraction for this. execute_process( COMMAND "${CMAKE_${lang}_COMPILER}" diff --git a/Modules/Compiler/GNU-CXX-CXXImportStd.cmake b/Modules/Compiler/GNU-CXX-CXXImportStd.cmake new file mode 100644 index 0000000..965e25a --- /dev/null +++ b/Modules/Compiler/GNU-CXX-CXXImportStd.cmake @@ -0,0 +1,134 @@ +function (_cmake_cxx_import_std std variable) + if (NOT CMAKE_CXX_STANDARD_LIBRARY STREQUAL "libstdc++") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Only `libstdc++` is supported\")\n" + PARENT_SCOPE) + 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 () + endif () + + # Without this file, we do not have modules installed. + if (NOT EXISTS "${_gnu_libstdcxx_modules_json_file}") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libstdc++.modules.json` resource does not exist\")\n" + PARENT_SCOPE) + return () + endif () + + file(READ "${_gnu_libstdcxx_modules_json_file}" _gnu_libstdcxx_modules_json) + string(JSON _gnu_modules_json_version GET "${_gnu_libstdcxx_modules_json}" "version") + string(JSON _gnu_modules_json_revision GET "${_gnu_libstdcxx_modules_json}" "revision") + # Require version 1. + if (NOT _gnu_modules_json_version EQUAL "1") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libstdc++.modules.json` version ${_gnu_modules_json_version}.${_gnu_modules_json_revision} is not recognized\")\n" + PARENT_SCOPE) + return () + endif () + + string(JSON _gnu_modules_json_nmodules LENGTH "${_gnu_libstdcxx_modules_json}" "modules") + # Don't declare the target without any modules. + if (NOT _gnu_modules_json_nmodules) + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libstdc++.modules.json` does not list any available modules\")\n" + PARENT_SCOPE) + return () + endif () + + # Declare the target. + set(_gnu_libstdcxx_target "") + string(APPEND _gnu_libstdcxx_target + "add_library(__CMAKE::CXX${std} IMPORTED INTERFACE)\n") + string(APPEND _gnu_libstdcxx_target + "target_compile_features(__CMAKE::CXX${std} INTERFACE cxx_std_${std})\n") + + set(_gnu_modules_is_stdlib 0) + set(_gnu_modules_include_dirs_list "") + set(_gnu_modules_module_paths "") + get_filename_component(_gnu_modules_dir "${_gnu_libstdcxx_modules_json_file}" DIRECTORY) + + # Add module sources. + math(EXPR _gnu_modules_json_nmodules_range "${_gnu_modules_json_nmodules} - 1") + foreach (_gnu_modules_json_modules_idx RANGE 0 "${_gnu_modules_json_nmodules_range}") + string(JSON _gnu_modules_json_module GET "${_gnu_libstdcxx_modules_json}" "modules" "${_gnu_modules_json_modules_idx}") + + string(JSON _gnu_modules_json_module_source GET "${_gnu_modules_json_module}" "source-path") + string(JSON _gnu_modules_json_module_is_stdlib GET "${_gnu_modules_json_module}" "is-std-library") + string(JSON _gnu_modules_json_module_local_arguments ERROR_VARIABLE _gnu_modules_json_module_local_arguments_error GET "${_gnu_modules_json_module}" "local-arguments") + string(JSON _gnu_modules_json_module_nsystem_include_directories ERROR_VARIABLE _gnu_modules_json_module_nsystem_include_directories_error LENGTH "${_gnu_modules_json_module_local_arguments}" "system-include-directories") + + if (_gnu_modules_json_module_local_arguments_error STREQUAL "NOTFOUND") + set(_gnu_modules_json_module_local_arguments "") + endif () + if (_gnu_modules_json_module_nsystem_include_directories_error STREQUAL "NOTFOUND") + set(_gnu_modules_json_module_nsystem_include_directories 0) + endif () + + if (NOT IS_ABSOLUTE "${_gnu_modules_json_module_source}") + string(PREPEND _gnu_modules_json_module_source "${_gnu_modules_dir}/") + endif () + list(APPEND _gnu_modules_module_paths + "${_gnu_modules_json_module_source}") + + if (_gnu_modules_json_module_is_stdlib) + set(_gnu_modules_is_stdlib 1) + endif () + + if (_gnu_modules_json_module_nsystem_include_directories) + math(EXPR _gnu_modules_json_module_nsystem_include_directories_range "${_gnu_modules_json_module_nsystem_include_directories} - 1") + foreach (_gnu_modules_json_modules_system_include_directories_idx RANGE 0 "${_gnu_modules_json_module_nsystem_include_directories_range}") + string(JSON _gnu_modules_json_module_system_include_directory GET "${_gnu_modules_json_module_local_arguments}" "system-include-directories" "${_gnu_modules_json_modules_system_include_directories_idx}") + + if (NOT IS_ABSOLUTE "${_gnu_modules_json_module_system_include_directory}") + string(PREPEND _gnu_modules_json_module_system_include_directory "${_gnu_modules_dir}/") + endif () + list(APPEND _gnu_modules_include_dirs_list + "${_gnu_modules_json_module_system_include_directory}") + endforeach () + endif () + endforeach () + + # Split the paths into basedirs and module paths. + set(_gnu_modules_base_dirs_list "") + set(_gnu_modules_files "") + foreach (_gnu_modules_module_path IN LISTS _gnu_modules_module_paths) + get_filename_component(_gnu_module_dir "${_gnu_modules_module_path}" DIRECTORY) + + list(APPEND _gnu_modules_base_dirs_list + "${_gnu_module_dir}") + string(APPEND _gnu_modules_files + " \"${_gnu_modules_module_path}\"") + endforeach () + list(REMOVE_DUPLICATES _gnu_modules_base_dirs_list) + set(_gnu_modules_base_dirs "") + foreach (_gnu_modules_base_dir IN LISTS _gnu_modules_base_dirs_list) + string(APPEND _gnu_modules_base_dirs + " \"${_gnu_modules_base_dir}\"") + endforeach () + + # Create the file set for the modules. + string(APPEND _gnu_libstdcxx_target + "target_sources(__CMAKE::CXX${std} + INTERFACE + FILE_SET std TYPE CXX_MODULES + BASE_DIRS ${_gnu_modules_base_dirs} + FILES ${_gnu_modules_files})\n") + + set("${variable}" "${_gnu_libstdcxx_target}" PARENT_SCOPE) +endfunction () diff --git a/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-build-stdout.txt b/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-build-stdout.txt index d473333..a94f02a 100644 --- a/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-build-stdout.txt +++ b/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-build-stdout.txt @@ -1 +1 @@ -((Clang)?module 'std' not found|(MSVC)?could not find module 'std') +((GNU)?fatal error: unknown compiled module interface: no such module|(Clang)?module 'std' not found|(MSVC)?could not find module 'std') -- cgit v0.12