diff options
Diffstat (limited to 'Source/cmTarget.cxx')
-rw-r--r-- | Source/cmTarget.cxx | 776 |
1 files changed, 491 insertions, 285 deletions
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 57e31b9..80d1940 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -13,6 +13,7 @@ #include <unordered_set> #include <cm/memory> +#include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -164,6 +165,66 @@ cmValue cmTargetPropertyComputer::GetSources<cmTarget>(cmTarget const* tgt, return cmValue(srcs); } +namespace { +struct FileSetEntries +{ + FileSetEntries(cm::static_string_view propertyName) + : PropertyName(propertyName) + { + } + + cm::static_string_view const PropertyName; + std::vector<BT<std::string>> Entries; +}; + +struct FileSetType +{ + FileSetType(cm::static_string_view typeName, + cm::static_string_view defaultDirectoryProperty, + cm::static_string_view defaultPathProperty, + cm::static_string_view directoryPrefix, + cm::static_string_view pathPrefix, + cm::static_string_view typeDescription, + cm::static_string_view defaultDescription, + cm::static_string_view arbitraryDescription, + FileSetEntries selfEntries, FileSetEntries interfaceEntries) + : TypeName(typeName) + , DefaultDirectoryProperty(defaultDirectoryProperty) + , DefaultPathProperty(defaultPathProperty) + , DirectoryPrefix(directoryPrefix) + , PathPrefix(pathPrefix) + , TypeDescription(typeDescription) + , DefaultDescription(defaultDescription) + , ArbitraryDescription(arbitraryDescription) + , SelfEntries(std::move(selfEntries)) + , InterfaceEntries(std::move(interfaceEntries)) + { + } + + cm::static_string_view const TypeName; + cm::static_string_view const DefaultDirectoryProperty; + cm::static_string_view const DefaultPathProperty; + cm::static_string_view const DirectoryPrefix; + cm::static_string_view const PathPrefix; + cm::static_string_view const TypeDescription; + cm::static_string_view const DefaultDescription; + cm::static_string_view const ArbitraryDescription; + + FileSetEntries SelfEntries; + FileSetEntries InterfaceEntries; + + template <typename ValueType> + bool WriteProperties(cmTarget* tgt, cmTargetInternals* impl, + const std::string& prop, ValueType value, bool clear); + std::pair<bool, cmValue> ReadProperties(cmTarget const* tgt, + cmTargetInternals const* impl, + const std::string& prop) const; + + void AddFileSet(const std::string& name, cmFileSetVisibility vis, + cmListFileBacktrace bt); +}; +} + class cmTargetInternals { public: @@ -203,19 +264,154 @@ public: std::vector<BT<std::string>> LinkDirectoriesEntries; std::vector<BT<std::string>> LinkImplementationPropertyEntries; std::vector<BT<std::string>> LinkInterfacePropertyEntries; - std::vector<BT<std::string>> HeaderSetsEntries; - std::vector<BT<std::string>> InterfaceHeaderSetsEntries; + std::vector<BT<std::string>> LinkInterfaceDirectPropertyEntries; + std::vector<BT<std::string>> LinkInterfaceDirectExcludePropertyEntries; std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>> TLLCommands; std::map<std::string, cmFileSet> FileSets; cmListFileBacktrace Backtrace; + FileSetType HeadersFileSets; + + cmTargetInternals(); + bool CheckImportedLibName(std::string const& prop, std::string const& value) const; std::string ProcessSourceItemCMP0049(const std::string& s) const; + + template <typename ValueType> + void AddDirectoryToFileSet(cmTarget* self, std::string const& fileSetName, + ValueType value, cm::string_view fileSetType, + cm::string_view description, bool clear); + template <typename ValueType> + void AddPathToFileSet(cmTarget* self, std::string const& fileSetName, + ValueType value, cm::string_view fileSetType, + cm::string_view description, bool clear); + cmValue GetFileSetDirectories(cmTarget const* self, + std::string const& fileSetName, + cm::string_view fileSetType) const; + cmValue GetFileSetPaths(cmTarget const* self, std::string const& fileSetName, + cm::string_view fileSetType) const; }; +cmTargetInternals::cmTargetInternals() + : HeadersFileSets("HEADERS"_s, "HEADER_DIRS"_s, "HEADER_SET"_s, + "HEADER_DIRS_"_s, "HEADER_SET_"_s, "Header"_s, + "The default header set"_s, "Header set"_s, + FileSetEntries("HEADER_SETS"_s), + FileSetEntries("INTERFACE_HEADER_SETS"_s)) +{ +} + +template <typename ValueType> +bool FileSetType::WriteProperties(cmTarget* tgt, cmTargetInternals* impl, + const std::string& prop, ValueType value, + bool clear) +{ + if (prop == this->DefaultDirectoryProperty) { + impl->AddDirectoryToFileSet(tgt, std::string(this->TypeName), value, + this->TypeName, this->DefaultDescription, + clear); + return true; + } + if (prop == this->DefaultPathProperty) { + impl->AddPathToFileSet(tgt, std::string(this->TypeName), value, + this->TypeName, this->DefaultDescription, clear); + return true; + } + if (cmHasPrefix(prop, this->DirectoryPrefix)) { + auto fileSetName = prop.substr(this->DirectoryPrefix.size()); + if (fileSetName.empty()) { + impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->ArbitraryDescription, " name cannot be empty.")); + } else { + impl->AddDirectoryToFileSet( + tgt, fileSetName, value, this->TypeName, + cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""), clear); + } + return true; + } + if (cmHasPrefix(prop, this->PathPrefix)) { + auto fileSetName = prop.substr(this->PathPrefix.size()); + if (fileSetName.empty()) { + impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->ArbitraryDescription, " name cannot be empty.")); + } else { + impl->AddPathToFileSet( + tgt, fileSetName, value, this->TypeName, + cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""), clear); + } + return true; + } + if (prop == this->SelfEntries.PropertyName) { + impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->SelfEntries.PropertyName, " property is read-only\n")); + return true; + } + if (prop == this->InterfaceEntries.PropertyName) { + impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat(this->InterfaceEntries.PropertyName, + " property is read-only\n")); + return true; + } + return false; +} + +std::pair<bool, cmValue> FileSetType::ReadProperties( + cmTarget const* tgt, cmTargetInternals const* impl, + const std::string& prop) const +{ + bool did_read = false; + cmValue value = nullptr; + if (prop == this->DefaultDirectoryProperty) { + value = impl->GetFileSetDirectories(tgt, std::string(this->TypeName), + this->TypeName); + did_read = true; + } else if (prop == this->DefaultPathProperty) { + value = + impl->GetFileSetPaths(tgt, std::string(this->TypeName), this->TypeName); + did_read = true; + } else if (prop == this->SelfEntries.PropertyName) { + static std::string output; + output = cmJoin(this->SelfEntries.Entries, ";"_s); + value = cmValue(output); + did_read = true; + } else if (prop == this->InterfaceEntries.PropertyName) { + static std::string output; + output = cmJoin(this->InterfaceEntries.Entries, ";"_s); + value = cmValue(output); + did_read = true; + } else if (cmHasPrefix(prop, this->DirectoryPrefix)) { + std::string fileSetName = prop.substr(this->DirectoryPrefix.size()); + if (!fileSetName.empty()) { + value = impl->GetFileSetDirectories(tgt, fileSetName, this->TypeName); + } + did_read = true; + } else if (cmHasPrefix(prop, this->PathPrefix)) { + std::string fileSetName = prop.substr(this->PathPrefix.size()); + if (!fileSetName.empty()) { + value = impl->GetFileSetPaths(tgt, fileSetName, this->TypeName); + } + did_read = true; + } + return { did_read, value }; +} + +void FileSetType::AddFileSet(const std::string& name, cmFileSetVisibility vis, + cmListFileBacktrace bt) +{ + if (cmFileSetVisibilityIsForSelf(vis)) { + this->SelfEntries.Entries.emplace_back(name, bt); + } + if (cmFileSetVisibilityIsForInterface(vis)) { + this->InterfaceEntries.Entries.emplace_back(name, std::move(bt)); + } +} + namespace { #define SETUP_COMMON_LANGUAGE_PROPERTIES(lang) \ initProp(#lang "_COMPILER_LAUNCHER"); \ @@ -347,6 +543,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("LINK_DEPENDS_NO_SHARED"); initProp("LINK_INTERFACE_LIBRARIES"); initProp("MSVC_RUNTIME_LIBRARY"); + initProp("WATCOM_RUNTIME_LIBRARY"); initProp("WIN32_EXECUTABLE"); initProp("MACOSX_BUNDLE"); initProp("MACOSX_RPATH"); @@ -391,6 +588,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("UNITY_BUILD_UNIQUE_ID"); initProp("OPTIMIZE_DEPENDENCIES"); initProp("EXPORT_COMPILE_COMMANDS"); + initProp("COMPILE_WARNING_AS_ERROR"); initPropValue("UNITY_BUILD_BATCH_SIZE", "8"); initPropValue("UNITY_BUILD_MODE", "BATCH"); initPropValue("PCH_WARN_INVALID", "ON"); @@ -423,6 +621,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, } initProp("FOLDER"); + initProp("VERIFY_HEADER_SETS"); if (this->GetGlobalGenerator()->IsXcode()) { initProp("XCODE_GENERATE_SCHEME"); @@ -688,6 +887,11 @@ bool cmTarget::IsAndroidGuiExecutable() const this->impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")); } +bool cmTarget::HasKnownObjectFileLocation(std::string* reason) const +{ + return this->GetGlobalGenerator()->HasKnownObjectFileLocation(*this, reason); +} + std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const { return this->impl->PreBuildCommands; @@ -1089,7 +1293,12 @@ void cmTarget::AddInstallIncludeDirectories(cmTargetExport const& te, cmStringRange cmTarget::GetInstallIncludeDirectoriesEntries( cmTargetExport const& te) const { - return cmMakeRange(this->impl->InstallIncludeDirectoriesEntries[&te]); + auto i = this->impl->InstallIncludeDirectoriesEntries.find(&te); + if (i == this->impl->InstallIncludeDirectoriesEntries.end()) { + decltype(i->second) empty; + return cmMakeRange(empty); + } + return cmMakeRange(i->second); } cmBTStringRange cmTarget::GetIncludeDirectoriesEntries() const @@ -1142,14 +1351,24 @@ cmBTStringRange cmTarget::GetLinkInterfaceEntries() const return cmMakeRange(this->impl->LinkInterfacePropertyEntries); } +cmBTStringRange cmTarget::GetLinkInterfaceDirectEntries() const +{ + return cmMakeRange(this->impl->LinkInterfaceDirectPropertyEntries); +} + +cmBTStringRange cmTarget::GetLinkInterfaceDirectExcludeEntries() const +{ + return cmMakeRange(this->impl->LinkInterfaceDirectExcludePropertyEntries); +} + cmBTStringRange cmTarget::GetHeaderSetsEntries() const { - return cmMakeRange(this->impl->HeaderSetsEntries); + return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries); } cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const { - return cmMakeRange(this->impl->InterfaceHeaderSetsEntries); + return cmMakeRange(this->impl->HeadersFileSets.InterfaceEntries.Entries); } namespace { @@ -1181,11 +1400,9 @@ 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); MAKE_PROP(INTERFACE_LINK_LIBRARIES); +MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT); +MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE); #undef MAKE_PROP } @@ -1207,19 +1424,25 @@ std::string ConvertToString<cmValue>(cmValue value) } template <typename ValueType> -bool StringIsEmpty(ValueType value); +bool StringIsEmpty(ValueType const& value); template <> -bool StringIsEmpty<const char*>(const char* value) +bool StringIsEmpty<const char*>(const char* const& value) { return cmValue::IsEmpty(value); } template <> -bool StringIsEmpty<cmValue>(cmValue value) +bool StringIsEmpty<cmValue>(cmValue const& value) { return value.IsEmpty(); } + +template <> +bool StringIsEmpty<std::string>(std::string const& value) +{ + return value.empty(); +} } template <typename ValueType> @@ -1317,6 +1540,19 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value) cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt); } + } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) { + this->impl->LinkInterfaceDirectPropertyEntries.clear(); + if (value) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt); + } + } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) { + this->impl->LinkInterfaceDirectExcludePropertyEntries.clear(); + if (value) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value, + lfbt); + } } else if (prop == propSOURCES) { this->impl->SourceEntries.clear(); if (value) { @@ -1338,7 +1574,9 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value) } } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") && !this->impl->CheckImportedLibName( - prop, value ? value : std::string{})) { + prop, + value ? value + : std::string{})) { // NOLINT(bugprone-branch-clone) /* error was reported by check method */ } else if (prop == propCUDA_PTX_COMPILATION && this->GetType() != cmStateEnums::OBJECT_LIBRARY) { @@ -1389,81 +1627,9 @@ 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) { - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "HEADER_SETS property is read-only\n"); - return; - } else if (prop == propINTERFACE_HEADER_SETS) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "INTERFACE_HEADER_SETS property is read-only\n"); - return; + } else if (this->impl->HeadersFileSets.WriteProperties( + this, this->impl.get(), prop, value, true)) { + /* Handled in the `if` condition. */ } else { this->impl->Properties.SetProperty(prop, value); } @@ -1552,6 +1718,17 @@ void cmTarget::AppendProperty(const std::string& prop, cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt); } + } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) { + if (!value.empty()) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt); + } + } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) { + if (!value.empty()) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value, + lfbt); + } } else if (prop == "SOURCES") { cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); this->impl->SourceEntries.emplace_back(value, lfbt); @@ -1563,69 +1740,9 @@ 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") { - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "HEADER_SETS property is read-only\n"); - return; - } else if (prop == "INTERFACE_HEADER_SETS") { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "INTERFACE_HEADER_SETS property is read-only\n"); - return; + } else if (this->impl->HeadersFileSets.WriteProperties( + this, this->impl.get(), prop, value, false)) { + /* Handled in the `if` condition. */ } else { this->impl->Properties.AppendProperty(prop, value, asString); } @@ -1640,6 +1757,102 @@ void cmTarget::SetProperty(const std::string& prop, cmValue value) this->StoreProperty(prop, value); } +template <typename ValueType> +void cmTargetInternals::AddDirectoryToFileSet( + cmTarget* self, std::string const& fileSetName, ValueType value, + cm::string_view fileSetType, cm::string_view description, bool clear) +{ + auto* fileSet = self->GetFileSet(fileSetName); + if (!fileSet) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(description, "has not yet been created.")); + return; + } + if (fileSet->GetType() != fileSetType) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is not of type \"", fileSetType, + "\".")); + return; + } + if (clear) { + fileSet->ClearDirectoryEntries(); + } + if (!StringIsEmpty(value)) { + fileSet->AddDirectoryEntry( + BT<std::string>(value, this->Makefile->GetBacktrace())); + } +} + +template <typename ValueType> +void cmTargetInternals::AddPathToFileSet( + cmTarget* self, std::string const& fileSetName, ValueType value, + cm::string_view fileSetType, cm::string_view description, bool clear) +{ + auto* fileSet = self->GetFileSet(fileSetName); + if (!fileSet) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(description, "has not yet been created.")); + return; + } + if (fileSet->GetType() != fileSetType) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is not of type \"", fileSetType, + "\".")); + return; + } + if (clear) { + fileSet->ClearFileEntries(); + } + if (!StringIsEmpty(value)) { + fileSet->AddFileEntry( + BT<std::string>(value, this->Makefile->GetBacktrace())); + } +} + +cmValue cmTargetInternals::GetFileSetDirectories( + cmTarget const* self, std::string const& fileSetName, + cm::string_view fileSetType) const +{ + auto const* fileSet = self->GetFileSet(fileSetName); + if (!fileSet) { + return nullptr; + } + if (fileSet->GetType() != fileSetType) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is not of type \"", fileSetType, + "\".")); + return nullptr; + } + static std::string output; + output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s); + return cmValue(output); +} + +cmValue cmTargetInternals::GetFileSetPaths(cmTarget const* self, + std::string const& fileSetName, + cm::string_view fileSetType) const +{ + auto const* fileSet = self->GetFileSet(fileSetName); + if (!fileSet) { + return nullptr; + } + if (fileSet->GetType() != fileSetType) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is not of type \"", fileSetType, + "\".")); + return nullptr; + } + static std::string output; + output = cmJoin(fileSet->GetFileEntries(), ";"_s); + return cmValue(output); +} + void cmTarget::AppendBuildInterfaceIncludes() { if (this->GetType() != cmStateEnums::SHARED_LIBRARY && @@ -1709,69 +1922,94 @@ void cmTarget::InsertPrecompileHeader(BT<std::string> const& entry) this->impl->PrecompileHeadersEntries.push_back(entry); } -static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop, - const std::string& value, - cmMakefile* context, - bool imported) +namespace { +void CheckLinkLibraryPattern(const std::string& property, + const std::string& value, cmMakefile* context) { - // Look for link-type keywords in the value. - static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)"); - if (!keys.find(value)) { + // Look for <LINK_LIBRARY:> and </LINK_LIBRARY:> internal tags + static cmsys::RegularExpression linkPattern( + "(^|;)(</?LINK_(LIBRARY|GROUP):[^;>]*>)(;|$)"); + if (!linkPattern.find(value)) { return; } + // Report an error. + context->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Property ", property, " contains the invalid item \"", + linkPattern.match(2), "\". The ", property, + " property may contain the generator-expression \"$<LINK_", + linkPattern.match(3), + ":...>\" which may be used to specify how the libraries are linked.")); +} + +void CheckLINK_INTERFACE_LIBRARIES(const std::string& prop, + const std::string& value, + cmMakefile* context, bool imported) +{ // Support imported and non-imported versions of the property. const char* base = (imported ? "IMPORTED_LINK_INTERFACE_LIBRARIES" : "LINK_INTERFACE_LIBRARIES"); - // Report an error. - std::ostringstream e; - e << "Property " << prop << " may not contain link-type keyword \"" - << keys.match(2) << "\". " - << "The " << base << " property has a per-configuration " - << "version called " << base << "_<CONFIG> which may be " - << "used to specify per-configuration rules."; - if (!imported) { - e << " " - << "Alternatively, an IMPORTED library may be created, configured " - << "with a per-configuration location, and then named in the " - << "property value. " - << "See the add_library command's IMPORTED mode for details." - << "\n" - << "If you have a list of libraries that already contains the " - << "keyword, use the target_link_libraries command with its " - << "LINK_INTERFACE_LIBRARIES mode to set the property. " - << "The command automatically recognizes link-type keywords and sets " - << "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG " - << "properties accordingly."; - } - context->IssueMessage(MessageType::FATAL_ERROR, e.str()); -} - -static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const std::string& value, - cmMakefile* context) -{ // Look for link-type keywords in the value. static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)"); - if (!keys.find(value)) { - return; + if (keys.find(value)) { + // Report an error. + std::ostringstream e; + e << "Property " << prop << " may not contain link-type keyword \"" + << keys.match(2) << "\". " + << "The " << base << " property has a per-configuration " + << "version called " << base << "_<CONFIG> which may be " + << "used to specify per-configuration rules."; + if (!imported) { + e << " " + << "Alternatively, an IMPORTED library may be created, configured " + << "with a per-configuration location, and then named in the " + << "property value. " + << "See the add_library command's IMPORTED mode for details." + << "\n" + << "If you have a list of libraries that already contains the " + << "keyword, use the target_link_libraries command with its " + << "LINK_INTERFACE_LIBRARIES mode to set the property. " + << "The command automatically recognizes link-type keywords and sets " + << "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG " + << "properties accordingly."; + } + context->IssueMessage(MessageType::FATAL_ERROR, e.str()); } - // Report an error. - std::ostringstream e; + CheckLinkLibraryPattern(base, value, context); +} + +void CheckLINK_LIBRARIES(const std::string& value, cmMakefile* context) +{ + CheckLinkLibraryPattern("LINK_LIBRARIES", value, context); +} + +void CheckINTERFACE_LINK_LIBRARIES(const std::string& value, + cmMakefile* context) +{ + // Look for link-type keywords in the value. + static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)"); + if (keys.find(value)) { + // Report an error. + std::ostringstream e; - e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type " - "keyword \"" - << keys.match(2) - << "\". The INTERFACE_LINK_LIBRARIES " - "property may contain configuration-sensitive generator-expressions " - "which may be used to specify per-configuration rules."; + e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type " + "keyword \"" + << keys.match(2) + << "\". The INTERFACE_LINK_LIBRARIES " + "property may contain configuration-sensitive generator-expressions " + "which may be used to specify per-configuration rules."; - context->IssueMessage(MessageType::FATAL_ERROR, e.str()); + context->IssueMessage(MessageType::FATAL_ERROR, e.str()); + } + + CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES", value, context); } -static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target, - cmMakefile* context) +void CheckIMPORTED_GLOBAL(const cmTarget* target, cmMakefile* context) { const auto& targets = context->GetOwnedImportedTargets(); auto it = @@ -1787,6 +2025,7 @@ static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target, context->IssueMessage(MessageType::FATAL_ERROR, e.str()); } } +} void cmTarget::CheckProperty(const std::string& prop, cmMakefile* context) const @@ -1794,22 +2033,23 @@ void cmTarget::CheckProperty(const std::string& prop, // Certain properties need checking. if (cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES")) { if (cmValue value = this->GetProperty(prop)) { - cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false); + CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false); } - } - if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) { + } else if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) { if (cmValue value = this->GetProperty(prop)) { - cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true); + CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true); } - } - if (prop == "INTERFACE_LINK_LIBRARIES") { + } else if (prop == "LINK_LIBRARIES") { if (cmValue value = this->GetProperty(prop)) { - cmTargetCheckINTERFACE_LINK_LIBRARIES(*value, context); + CheckLINK_LIBRARIES(*value, context); } - } - if (prop == "IMPORTED_GLOBAL") { + } else if (prop == "INTERFACE_LINK_LIBRARIES") { + if (cmValue value = this->GetProperty(prop)) { + CheckINTERFACE_LINK_LIBRARIES(*value, context); + } + } else if (prop == "IMPORTED_GLOBAL") { if (this->IsImported()) { - cmTargetCheckIMPORTED_GLOBAL(this, context); + CheckIMPORTED_GLOBAL(this, context); } } } @@ -1844,11 +2084,9 @@ cmValue cmTarget::GetProperty(const std::string& prop) const propBINARY_DIR, propSOURCE_DIR, propSOURCES, - propHEADER_DIRS, - propHEADER_SET, - propHEADER_SETS, - propINTERFACE_HEADER_SETS, propINTERFACE_LINK_LIBRARIES, + propINTERFACE_LINK_LIBRARIES_DIRECT, + propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, }; if (specialProps.count(prop)) { if (prop == propC_STANDARD || prop == propCXX_STANDARD || @@ -1878,6 +2116,25 @@ cmValue cmTarget::GetProperty(const std::string& prop) const output = cmJoin(this->impl->LinkInterfacePropertyEntries, ";"); return cmValue(output); } + if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) { + if (this->impl->LinkInterfaceDirectPropertyEntries.empty()) { + return nullptr; + } + + static std::string output; + output = cmJoin(this->impl->LinkInterfaceDirectPropertyEntries, ";"); + return cmValue(output); + } + if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) { + if (this->impl->LinkInterfaceDirectExcludePropertyEntries.empty()) { + return nullptr; + } + + static std::string output; + output = + cmJoin(this->impl->LinkInterfaceDirectExcludePropertyEntries, ";"); + return cmValue(output); + } // the type property returns what type the target is if (prop == propTYPE) { return cmValue(cmState::GetTargetTypeName(this->GetType())); @@ -1983,73 +2240,15 @@ 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) { - std::vector<std::string> set_names; - for (auto const& file_set : this->impl->FileSets) { - if (cmFileSetVisibilityIsForSelf(file_set.second.GetVisibility())) { - set_names.push_back(file_set.second.GetName()); - } - } - static std::string output; - output = cmJoin(set_names, ";"_s); - return cmValue(output); - } - if (prop == propINTERFACE_HEADER_SETS) { - std::vector<std::string> set_names; - for (auto const& file_set : this->impl->FileSets) { - if (cmFileSetVisibilityIsForInterface( - file_set.second.GetVisibility())) { - set_names.push_back(file_set.second.GetName()); - } - } - static std::string output; - output = cmJoin(set_names, ";"_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; + + // Check fileset properties. + { + auto headers = + this->impl->HeadersFileSets.ReadProperties(this, this->impl.get(), prop); + if (headers.first) { + return headers.second; } - static std::string output; - output = cmJoin(fileSet->GetFileEntries(), ";"_s); - return cmValue(output); } cmValue retVal = this->impl->Properties.GetPropertyValue(prop); @@ -2324,13 +2523,9 @@ std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet( auto result = this->impl->FileSets.emplace( std::make_pair(name, cmFileSet(name, type, vis))); if (result.second) { - if (cmFileSetVisibilityIsForSelf(vis)) { - this->impl->HeaderSetsEntries.emplace_back( - name, this->impl->Makefile->GetBacktrace()); - } - if (cmFileSetVisibilityIsForInterface(vis)) { - this->impl->InterfaceHeaderSetsEntries.emplace_back( - name, this->impl->Makefile->GetBacktrace()); + auto bt = this->impl->Makefile->GetBacktrace(); + if (type == this->impl->HeadersFileSets.TypeName) { + this->impl->HeadersFileSets.AddFileSet(name, vis, std::move(bt)); } } return std::make_pair(&result.first->second, result.second); @@ -2352,6 +2547,17 @@ std::string cmTarget::GetInterfaceFileSetsPropertyName(const std::string& type) return ""; } +std::vector<std::string> cmTarget::GetAllFileSetNames() const +{ + std::vector<std::string> result; + + for (auto const& it : this->impl->FileSets) { + result.push_back(it.first); + } + + return result; +} + std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const { std::vector<std::string> result; @@ -2364,7 +2570,7 @@ std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const } }; - appendEntries(this->impl->InterfaceHeaderSetsEntries); + appendEntries(this->impl->HeadersFileSets.InterfaceEntries.Entries); return result; } |