mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 02:39:48 -06:00
Clang: support creating a target for imported modules
This commit is contained in:
@@ -92,6 +92,7 @@ Compilers which CMake natively supports module dependency scanning include:
|
||||
Support for ``import std`` is limited to the following toolchain and standard
|
||||
library combinations:
|
||||
|
||||
* Clang 18.1.2 and newer with ``-stdlib=libc++``
|
||||
* MSVC toolset 14.36 and newer (provided with Visual Studio 17.6 Preview 2 and
|
||||
newer)
|
||||
|
||||
|
||||
153
Modules/Compiler/Clang-CXX-CXXImportStd.cmake
Normal file
153
Modules/Compiler/Clang-CXX-CXXImportStd.cmake
Normal file
@@ -0,0 +1,153 @@
|
||||
function (_cmake_cxx_import_std std variable)
|
||||
if (NOT CMAKE_CXX_STANDARD_LIBRARY STREQUAL "libc++")
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
"${CMAKE_CXX_COMPILER}"
|
||||
${CMAKE_CXX_COMPILER_ID_ARG1}
|
||||
-print-file-name=libc++.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)
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
# Without this file, we do not have modules installed.
|
||||
if (NOT EXISTS "${_clang_libcxx_modules_json_file}")
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "18.1.2")
|
||||
# The original PR had a key spelling mismatch internally. Do not support it
|
||||
# and instead require a release known to have the fix.
|
||||
# https://github.com/llvm/llvm-project/pull/83036
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
file(READ "${_clang_libcxx_modules_json_file}" _clang_libcxx_modules_json)
|
||||
string(JSON _clang_modules_json_version GET "${_clang_libcxx_modules_json}" "version")
|
||||
string(JSON _clang_modules_json_revision GET "${_clang_libcxx_modules_json}" "revision")
|
||||
# Require version 1.
|
||||
if (NOT _clang_modules_json_version EQUAL "1")
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
string(JSON _clang_modules_json_nmodules LENGTH "${_clang_libcxx_modules_json}" "modules")
|
||||
# Don't declare the target without any modules.
|
||||
if (NOT _clang_modules_json_nmodules)
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
# Declare the target.
|
||||
set(_clang_libcxx_target "")
|
||||
# Clang 18 does not provide the module initializer for the `std` modules.
|
||||
# Create a static library to hold these. Hope that Clang 19 can provide this,
|
||||
# but never run the code.
|
||||
string(APPEND _clang_libcxx_target
|
||||
"add_library(__cmake_cxx${std} STATIC)\n")
|
||||
string(APPEND _clang_libcxx_target
|
||||
"target_sources(__cmake_cxx${std} INTERFACE \"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>:$<TARGET_OBJECTS:__cmake_cxx${std}>>\")\n")
|
||||
string(APPEND _clang_libcxx_target
|
||||
"set_property(TARGET __cmake_cxx${std} PROPERTY EXCLUDE_FROM_ALL 1)\n")
|
||||
string(APPEND _clang_libcxx_target
|
||||
"set_property(TARGET __cmake_cxx${std} PROPERTY CXX_SCAN_FOR_MODULES 1)\n")
|
||||
string(APPEND _clang_libcxx_target
|
||||
"set_property(TARGET __cmake_cxx${std} PROPERTY CXX_MODULE_STD 0)\n")
|
||||
string(APPEND _clang_libcxx_target
|
||||
"target_compile_features(__cmake_cxx${std} PUBLIC cxx_std_${std})\n")
|
||||
|
||||
set(_clang_modules_is_stdlib 0)
|
||||
set(_clang_modules_include_dirs_list "")
|
||||
set(_clang_modules_module_paths "")
|
||||
get_filename_component(_clang_modules_dir "${_clang_libcxx_modules_json_file}" DIRECTORY)
|
||||
|
||||
# Add module sources.
|
||||
math(EXPR _clang_modules_json_nmodules_range "${_clang_modules_json_nmodules} - 1")
|
||||
foreach (_clang_modules_json_modules_idx RANGE 0 "${_clang_modules_json_nmodules_range}")
|
||||
string(JSON _clang_modules_json_module GET "${_clang_libcxx_modules_json}" "modules" "${_clang_modules_json_modules_idx}")
|
||||
|
||||
string(JSON _clang_modules_json_module_source GET "${_clang_modules_json_module}" "source-path")
|
||||
string(JSON _clang_modules_json_module_is_stdlib GET "${_clang_modules_json_module}" "is-std-library")
|
||||
string(JSON _clang_modules_json_module_local_arguments GET "${_clang_modules_json_module}" "local-arguments")
|
||||
string(JSON _clang_modules_json_module_nsystem_include_directories LENGTH "${_clang_modules_json_module_local_arguments}" "system-include-directories")
|
||||
|
||||
if (NOT IS_ABSOLUTE "${_clang_modules_json_module_source}")
|
||||
string(PREPEND _clang_modules_json_module_source "${_clang_modules_dir}/")
|
||||
endif ()
|
||||
list(APPEND _clang_modules_module_paths
|
||||
"${_clang_modules_json_module_source}")
|
||||
|
||||
if (_clang_modules_json_module_is_stdlib)
|
||||
set(_clang_modules_is_stdlib 1)
|
||||
endif ()
|
||||
|
||||
math(EXPR _clang_modules_json_module_nsystem_include_directories_range "${_clang_modules_json_module_nsystem_include_directories} - 1")
|
||||
foreach (_clang_modules_json_modules_system_include_directories_idx RANGE 0 "${_clang_modules_json_module_nsystem_include_directories_range}")
|
||||
string(JSON _clang_modules_json_module_system_include_directory GET "${_clang_modules_json_module_local_arguments}" "system-include-directories" "${_clang_modules_json_modules_system_include_directories_idx}")
|
||||
|
||||
if (NOT IS_ABSOLUTE "${_clang_modules_json_module_system_include_directory}")
|
||||
string(PREPEND _clang_modules_json_module_system_include_directory "${_clang_modules_dir}/")
|
||||
endif ()
|
||||
list(APPEND _clang_modules_include_dirs_list
|
||||
"${_clang_modules_json_module_system_include_directory}")
|
||||
endforeach ()
|
||||
endforeach ()
|
||||
|
||||
# Split the paths into basedirs and module paths.
|
||||
set(_clang_modules_base_dirs_list "")
|
||||
set(_clang_modules_files "")
|
||||
foreach (_clang_modules_module_path IN LISTS _clang_modules_module_paths)
|
||||
get_filename_component(_clang_module_dir "${_clang_modules_module_path}" DIRECTORY)
|
||||
|
||||
list(APPEND _clang_modules_base_dirs_list
|
||||
"${_clang_module_dir}")
|
||||
string(APPEND _clang_modules_files
|
||||
" \"${_clang_modules_module_path}\"")
|
||||
endforeach ()
|
||||
list(REMOVE_DUPLICATES _clang_modules_base_dirs_list)
|
||||
set(_clang_modules_base_dirs "")
|
||||
foreach (_clang_modules_base_dir IN LISTS _clang_modules_base_dirs_list)
|
||||
string(APPEND _clang_modules_base_dirs
|
||||
" \"${_clang_modules_base_dir}\"")
|
||||
endforeach ()
|
||||
|
||||
# If we have a standard library module, suppress warnings about reserved
|
||||
# module names.
|
||||
if (_clang_modules_is_stdlib)
|
||||
string(APPEND _clang_libcxx_target
|
||||
"target_compile_options(__cmake_cxx${std} PRIVATE -Wno-reserved-module-identifier)\n")
|
||||
endif ()
|
||||
|
||||
# Set up include directories.
|
||||
list(REMOVE_DUPLICATES _clang_modules_include_dirs_list)
|
||||
set(_clang_modules_include_dirs "")
|
||||
foreach (_clang_modules_include_dir IN LISTS _clang_modules_include_dirs_list)
|
||||
string(APPEND _clang_modules_include_dirs
|
||||
" \"${_clang_modules_include_dir}\"")
|
||||
endforeach ()
|
||||
string(APPEND _clang_libcxx_target
|
||||
"target_include_directories(__cmake_cxx${std} PRIVATE ${_clang_modules_include_dirs})\n")
|
||||
|
||||
# Create the file set for the modules.
|
||||
string(APPEND _clang_libcxx_target
|
||||
"target_sources(__cmake_cxx${std}
|
||||
PUBLIC
|
||||
FILE_SET std TYPE CXX_MODULES
|
||||
BASE_DIRS ${_clang_modules_base_dirs}
|
||||
FILES ${_clang_modules_files})\n")
|
||||
|
||||
# Wrap the `__cmake_cxx${std}` target in a check.
|
||||
string(PREPEND _clang_libcxx_target
|
||||
"if (NOT TARGET \"__cmake_cxx${std}\")\n")
|
||||
string(APPEND _clang_libcxx_target
|
||||
"endif ()\n")
|
||||
string(APPEND _clang_libcxx_target
|
||||
"add_library(__CMAKE::CXX${std} ALIAS __cmake_cxx${std})\n")
|
||||
|
||||
set("${variable}" "${_clang_libcxx_target}" PARENT_SCOPE)
|
||||
endfunction ()
|
||||
Reference in New Issue
Block a user