|
|
@@ -14,11 +14,13 @@
|
|
|
|
|
|
#include <cm/memory>
|
|
|
#include <cmext/algorithm>
|
|
|
+#include <cmext/string_view>
|
|
|
|
|
|
#include "cmsys/RegularExpression.hxx"
|
|
|
|
|
|
#include "cmAlgorithms.h"
|
|
|
#include "cmCustomCommand.h"
|
|
|
+#include "cmFileSet.h"
|
|
|
#include "cmGeneratorExpression.h"
|
|
|
#include "cmGeneratorTarget.h"
|
|
|
#include "cmGlobalGenerator.h"
|
|
|
@@ -200,8 +202,11 @@ public:
|
|
|
std::vector<BT<std::string>> LinkOptionsEntries;
|
|
|
std::vector<BT<std::string>> LinkDirectoriesEntries;
|
|
|
std::vector<BT<std::string>> LinkImplementationPropertyEntries;
|
|
|
+ std::vector<BT<std::string>> HeaderSetsEntries;
|
|
|
+ std::vector<BT<std::string>> InterfaceHeaderSetsEntries;
|
|
|
std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
|
|
|
TLLCommands;
|
|
|
+ std::map<std::string, cmFileSet> FileSets;
|
|
|
cmListFileBacktrace Backtrace;
|
|
|
|
|
|
bool CheckImportedLibName(std::string const& prop,
|
|
|
@@ -1110,6 +1115,16 @@ cmBTStringRange cmTarget::GetLinkImplementationEntries() const
|
|
|
return cmMakeRange(this->impl->LinkImplementationPropertyEntries);
|
|
|
}
|
|
|
|
|
|
+cmBTStringRange cmTarget::GetHeaderSetsEntries() const
|
|
|
+{
|
|
|
+ return cmMakeRange(this->impl->HeaderSetsEntries);
|
|
|
+}
|
|
|
+
|
|
|
+cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const
|
|
|
+{
|
|
|
+ return cmMakeRange(this->impl->InterfaceHeaderSetsEntries);
|
|
|
+}
|
|
|
+
|
|
|
namespace {
|
|
|
#define MAKE_PROP(PROP) const std::string prop##PROP = #PROP
|
|
|
MAKE_PROP(C_STANDARD);
|
|
|
@@ -1139,6 +1154,10 @@ MAKE_PROP(BINARY_DIR);
|
|
|
MAKE_PROP(SOURCE_DIR);
|
|
|
MAKE_PROP(FALSE);
|
|
|
MAKE_PROP(TRUE);
|
|
|
+MAKE_PROP(HEADER_DIRS);
|
|
|
+MAKE_PROP(HEADER_SET);
|
|
|
+MAKE_PROP(HEADER_SETS);
|
|
|
+MAKE_PROP(INTERFACE_HEADER_SETS);
|
|
|
#undef MAKE_PROP
|
|
|
}
|
|
|
|
|
|
@@ -1158,6 +1177,21 @@ std::string ConvertToString<cmValue>(cmValue value)
|
|
|
{
|
|
|
return std::string(*value);
|
|
|
}
|
|
|
+
|
|
|
+template <typename ValueType>
|
|
|
+bool StringIsEmpty(ValueType value);
|
|
|
+
|
|
|
+template <>
|
|
|
+bool StringIsEmpty<const char*>(const char* value)
|
|
|
+{
|
|
|
+ return cmValue::IsEmpty(value);
|
|
|
+}
|
|
|
+
|
|
|
+template <>
|
|
|
+bool StringIsEmpty<cmValue>(cmValue value)
|
|
|
+{
|
|
|
+ return value.IsEmpty();
|
|
|
+}
|
|
|
}
|
|
|
|
|
|
template <typename ValueType>
|
|
|
@@ -1321,6 +1355,104 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value)
|
|
|
} else {
|
|
|
this->impl->LanguageStandardProperties.erase(prop);
|
|
|
}
|
|
|
+ } else if (prop == propHEADER_DIRS) {
|
|
|
+ auto* fileSet = this->GetFileSet("HEADERS");
|
|
|
+ if (!fileSet) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ "The default header set has not yet been created.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileSet->ClearDirectoryEntries();
|
|
|
+ if (!StringIsEmpty(value)) {
|
|
|
+ fileSet->AddDirectoryEntry(
|
|
|
+ BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
|
|
|
+ }
|
|
|
+ } else if (prop == propHEADER_SET) {
|
|
|
+ auto* fileSet = this->GetFileSet("HEADERS");
|
|
|
+ if (!fileSet) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ "The default header set has not yet been created.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileSet->ClearFileEntries();
|
|
|
+ if (!StringIsEmpty(value)) {
|
|
|
+ fileSet->AddFileEntry(
|
|
|
+ BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
|
|
|
+ }
|
|
|
+ } else if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) {
|
|
|
+ auto fileSetName = prop.substr(cmStrLen("HEADER_DIRS_"));
|
|
|
+ if (fileSetName.empty()) {
|
|
|
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
|
|
|
+ "Header set name cannot be empty.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ auto* fileSet = this->GetFileSet(fileSetName);
|
|
|
+ if (!fileSet) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat("Header set \"", fileSetName,
|
|
|
+ "\" has not yet been created."));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileSet->ClearDirectoryEntries();
|
|
|
+ if (!StringIsEmpty(value)) {
|
|
|
+ fileSet->AddDirectoryEntry(
|
|
|
+ BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
|
|
|
+ }
|
|
|
+ } else if (cmHasLiteralPrefix(prop, "HEADER_SET_")) {
|
|
|
+ auto fileSetName = prop.substr(cmStrLen("HEADER_SET_"));
|
|
|
+ if (fileSetName.empty()) {
|
|
|
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
|
|
|
+ "Header set name cannot be empty.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ auto* fileSet = this->GetFileSet(fileSetName);
|
|
|
+ if (!fileSet) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat("Header set \"", fileSetName,
|
|
|
+ "\" has not yet been created."));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileSet->ClearFileEntries();
|
|
|
+ if (!StringIsEmpty(value)) {
|
|
|
+ fileSet->AddFileEntry(
|
|
|
+ BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
|
|
|
+ }
|
|
|
+ } else if (prop == propHEADER_SETS) {
|
|
|
+ if (value) {
|
|
|
+ for (auto const& name : cmExpandedList(value)) {
|
|
|
+ if (!this->GetFileSet(name)) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat("Header set \"", name, "\" has not yet been created."));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this->impl->HeaderSetsEntries.clear();
|
|
|
+ if (!StringIsEmpty(value)) {
|
|
|
+ this->impl->HeaderSetsEntries.emplace_back(
|
|
|
+ value, this->impl->Makefile->GetBacktrace());
|
|
|
+ }
|
|
|
+ } else if (prop == propINTERFACE_HEADER_SETS) {
|
|
|
+ if (value) {
|
|
|
+ for (auto const& name : cmExpandedList(value)) {
|
|
|
+ if (!this->GetFileSet(name)) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat("Header set \"", name, "\" has not yet been created."));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this->impl->InterfaceHeaderSetsEntries.clear();
|
|
|
+ if (!StringIsEmpty(value)) {
|
|
|
+ this->impl->InterfaceHeaderSetsEntries.emplace_back(
|
|
|
+ value, this->impl->Makefile->GetBacktrace());
|
|
|
+ }
|
|
|
} else {
|
|
|
this->impl->Properties.SetProperty(prop, value);
|
|
|
}
|
|
|
@@ -1415,6 +1547,82 @@ void cmTarget::AppendProperty(const std::string& prop,
|
|
|
prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") {
|
|
|
this->impl->Makefile->IssueMessage(
|
|
|
MessageType::FATAL_ERROR, prop + " property may not be appended.");
|
|
|
+ } else if (prop == "HEADER_DIRS") {
|
|
|
+ auto* fileSet = this->GetFileSet("HEADERS");
|
|
|
+ if (!fileSet) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ "The default header set has not yet been created.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileSet->AddDirectoryEntry(
|
|
|
+ BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
|
|
|
+ } else if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) {
|
|
|
+ auto fileSetName = prop.substr(cmStrLen("HEADER_DIRS_"));
|
|
|
+ if (fileSetName.empty()) {
|
|
|
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
|
|
|
+ "Header set name cannot be empty.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ auto* fileSet = this->GetFileSet(fileSetName);
|
|
|
+ if (!fileSet) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat("Header set \"", fileSetName,
|
|
|
+ "\" has not yet been created."));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileSet->AddDirectoryEntry(
|
|
|
+ BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
|
|
|
+ } else if (prop == "HEADER_SET") {
|
|
|
+ auto* fileSet = this->GetFileSet("HEADERS");
|
|
|
+ if (!fileSet) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ "The default header set has not yet been created.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileSet->AddFileEntry(
|
|
|
+ BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
|
|
|
+ } else if (cmHasLiteralPrefix(prop, "HEADER_SET_")) {
|
|
|
+ auto fileSetName = prop.substr(cmStrLen("HEADER_SET_"));
|
|
|
+ if (fileSetName.empty()) {
|
|
|
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
|
|
|
+ "Header set name cannot be empty.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ auto* fileSet = this->GetFileSet(fileSetName);
|
|
|
+ if (!fileSet) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat("Header set \"", fileSetName,
|
|
|
+ "\" has not yet been created."));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fileSet->AddFileEntry(
|
|
|
+ BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
|
|
|
+ } else if (prop == "HEADER_SETS") {
|
|
|
+ for (auto const& name : cmExpandedList(value)) {
|
|
|
+ if (!this->GetFileSet(name)) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat("Header set \"", name, "\" has not yet been created."));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this->impl->HeaderSetsEntries.emplace_back(
|
|
|
+ value, this->impl->Makefile->GetBacktrace());
|
|
|
+ } else if (prop == "INTERFACE_HEADER_SETS") {
|
|
|
+ for (auto const& name : cmExpandedList(value)) {
|
|
|
+ if (!this->GetFileSet(name)) {
|
|
|
+ this->impl->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat("Header set \"", name, "\" has not yet been created."));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this->impl->InterfaceHeaderSetsEntries.emplace_back(
|
|
|
+ value, this->impl->Makefile->GetBacktrace());
|
|
|
} else {
|
|
|
this->impl->Properties.AppendProperty(prop, value, asString);
|
|
|
}
|
|
|
@@ -1633,7 +1841,11 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
|
|
|
propNAME,
|
|
|
propBINARY_DIR,
|
|
|
propSOURCE_DIR,
|
|
|
- propSOURCES
|
|
|
+ propSOURCES,
|
|
|
+ propHEADER_DIRS,
|
|
|
+ propHEADER_SET,
|
|
|
+ propHEADER_SETS,
|
|
|
+ propINTERFACE_HEADER_SETS,
|
|
|
};
|
|
|
if (specialProps.count(prop)) {
|
|
|
if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
|
|
|
@@ -1759,6 +1971,60 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
|
|
|
.GetDirectory()
|
|
|
.GetCurrentSource());
|
|
|
}
|
|
|
+ if (prop == propHEADER_DIRS) {
|
|
|
+ auto const* fileSet = this->GetFileSet("HEADERS");
|
|
|
+ if (!fileSet) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ static std::string output;
|
|
|
+ output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s);
|
|
|
+ return cmValue(output);
|
|
|
+ }
|
|
|
+ if (prop == propHEADER_SET) {
|
|
|
+ auto const* fileSet = this->GetFileSet("HEADERS");
|
|
|
+ if (!fileSet) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ static std::string output;
|
|
|
+ output = cmJoin(fileSet->GetFileEntries(), ";"_s);
|
|
|
+ return cmValue(output);
|
|
|
+ }
|
|
|
+ if (prop == propHEADER_SETS) {
|
|
|
+ static std::string output;
|
|
|
+ output = cmJoin(this->impl->HeaderSetsEntries, ";"_s);
|
|
|
+ return cmValue(output);
|
|
|
+ }
|
|
|
+ if (prop == propINTERFACE_HEADER_SETS) {
|
|
|
+ static std::string output;
|
|
|
+ output = cmJoin(this->impl->InterfaceHeaderSetsEntries, ";"_s);
|
|
|
+ return cmValue(output);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) {
|
|
|
+ std::string fileSetName = prop.substr(cmStrLen("HEADER_DIRS_"));
|
|
|
+ if (fileSetName.empty()) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ auto const* fileSet = this->GetFileSet(fileSetName);
|
|
|
+ if (!fileSet) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ static std::string output;
|
|
|
+ output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s);
|
|
|
+ return cmValue(output);
|
|
|
+ }
|
|
|
+ if (cmHasLiteralPrefix(prop, "HEADER_SET_")) {
|
|
|
+ std::string fileSetName = prop.substr(cmStrLen("HEADER_SET_"));
|
|
|
+ if (fileSetName.empty()) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ auto const* fileSet = this->GetFileSet(fileSetName);
|
|
|
+ if (!fileSet) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ static std::string output;
|
|
|
+ output = cmJoin(fileSet->GetFileEntries(), ";"_s);
|
|
|
+ return cmValue(output);
|
|
|
}
|
|
|
|
|
|
cmValue retVal = this->impl->Properties.GetPropertyValue(prop);
|
|
|
@@ -2015,6 +2281,59 @@ std::string cmTarget::ImportedGetFullPath(
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+const cmFileSet* cmTarget::GetFileSet(const std::string& name) const
|
|
|
+{
|
|
|
+ auto it = this->impl->FileSets.find(name);
|
|
|
+ return it == this->impl->FileSets.end() ? nullptr : &it->second;
|
|
|
+}
|
|
|
+
|
|
|
+cmFileSet* cmTarget::GetFileSet(const std::string& name)
|
|
|
+{
|
|
|
+ auto it = this->impl->FileSets.find(name);
|
|
|
+ return it == this->impl->FileSets.end() ? nullptr : &it->second;
|
|
|
+}
|
|
|
+
|
|
|
+std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
|
|
|
+ const std::string& name, const std::string& type)
|
|
|
+{
|
|
|
+ auto result =
|
|
|
+ this->impl->FileSets.emplace(std::make_pair(name, cmFileSet(name, type)));
|
|
|
+ return std::make_pair(&result.first->second, result.second);
|
|
|
+}
|
|
|
+
|
|
|
+std::string cmTarget::GetFileSetsPropertyName(const std::string& type)
|
|
|
+{
|
|
|
+ if (type == "HEADERS") {
|
|
|
+ return "HEADER_SETS";
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+}
|
|
|
+
|
|
|
+std::string cmTarget::GetInterfaceFileSetsPropertyName(const std::string& type)
|
|
|
+{
|
|
|
+ if (type == "HEADERS") {
|
|
|
+ return "INTERFACE_HEADER_SETS";
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+}
|
|
|
+
|
|
|
+std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const
|
|
|
+{
|
|
|
+ std::vector<std::string> result;
|
|
|
+ auto inserter = std::back_inserter(result);
|
|
|
+
|
|
|
+ auto appendEntries = [=](const std::vector<BT<std::string>>& entries) {
|
|
|
+ for (auto const& entry : entries) {
|
|
|
+ auto expanded = cmExpandedList(entry.Value);
|
|
|
+ std::copy(expanded.begin(), expanded.end(), inserter);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ appendEntries(this->impl->InterfaceHeaderSetsEntries);
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
|
|
|
std::string const& value) const
|
|
|
{
|