summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake-cxxmodules.7.rst9
-rw-r--r--Source/cmGeneratorTarget.cxx103
-rw-r--r--Source/cmGeneratorTarget.h1
-rw-r--r--Source/cmGlobalGenerator.cxx23
-rw-r--r--Source/cmGlobalGenerator.h1
5 files changed, 136 insertions, 1 deletions
diff --git a/Help/manual/cmake-cxxmodules.7.rst b/Help/manual/cmake-cxxmodules.7.rst
index 8f62b5a..0c9c46e 100644
--- a/Help/manual/cmake-cxxmodules.7.rst
+++ b/Help/manual/cmake-cxxmodules.7.rst
@@ -86,6 +86,12 @@ Compilers which CMake natively supports module dependency scanning include:
* LLVM/Clang 16.0 and newer
* GCC 14 (for the in-development branch, after 2023-09-20) and newer
+``import std`` Support
+======================
+
+Support for ``import std`` is limited to the following toolchain and standard
+library combinations:
+
Generator Support
=================
@@ -116,6 +122,7 @@ For the :ref:`Visual Studio Generators`:
- Only Visual Studio 2022 and MSVC toolsets 14.34 (Visual Studio
17.4) and newer.
- No support for exporting or installing BMI or module information.
-- No support for compiling BMIs from ``IMPORTED`` targets with C++ modules.
+- No support for compiling BMIs from ``IMPORTED`` targets with C++ modules
+ (including ``import std``).
- No diagnosis of using modules provided by ``PRIVATE`` sources from
``PUBLIC`` module sources.
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index f0acb9c..1dba976 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -8411,6 +8411,106 @@ 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;
+ }
+
+ this->Target->AppendProperty(
+ "LINK_LIBRARIES",
+ cmStrCat("$<BUILD_LOCAL_INTERFACE:$<$<CONFIG:", config, ">:", targetName,
+ ">>"));
+ }
+
+ return true;
+}
+
bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
std::string const& config)
{
@@ -8500,6 +8600,9 @@ bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
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);
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 c0af34b..e397fa2 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1594,6 +1594,16 @@ 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.
+ //
+ // 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?
@@ -1830,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();