Browse Source

MSVC: support `import std`

Ben Boeckel 1 year ago
parent
commit
4617f272b4
2 changed files with 105 additions and 0 deletions
  1. 3 0
      Help/manual/cmake-cxxmodules.7.rst
  2. 102 0
      Modules/Compiler/MSVC-CXX-CXXImportStd.cmake

+ 3 - 0
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

+ 102 - 0
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 \"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>:$<TARGET_OBJECTS:__cmake_cxx${std}>>\")\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 ()