target_sources(): Add FILE_SET mode

This commit is contained in:
Kyle Edwards
2021-08-27 16:41:36 -04:00
parent f2bd022468
commit d8af2d954f
3 changed files with 169 additions and 5 deletions

View File

@@ -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)
{

View File

@@ -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;
};

View File

@@ -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,