diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2021-08-27 20:41:36 (GMT) |
---|---|---|
committer | Kyle Edwards <kyle.edwards@kitware.com> | 2021-10-27 19:17:23 (GMT) |
commit | d8af2d954f8619f0e8bc42252d310085dec94df4 (patch) | |
tree | 7305103f3b2efcdafccca1d687c4a925a2b86e83 /Source | |
parent | f2bd02246830617c3dec5b517821f14a9aa3453c (diff) | |
download | CMake-d8af2d954f8619f0e8bc42252d310085dec94df4.zip CMake-d8af2d954f8619f0e8bc42252d310085dec94df4.tar.gz CMake-d8af2d954f8619f0e8bc42252d310085dec94df4.tar.bz2 |
target_sources(): Add FILE_SET mode
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmTargetPropCommandBase.cxx | 4 | ||||
-rw-r--r-- | Source/cmTargetPropCommandBase.h | 6 | ||||
-rw-r--r-- | Source/cmTargetSourcesCommand.cxx | 164 |
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, |