diff --git a/Modules/Compiler/CMakeCommonCompilerMacros.cmake b/Modules/Compiler/CMakeCommonCompilerMacros.cmake index 9eead201bd..75a9da228f 100644 --- a/Modules/Compiler/CMakeCommonCompilerMacros.cmake +++ b/Modules/Compiler/CMakeCommonCompilerMacros.cmake @@ -211,6 +211,9 @@ function(cmake_create_cxx_import_std std variable) 26) list(FIND _cmake_supported_import_std_features "${std}" _cmake_supported_import_std_idx) if (_cmake_supported_import_std_idx EQUAL "-1") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Unsupported C++ standard: C++${std}\")\n" + PARENT_SCOPE) return () endif () # If the target exists, skip. A toolchain file may have provided it. @@ -219,14 +222,23 @@ function(cmake_create_cxx_import_std std variable) endif () # The generator must support imported C++ modules. if (NOT CMAKE_GENERATOR MATCHES "Ninja") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Unsupported generator: ${CMAKE_GENERATOR}\")\n" + PARENT_SCOPE) return () endif () # Check if the compiler understands how to `import std;`. include("${CMAKE_ROOT}/Modules/Compiler/${CMAKE_CXX_COMPILER_ID}-CXX-CXXImportStd.cmake" OPTIONAL RESULT_VARIABLE _cmake_import_std_res) if (NOT _cmake_import_std_res) + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Toolchain does not support discovering `import std` support\")\n" + PARENT_SCOPE) return () endif () if (NOT COMMAND _cmake_cxx_import_std) + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Toolchain does not provide `import std` discovery command\")\n" + PARENT_SCOPE) return () endif () @@ -237,6 +249,9 @@ function(cmake_create_cxx_import_std std variable) "CxxImportStd" _cmake_supported_import_std_experimental) if (NOT _cmake_supported_import_std_experimental) + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Experimental `import std` support not enabled when detecting toolchain\")\n" + PARENT_SCOPE) return () endif () diff --git a/Modules/Compiler/Clang-CXX-CXXImportStd.cmake b/Modules/Compiler/Clang-CXX-CXXImportStd.cmake index 3934db92ff..55dbfb85bf 100644 --- a/Modules/Compiler/Clang-CXX-CXXImportStd.cmake +++ b/Modules/Compiler/Clang-CXX-CXXImportStd.cmake @@ -14,11 +14,17 @@ function (_cmake_cxx_import_std std variable) 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 `libc++.modules.json` resource\")\n" + PARENT_SCOPE) return () endif () # Without this file, we do not have modules installed. if (NOT EXISTS "${_clang_libcxx_modules_json_file}") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libc++.modules.json` resource does not exist\")\n" + PARENT_SCOPE) return () endif () @@ -26,6 +32,9 @@ function (_cmake_cxx_import_std std variable) # 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 + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"LLVM 18.1.2 is required for `libc++.modules.json` format fix\")\n" + PARENT_SCOPE) return () endif () @@ -34,12 +43,18 @@ function (_cmake_cxx_import_std std variable) string(JSON _clang_modules_json_revision GET "${_clang_libcxx_modules_json}" "revision") # Require version 1. if (NOT _clang_modules_json_version EQUAL "1") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libc++.modules.json` version ${_clang_modules_json_version}.${_clang_modules_json_revision} is not recognized\")\n" + PARENT_SCOPE) 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) + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libc++.modules.json` does not list any available modules\")\n" + PARENT_SCOPE) return () endif () diff --git a/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake b/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake index f253f9ec66..08199f7e6c 100644 --- a/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake +++ b/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake @@ -12,6 +12,9 @@ function (_cmake_cxx_import_std std variable) 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 () @@ -20,18 +23,27 @@ function (_cmake_cxx_import_std std variable) string(JSON _msvc_json_revision GET "${_msvc_modules_json}" "revision") # Require version 1. if (NOT _msvc_json_version EQUAL "1") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`modules.json` version ${_msvc_json_version}.${_msvc_json_revision} is not recognized\")\n" + PARENT_SCOPE) 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") + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`modules.json` library `${_msvc_json_library}` is not recognized\")\n" + PARENT_SCOPE) 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) + set("${variable}" + "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`modules.json` does not list any available modules\")\n" + PARENT_SCOPE) return () endif () diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 75f3b6d7ed..c1c04358a4 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -8583,15 +8583,22 @@ bool cmGeneratorTarget::ApplyCXXStdTargets() continue; } - auto const targetName = cmStrCat( - "__CMAKE::CXX", standardResolver.GetLevelString("CXX", *explicitLevel)); + auto const stdLevel = + standardResolver.GetLevelString("CXX", *explicitLevel); + auto const targetName = cmStrCat("__CMAKE::CXX", stdLevel); if (!this->Makefile->FindTargetToUse(targetName)) { + auto basicReason = this->Makefile->GetDefinition(cmStrCat( + "CMAKE_CXX", stdLevel, "_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE")); + std::string reason; + if (!basicReason.IsEmpty()) { + reason = cmStrCat(" Reason:\n ", basicReason); + } this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat( - R"(The "CXX_MODULE_STD" property on the target ")", this->GetName(), - "\" requires that the \"", targetName, - "\" target exist, but it was not provided by the toolchain.")); + cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")", + this->GetName(), "\" requires that the \"", targetName, + "\" target exist, but it was not provided by the toolchain.", + reason)); break; } diff --git a/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt index 56468d0db7..e3d31c5a6e 100644 --- a/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt +++ b/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt @@ -1,4 +1,9 @@ CMake Error in CMakeLists.txt: The "CXX_MODULE_STD" property on the target "nocxx23target" requires that the "__CMAKE::CXX23" target exist, but it was not provided by the - toolchain. + toolchain. Reason: + + (Toolchain does not support discovering `import std` support|Experimental `import std` support not enabled when detecting toolchain|Unsupported generator: [^\n]*) + + +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoCXX26TargetNotRequired.cmake b/Tests/RunCMake/CXXModules/NoCXX26TargetNotRequired.cmake new file mode 100644 index 0000000000..b91fa9b719 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX26TargetNotRequired.cmake @@ -0,0 +1,11 @@ +enable_language(CXX) +set(CMAKE_CXX_SCANDEP_SOURCE "echo") + +set(CMAKE_CXX_MODULE_STD 0) + +add_library(nocxx26target) +target_sources(nocxx26target + PRIVATE + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(nocxx26target PRIVATE cxx_std_26) diff --git a/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-result.txt b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt new file mode 100644 index 0000000000..8addcb2452 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt @@ -0,0 +1,9 @@ +CMake Error in CMakeLists.txt: + The "CXX_MODULE_STD" property on the target "nocxx26target" requires that + the "__CMAKE::CXX26" target exist, but it was not provided by the + toolchain. Reason: + + (Toolchain does not support discovering `import std` support|Experimental `import std` support not enabled when detecting toolchain|Unsupported generator: [^\n]*) + + +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoCXX26TargetRequired.cmake b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired.cmake new file mode 100644 index 0000000000..79dcb792e2 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired.cmake @@ -0,0 +1,11 @@ +enable_language(CXX) +set(CMAKE_CXX_SCANDEP_SOURCE "echo") + +set(CMAKE_CXX_MODULE_STD 1) + +add_library(nocxx26target) +target_sources(nocxx26target + PRIVATE + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(nocxx26target PRIVATE cxx_std_26) diff --git a/Tests/RunCMake/CXXModules/NoCXX26TargetUnset.cmake b/Tests/RunCMake/CXXModules/NoCXX26TargetUnset.cmake new file mode 100644 index 0000000000..85108ff24a --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX26TargetUnset.cmake @@ -0,0 +1,13 @@ +enable_language(CXX) +set(CMAKE_CXX_SCANDEP_SOURCE "echo") + +# TODO(cxxmodules): Add instances of this test which test the policy +# of the property's unset behavior. +# set(CMAKE_CXX_MODULE_STD …) + +add_library(nocxx26target) +target_sources(nocxx26target + PRIVATE + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(nocxx26target PRIVATE cxx_std_26) diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake index 8c76afcc40..8b7bc8628b 100644 --- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake +++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake @@ -97,6 +97,13 @@ if ("cxx_std_23" IN_LIST CMAKE_CXX_COMPILE_FEATURES AND run_cmake(NoCXX23TargetRequired) endif () +if ("cxx_std_26" IN_LIST CMAKE_CXX_COMPILE_FEATURES AND + NOT have_cxx26_import_std) + run_cmake(NoCXX26TargetUnset) + run_cmake(NoCXX26TargetNotRequired) + run_cmake(NoCXX26TargetRequired) +endif () + run_cmake(InstallBMI) run_cmake(InstallBMIGenericArgs) run_cmake(InstallBMIIgnore)