From 4617f272b47e5d2910647d2f6054d574abbb3d2a Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 26 Feb 2024 09:45:47 -0500 Subject: MSVC: support `import std` --- Help/manual/cmake-cxxmodules.7.rst | 3 + Modules/Compiler/MSVC-CXX-CXXImportStd.cmake | 102 +++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 Modules/Compiler/MSVC-CXX-CXXImportStd.cmake diff --git a/Help/manual/cmake-cxxmodules.7.rst b/Help/manual/cmake-cxxmodules.7.rst index 12ea0a0..9ffb529 100644 --- a/Help/manual/cmake-cxxmodules.7.rst +++ b/Help/manual/cmake-cxxmodules.7.rst @@ -92,6 +92,9 @@ Compilers which CMake natively supports module dependency scanning include: Support for ``import std`` is limited to the following toolchain and standard library combinations: +* MSVC toolset 14.36 and newer (provided with Visual Studio 17.6 Preview 2 and + newer) + .. note :: This support is provided only when experimental support for diff --git a/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake b/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake new file mode 100644 index 0000000..9966b9b --- /dev/null +++ b/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake @@ -0,0 +1,102 @@ +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}/../../.." + PATH_SUFFIXES + ../modules + NO_CACHE) + # Without this file, we do not have modules installed. + if (NOT EXISTS "${_msvc_modules_json_file}") + return () + endif () + + file(READ "${_msvc_modules_json_file}" _msvc_modules_json) + string(JSON _msvc_json_version GET "${_msvc_modules_json}" "version") + string(JSON _msvc_json_revision GET "${_msvc_modules_json}" "revision") + # Require version 1. + if (NOT _msvc_json_version EQUAL "1") + return () + endif () + + string(JSON _msvc_json_library GET "${_msvc_modules_json}" "library") + # Bail if we don't understand the library. + if (NOT _msvc_json_library STREQUAL "microsoft/STL") + return () + endif () + + string(JSON _msvc_json_nmodules LENGTH "${_msvc_modules_json}" "module-sources") + # Don't declare the target without any modules. + if (NOT _msvc_json_nmodules) + return () + endif () + + # Declare the target. + set(_msvc_std_target "") + string(APPEND _msvc_std_target + "add_library(__cmake_cxx${std} STATIC)\n") + string(APPEND _msvc_std_target + "target_sources(__cmake_cxx${std} INTERFACE \"$<$,STATIC_LIBRARY>:$>\")\n") + string(APPEND _msvc_std_target + "set_property(TARGET __cmake_cxx${std} PROPERTY EXCLUDE_FROM_ALL 1)\n") + string(APPEND _msvc_std_target + "set_property(TARGET __cmake_cxx${std} PROPERTY CXX_SCAN_FOR_MODULES 1)\n") + string(APPEND _msvc_std_target + "set_property(TARGET __cmake_cxx${std} PROPERTY CXX_MODULE_STD 0)\n") + string(APPEND _msvc_std_target + "target_compile_features(__cmake_cxx${std} PUBLIC cxx_std_${std})\n") + + set(_msvc_modules_module_paths "") + get_filename_component(_msvc_modules_dir "${_msvc_modules_json_file}" DIRECTORY) + + # Add module sources. + math(EXPR _msvc_modules_json_nmodules_range "${_msvc_json_nmodules} - 1") + foreach (_msvc_modules_json_modules_idx RANGE 0 "${_msvc_modules_json_nmodules_range}") + string(JSON _msvc_modules_json_module_source GET "${_msvc_modules_json}" "module-sources" "${_msvc_modules_json_modules_idx}") + + if (NOT IS_ABSOLUTE "${_msvc_modules_json_module_source}") + string(PREPEND _msvc_modules_json_module_source "${_msvc_modules_dir}/") + endif () + list(APPEND _msvc_modules_module_paths + "${_msvc_modules_json_module_source}") + endforeach () + + # Split the paths into basedirs and module paths. + set(_msvc_modules_base_dirs_list "") + set(_msvc_modules_files "") + foreach (_msvc_modules_module_path IN LISTS _msvc_modules_module_paths) + get_filename_component(_msvc_module_dir "${_msvc_modules_module_path}" DIRECTORY) + + list(APPEND _msvc_modules_base_dirs_list + "${_msvc_module_dir}") + string(APPEND _msvc_modules_files + " \"${_msvc_modules_module_path}\"") + endforeach () + list(REMOVE_DUPLICATES _msvc_modules_base_dirs_list) + set(_msvc_modules_base_dirs "") + foreach (_msvc_modules_base_dir IN LISTS _msvc_modules_base_dirs_list) + string(APPEND _msvc_modules_base_dirs + " \"${_msvc_modules_base_dir}\"") + endforeach () + + # Create the file set for the modules. + string(APPEND _msvc_std_target + "target_sources(__cmake_cxx${std} + PUBLIC + FILE_SET std TYPE CXX_MODULES + BASE_DIRS ${_msvc_modules_base_dirs} + FILES ${_msvc_modules_files})\n") + + # Wrap the `__cmake_cxx${std}` target in a check. + string(PREPEND _msvc_std_target + "if (NOT TARGET \"__cmake_cxx${std}\")\n") + string(APPEND _msvc_std_target + "endif ()\n") + string(APPEND _msvc_std_target + "add_library(__CMAKE::CXX${std} ALIAS __cmake_cxx${std})\n") + + set("${variable}" "${_msvc_std_target}" PARENT_SCOPE) +endfunction () -- cgit v0.12