mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-01 19:30:13 -06:00
target_sources(): Add FILE_SET mode
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user