summaryrefslogtreecommitdiffstats
path: root/Source/cmGeneratorTarget.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmGeneratorTarget.cxx')
-rw-r--r--Source/cmGeneratorTarget.cxx124
1 files changed, 124 insertions, 0 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index b32d0b8..d6560d0 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"
@@ -8412,9 +8413,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);
@@ -8489,9 +8600,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;