mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-24 09:09:43 -05:00
cmTarget: add support for C++ module fileset types
C++ modules have two variants which are of importance to CMake:
- `CXX_MODULES`: interface modules (those using `export module M;`,
`export module M:part;`, or `module M:internal_part;`)
- `CXX_MODULE_HEADER_UNITS`: importable header units
Creating C++ modules or partitions are *not* supported in any other
source listing. This is because the source files must be installed (so
their scope matters), but not part of usage requirements (what it means
for a module source to be injected into a consumer is not clear at this
moment). Due to the way `FILE_SET` works with scopes, they are a perfect
fit as long as `INTERFACE` is not allowed (which it is not).
This commit is contained in:
@@ -9,7 +9,9 @@
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include <cm/string_view>
|
||||
#include <cmext/algorithm>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmExportSet.h"
|
||||
#include "cmFileSet.h"
|
||||
@@ -382,6 +384,21 @@ std::string cmExportBuildFileGenerator::GetFileSetDirectories(
|
||||
std::any_of(directoryEntries.begin(), directoryEntries.end(),
|
||||
EntryIsContextSensitive);
|
||||
|
||||
auto const& type = fileSet->GetType();
|
||||
// C++ modules do not support interface file sets which are dependent upon
|
||||
// the configuration.
|
||||
if (contextSensitive &&
|
||||
(type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
|
||||
auto* mf = this->LG->GetMakefile();
|
||||
std::ostringstream e;
|
||||
e << "The \"" << gte->GetName() << "\" target's interface file set \""
|
||||
<< fileSet->GetName() << "\" of type \"" << type
|
||||
<< "\" contains context-sensitive base directory entries which is not "
|
||||
"supported.";
|
||||
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
for (auto const& directory : directories) {
|
||||
auto dest = cmOutputConverter::EscapeForCMake(
|
||||
directory, cmOutputConverter::WrapQuotes::NoWrap);
|
||||
@@ -427,6 +444,21 @@ std::string cmExportBuildFileGenerator::GetFileSetFiles(cmGeneratorTarget* gte,
|
||||
std::any_of(fileEntries.begin(), fileEntries.end(),
|
||||
EntryIsContextSensitive);
|
||||
|
||||
auto const& type = fileSet->GetType();
|
||||
// C++ modules do not support interface file sets which are dependent upon
|
||||
// the configuration.
|
||||
if (contextSensitive &&
|
||||
(type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
|
||||
auto* mf = this->LG->GetMakefile();
|
||||
std::ostringstream e;
|
||||
e << "The \"" << gte->GetName() << "\" target's interface file set \""
|
||||
<< fileSet->GetName() << "\" of type \"" << type
|
||||
<< "\" contains context-sensitive file entries which is not "
|
||||
"supported.";
|
||||
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
for (auto const& it : files) {
|
||||
for (auto const& filename : it.second) {
|
||||
auto escapedFile = cmOutputConverter::EscapeForCMake(
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include <cm/string_view>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmExportSet.h"
|
||||
#include "cmFileSet.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
@@ -18,6 +21,7 @@
|
||||
#include "cmInstallTargetGenerator.h"
|
||||
#include "cmLocalGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmOutputConverter.h"
|
||||
#include "cmPolicies.h"
|
||||
#include "cmStateTypes.h"
|
||||
@@ -562,6 +566,21 @@ std::string cmExportInstallFileGenerator::GetFileSetDirectories(
|
||||
cge->Evaluate(gte->LocalGenerator, config, gte),
|
||||
cmOutputConverter::WrapQuotes::NoWrap));
|
||||
|
||||
auto const& type = fileSet->GetType();
|
||||
// C++ modules do not support interface file sets which are dependent upon
|
||||
// the configuration.
|
||||
if (cge->GetHadContextSensitiveCondition() &&
|
||||
(type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
|
||||
auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile();
|
||||
std::ostringstream e;
|
||||
e << "The \"" << gte->GetName() << "\" target's interface file set \""
|
||||
<< fileSet->GetName() << "\" of type \"" << type
|
||||
<< "\" contains context-sensitive base file entries which is not "
|
||||
"supported.";
|
||||
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) {
|
||||
resultVector.push_back(
|
||||
cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
|
||||
@@ -610,6 +629,21 @@ std::string cmExportInstallFileGenerator::GetFileSetFiles(
|
||||
std::any_of(fileEntries.begin(), fileEntries.end(),
|
||||
EntryIsContextSensitive);
|
||||
|
||||
auto const& type = fileSet->GetType();
|
||||
// C++ modules do not support interface file sets which are dependent upon
|
||||
// the configuration.
|
||||
if (contextSensitive &&
|
||||
(type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
|
||||
auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile();
|
||||
std::ostringstream e;
|
||||
e << "The \"" << gte->GetName() << "\" target's interface file set \""
|
||||
<< fileSet->GetName() << "\" of type \"" << type
|
||||
<< "\" contains context-sensitive base file entries which is not "
|
||||
"supported.";
|
||||
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
for (auto const& it : files) {
|
||||
auto prefix = it.first.empty() ? "" : cmStrCat(it.first, '/');
|
||||
for (auto const& filename : it.second) {
|
||||
|
||||
@@ -1707,7 +1707,8 @@ void addFileSetEntry(cmGeneratorTarget const* headTarget,
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (fileSet->GetType() == "HEADERS"_s) {
|
||||
if (fileSet->GetType() == "HEADERS"_s ||
|
||||
fileSet->GetType() == "CXX_MODULE_HEADER_UNITS"_s) {
|
||||
headTarget->Makefile->GetOrCreateSourceGroup("Header Files")
|
||||
->AddGroupFile(path);
|
||||
}
|
||||
@@ -1728,6 +1729,20 @@ void AddFileSetEntries(cmGeneratorTarget const* headTarget,
|
||||
addFileSetEntry(headTarget, config, dagChecker, headerSet, entries);
|
||||
}
|
||||
}
|
||||
for (auto const& entry : headTarget->Target->GetCxxModuleSetsEntries()) {
|
||||
for (auto const& name : cmExpandedList(entry.Value)) {
|
||||
auto const* cxxModuleSet = headTarget->Target->GetFileSet(name);
|
||||
addFileSetEntry(headTarget, config, dagChecker, cxxModuleSet, entries);
|
||||
}
|
||||
}
|
||||
for (auto const& entry :
|
||||
headTarget->Target->GetCxxModuleHeaderSetsEntries()) {
|
||||
for (auto const& name : cmExpandedList(entry.Value)) {
|
||||
auto const* cxxModuleHeaderSet = headTarget->Target->GetFileSet(name);
|
||||
addFileSetEntry(headTarget, config, dagChecker, cxxModuleHeaderSet,
|
||||
entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool processSources(cmGeneratorTarget const* tgt,
|
||||
@@ -8700,3 +8715,76 @@ std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::HaveCxx20ModuleSources() const
|
||||
{
|
||||
auto const& fs_names = this->Target->GetAllFileSetNames();
|
||||
return std::any_of(fs_names.begin(), fs_names.end(),
|
||||
[this](std::string const& name) -> bool {
|
||||
auto const* file_set = this->Target->GetFileSet(name);
|
||||
if (!file_set) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::INTERNAL_ERROR,
|
||||
cmStrCat("Target \"", this->Target->GetName(),
|
||||
"\" is tracked to have file set \"", name,
|
||||
"\", but it was not found."));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const& fs_type = file_set->GetType();
|
||||
return fs_type == "CXX_MODULES"_s ||
|
||||
fs_type == "CXX_MODULE_HEADER_UNITS"_s;
|
||||
});
|
||||
}
|
||||
|
||||
cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport(
|
||||
std::string const& config) const
|
||||
{
|
||||
auto const* state = this->Makefile->GetState();
|
||||
if (!state->GetLanguageEnabled("CXX")) {
|
||||
return Cxx20SupportLevel::MissingCxx;
|
||||
}
|
||||
cmStandardLevelResolver standardResolver(this->Makefile);
|
||||
if (!standardResolver.HaveStandardAvailable(this, "CXX", config,
|
||||
"cxx_std_20")) {
|
||||
return Cxx20SupportLevel::NoCxx20;
|
||||
}
|
||||
if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
|
||||
return Cxx20SupportLevel::MissingExperimentalFlag;
|
||||
}
|
||||
return Cxx20SupportLevel::Supported;
|
||||
}
|
||||
|
||||
void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const
|
||||
{
|
||||
// Check for `CXX_MODULE*` file sets and a lack of support.
|
||||
if (this->HaveCxx20ModuleSources()) {
|
||||
switch (this->HaveCxxModuleSupport(config)) {
|
||||
case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx:
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("The \"", this->GetName(),
|
||||
"\" target has C++ module sources but the \"CXX\" language "
|
||||
"has not been enabled"));
|
||||
break;
|
||||
case cmGeneratorTarget::Cxx20SupportLevel::MissingExperimentalFlag:
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("The \"", this->GetName(),
|
||||
"\" target has C++ module sources but its experimental "
|
||||
"support has not been requested"));
|
||||
break;
|
||||
case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20:
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat(
|
||||
"The \"", this->GetName(),
|
||||
"\" target has C++ module sources but is not using at least "
|
||||
"\"cxx_std_20\""));
|
||||
break;
|
||||
case cmGeneratorTarget::Cxx20SupportLevel::Supported:
|
||||
// All is well.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1196,4 +1196,34 @@ public:
|
||||
bool operator()(cmGeneratorTarget const* t1,
|
||||
cmGeneratorTarget const* t2) const;
|
||||
};
|
||||
|
||||
// C++20 module support queries.
|
||||
|
||||
/**
|
||||
* Query whether the target expects C++20 module support.
|
||||
*
|
||||
* This will inspect the target itself to see if C++20 module
|
||||
* support is expected to work based on its sources.
|
||||
*/
|
||||
bool HaveCxx20ModuleSources() const;
|
||||
|
||||
enum class Cxx20SupportLevel
|
||||
{
|
||||
// C++ is not available.
|
||||
MissingCxx,
|
||||
// The experimental feature is not available.
|
||||
MissingExperimentalFlag,
|
||||
// The target does not require at least C++20.
|
||||
NoCxx20,
|
||||
// C++20 modules are available and working.
|
||||
Supported,
|
||||
};
|
||||
/**
|
||||
* Query whether the target has C++20 module support available (regardless of
|
||||
* whether it is required or not).
|
||||
*/
|
||||
Cxx20SupportLevel HaveCxxModuleSupport(std::string const& config) const;
|
||||
|
||||
// Check C++ module status for the target.
|
||||
void CheckCxxModuleStatus(std::string const& config) const;
|
||||
};
|
||||
|
||||
@@ -395,12 +395,27 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
|
||||
{
|
||||
VisualStudioFolders.clear();
|
||||
|
||||
std::vector<std::string> configs =
|
||||
root->GetMakefile()->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
|
||||
|
||||
for (cmGeneratorTarget const* target : projectTargets) {
|
||||
if (!this->IsInSolution(target)) {
|
||||
continue;
|
||||
}
|
||||
bool written = false;
|
||||
|
||||
for (auto const& c : configs) {
|
||||
target->CheckCxxModuleStatus(c);
|
||||
}
|
||||
|
||||
if (target->HaveCxx20ModuleSources() && !this->SupportsCxxModuleDyndep()) {
|
||||
root->GetMakefile()->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("The \"", target->GetName(),
|
||||
"\" target contains C++ module sources which are not "
|
||||
"supported by the generator"));
|
||||
}
|
||||
|
||||
// handle external vc project files
|
||||
cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
|
||||
if (expath) {
|
||||
|
||||
@@ -157,6 +157,8 @@ protected:
|
||||
cmValue typeGuid,
|
||||
const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0;
|
||||
|
||||
virtual bool SupportsCxxModuleDyndep() const { return false; }
|
||||
|
||||
std::string ConvertToSolutionPath(const std::string& path);
|
||||
|
||||
std::set<std::string> IsPartOfDefaultBuild(
|
||||
|
||||
@@ -1376,6 +1376,18 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget(
|
||||
return true;
|
||||
}
|
||||
|
||||
for (std::string const& configName : this->CurrentConfigurationTypes) {
|
||||
gtgt->CheckCxxModuleStatus(configName);
|
||||
}
|
||||
|
||||
if (gtgt->HaveCxx20ModuleSources()) {
|
||||
gtgt->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("The \"", gtgt->GetName(),
|
||||
"\" target contains C++ module sources which are not "
|
||||
"supported by the generator"));
|
||||
}
|
||||
|
||||
auto& gtgt_visited = this->CommandsVisited[gtgt];
|
||||
auto& deps = this->GetTargetDirectDepends(gtgt);
|
||||
for (auto& d : deps) {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "cmComputeLinkInformation.h"
|
||||
#include "cmCustomCommand.h"
|
||||
#include "cmCustomCommandGenerator.h"
|
||||
#include "cmFileSet.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
@@ -46,6 +47,7 @@
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmTarget.h"
|
||||
#include "cmValue.h"
|
||||
#include "cmake.h"
|
||||
|
||||
@@ -190,6 +192,16 @@ void cmMakefileTargetGenerator::CreateRuleFile()
|
||||
|
||||
void cmMakefileTargetGenerator::WriteTargetBuildRules()
|
||||
{
|
||||
this->GeneratorTarget->CheckCxxModuleStatus(this->GetConfigName());
|
||||
|
||||
if (this->GeneratorTarget->HaveCxx20ModuleSources()) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("The \"", this->GeneratorTarget->GetName(),
|
||||
"\" target contains C++ module sources which are not supported "
|
||||
"by the generator"));
|
||||
}
|
||||
|
||||
// -- Write the custom commands for this target
|
||||
|
||||
// Evaluates generator expressions and expands prop_value
|
||||
@@ -302,6 +314,40 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> file_set_map;
|
||||
|
||||
auto const* tgt = this->GeneratorTarget->Target;
|
||||
for (auto const& name : tgt->GetAllFileSetNames()) {
|
||||
auto const* file_set = tgt->GetFileSet(name);
|
||||
if (!file_set) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::INTERNAL_ERROR,
|
||||
cmStrCat("Target \"", tgt->GetName(),
|
||||
"\" is tracked to have file set \"", name,
|
||||
"\", but it was not found."));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fileEntries = file_set->CompileFileEntries();
|
||||
auto directoryEntries = file_set->CompileDirectoryEntries();
|
||||
auto directories = file_set->EvaluateDirectoryEntries(
|
||||
directoryEntries, this->LocalGenerator, this->GetConfigName(),
|
||||
this->GeneratorTarget);
|
||||
|
||||
std::map<std::string, std::vector<std::string>> files;
|
||||
for (auto const& entry : fileEntries) {
|
||||
file_set->EvaluateFileEntry(directories, files, entry,
|
||||
this->LocalGenerator, this->GetConfigName(),
|
||||
this->GeneratorTarget);
|
||||
}
|
||||
|
||||
for (auto const& it : files) {
|
||||
for (auto const& filename : it.second) {
|
||||
file_set_map[filename] = file_set->GetType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<cmSourceFile const*> objectSources;
|
||||
this->GeneratorTarget->GetObjectSources(objectSources,
|
||||
this->GetConfigName());
|
||||
@@ -314,6 +360,25 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
|
||||
this->WriteObjectRuleFiles(*sf);
|
||||
}
|
||||
}
|
||||
|
||||
for (cmSourceFile const* sf : objectSources) {
|
||||
auto const& path = sf->GetFullPath();
|
||||
auto const it = file_set_map.find(path);
|
||||
if (it != file_set_map.end()) {
|
||||
auto const& file_set_type = it->second;
|
||||
if (file_set_type == "CXX_MODULES"_s ||
|
||||
file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
|
||||
if (sf->GetLanguage() != "CXX"_s) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat(
|
||||
"Target \"", tgt->GetName(), "\" contains the source\n ", path,
|
||||
"\nin a file set of type \"", file_set_type,
|
||||
R"(" but the source is not classified as a "CXX" source.)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmMakefileTargetGenerator::WriteCommonCodeRules()
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "cmRange.h"
|
||||
#include "cmRulePlaceholderExpander.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmStandardLevelResolver.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
@@ -153,17 +152,12 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule(
|
||||
bool cmNinjaTargetGenerator::NeedCxxModuleSupport(
|
||||
std::string const& lang, std::string const& config) const
|
||||
{
|
||||
if (lang != "CXX") {
|
||||
if (lang != "CXX"_s) {
|
||||
return false;
|
||||
}
|
||||
if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
|
||||
return false;
|
||||
}
|
||||
cmGeneratorTarget const* tgt = this->GetGeneratorTarget();
|
||||
cmStandardLevelResolver standardResolver(this->Makefile);
|
||||
bool const uses_cxx20 =
|
||||
standardResolver.HaveStandardAvailable(tgt, "CXX", config, "cxx_std_20");
|
||||
return uses_cxx20 && this->GetGlobalGenerator()->CheckCxxModuleSupport();
|
||||
return this->GetGeneratorTarget()->HaveCxxModuleSupport(config) ==
|
||||
cmGeneratorTarget::Cxx20SupportLevel::Supported &&
|
||||
this->GetGlobalGenerator()->CheckCxxModuleSupport();
|
||||
}
|
||||
|
||||
bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang,
|
||||
@@ -255,52 +249,54 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
|
||||
flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
|
||||
}
|
||||
|
||||
if (this->NeedCxxModuleSupport(language, config)) {
|
||||
auto const& path = source->GetFullPath();
|
||||
auto const* tgt = this->GeneratorTarget->Target;
|
||||
auto const& path = source->GetFullPath();
|
||||
auto const* tgt = this->GeneratorTarget->Target;
|
||||
|
||||
std::string file_set_type;
|
||||
std::string file_set_type;
|
||||
|
||||
for (auto const& name : tgt->GetAllFileSetNames()) {
|
||||
auto const* file_set = tgt->GetFileSet(name);
|
||||
if (!file_set) {
|
||||
for (auto const& name : tgt->GetAllFileSetNames()) {
|
||||
auto const* file_set = tgt->GetFileSet(name);
|
||||
if (!file_set) {
|
||||
this->GetMakefile()->IssueMessage(
|
||||
MessageType::INTERNAL_ERROR,
|
||||
cmStrCat("Target \"", tgt->GetName(),
|
||||
"\" is tracked to have file set \"", name,
|
||||
"\", but it was not found."));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fileEntries = file_set->CompileFileEntries();
|
||||
auto directoryEntries = file_set->CompileDirectoryEntries();
|
||||
auto directories = file_set->EvaluateDirectoryEntries(
|
||||
directoryEntries, this->LocalGenerator, config, this->GeneratorTarget);
|
||||
|
||||
std::map<std::string, std::vector<std::string>> files;
|
||||
for (auto const& entry : fileEntries) {
|
||||
file_set->EvaluateFileEntry(directories, files, entry,
|
||||
this->LocalGenerator, config,
|
||||
this->GeneratorTarget);
|
||||
}
|
||||
|
||||
for (auto const& it : files) {
|
||||
for (auto const& filename : it.second) {
|
||||
if (filename == path) {
|
||||
file_set_type = file_set->GetType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file_set_type == "CXX_MODULES"_s ||
|
||||
file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
|
||||
if (source->GetLanguage() != "CXX"_s) {
|
||||
this->GetMakefile()->IssueMessage(
|
||||
MessageType::INTERNAL_ERROR,
|
||||
cmStrCat("Target `", tgt->GetName(),
|
||||
"` is tracked to have file set `", name,
|
||||
"`, but it was not found."));
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat(
|
||||
"Target \"", tgt->GetName(), "\" contains the source\n ", path,
|
||||
"\nin a file set of type \"", file_set_type,
|
||||
R"(" but the source is not classified as a "CXX" source.)"));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fileEntries = file_set->CompileFileEntries();
|
||||
auto directoryEntries = file_set->CompileDirectoryEntries();
|
||||
auto directories = file_set->EvaluateDirectoryEntries(
|
||||
directoryEntries, this->LocalGenerator, config, this->GeneratorTarget);
|
||||
|
||||
std::map<std::string, std::vector<std::string>> files;
|
||||
for (auto const& entry : fileEntries) {
|
||||
file_set->EvaluateFileEntry(directories, files, entry,
|
||||
this->LocalGenerator, config,
|
||||
this->GeneratorTarget);
|
||||
}
|
||||
|
||||
for (auto const& it : files) {
|
||||
for (auto const& filename : it.second) {
|
||||
if (filename == path) {
|
||||
file_set_type = file_set->GetType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_set_type.empty()) {
|
||||
std::string source_type_var = cmStrCat(
|
||||
"CMAKE_EXPERIMENTAL_CXX_MODULE_SOURCE_TYPE_FLAG_", file_set_type);
|
||||
cmMakefile* mf = this->GetMakefile();
|
||||
if (cmValue source_type_flag = mf->GetDefinition(source_type_var)) {
|
||||
this->LocalGenerator->AppendFlags(flags, *source_type_flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1038,6 +1034,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
|
||||
const std::string& config, const std::string& fileConfig,
|
||||
bool firstForConfig)
|
||||
{
|
||||
this->GeneratorTarget->CheckCxxModuleStatus(config);
|
||||
|
||||
// Write comments.
|
||||
cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
|
||||
this->GetImplFileStream(fileConfig)
|
||||
|
||||
@@ -272,6 +272,8 @@ public:
|
||||
cmListFileBacktrace Backtrace;
|
||||
|
||||
FileSetType HeadersFileSets;
|
||||
FileSetType CxxModulesFileSets;
|
||||
FileSetType CxxModuleHeadersFileSets;
|
||||
|
||||
cmTargetInternals();
|
||||
|
||||
@@ -301,6 +303,19 @@ cmTargetInternals::cmTargetInternals()
|
||||
"The default header set"_s, "Header set"_s,
|
||||
FileSetEntries("HEADER_SETS"_s),
|
||||
FileSetEntries("INTERFACE_HEADER_SETS"_s))
|
||||
, CxxModulesFileSets("CXX_MODULES"_s, "CXX_MODULE_DIRS"_s,
|
||||
"CXX_MODULE_SET"_s, "CXX_MODULE_DIRS_"_s,
|
||||
"CXX_MODULE_SET_"_s, "C++ module"_s,
|
||||
"The default C++ module set"_s, "C++ module set"_s,
|
||||
FileSetEntries("CXX_MODULE_SETS"_s),
|
||||
FileSetEntries("INTERFACE_CXX_MODULE_SETS"_s))
|
||||
, CxxModuleHeadersFileSets(
|
||||
"CXX_MODULE_HEADER_UNITS"_s, "CXX_MODULE_HEADER_UNIT_DIRS"_s,
|
||||
"CXX_MODULE_HEADER_UNIT_SET"_s, "CXX_MODULE_HEADER_UNIT_DIRS_"_s,
|
||||
"CXX_MODULE_HEADER_UNIT_SET_"_s, "C++ module header"_s,
|
||||
"The default C++ module header set"_s, "C++ module header set"_s,
|
||||
FileSetEntries("CXX_MODULE_HEADER_UNIT_SETS"_s),
|
||||
FileSetEntries("INTERFACE_CXX_MODULE_HEADER_UNIT_SETS"_s))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1366,11 +1381,32 @@ cmBTStringRange cmTarget::GetHeaderSetsEntries() const
|
||||
return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries);
|
||||
}
|
||||
|
||||
cmBTStringRange cmTarget::GetCxxModuleSetsEntries() const
|
||||
{
|
||||
return cmMakeRange(this->impl->CxxModulesFileSets.SelfEntries.Entries);
|
||||
}
|
||||
|
||||
cmBTStringRange cmTarget::GetCxxModuleHeaderSetsEntries() const
|
||||
{
|
||||
return cmMakeRange(this->impl->CxxModuleHeadersFileSets.SelfEntries.Entries);
|
||||
}
|
||||
|
||||
cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const
|
||||
{
|
||||
return cmMakeRange(this->impl->HeadersFileSets.InterfaceEntries.Entries);
|
||||
}
|
||||
|
||||
cmBTStringRange cmTarget::GetInterfaceCxxModuleSetsEntries() const
|
||||
{
|
||||
return cmMakeRange(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
|
||||
}
|
||||
|
||||
cmBTStringRange cmTarget::GetInterfaceCxxModuleHeaderSetsEntries() const
|
||||
{
|
||||
return cmMakeRange(
|
||||
this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
|
||||
}
|
||||
|
||||
namespace {
|
||||
#define MAKE_PROP(PROP) const std::string prop##PROP = #PROP
|
||||
MAKE_PROP(C_STANDARD);
|
||||
@@ -1630,6 +1666,12 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value)
|
||||
} else if (this->impl->HeadersFileSets.WriteProperties(
|
||||
this, this->impl.get(), prop, value, true)) {
|
||||
/* Handled in the `if` condition. */
|
||||
} else if (this->impl->CxxModulesFileSets.WriteProperties(
|
||||
this, this->impl.get(), prop, value, true)) {
|
||||
/* Handled in the `if` condition. */
|
||||
} else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
|
||||
this, this->impl.get(), prop, value, true)) {
|
||||
/* Handled in the `if` condition. */
|
||||
} else {
|
||||
this->impl->Properties.SetProperty(prop, value);
|
||||
}
|
||||
@@ -1741,6 +1783,13 @@ void cmTarget::AppendProperty(const std::string& prop,
|
||||
this->impl->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR, prop + " property may not be appended.");
|
||||
} else if (this->impl->HeadersFileSets.WriteProperties(
|
||||
this, this->impl.get(), prop, value,
|
||||
false)) { // NOLINT(bugprone-branch-clone)
|
||||
/* Handled in the `if` condition. */
|
||||
} else if (this->impl->CxxModulesFileSets.WriteProperties(
|
||||
this, this->impl.get(), prop, value, false)) {
|
||||
/* Handled in the `if` condition. */
|
||||
} else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
|
||||
this, this->impl.get(), prop, value, false)) {
|
||||
/* Handled in the `if` condition. */
|
||||
} else {
|
||||
@@ -2249,6 +2298,17 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
|
||||
if (headers.first) {
|
||||
return headers.second;
|
||||
}
|
||||
auto cxx_modules = this->impl->CxxModulesFileSets.ReadProperties(
|
||||
this, this->impl.get(), prop);
|
||||
if (cxx_modules.first) {
|
||||
return cxx_modules.second;
|
||||
}
|
||||
auto cxx_module_headers =
|
||||
this->impl->CxxModuleHeadersFileSets.ReadProperties(
|
||||
this, this->impl.get(), prop);
|
||||
if (cxx_module_headers.first) {
|
||||
return cxx_module_headers.second;
|
||||
}
|
||||
}
|
||||
|
||||
cmValue retVal = this->impl->Properties.GetPropertyValue(prop);
|
||||
@@ -2526,6 +2586,11 @@ std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
|
||||
auto bt = this->impl->Makefile->GetBacktrace();
|
||||
if (type == this->impl->HeadersFileSets.TypeName) {
|
||||
this->impl->HeadersFileSets.AddFileSet(name, vis, std::move(bt));
|
||||
} else if (type == this->impl->CxxModulesFileSets.TypeName) {
|
||||
this->impl->CxxModulesFileSets.AddFileSet(name, vis, std::move(bt));
|
||||
} else if (type == this->impl->CxxModuleHeadersFileSets.TypeName) {
|
||||
this->impl->CxxModuleHeadersFileSets.AddFileSet(name, vis,
|
||||
std::move(bt));
|
||||
}
|
||||
}
|
||||
return std::make_pair(&result.first->second, result.second);
|
||||
@@ -2536,6 +2601,12 @@ std::string cmTarget::GetFileSetsPropertyName(const std::string& type)
|
||||
if (type == "HEADERS") {
|
||||
return "HEADER_SETS";
|
||||
}
|
||||
if (type == "CXX_MODULES") {
|
||||
return "CXX_MODULE_SETS";
|
||||
}
|
||||
if (type == "CXX_MODULE_HEADER_UNITS") {
|
||||
return "CXX_MODULE_HEADER_UNIT_SETS";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -2544,6 +2615,12 @@ std::string cmTarget::GetInterfaceFileSetsPropertyName(const std::string& type)
|
||||
if (type == "HEADERS") {
|
||||
return "INTERFACE_HEADER_SETS";
|
||||
}
|
||||
if (type == "CXX_MODULES") {
|
||||
return "INTERFACE_CXX_MODULE_SETS";
|
||||
}
|
||||
if (type == "CXX_MODULE_HEADER_UNITS") {
|
||||
return "INTERFACE_CXX_MODULE_HEADER_UNIT_SETS";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -2571,6 +2648,8 @@ std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const
|
||||
};
|
||||
|
||||
appendEntries(this->impl->HeadersFileSets.InterfaceEntries.Entries);
|
||||
appendEntries(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
|
||||
appendEntries(this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -275,8 +275,12 @@ public:
|
||||
cmBTStringRange GetLinkInterfaceDirectExcludeEntries() const;
|
||||
|
||||
cmBTStringRange GetHeaderSetsEntries() const;
|
||||
cmBTStringRange GetCxxModuleSetsEntries() const;
|
||||
cmBTStringRange GetCxxModuleHeaderSetsEntries() const;
|
||||
|
||||
cmBTStringRange GetInterfaceHeaderSetsEntries() const;
|
||||
cmBTStringRange GetInterfaceCxxModuleSetsEntries() const;
|
||||
cmBTStringRange GetInterfaceCxxModuleHeaderSetsEntries() const;
|
||||
|
||||
std::string ImportedGetFullPath(const std::string& config,
|
||||
cmStateEnums::ArtifactType artifact) const;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
#include "cmExperimental.h"
|
||||
#include "cmFileSet.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmListFileCache.h"
|
||||
@@ -256,9 +257,30 @@ bool TargetSourcesImpl::HandleOneFileSet(
|
||||
this->SetError("Must specify a TYPE when creating file set");
|
||||
return false;
|
||||
}
|
||||
if (type != "HEADERS"_s) {
|
||||
this->SetError("File set TYPE may only be \"HEADERS\"");
|
||||
return false;
|
||||
bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
|
||||
*this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
|
||||
|
||||
if (supportCxx20FileSetTypes) {
|
||||
if (type != "HEADERS"_s && type != "CXX_MODULES"_s &&
|
||||
type != "CXX_MODULE_HEADER_UNITS"_s) {
|
||||
this->SetError(
|
||||
R"(File set TYPE may only be "HEADERS", "CXX_MODULES", or "CXX_MODULE_HEADER_UNITS")");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cmFileSetVisibilityIsForInterface(visibility) &&
|
||||
!cmFileSetVisibilityIsForSelf(visibility)) {
|
||||
if (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
|
||||
this->SetError(
|
||||
R"(File set TYPEs "CXX_MODULES" and "CXX_MODULE_HEADER_UNITS" may not have "INTERFACE" visibility)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (type != "HEADERS"_s) {
|
||||
this->SetError("File set TYPE may only be \"HEADERS\"");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.BaseDirs.empty()) {
|
||||
@@ -294,7 +316,7 @@ bool TargetSourcesImpl::HandleOneFileSet(
|
||||
if (!baseDirectories.empty()) {
|
||||
fileSet.first->AddDirectoryEntry(
|
||||
BT<std::string>(baseDirectories, this->Makefile->GetBacktrace()));
|
||||
if (type == "HEADERS"_s) {
|
||||
if (type == "HEADERS"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
|
||||
for (auto const& dir : cmExpandedList(baseDirectories)) {
|
||||
auto interfaceDirectoriesGenex =
|
||||
cmStrCat("$<BUILD_INTERFACE:", dir, ">");
|
||||
|
||||
@@ -347,6 +347,18 @@ std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString(
|
||||
|
||||
void cmVisualStudio10TargetGenerator::Generate()
|
||||
{
|
||||
for (std::string const& config : this->Configurations) {
|
||||
this->GeneratorTarget->CheckCxxModuleStatus(config);
|
||||
}
|
||||
|
||||
if (this->GeneratorTarget->HaveCxx20ModuleSources()) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("The \"", this->GeneratorTarget->GetName(),
|
||||
"\" target contains C++ module sources which are not supported "
|
||||
"by the generator"));
|
||||
}
|
||||
|
||||
this->ProjectType = this->ComputeProjectType(this->GeneratorTarget);
|
||||
this->Managed = this->ProjectType == VsProjectType::csproj;
|
||||
const std::string ProjectFileExtension =
|
||||
|
||||
Reference in New Issue
Block a user