summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/cmTargetPropCommandBase.cxx4
-rw-r--r--Source/cmTargetPropCommandBase.h6
-rw-r--r--Source/cmTargetSourcesCommand.cxx164
3 files changed, 169 insertions, 5 deletions
diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx
index 3bd1ea3..391b954 100644
--- a/Source/cmTargetPropCommandBase.cxx
+++ b/Source/cmTargetPropCommandBase.cxx
@@ -155,10 +155,10 @@ bool cmTargetPropCommandBase::ProcessContentArgs(
return false;
}
}
- return this->PopulateTargetProperies(scope, content, prepend, system);
+ return this->PopulateTargetProperties(scope, content, prepend, system);
}
-bool cmTargetPropCommandBase::PopulateTargetProperies(
+bool cmTargetPropCommandBase::PopulateTargetProperties(
const std::string& scope, const std::vector<std::string>& content,
bool prepend, bool system)
{
diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h
index fc24fe8..6bf7c3c 100644
--- a/Source/cmTargetPropCommandBase.h
+++ b/Source/cmTargetPropCommandBase.h
@@ -40,6 +40,9 @@ protected:
virtual void HandleInterfaceContent(cmTarget* tgt,
const std::vector<std::string>& content,
bool prepend, bool system);
+ virtual bool PopulateTargetProperties(
+ const std::string& scope, const std::vector<std::string>& content,
+ bool prepend, bool system);
private:
virtual void HandleMissingTarget(const std::string& name) = 0;
@@ -52,9 +55,6 @@ private:
bool ProcessContentArgs(std::vector<std::string> const& args,
unsigned int& argIndex, bool prepend, bool system);
- bool PopulateTargetProperies(const std::string& scope,
- const std::vector<std::string>& content,
- bool prepend, bool system);
cmExecutionStatus& Status;
};
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index 88841bc..818e271 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -2,9 +2,17 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTargetSourcesCommand.h"
+#include <algorithm>
#include <sstream>
+#include <utility>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h"
+#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
@@ -15,6 +23,20 @@
namespace {
+struct FileSetArgs
+{
+ std::string Type;
+ std::string FileSet;
+ std::vector<std::string> BaseDirs;
+ std::vector<std::string> Files;
+};
+
+auto const FileSetArgsParser = cmArgumentParser<FileSetArgs>()
+ .Bind("TYPE"_s, &FileSetArgs::Type)
+ .Bind("FILE_SET"_s, &FileSetArgs::FileSet)
+ .Bind("BASE_DIRS"_s, &FileSetArgs::BaseDirs)
+ .Bind("FILES"_s, &FileSetArgs::Files);
+
class TargetSourcesImpl : public cmTargetPropCommandBase
{
public:
@@ -51,6 +73,17 @@ private:
return true; // Successfully handled.
}
+ bool PopulateTargetProperties(const std::string& scope,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) override
+ {
+ if (!content.empty() && content.front() == "FILE_SET"_s) {
+ return this->HandleFileSetMode(scope, content, prepend, system);
+ }
+ return this->cmTargetPropCommandBase::PopulateTargetProperties(
+ scope, content, prepend, system);
+ }
+
std::string Join(const std::vector<std::string>& content) override
{
return cmJoin(content, ";");
@@ -69,6 +102,10 @@ private:
std::vector<std::string> ConvertToAbsoluteContent(
cmTarget* tgt, const std::vector<std::string>& content,
IsInterface isInterfaceContent, CheckCMP0076 checkCmp0076);
+
+ bool HandleFileSetMode(const std::string& scope,
+ const std::vector<std::string>& content, bool prepend,
+ bool system);
};
std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent(
@@ -147,6 +184,133 @@ std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent(
return useAbsoluteContent ? absoluteContent : content;
}
+bool TargetSourcesImpl::HandleFileSetMode(
+ const std::string& scope, const std::vector<std::string>& content,
+ bool /*prepend*/, bool /*system*/)
+{
+ std::vector<std::string> unparsed;
+ auto args = FileSetArgsParser.Parse(content, &unparsed);
+
+ if (!unparsed.empty()) {
+ this->SetError(
+ cmStrCat("Unrecognized keyword: \"", unparsed.front(), "\""));
+ return false;
+ }
+
+ if (args.FileSet.empty()) {
+ this->SetError("FILE_SET must not be empty");
+ return false;
+ }
+
+ bool const isDefault = args.Type == args.FileSet ||
+ (args.Type.empty() && args.FileSet[0] >= 'A' && args.FileSet[0] <= 'Z');
+ std::string type = isDefault ? args.FileSet : args.Type;
+
+ auto fileSet = this->Target->GetOrCreateFileSet(args.FileSet, type);
+ if (fileSet.second) {
+ if (!isDefault) {
+ if (args.FileSet[0] >= 'A' && args.FileSet[0] <= 'Z') {
+ this->SetError(
+ "Non-default file set name must not start with a capital letter");
+ return false;
+ }
+ }
+ if (type.empty()) {
+ 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;
+ }
+
+ if (args.BaseDirs.empty()) {
+ args.BaseDirs.emplace_back(this->Makefile->GetCurrentSourceDirectory());
+ }
+
+ if (scope == "PRIVATE"_s || scope == "PUBLIC"_s) {
+ this->Target->AppendProperty(cmTarget::GetFileSetsPropertyName(type),
+ args.FileSet);
+ }
+ if (scope == "INTERFACE"_s || scope == "PUBLIC"_s) {
+ this->Target->AppendProperty(
+ cmTarget::GetInterfaceFileSetsPropertyName(type), args.FileSet);
+ }
+ } else {
+ type = fileSet.first->GetType();
+ if (!args.Type.empty() && args.Type != type) {
+ this->SetError(cmStrCat(
+ "Type \"", args.Type, "\" for file set \"", fileSet.first->GetName(),
+ "\" does not match original type \"", type, "\""));
+ return false;
+ }
+
+ std::string existingScope = "PRIVATE";
+
+ auto const fileSetsProperty = cmTarget::GetFileSetsPropertyName(type);
+ auto const interfaceFileSetsProperty =
+ cmTarget::GetInterfaceFileSetsPropertyName(type);
+ std::vector<std::string> fileSets;
+ std::vector<std::string> interfaceFileSets;
+ cmExpandList(this->Target->GetSafeProperty(fileSetsProperty), fileSets);
+ cmExpandList(this->Target->GetSafeProperty(interfaceFileSetsProperty),
+ interfaceFileSets);
+
+ if (std::find(interfaceFileSets.begin(), interfaceFileSets.end(),
+ args.FileSet) != interfaceFileSets.end()) {
+ existingScope = "INTERFACE";
+ }
+ if (std::find(fileSets.begin(), fileSets.end(), args.FileSet) !=
+ fileSets.end()) {
+ if (existingScope == "INTERFACE"_s) {
+ existingScope = "PUBLIC";
+ }
+ } else if (existingScope != "INTERFACE"_s) {
+ this->SetError(cmStrCat("File set \"", args.FileSet, "\" is not in ",
+ fileSetsProperty, " or ",
+ interfaceFileSetsProperty));
+ return false;
+ }
+
+ if (scope != existingScope) {
+ this->SetError(
+ cmStrCat("Scope ", scope, " for file set \"", args.FileSet,
+ "\" does not match original scope ", existingScope));
+ return false;
+ }
+ }
+
+ auto files = this->Join(this->ConvertToAbsoluteContent(
+ this->Target, args.Files, IsInterface::Yes, CheckCMP0076::No));
+ if (!files.empty()) {
+ fileSet.first->AddFileEntry(
+ BT<std::string>(files, this->Makefile->GetBacktrace()));
+ }
+
+ auto baseDirectories = this->Join(this->ConvertToAbsoluteContent(
+ this->Target, args.BaseDirs, IsInterface::Yes, CheckCMP0076::No));
+ if (!baseDirectories.empty()) {
+ fileSet.first->AddDirectoryEntry(
+ BT<std::string>(baseDirectories, this->Makefile->GetBacktrace()));
+ if (type == "HEADERS"_s) {
+ for (auto const& dir : cmExpandedList(baseDirectories)) {
+ auto interfaceDirectoriesGenex =
+ cmStrCat("$<BUILD_INTERFACE:", dir, ">");
+ if (scope == "PRIVATE"_s || scope == "PUBLIC"_s) {
+ this->Target->AppendProperty("INCLUDE_DIRECTORIES",
+ interfaceDirectoriesGenex);
+ }
+ if (scope == "INTERFACE"_s || scope == "PUBLIC"_s) {
+ this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
+ interfaceDirectoriesGenex);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
} // namespace
bool cmTargetSourcesCommand(std::vector<std::string> const& args,