c++modules: single import std target

This commit is contained in:
Vito Gamberini
2026-06-18 15:20:54 -04:00
parent d9c35d02bb
commit 6d3e9d8220
27 changed files with 50 additions and 111 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ In order to activate support for ``import std`` in C++23 and newer targets,
set
* variable ``CMAKE_EXPERIMENTAL_CXX_IMPORT_STD`` to
* value ``451f2fe2-a8a2-47c3-bc32-94786d8fc91b``.
* value ``f35a9ac6-8463-4d38-8eec-5d6008153e7d``.
This UUID may change in future versions of CMake. Be sure to use the value
documented here by the source tree of the version of CMake with which you are
+1 -1
View File
@@ -158,7 +158,7 @@ function(cmake_determine_compiler_support lang)
foreach(_cmake_import_std_version IN ITEMS 23 26)
if(CMAKE_CXX${_cmake_import_std_version}_COMPILE_FEATURES)
# Modules JSON covers all versions, otherwise rely on toolchain targets
if(CMAKE_CXX_STDLIB_MODULES_JSON OR (TARGET "__CMAKE:CXX${_cmake_import_std_version}"))
if(CMAKE_CXX_STDLIB_MODULES_JSON)
list(APPEND CMAKE_CXX_COMPILER_IMPORT_STD ${_cmake_import_std_version})
endif()
endif()
+1 -1
View File
@@ -31,7 +31,7 @@ cmExperimental::FeatureData const LookupTable[] = {
cmExperimental::TryCompileCondition::Always },
// CxxImportStd
{ "CxxImportStd",
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b",
"f35a9ac6-8463-4d38-8eec-5d6008153e7d",
"CMAKE_EXPERIMENTAL_CXX_IMPORT_STD",
"CMake's support for `import std;` in C++23 and newer is experimental. It "
"is meant only for experimentation and feedback to CMake developers.",
+20 -43
View File
@@ -5330,8 +5330,6 @@ bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
namespace {
bool CreateCxxStdlibTarget(cmMakefile* makefile, cmLocalGenerator* lg,
std::string const& targetName,
std::string const& cxxTargetName,
std::string const& stdLevel,
std::vector<std::string> const& configs)
{
#ifndef CMAKE_BOOTSTRAP
@@ -5377,20 +5375,17 @@ bool CreateCxxStdlibTarget(cmMakefile* makefile, cmLocalGenerator* lg,
metadata = std::move(*parseResult.Meta);
}
auto const localTargetName = cmStrCat("__cmake_cxx_std_", stdLevel);
cmStandardLevelResolver standardResolver(makefile);
auto* stdlibTgt = makefile->AddLibrary(
localTargetName, cmStateEnums::STATIC_LIBRARY, {}, true);
"@cmake_cxx_std", cmStateEnums::STATIC_LIBRARY, {}, true);
cmCxxModuleMetadata::PopulateTarget(*stdlibTgt, *metadata, configs);
standardResolver.AddRequiredTargetFeature(stdlibTgt,
cmStrCat("cxx_std_", stdLevel));
cmStandardLevelResolver standardResolver(makefile);
standardResolver.AddRequiredTargetFeature(stdlibTgt, "cxx_std_20");
auto gt = cm::make_unique<cmGeneratorTarget>(stdlibTgt, lg);
for (auto const& config : configs) {
gt->ComputeCompileFeatures(config);
}
lg->AddGeneratorTarget(std::move(gt));
makefile->AddAlias(cxxTargetName, localTargetName);
#endif // CMAKE_BOOTSTRAP
@@ -5398,11 +5393,8 @@ bool CreateCxxStdlibTarget(cmMakefile* makefile, cmLocalGenerator* lg,
}
} // namespace
bool cmGeneratorTarget::ApplyCXXStdTargets()
bool cmGeneratorTarget::ApplyCXXStdTarget()
{
cmStandardLevelResolver standardResolver(this->Makefile);
cmStandardLevel const cxxStd23 =
*standardResolver.LanguageStandardLevel("CXX", "23");
std::vector<std::string> const& configs =
this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
auto std_prop = this->GetProperty("CXX_MODULE_STD");
@@ -5466,35 +5458,18 @@ bool cmGeneratorTarget::ApplyCXXStdTargets()
return true;
}
for (auto const& config : configs) {
if (this->HaveCxxModuleSupport(config) != Cxx20SupportLevel::Supported) {
continue;
}
cm::optional<cmStandardLevel> explicitLevel =
this->GetExplicitStandardLevel("CXX", config);
if (!explicitLevel || *explicitLevel < cxxStd23) {
continue;
}
auto const stdLevel =
standardResolver.GetLevelString("CXX", *explicitLevel);
auto const cxxTargetName = cmStrCat("__CMAKE::CXX", stdLevel);
// Create the __CMAKE::CXX## target if it doesn't already exist
if (!this->Makefile->FindTargetToUse(cxxTargetName) &&
!CreateCxxStdlibTarget(this->Makefile, this->LocalGenerator,
this->GetName(), cxxTargetName, stdLevel,
configs)) {
return false;
}
this->Target->AppendProperty(
"LINK_LIBRARIES",
cmStrCat("$<BUILD_LOCAL_INTERFACE:$<$<CONFIG:", config,
">:", cxxTargetName, ">>"));
// Create the single, unreferenceable import std target if it doesn't
// already exist. BMI compatibility handles per-consumer standard level
// differences by creating synthetic targets as needed.
if (!this->Makefile->FindTargetToUse("@cmake_cxx_std") &&
!CreateCxxStdlibTarget(this->Makefile, this->LocalGenerator,
this->GetName(), configs)) {
return false;
}
this->Target->AppendProperty("LINK_LIBRARIES",
"$<BUILD_LOCAL_INTERFACE:@cmake_cxx_std>");
// Check the experimental feature here. A toolchain may have
// skipped the check in the toolchain preparation logic.
if (!cmExperimental::HasSupportEnabled(
@@ -5577,8 +5552,10 @@ cmGeneratorTarget const* cmGeneratorTarget::GetCxxSyntheticTarget(
}
}
// Copy properties which effect consumer compatibility
tgt->CopyUsageEffects(bmiConsumer.Target);
// Copy properties which effect consumer compatibility.
// CopyUsageEffects now uses the consumer's full (own + transitive)
// compile features and options.
tgt->CopyUsageEffects(&bmiConsumer, config);
// Copy properties which don't effect consumer compatibility
tgt->CopyCxxModulesEntries(model);
@@ -5599,9 +5576,9 @@ cmGeneratorTarget const* cmGeneratorTarget::GetCxxSyntheticTarget(
for (auto const& innerConfig : allConfigs) {
gtp->ComputeCompileFeatures(innerConfig);
}
// See `cmGlobalGenerator::ApplyCXXStdTargets` in
// See `cmGlobalGenerator::ApplyCXXStdTarget` in
// `cmGlobalGenerator::Compute` for non-synthetic target resolutions.
if (!gtp->ApplyCXXStdTargets()) {
if (!gtp->ApplyCXXStdTarget()) {
return nullptr;
}
+1 -1
View File
@@ -1146,7 +1146,7 @@ public:
std::string GetImportedXcFrameworkPath(std::string const& config) const;
bool ApplyCXXStdTargets();
bool ApplyCXXStdTarget();
cmCxxModuleUsageEffects const& GetCxxModuleUsageEffects() const;
cmGeneratorTarget const* GetTargetForCxxModules(
std::string const& config, cmGeneratorTarget const& bmiConsumer) const;
+7 -8
View File
@@ -1676,13 +1676,12 @@ bool cmGlobalGenerator::Compute()
}
}
// We now have all targets set up and std levels constructed. Add
// `__CMAKE::CXX*` targets as link dependencies to all targets which need
// them.
// We now have all targets set up. Add the `@cmake_cxx_std` target as a link
// dependency to all targets which need it.
//
// Synthetic targets performed this inside of
// `cmLocalGenerator::DiscoverSyntheticTargets`
if (!this->ApplyCXXStdTargets()) {
if (!this->ApplyCXXStdTarget()) {
return false;
}
@@ -1997,12 +1996,12 @@ void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
entry->second = index++;
}
bool cmGlobalGenerator::ApplyCXXStdTargets()
bool cmGlobalGenerator::ApplyCXXStdTarget()
{
for (auto const& gen : this->LocalGenerators) {
// tgt->ApplyCXXStd can create targets itself, so we need iterators which
// won't be invalidated by that target creation
// tgt->ApplyCXXStdTarget can create a target itself, so we need iterators
// which won't be invalidated by that target creation
auto const& genTgts = gen->GetGeneratorTargets();
std::vector<cmGeneratorTarget*> existingTgts;
existingTgts.reserve(genTgts.size());
@@ -2011,7 +2010,7 @@ bool cmGlobalGenerator::ApplyCXXStdTargets()
}
for (auto const& tgt : existingTgts) {
if (!tgt->ApplyCXXStdTargets()) {
if (!tgt->ApplyCXXStdTarget()) {
return false;
}
}
+1 -1
View File
@@ -800,7 +800,7 @@ protected:
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
bool ApplyCXXStdTargets();
bool ApplyCXXStdTarget();
bool DiscoverSyntheticTargets();
bool AddHeaderSetVerification();
@@ -1,6 +1,3 @@
# Block making C++ `import std` targets.
add_library(__CMAKE::CXX23 IMPORTED INTERFACE)
enable_language(CXX)
unset(CMAKE_CXX_SCANDEP_SOURCE)
@@ -1,6 +1,3 @@
# Block making C++ `import std` targets.
add_library(__CMAKE::CXX23 IMPORTED INTERFACE)
enable_language(CXX)
unset(CMAKE_CXX_SCANDEP_SOURCE)
@@ -1,9 +1,6 @@
# Enable scanning by default for targets that explicitly use C++ 20.
cmake_policy(SET CMP0155 NEW)
# Block making C++ `import std` targets.
add_library(__CMAKE::CXX23 IMPORTED INTERFACE)
# Force CMAKE_CXX_STANDARD_DEFAULT to be C++ 20.
set(ENV{CXXFLAGS} "$ENV{CXXFLAGS} ${CMAKE_CXX20_STANDARD_COMPILE_OPTION}")
enable_language(CXX)
-16
View File
@@ -15,22 +15,6 @@ if (CMAKE_CXX_FLAGS MATCHES "-std=")
set(forced_cxx_standard 1)
endif ()
macro (cxx_check_import_std version)
set(have_cxx${version}_import_std 0)
if ("${version}" IN_LIST CMAKE_CXX_COMPILER_IMPORT_STD)
set(have_cxx${version}_import_std 1)
endif ()
if (TARGET "__CMAKE:CXX${version}" AND NOT have_cxx${version}_import_std)
message(FATAL_ERROR
"The toolchain's C++${version} target exists, but the user variable does "
"not indicate it.")
endif ()
endmacro ()
cxx_check_import_std(23)
cxx_check_import_std(26)
# Forward information about the C++ compile features.
string(APPEND info "\
set(CMAKE_CXX_COMPILE_FEATURES \"${CMAKE_CXX_COMPILE_FEATURES}\")
-3
View File
@@ -1,6 +1,3 @@
# Block making C++ `import std` targets.
add_library(__CMAKE::CXX23 IMPORTED INTERFACE)
enable_language(CXX)
add_library(nocxx20)
@@ -1,9 +1,6 @@
# Enable scanning by default for targets that explicitly use C++ 20.
cmake_policy(SET CMP0155 NEW)
# Block making C++ `import std` targets.
add_library(__CMAKE::CXX23 IMPORTED INTERFACE)
enable_language(CXX)
# Hide any real scanning rule that may be available.
@@ -1,5 +1,5 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
set(CMAKE_CXX_STDLIB_MODULES_JSON
"${CMAKE_CURRENT_LIST_DIR}/../dummy-std/manifest/dummy-std.modules.json"
)
@@ -1,5 +1,5 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_minimum_required(VERSION 3.29)
project(cxx_modules_import_std_export_no_std CXX)
@@ -39,7 +39,7 @@ list(FILTER usage_dependent_targets EXCLUDE REGEX "CXXModules::")
# Strip quotes.
string(REPLACE "\"" "" usage_dependent_targets "${usage_dependent_targets}")
if ("__CMAKE::CXX23" IN_LIST usage_dependent_targets)
if ("@cmake_cxx_std" IN_LIST usage_dependent_targets)
message(SEND_ERROR
"The main export requires the '__CMAKE::CXX23' target")
"The main export requires the '@cmake_cxx_std' target")
endif ()
@@ -1,5 +1,5 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_minimum_required(VERSION 3.29)
project(cxx_modules_import_std_export_no_std CXX)
@@ -39,7 +39,7 @@ list(FILTER usage_dependent_targets EXCLUDE REGEX "CXXModules::")
# Strip quotes.
string(REPLACE "\"" "" usage_dependent_targets "${usage_dependent_targets}")
if ("__CMAKE::CXX23" IN_LIST usage_dependent_targets)
if ("@cmake_cxx_std" IN_LIST usage_dependent_targets)
message(SEND_ERROR
"The main export requires the '__CMAKE::CXX23' target")
"The main export requires the '@cmake_cxx_std' target")
endif ()
@@ -1,5 +1,5 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_minimum_required(VERSION 3.29)
project(cxx_modules_import_std_no_std_property CXX)
@@ -1,5 +1,5 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_minimum_required(VERSION 3.29)
project(cxx_modules_import_std_not_in_export CXX)
@@ -39,7 +39,7 @@ list(FILTER usage_dependent_targets EXCLUDE REGEX "CXXModules::")
# Strip quotes.
string(REPLACE "\"" "" usage_dependent_targets "${usage_dependent_targets}")
if ("__CMAKE::CXX23" IN_LIST usage_dependent_targets)
if ("@cmake_cxx_std" IN_LIST usage_dependent_targets)
message(SEND_ERROR
"The main export requires the '__CMAKE::CXX23' target")
"The main export requires the '@cmake_cxx_std' target")
endif ()
@@ -1,5 +1,5 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_minimum_required(VERSION 3.29)
project(cxx_modules_import_std_not_in_export CXX)
@@ -39,7 +39,7 @@ list(FILTER usage_dependent_targets EXCLUDE REGEX "CXXModules::")
# Strip quotes.
string(REPLACE "\"" "" usage_dependent_targets "${usage_dependent_targets}")
if ("__CMAKE::CXX23" IN_LIST usage_dependent_targets)
if ("@cmake_cxx_std" IN_LIST usage_dependent_targets)
message(SEND_ERROR
"The main export requires the '__CMAKE::CXX23' target")
"The main export requires the '@cmake_cxx_std' target")
endif ()
@@ -1,14 +1,8 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_minimum_required(VERSION 3.29)
if (EXPORT_NO_STD)
# Block making C++ `import std` targets.
add_library(__CMAKE::CXX23 IMPORTED INTERFACE)
add_library(__CMAKE::CXX26 IMPORTED INTERFACE)
endif ()
project(cxx_modules_import_std_transitive CXX)
include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
@@ -1,5 +1,5 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_minimum_required(VERSION 3.29)
project(cxx_modules_import_std CXX)
@@ -13,7 +13,7 @@ if (NOT feature_present STREQUAL "FALSE")
endif ()
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_language(GET_EXPERIMENTAL_FEATURE_ENABLED
"CxxImportStd"
@@ -1,5 +1,5 @@
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
"451f2fe2-a8a2-47c3-bc32-94786d8fc91b")
"f35a9ac6-8463-4d38-8eec-5d6008153e7d")
cmake_language(GET_EXPERIMENTAL_FEATURE_ENABLED
"CxxImportStd"