summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2024-04-15 13:56:40 (GMT)
committerKitware Robot <kwrobot@kitware.com>2024-04-15 13:56:53 (GMT)
commitca449572ef8b1c6066e88879795900aea9727834 (patch)
treeb7f4f67018d8fead9292e9d0133fa02e22879918 /Source
parentabd572de909de2f30ca93e3b1cca1311e33c4f75 (diff)
parent429902ebad620c877b869068583d2a32bb6197b4 (diff)
downloadCMake-ca449572ef8b1c6066e88879795900aea9727834.zip
CMake-ca449572ef8b1c6066e88879795900aea9727834.tar.gz
CMake-ca449572ef8b1c6066e88879795900aea9727834.tar.bz2
Merge topic 'cxxmodules-import-std'
429902ebad Clang: support creating a target for imported modules 4617f272b4 MSVC: support `import std` 62a71047bb cmGraphVizWriter: ignore `__cmake_`-prefixed targets 442086c1dc fileapi: ignore `__cmake_`-prefixed targets ffe74289b3 CMakeDetermineCompilerId: extract C++ standard library impl 15bbd1d9b8 Experimental: add an experimental feature gate for `import std` f80c60df02 CMakeDetermineCompilerSupport: construct C++ modules targets 19341e2582 ci: enable `import_std23` C++ module tests on MSVC ... Acked-by: Kitware Robot <kwrobot@kitware.com> Tested-by: buildbot <buildbot@kitware.com> Merge-request: !9337
Diffstat (limited to 'Source')
-rw-r--r--Source/cmExperimental.cxx9
-rw-r--r--Source/cmExperimental.h1
-rw-r--r--Source/cmExportFileGenerator.cxx41
-rw-r--r--Source/cmFileAPICodemodel.cxx5
-rw-r--r--Source/cmGeneratorTarget.cxx124
-rw-r--r--Source/cmGeneratorTarget.h1
-rw-r--r--Source/cmGlobalGenerator.cxx49
-rw-r--r--Source/cmGlobalGenerator.h1
-rw-r--r--Source/cmGraphVizWriter.cxx3
-rw-r--r--Source/cmStandardLevelResolver.cxx15
-rw-r--r--Source/cmStandardLevelResolver.h3
-rw-r--r--Source/cmTarget.cxx2
12 files changed, 234 insertions, 20 deletions
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
index 8adf4e2..a2e6e70 100644
--- a/Source/cmExperimental.cxx
+++ b/Source/cmExperimental.cxx
@@ -37,6 +37,15 @@ cmExperimental::FeatureData LookupTable[] = {
{},
cmExperimental::TryCompileCondition::Always,
false },
+ // CxxImportStd
+ { "CxxImportStd",
+ "0e5b6991-d74f-4b3d-a41c-cf096e0b2508",
+ "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.",
+ {},
+ cmExperimental::TryCompileCondition::Always,
+ false },
};
static_assert(sizeof(LookupTable) / sizeof(LookupTable[0]) ==
static_cast<size_t>(cmExperimental::Feature::Sentinel),
diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h
index 1abfbc3..05764f9 100644
--- a/Source/cmExperimental.h
+++ b/Source/cmExperimental.h
@@ -19,6 +19,7 @@ public:
{
ExportPackageDependencies,
WindowsKernelModeDriver,
+ CxxImportStd,
Sentinel,
};
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 7867a8e..9bd7f49 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -1388,6 +1388,12 @@ void cmExportFileGenerator::GenerateImportedFileChecksCode(
os << ")\n\n";
}
+enum class ExportWhen
+{
+ Defined,
+ Always,
+};
+
enum class PropertyType
{
Strings,
@@ -1409,6 +1415,12 @@ bool PropertyTypeIsForPaths(PropertyType pt)
}
}
+struct ModuleTargetPropertyTable
+{
+ cm::static_string_view Name;
+ ExportWhen Cond;
+};
+
struct ModulePropertyTable
{
cm::static_string_view Name;
@@ -1424,18 +1436,29 @@ bool cmExportFileGenerator::PopulateCxxModuleExportProperties(
return true;
}
- const cm::static_string_view exportedDirectModuleProperties[] = {
- "CXX_EXTENSIONS"_s,
+ const ModuleTargetPropertyTable exportedDirectModuleProperties[] = {
+ { "CXX_EXTENSIONS"_s, ExportWhen::Defined },
+ // Always define this property as it is an intrinsic property of the target
+ // and should not be inherited from the in-scope `CMAKE_CXX_MODULE_STD`
+ // variable.
+ //
+ // TODO(cxxmodules): A future policy may make this "ON" based on the target
+ // policies if unset. Add a new `ExportWhen` condition to handle it when
+ // this happens.
+ { "CXX_MODULE_STD"_s, ExportWhen::Always },
};
- for (auto const& propName : exportedDirectModuleProperties) {
- auto const propNameStr = std::string(propName);
- cmValue prop = gte->Target->GetComputedProperty(
+ for (auto const& prop : exportedDirectModuleProperties) {
+ auto const propNameStr = std::string(prop.Name);
+ cmValue propValue = gte->Target->GetComputedProperty(
propNameStr, *gte->Target->GetMakefile());
- if (!prop) {
- prop = gte->Target->GetProperty(propNameStr);
+ if (!propValue) {
+ propValue = gte->Target->GetProperty(propNameStr);
}
- if (prop) {
- properties[propNameStr] = cmGeneratorExpression::Preprocess(*prop, ctx);
+ if (propValue) {
+ properties[propNameStr] =
+ cmGeneratorExpression::Preprocess(*propValue, ctx);
+ } else if (prop.Cond == ExportWhen::Always) {
+ properties[propNameStr] = "";
}
}
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index e9302da..869b94a 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -685,6 +685,11 @@ Json::Value CodemodelConfig::DumpTargets()
continue;
}
+ // Ignore targets starting with `__cmake_` as they are internal.
+ if (cmHasLiteralPrefix(gt->GetName(), "__cmake_")) {
+ continue;
+ }
+
targets.append(this->DumpTarget(gt, targets.size()));
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 2ec1a29..be82099 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -32,6 +32,7 @@
#include "cmCustomCommandGenerator.h"
#include "cmCxxModuleUsageEffects.h"
#include "cmEvaluatedTargetProperty.h"
+#include "cmExperimental.h"
#include "cmFileSet.h"
#include "cmFileTimes.h"
#include "cmGeneratedFileStream.h"
@@ -8411,9 +8412,119 @@ void ComputeLinkImplTransitive(cmGeneratorTarget const* self,
}
}
+bool cmGeneratorTarget::ApplyCXXStdTargets()
+{
+ 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");
+ if (!std_prop) {
+ // TODO(cxxmodules): Add a target policy to flip the default here. Set
+ // `std_prop` based on it.
+ return true;
+ }
+
+ std::string std_prop_value;
+ if (std_prop) {
+ // Evaluate generator expressions.
+ cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance());
+ auto cge = ge.Parse(*std_prop);
+ if (!cge) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
+ this->GetName(), "\" is not a valid generator expression."));
+ return false;
+ }
+ // But do not allow context-sensitive queries. Whether a target uses
+ // `import std` should not depend on configuration or properties of the
+ // consumer (head target). The link language also shouldn't matter, so ban
+ // it as well.
+ if (cge->GetHadHeadSensitiveCondition()) {
+ // Not reachable; all target-sensitive genexes actually fail to parse.
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
+ this->GetName(),
+ "\" contains a condition that queries the "
+ "consuming target which is not supported."));
+ return false;
+ }
+ if (cge->GetHadLinkLanguageSensitiveCondition()) {
+ // Not reachable; all link language genexes actually fail to parse.
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
+ this->GetName(),
+ "\" contains a condition that queries the "
+ "link language which is not supported."));
+ return false;
+ }
+ std_prop_value = cge->Evaluate(this->LocalGenerator, "");
+ if (cge->GetHadContextSensitiveCondition()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
+ this->GetName(),
+ "\" contains a context-sensitive condition "
+ "that is not supported."));
+ return false;
+ }
+ }
+ auto use_std = cmIsOn(std_prop_value);
+
+ // If we have a value and it is not true, there's nothing to do.
+ if (std_prop && !use_std) {
+ 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 targetName = cmStrCat(
+ "__CMAKE::CXX", standardResolver.GetLevelString("CXX", *explicitLevel));
+ if (!this->Makefile->FindTargetToUse(targetName)) {
+ 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."));
+ break;
+ }
+
+ // Check the experimental feature here as well. A toolchain may have
+ // provided the target and skipped the check in the toolchain preparation
+ // logic.
+ if (!cmExperimental::HasSupportEnabled(
+ *this->Makefile, cmExperimental::Feature::CxxImportStd)) {
+ break;
+ }
+
+ this->Target->AppendProperty(
+ "LINK_LIBRARIES",
+ cmStrCat("$<BUILD_LOCAL_INTERFACE:$<$<CONFIG:", config, ">:", targetName,
+ ">>"));
+ }
+
+ return true;
+}
+
bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
std::string const& config)
{
+ std::vector<std::string> allConfigs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
cmOptionalLinkImplementation impl;
this->ComputeLinkImplementationLibraries(config, impl, this,
LinkInterfaceFor::Link);
@@ -8488,9 +8599,22 @@ bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
// Create the generator target and attach it to the local generator.
auto gtp = cm::make_unique<cmGeneratorTarget>(tgt, lg);
+
synthDep = gtp.get();
cache.CxxModuleTargets[targetName] = synthDep;
+
+ // See `localGen->ComputeTargetCompileFeatures()` call in
+ // `cmGlobalGenerator::Compute` for where non-synthetic targets resolve
+ // this.
+ for (auto const& innerConfig : allConfigs) {
+ gtp->ComputeCompileFeatures(innerConfig);
+ }
+ // See `cmGlobalGenerator::ApplyCXXStdTargets` in
+ // `cmGlobalGenerator::Compute` for non-synthetic target resolutions.
+ gtp->ApplyCXXStdTargets();
+
gtp->DiscoverSyntheticTargets(cache, config);
+
lg->AddGeneratorTarget(std::move(gtp));
} else {
synthDep = cached->second;
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index fd4b2ec..28ad898 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -961,6 +961,7 @@ public:
std::string GetImportedXcFrameworkPath(const std::string& config) const;
+ bool ApplyCXXStdTargets();
bool DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
std::string const& config);
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 213142a..e397fa2 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1581,6 +1581,29 @@ bool cmGlobalGenerator::Compute()
}
#endif
+ // Perform up-front computation in order to handle errors (such as unknown
+ // features) at this point. While processing the compile features we also
+ // calculate and cache the language standard required by the compile
+ // features.
+ //
+ // Synthetic targets performed this inside of
+ // `cmLocalGenerator::DiscoverSyntheticTargets`
+ for (const auto& localGen : this->LocalGenerators) {
+ if (!localGen->ComputeTargetCompileFeatures()) {
+ return false;
+ }
+ }
+
+ // We now have all targets set up and std levels constructed. Add
+ // `__CMAKE::CXX*` targets as link dependencies to all targets which need
+ // them.
+ //
+ // Synthetic targets performed this inside of
+ // `cmLocalGenerator::DiscoverSyntheticTargets`
+ if (!this->ApplyCXXStdTargets()) {
+ return false;
+ }
+
// Iterate through all targets and set up C++20 module targets.
// Create target templates for each imported target with C++20 modules.
// INTERFACE library with BMI-generating rules and a collation step?
@@ -1588,6 +1611,9 @@ bool cmGlobalGenerator::Compute()
// Make `add_dependencies(imported_target
// $<$<TARGET_NAME_IF_EXISTS:uses_imported>:synth1>
// $<$<TARGET_NAME_IF_EXISTS:other_uses_imported>:synth2>)`
+ //
+ // Note that synthetic target creation performs the above marked
+ // steps on the created targets.
if (!this->DiscoverSyntheticTargets()) {
return false;
}
@@ -1597,16 +1623,6 @@ bool cmGlobalGenerator::Compute()
localGen->AddHelperCommands();
}
- // Perform up-front computation in order to handle errors (such as unknown
- // features) at this point. While processing the compile features we also
- // calculate and cache the language standard required by the compile
- // features.
- for (const auto& localGen : this->LocalGenerators) {
- if (!localGen->ComputeTargetCompileFeatures()) {
- return false;
- }
- }
-
// Add automatically generated sources (e.g. unity build).
// Add unity sources after computing compile features. Unity sources do
// not change the set of languages or features, but we need to know them
@@ -1824,6 +1840,19 @@ void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
entry->second = index++;
}
+bool cmGlobalGenerator::ApplyCXXStdTargets()
+{
+ for (auto const& gen : this->LocalGenerators) {
+ for (auto const& tgt : gen->GetGeneratorTargets()) {
+ if (!tgt->ApplyCXXStdTargets()) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
bool cmGlobalGenerator::DiscoverSyntheticTargets()
{
cmSyntheticTargetCache cache;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index ba39768..1ca02d9 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -674,6 +674,7 @@ protected:
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
+ bool ApplyCXXStdTargets();
bool DiscoverSyntheticTargets();
bool AddHeaderSetVerification();
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index a8a7abb..6c3afef 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -284,7 +284,8 @@ void cmGraphVizWriter::Write()
// Reserved targets have inconsistent names across platforms (e.g. 'all'
// vs. 'ALL_BUILD'), which can disrupt the traversal ordering.
// We don't need or want them anyway.
- if (!cmGlobalGenerator::IsReservedTarget(gt->GetName())) {
+ if (!cmGlobalGenerator::IsReservedTarget(gt->GetName()) &&
+ !cmHasLiteralPrefix(gt->GetName(), "__cmake_")) {
sortedGeneratorTargets.insert(gt.get());
}
}
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
index c9ed380..44c4ae1 100644
--- a/Source/cmStandardLevelResolver.cxx
+++ b/Source/cmStandardLevelResolver.cxx
@@ -541,6 +541,21 @@ std::string cmStandardLevelResolver::GetEffectiveStandard(
return mapping->second.GetEffectiveStandard(this->Makefile, target, config);
}
+std::string cmStandardLevelResolver::GetLevelString(
+ std::string const& lang, cmStandardLevel const& level) const
+{
+ auto mapping = StandardComputerMapping.find(lang);
+ if (mapping == StandardComputerMapping.end()) {
+ return {};
+ }
+
+ if (mapping->second.LevelsAsStrings.size() <= level.Index()) {
+ return {};
+ }
+
+ return mapping->second.LevelsAsStrings[level.Index()];
+}
+
bool cmStandardLevelResolver::AddRequiredTargetFeature(
cmTarget* target, const std::string& feature, std::string* error) const
{
diff --git a/Source/cmStandardLevelResolver.h b/Source/cmStandardLevelResolver.h
index 29cab55..523aa73 100644
--- a/Source/cmStandardLevelResolver.h
+++ b/Source/cmStandardLevelResolver.h
@@ -29,6 +29,9 @@ public:
std::string const& lang,
std::string const& config) const;
+ std::string GetLevelString(std::string const& lang,
+ cmStandardLevel const& level) const;
+
bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature,
std::string* error = nullptr) const;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 3f7e29b..1284130 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -412,6 +412,7 @@ TargetProperty const StaticTargetProperties[] = {
COMMON_LANGUAGE_PROPERTIES(C),
// ---- C++
COMMON_LANGUAGE_PROPERTIES(CXX),
+ { "CXX_MODULE_STD"_s, IC::CanCompileSources },
// ---- CSharp
{ "DOTNET_SDK"_s, IC::NonImportedTarget },
{ "DOTNET_TARGET_FRAMEWORK"_s, IC::TargetWithCommands },
@@ -1842,6 +1843,7 @@ void cmTarget::CopyImportedCxxModulesProperties(cmTarget const* tgt)
"CXX_STANDARD_REQUIRED",
"CXX_EXTENSIONS",
"CXX_VISIBILITY_PRESET",
+ "CXX_MODULE_STD",
// Static analysis
"CXX_CLANG_TIDY",