cxxmodules: link to std-providing targets when available

This commit is contained in:
Ben Boeckel
2024-02-27 11:53:32 -05:00
parent 15cd73d6c2
commit 2c8361f923
5 changed files with 136 additions and 1 deletions
+8 -1
View File
@@ -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.
+103
View File
@@ -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);
+1
View File
@@ -961,6 +961,7 @@ public:
std::string GetImportedXcFrameworkPath(const std::string& config) const;
bool ApplyCXXStdTargets();
bool DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
std::string const& config);
+23
View File
@@ -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;
+1
View File
@@ -674,6 +674,7 @@ protected:
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
bool ApplyCXXStdTargets();
bool DiscoverSyntheticTargets();
bool AddHeaderSetVerification();