From 28d7432468932ea3a7425579e909d51fe36a70c7 Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Mon, 1 Nov 2021 15:01:22 +0100 Subject: cmComputeLinkInformation: use cmComputeLinkDepends::LinkEntry In preparation of support of genex $, propagate cmComputeLinkDepends::LinkEntry instances to ensure to have, when needed, all attributes attached to the link item. --- Source/cmComputeLinkDepends.h | 8 +++ Source/cmComputeLinkInformation.cxx | 111 ++++++++++++++++++++++-------------- Source/cmComputeLinkInformation.h | 26 ++++----- 3 files changed, 88 insertions(+), 57 deletions(-) diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 72316f1..727c666 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "cmGraphAdjacencyList.h" @@ -38,6 +39,13 @@ public: // Basic information about each link item. struct LinkEntry { + LinkEntry() = default; + LinkEntry(BT item, cmGeneratorTarget const* target = nullptr) + : Item(std::move(item)) + , Target(target) + { + } + BT Item; cmGeneratorTarget const* Target = nullptr; bool IsSharedDep = false; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 2ff91fe..62a96dd 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -517,10 +517,9 @@ bool cmComputeLinkInformation::Compute() // Add the link line items. for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) { if (linkEntry.IsSharedDep) { - this->AddSharedDepItem(linkEntry.Item, linkEntry.Target); + this->AddSharedDepItem(linkEntry); } else { - this->AddItem(linkEntry.Item, linkEntry.Target, - linkEntry.IsObject ? ItemIsObject::Yes : ItemIsObject::No); + this->AddItem(linkEntry); } } @@ -610,7 +609,7 @@ void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang) std::vector libsVec = cmExpandedList(*runtimeLinkOptions); for (std::string const& i : libsVec) { if (!cm::contains(this->ImplicitLinkLibs, i)) { - this->AddItem(i, nullptr); + this->AddItem({ i }); } } } @@ -625,7 +624,7 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang) std::vector libsVec = cmExpandedList(*libs); for (std::string const& i : libsVec) { if (!cm::contains(this->ImplicitLinkLibs, i)) { - this->AddItem(i, nullptr); + this->AddItem({ i }); } } } @@ -639,10 +638,11 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang) } } -void cmComputeLinkInformation::AddItem(BT const& item, - cmGeneratorTarget const* tgt, - ItemIsObject isObject) +void cmComputeLinkInformation::AddItem(LinkEntry const& entry) { + cmGeneratorTarget const* tgt = entry.Target; + BT const& item = entry.Item; + // Compute the proper name to use to link this library. const std::string& config = this->Config; bool impexe = (tgt && tgt->IsExecutableWithExports()); @@ -678,7 +678,7 @@ void cmComputeLinkInformation::AddItem(BT const& item, // Also add the item the interface specifies to be used in its place. std::string const& libName = tgt->GetImportedLibName(config); if (!libName.empty()) { - this->AddItem(BT(libName, item.Backtrace), nullptr); + this->AddItem(BT(libName, item.Backtrace)); } } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) { // Ignore object library! @@ -706,7 +706,9 @@ void cmComputeLinkInformation::AddItem(BT const& item, this->Depends.push_back(lib.Value); } - this->AddTargetItem(lib, tgt); + LinkEntry libEntry{ entry }; + libEntry.Item = lib; + this->AddTargetItem(libEntry); this->AddLibraryRuntimeInfo(lib.Value, tgt); if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY && this->Target->IsDLLPlatform()) { @@ -719,26 +721,28 @@ void cmComputeLinkInformation::AddItem(BT const& item, if (cmSystemTools::IsPathToFramework(item.Value) && this->Makefile->IsOn("APPLE")) { // This is a framework. - this->AddFrameworkItem(item.Value); + this->AddFrameworkItem(entry); } else if (cmSystemTools::FileIsDirectory(item.Value)) { // This is a directory. this->DropDirectoryItem(item); } else { // Use the full path given to the library file. this->Depends.push_back(item.Value); - this->AddFullItem(item, isObject); + this->AddFullItem(entry); this->AddLibraryRuntimeInfo(item.Value); } } else { // This is a library or option specified by the user. - this->AddUserItem(item, true); + this->AddUserItem(entry, true); } } } -void cmComputeLinkInformation::AddSharedDepItem(BT const& item, - const cmGeneratorTarget* tgt) +void cmComputeLinkInformation::AddSharedDepItem(LinkEntry const& entry) { + BT const& item = entry.Item; + const cmGeneratorTarget* tgt = entry.Target; + // Record dependencies on DLLs. if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY && this->Target->IsDLLPlatform() && @@ -776,7 +780,7 @@ void cmComputeLinkInformation::AddSharedDepItem(BT const& item, // If in linking mode, just link to the shared library. if (this->SharedDependencyMode == SharedDepModeLink) { - this->AddItem(item, tgt); + this->AddItem(entry); return; } @@ -1058,8 +1062,7 @@ void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt) } } -void cmComputeLinkInformation::AddTargetItem(BT const& item, - cmGeneratorTarget const* target) +void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) { // This is called to handle a link item that is a full path to a target. // If the target is not a static library make sure the link type is @@ -1067,6 +1070,9 @@ void cmComputeLinkInformation::AddTargetItem(BT const& item, // shared and static libraries but static-mode can handle only // static libraries. If a previous user item changed the link type // to static we need to make sure it is back to shared. + BT const& item = entry.Item; + cmGeneratorTarget const* target = entry.Target; + if (target->GetType() != cmStateEnums::STATIC_LIBRARY) { this->SetCurrentLinkType(LinkShared); } @@ -1079,7 +1085,7 @@ void cmComputeLinkInformation::AddTargetItem(BT const& item, // Handle case of an imported shared library with no soname. if (this->NoSONameUsesPath && target->IsImportedSharedLibWithoutSOName(this->Config)) { - this->AddSharedLibNoSOName(item.Value); + this->AddSharedLibNoSOName(entry); return; } @@ -1095,16 +1101,17 @@ void cmComputeLinkInformation::AddTargetItem(BT const& item, this->Items.emplace_back(item, ItemIsPath::Yes, ItemIsObject::No, target); } -void cmComputeLinkInformation::AddFullItem(BT const& item, - ItemIsObject isObject) +void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry) { + BT const& item = entry.Item; + // Check for the implicit link directory special case. - if (this->CheckImplicitDirItem(item.Value)) { + if (this->CheckImplicitDirItem(entry)) { return; } // Check for case of shared library with no builtin soname. - if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(item.Value)) { + if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(entry)) { return; } @@ -1116,7 +1123,7 @@ void cmComputeLinkInformation::AddFullItem(BT const& item, generator.find("Xcode") != std::string::npos)) { std::string file = cmSystemTools::GetFilenameName(item.Value); if (!this->ExtractAnyLibraryName.find(file)) { - this->HandleBadFullItem(item.Value, file); + this->HandleBadFullItem(entry, file); return; } } @@ -1147,11 +1154,15 @@ void cmComputeLinkInformation::AddFullItem(BT const& item, } // Now add the full path to the library. - this->Items.emplace_back(item, ItemIsPath::Yes, isObject); + this->Items.emplace_back(item, ItemIsPath::Yes, + entry.IsObject ? ItemIsObject::Yes + : ItemIsObject::No); } -bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) +bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry) { + BT const& item = entry.Item; + // We only switch to a pathless item if the link type may be // enforced. Fortunately only platforms that support link types // seem to have magic per-architecture implicit link directories. @@ -1160,7 +1171,7 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) } // Check if this item is in an implicit link directory. - std::string dir = cmSystemTools::GetFilenamePath(item); + std::string dir = cmSystemTools::GetFilenamePath(item.Value); if (!cm::contains(this->ImplicitLinkDirs, dir)) { // Only libraries in implicit link directories are converted to // pathless items. @@ -1169,7 +1180,7 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) // Only apply the policy below if the library file is one that can // be found by the linker. - std::string file = cmSystemTools::GetFilenameName(item); + std::string file = cmSystemTools::GetFilenameName(item.Value); if (!this->ExtractAnyLibraryName.find(file)) { return false; } @@ -1179,10 +1190,10 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) case cmPolicies::WARN: if (this->CMP0060Warn) { // Print the warning at most once for this item. - std::string const& wid = "CMP0060-WARNING-GIVEN-" + item; + std::string const& wid = "CMP0060-WARNING-GIVEN-" + item.Value; if (!this->CMakeInstance->GetPropertyAsBool(wid)) { this->CMakeInstance->SetProperty(wid, "1"); - this->CMP0060WarnItems.insert(item); + this->CMP0060WarnItems.insert(item.Value); } } CM_FALLTHROUGH; @@ -1200,15 +1211,19 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) // directory then just report the file name without the directory // portion. This will allow the system linker to locate the proper // library for the architecture at link time. - this->AddUserItem(file, false); + LinkEntry fileEntry{ entry }; + fileEntry.Item = file; + this->AddUserItem(fileEntry, false); // Make sure the link directory ordering will find the library. - this->OrderLinkerSearchPath->AddLinkLibrary(item); + this->OrderLinkerSearchPath->AddLinkLibrary(item.Value); return true; } -void cmComputeLinkInformation::AddUserItem(BT const& item, +// void cmComputeLinkInformation::AddUserItem(BT const& item, +// bool pathNotKnown) +void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry, bool pathNotKnown) { // This is called to handle a link item that does not match a CMake @@ -1219,6 +1234,8 @@ void cmComputeLinkInformation::AddUserItem(BT const& item, // foo ==> -lfoo // libfoo.a ==> -Wl,-Bstatic -lfoo + BT const& item = entry.Item; + // Pass flags through untouched. if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') { // if this is a -l option then we might need to warn about @@ -1315,8 +1332,10 @@ void cmComputeLinkInformation::AddUserItem(BT const& item, // specification. } -void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) +void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry) { + std::string const& item = entry.Item.Value; + // Try to separate the framework name and path. if (!this->SplitFramework.find(item)) { std::ostringstream e; @@ -1390,42 +1409,44 @@ void cmComputeLinkInformation::AddFrameworkPath(std::string const& p) } } -bool cmComputeLinkInformation::CheckSharedLibNoSOName(std::string const& item) +bool cmComputeLinkInformation::CheckSharedLibNoSOName(LinkEntry const& entry) { // This platform will use the path to a library as its soname if the // library is given via path and was not built with an soname. If // this is a shared library that might be the case. - std::string file = cmSystemTools::GetFilenameName(item); + std::string file = cmSystemTools::GetFilenameName(entry.Item.Value); if (this->ExtractSharedLibraryName.find(file)) { // If we can guess the soname fairly reliably then assume the // library has one. Otherwise assume the library has no builtin // soname. std::string soname; - if (!cmSystemTools::GuessLibrarySOName(item, soname)) { - this->AddSharedLibNoSOName(item); + if (!cmSystemTools::GuessLibrarySOName(entry.Item.Value, soname)) { + this->AddSharedLibNoSOName(entry); return true; } } return false; } -void cmComputeLinkInformation::AddSharedLibNoSOName(std::string const& item) +void cmComputeLinkInformation::AddSharedLibNoSOName(LinkEntry const& entry) { // We have a full path to a shared library with no soname. We need // to ask the linker to locate the item because otherwise the path // we give to it will be embedded in the target linked. Then at // runtime the dynamic linker will search for the library using the // path instead of just the name. - std::string file = cmSystemTools::GetFilenameName(item); - this->AddUserItem(file, false); + LinkEntry fileEntry{ entry }; + fileEntry.Item = cmSystemTools::GetFilenameName(entry.Item.Value); + this->AddUserItem(fileEntry, false); // Make sure the link directory ordering will find the library. - this->OrderLinkerSearchPath->AddLinkLibrary(item); + this->OrderLinkerSearchPath->AddLinkLibrary(entry.Item.Value); } -void cmComputeLinkInformation::HandleBadFullItem(std::string const& item, +void cmComputeLinkInformation::HandleBadFullItem(LinkEntry const& entry, std::string const& file) { + std::string const& item = entry.Item.Value; // Do not depend on things that do not exist. auto i = std::find(this->Depends.begin(), this->Depends.end(), item); if (i != this->Depends.end()) { @@ -1435,7 +1456,9 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item, // Tell the linker to search for the item and provide the proper // path for it. Do not contribute to any CMP0003 warning (do not // put in OldLinkDirItems or OldUserFlagItems). - this->AddUserItem(file, false); + LinkEntry fileEntry{ entry }; + fileEntry.Item = file; + this->AddUserItem(fileEntry, false); this->OrderLinkerSearchPath->AddLinkLibrary(item); // Produce any needed message. diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 0315540..2edcd5f 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -13,6 +13,7 @@ #include "cmsys/RegularExpression.hxx" +#include "cmComputeLinkDepends.h" #include "cmListFileCache.h" #include "cmValue.h" @@ -104,10 +105,10 @@ public: const cmGeneratorTarget* GetTarget() { return this->Target; } private: - void AddItem(BT const& item, const cmGeneratorTarget* tgt, - ItemIsObject isObject = ItemIsObject::No); - void AddSharedDepItem(BT const& item, - cmGeneratorTarget const* tgt); + using LinkEntry = cmComputeLinkDepends::LinkEntry; + + void AddItem(LinkEntry const& entry); + void AddSharedDepItem(LinkEntry const& entry); void AddRuntimeDLL(cmGeneratorTarget const* tgt); // Output information. @@ -181,16 +182,15 @@ private: std::string NoCaseExpression(std::string const& str); // Handling of link items. - void AddTargetItem(BT const& item, - const cmGeneratorTarget* target); - void AddFullItem(BT const& item, ItemIsObject isObject); - bool CheckImplicitDirItem(std::string const& item); - void AddUserItem(BT const& item, bool pathNotKnown); - void AddFrameworkItem(std::string const& item); + void AddTargetItem(LinkEntry const& entry); + void AddFullItem(LinkEntry const& entry); + bool CheckImplicitDirItem(LinkEntry const& entry); + void AddUserItem(LinkEntry const& entry, bool pathNotKnown); + void AddFrameworkItem(LinkEntry const& entry); void DropDirectoryItem(BT const& item); - bool CheckSharedLibNoSOName(std::string const& item); - void AddSharedLibNoSOName(std::string const& item); - void HandleBadFullItem(std::string const& item, std::string const& file); + bool CheckSharedLibNoSOName(LinkEntry const& entry); + void AddSharedLibNoSOName(LinkEntry const& entry); + void HandleBadFullItem(LinkEntry const& entry, std::string const& file); // Framework info. void ComputeFrameworkInfo(); -- cgit v0.12 From 4b55828a9f2afbc6c37e53f7cb0d4adec0fa73b5 Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Mon, 15 Nov 2021 14:27:34 +0100 Subject: cmExpandListWithBacktrace: add handling of empty elements. --- Source/cmListFileCache.cxx | 6 +++--- Source/cmListFileCache.h | 5 +++-- Source/cmLocalGenerator.cxx | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 3da266d..b28b282 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -539,11 +539,11 @@ std::ostream& operator<<(std::ostream& os, BT const& s) return os << s.Value; } -std::vector> ExpandListWithBacktrace( - std::string const& list, cmListFileBacktrace const& bt) +std::vector> cmExpandListWithBacktrace( + std::string const& list, cmListFileBacktrace const& bt, bool emptyArgs) { std::vector> result; - std::vector tmp = cmExpandedList(list); + std::vector tmp = cmExpandedList(list, emptyArgs); result.reserve(tmp.size()); for (std::string& i : tmp) { result.emplace_back(std::move(i), bt); diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 5d45027..58bc57e 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -230,9 +230,10 @@ public: friend bool operator==(T const& l, BTs const& r) { return l == r.Value; } }; -std::vector> ExpandListWithBacktrace( +std::vector> cmExpandListWithBacktrace( std::string const& list, - cmListFileBacktrace const& bt = cmListFileBacktrace()); + cmListFileBacktrace const& bt = cmListFileBacktrace(), + bool emptyArgs = false); struct cmListFile { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2adb232..3976c42 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -3199,7 +3199,7 @@ void cmLocalGenerator::AppendDefines(std::set& defines, std::string const& defines_list) const { std::set> tmp; - this->AppendDefines(tmp, ExpandListWithBacktrace(defines_list)); + this->AppendDefines(tmp, cmExpandListWithBacktrace(defines_list)); for (BT const& i : tmp) { defines.emplace(i.Value); } @@ -3214,7 +3214,7 @@ void cmLocalGenerator::AppendDefines(std::set>& defines, } // Expand the list of definitions. - this->AppendDefines(defines, ExpandListWithBacktrace(defines_list)); + this->AppendDefines(defines, cmExpandListWithBacktrace(defines_list)); } void cmLocalGenerator::AppendDefines( -- cgit v0.12 From 78dd7d5292cef930b3d435e6901cc3b10ee02513 Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Wed, 24 Nov 2021 16:45:22 +0100 Subject: cmRulePlaceholderExpander: add base class for placeholder expansion reuse --- Source/CMakeLists.txt | 2 + Source/cmPlaceholderExpander.cxx | 54 ++++++++ Source/cmPlaceholderExpander.h | 19 +++ Source/cmRulePlaceholderExpander.cxx | 245 +++++++++++++++-------------------- Source/cmRulePlaceholderExpander.h | 14 +- bootstrap | 1 + 6 files changed, 187 insertions(+), 148 deletions(-) create mode 100644 Source/cmPlaceholderExpander.cxx create mode 100644 Source/cmPlaceholderExpander.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index ddcdd7e..d6e0096 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -358,6 +358,8 @@ set(SRCS cmLocalCommonGenerator.h cmLocalGenerator.cxx cmLocalGenerator.h + cmPlaceholderExpander.cxx + cmPlaceholderExpander.h cmRulePlaceholderExpander.cxx cmRulePlaceholderExpander.h cmLocalUnixMakefileGenerator3.cxx diff --git a/Source/cmPlaceholderExpander.cxx b/Source/cmPlaceholderExpander.cxx new file mode 100644 index 0000000..118017e --- /dev/null +++ b/Source/cmPlaceholderExpander.cxx @@ -0,0 +1,54 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmPlaceholderExpander.h" + +#include + +std::string& cmPlaceholderExpander::ExpandVariables(std::string& s) +{ + std::string::size_type start = s.find('<'); + // no variables to expand + if (start == std::string::npos) { + return s; + } + std::string::size_type pos = 0; + std::string expandedInput; + while (start != std::string::npos && start < s.size() - 2) { + std::string::size_type end = s.find('>', start); + // if we find a < with no > we are done + if (end == std::string::npos) { + s = expandedInput; + return s; + } + char c = s[start + 1]; + // if the next char after the < is not A-Za-z then + // skip it and try to find the next < in the string + if (!isalpha(c)) { + start = s.find('<', start + 1); + } else { + // extract the var + std::string var = s.substr(start + 1, end - start - 1); + std::string replace = this->ExpandVariable(var); + expandedInput += s.substr(pos, start - pos); + + // Prevent consecutive whitespace in the output if the rule variable + // expands to an empty string. + bool consecutive = replace.empty() && start > 0 && s[start - 1] == ' ' && + end + 1 < s.size() && s[end + 1] == ' '; + if (consecutive) { + expandedInput.pop_back(); + } + + expandedInput += replace; + + // move to next one + start = s.find('<', start + var.size() + 2); + pos = end + 1; + } + } + // add the rest of the input + expandedInput += s.substr(pos, s.size() - pos); + s = expandedInput; + + return s; +} diff --git a/Source/cmPlaceholderExpander.h b/Source/cmPlaceholderExpander.h new file mode 100644 index 0000000..24225cc --- /dev/null +++ b/Source/cmPlaceholderExpander.h @@ -0,0 +1,19 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include + +class cmPlaceholderExpander +{ +public: + virtual ~cmPlaceholderExpander() = default; + + std::string& ExpandVariables(std::string& string); + +protected: + virtual std::string ExpandVariable(std::string const& variable) = 0; +}; diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index 4cee09d..b63d11c 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmRulePlaceholderExpander.h" -#include #include #include "cmOutputConverter.h" @@ -20,195 +19,194 @@ cmRulePlaceholderExpander::cmRulePlaceholderExpander( { } -std::string cmRulePlaceholderExpander::ExpandRuleVariable( - cmOutputConverter* outputConverter, std::string const& variable, - const RuleVariables& replaceValues) +std::string cmRulePlaceholderExpander::ExpandVariable( + std::string const& variable) { - if (replaceValues.LinkFlags) { + if (this->ReplaceValues->LinkFlags) { if (variable == "LINK_FLAGS") { - return replaceValues.LinkFlags; + return this->ReplaceValues->LinkFlags; } } - if (replaceValues.Manifests) { + if (this->ReplaceValues->Manifests) { if (variable == "MANIFESTS") { - return replaceValues.Manifests; + return this->ReplaceValues->Manifests; } } - if (replaceValues.Flags) { + if (this->ReplaceValues->Flags) { if (variable == "FLAGS") { - return replaceValues.Flags; + return this->ReplaceValues->Flags; } } - if (replaceValues.Source) { + if (this->ReplaceValues->Source) { if (variable == "SOURCE") { - return replaceValues.Source; + return this->ReplaceValues->Source; } } - if (replaceValues.DynDepFile) { + if (this->ReplaceValues->DynDepFile) { if (variable == "DYNDEP_FILE") { - return replaceValues.DynDepFile; + return this->ReplaceValues->DynDepFile; } } - if (replaceValues.PreprocessedSource) { + if (this->ReplaceValues->PreprocessedSource) { if (variable == "PREPROCESSED_SOURCE") { - return replaceValues.PreprocessedSource; + return this->ReplaceValues->PreprocessedSource; } } - if (replaceValues.AssemblySource) { + if (this->ReplaceValues->AssemblySource) { if (variable == "ASSEMBLY_SOURCE") { - return replaceValues.AssemblySource; + return this->ReplaceValues->AssemblySource; } } - if (replaceValues.Object) { + if (this->ReplaceValues->Object) { if (variable == "OBJECT") { - return replaceValues.Object; + return this->ReplaceValues->Object; } } - if (replaceValues.ObjectDir) { + if (this->ReplaceValues->ObjectDir) { if (variable == "OBJECT_DIR") { - return replaceValues.ObjectDir; + return this->ReplaceValues->ObjectDir; } } - if (replaceValues.ObjectFileDir) { + if (this->ReplaceValues->ObjectFileDir) { if (variable == "OBJECT_FILE_DIR") { - return replaceValues.ObjectFileDir; + return this->ReplaceValues->ObjectFileDir; } } - if (replaceValues.Objects) { + if (this->ReplaceValues->Objects) { if (variable == "OBJECTS") { - return replaceValues.Objects; + return this->ReplaceValues->Objects; } } - if (replaceValues.ObjectsQuoted) { + if (this->ReplaceValues->ObjectsQuoted) { if (variable == "OBJECTS_QUOTED") { - return replaceValues.ObjectsQuoted; + return this->ReplaceValues->ObjectsQuoted; } } - if (replaceValues.CudaCompileMode) { + if (this->ReplaceValues->CudaCompileMode) { if (variable == "CUDA_COMPILE_MODE") { - return replaceValues.CudaCompileMode; + return this->ReplaceValues->CudaCompileMode; } } - if (replaceValues.AIXExports) { + if (this->ReplaceValues->AIXExports) { if (variable == "AIX_EXPORTS") { - return replaceValues.AIXExports; + return this->ReplaceValues->AIXExports; } } - if (replaceValues.ISPCHeader) { + if (this->ReplaceValues->ISPCHeader) { if (variable == "ISPC_HEADER") { - return replaceValues.ISPCHeader; + return this->ReplaceValues->ISPCHeader; } } - if (replaceValues.Defines && variable == "DEFINES") { - return replaceValues.Defines; + if (this->ReplaceValues->Defines && variable == "DEFINES") { + return this->ReplaceValues->Defines; } - if (replaceValues.Includes && variable == "INCLUDES") { - return replaceValues.Includes; + if (this->ReplaceValues->Includes && variable == "INCLUDES") { + return this->ReplaceValues->Includes; } - if (replaceValues.SwiftLibraryName) { + if (this->ReplaceValues->SwiftLibraryName) { if (variable == "SWIFT_LIBRARY_NAME") { - return replaceValues.SwiftLibraryName; + return this->ReplaceValues->SwiftLibraryName; } } - if (replaceValues.SwiftModule) { + if (this->ReplaceValues->SwiftModule) { if (variable == "SWIFT_MODULE") { - return replaceValues.SwiftModule; + return this->ReplaceValues->SwiftModule; } } - if (replaceValues.SwiftModuleName) { + if (this->ReplaceValues->SwiftModuleName) { if (variable == "SWIFT_MODULE_NAME") { - return replaceValues.SwiftModuleName; + return this->ReplaceValues->SwiftModuleName; } } - if (replaceValues.SwiftOutputFileMap) { + if (this->ReplaceValues->SwiftOutputFileMap) { if (variable == "SWIFT_OUTPUT_FILE_MAP") { - return replaceValues.SwiftOutputFileMap; + return this->ReplaceValues->SwiftOutputFileMap; } } - if (replaceValues.SwiftSources) { + if (this->ReplaceValues->SwiftSources) { if (variable == "SWIFT_SOURCES") { - return replaceValues.SwiftSources; + return this->ReplaceValues->SwiftSources; } } - if (replaceValues.TargetPDB) { + if (this->ReplaceValues->TargetPDB) { if (variable == "TARGET_PDB") { - return replaceValues.TargetPDB; + return this->ReplaceValues->TargetPDB; } } - if (replaceValues.TargetCompilePDB) { + if (this->ReplaceValues->TargetCompilePDB) { if (variable == "TARGET_COMPILE_PDB") { - return replaceValues.TargetCompilePDB; + return this->ReplaceValues->TargetCompilePDB; } } - if (replaceValues.DependencyFile) { + if (this->ReplaceValues->DependencyFile) { if (variable == "DEP_FILE") { - return replaceValues.DependencyFile; + return this->ReplaceValues->DependencyFile; } } - if (replaceValues.DependencyTarget) { + if (this->ReplaceValues->DependencyTarget) { if (variable == "DEP_TARGET") { - return replaceValues.DependencyTarget; + return this->ReplaceValues->DependencyTarget; } } - if (replaceValues.Fatbinary) { + if (this->ReplaceValues->Fatbinary) { if (variable == "FATBINARY") { - return replaceValues.Fatbinary; + return this->ReplaceValues->Fatbinary; } } - if (replaceValues.RegisterFile) { + if (this->ReplaceValues->RegisterFile) { if (variable == "REGISTER_FILE") { - return replaceValues.RegisterFile; + return this->ReplaceValues->RegisterFile; } } - if (replaceValues.Target) { + if (this->ReplaceValues->Target) { if (variable == "TARGET_QUOTED") { - std::string targetQuoted = replaceValues.Target; + std::string targetQuoted = this->ReplaceValues->Target; if (!targetQuoted.empty() && targetQuoted.front() != '\"') { targetQuoted = '\"'; - targetQuoted += replaceValues.Target; + targetQuoted += this->ReplaceValues->Target; targetQuoted += '\"'; } return targetQuoted; } if (variable == "TARGET_UNQUOTED") { - std::string unquoted = replaceValues.Target; + std::string unquoted = this->ReplaceValues->Target; std::string::size_type sz = unquoted.size(); if (sz > 2 && unquoted.front() == '\"' && unquoted.back() == '\"') { unquoted = unquoted.substr(1, sz - 2); } return unquoted; } - if (replaceValues.LanguageCompileFlags) { + if (this->ReplaceValues->LanguageCompileFlags) { if (variable == "LANGUAGE_COMPILE_FLAGS") { - return replaceValues.LanguageCompileFlags; + return this->ReplaceValues->LanguageCompileFlags; } } - if (replaceValues.Target) { + if (this->ReplaceValues->Target) { if (variable == "TARGET") { - return replaceValues.Target; + return this->ReplaceValues->Target; } } if (variable == "TARGET_IMPLIB") { return this->TargetImpLib; } if (variable == "TARGET_VERSION_MAJOR") { - if (replaceValues.TargetVersionMajor) { - return replaceValues.TargetVersionMajor; + if (this->ReplaceValues->TargetVersionMajor) { + return this->ReplaceValues->TargetVersionMajor; } return "0"; } if (variable == "TARGET_VERSION_MINOR") { - if (replaceValues.TargetVersionMinor) { - return replaceValues.TargetVersionMinor; + if (this->ReplaceValues->TargetVersionMinor) { + return this->ReplaceValues->TargetVersionMinor; } return "0"; } - if (replaceValues.Target) { + if (this->ReplaceValues->Target) { if (variable == "TARGET_BASE") { // Strip the last extension off the target name. - std::string targetBase = replaceValues.Target; + std::string targetBase = this->ReplaceValues->Target; std::string::size_type pos = targetBase.rfind('.'); if (pos != std::string::npos) { return targetBase.substr(0, pos); @@ -220,54 +218,54 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" || variable == "TARGET_INSTALLNAME_DIR") { // All these variables depend on TargetSOName - if (replaceValues.TargetSOName) { + if (this->ReplaceValues->TargetSOName) { if (variable == "TARGET_SONAME") { - return replaceValues.TargetSOName; + return this->ReplaceValues->TargetSOName; } - if (variable == "SONAME_FLAG" && replaceValues.SONameFlag) { - return replaceValues.SONameFlag; + if (variable == "SONAME_FLAG" && this->ReplaceValues->SONameFlag) { + return this->ReplaceValues->SONameFlag; } - if (replaceValues.TargetInstallNameDir && + if (this->ReplaceValues->TargetInstallNameDir && variable == "TARGET_INSTALLNAME_DIR") { - return replaceValues.TargetInstallNameDir; + return this->ReplaceValues->TargetInstallNameDir; } } return ""; } - if (replaceValues.LinkLibraries) { + if (this->ReplaceValues->LinkLibraries) { if (variable == "LINK_LIBRARIES") { - return replaceValues.LinkLibraries; + return this->ReplaceValues->LinkLibraries; } } - if (replaceValues.Language) { + if (this->ReplaceValues->Language) { if (variable == "LANGUAGE") { - return replaceValues.Language; + return this->ReplaceValues->Language; } } - if (replaceValues.CMTargetName) { + if (this->ReplaceValues->CMTargetName) { if (variable == "TARGET_NAME") { - return replaceValues.CMTargetName; + return this->ReplaceValues->CMTargetName; } } - if (replaceValues.CMTargetType) { + if (this->ReplaceValues->CMTargetType) { if (variable == "TARGET_TYPE") { - return replaceValues.CMTargetType; + return this->ReplaceValues->CMTargetType; } } - if (replaceValues.Output) { + if (this->ReplaceValues->Output) { if (variable == "OUTPUT") { - return replaceValues.Output; + return this->ReplaceValues->Output; } } if (variable == "CMAKE_COMMAND") { - return outputConverter->ConvertToOutputFormat( + return this->OutputConverter->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); } auto compIt = this->Compilers.find(variable); if (compIt != this->Compilers.end()) { - std::string ret = outputConverter->ConvertToOutputForExisting( + std::string ret = this->OutputConverter->ConvertToOutputForExisting( this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER"]); std::string const& compilerArg1 = this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_ARG1"]; @@ -286,11 +284,12 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( this->VariableMappings["CMAKE_" + compIt->second + "_COMPILE_OPTIONS_SYSROOT"]; - if (compIt->second == replaceValues.Language && replaceValues.Launcher) { + if (compIt->second == this->ReplaceValues->Language && + this->ReplaceValues->Launcher) { // Add launcher as part of expansion so that it always appears // immediately before the command itself, regardless of whether the // overall rule template contains other content at the front. - ret = cmStrCat(replaceValues.Launcher, " ", ret); + ret = cmStrCat(this->ReplaceValues->Launcher, " ", ret); } // if there are required arguments to the compiler add it @@ -308,13 +307,14 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( !compilerOptionExternalToolchain.empty()) { ret += " "; ret += compilerOptionExternalToolchain; - ret += outputConverter->EscapeForShell(compilerExternalToolchain, true); + ret += + this->OutputConverter->EscapeForShell(compilerExternalToolchain, true); } std::string sysroot; // Some platforms may use separate sysroots for compiling and linking. // If we detect link flags, then we pass the link sysroot instead. // FIXME: Use a more robust way to detect link line expansion. - if (replaceValues.LinkFlags) { + if (this->ReplaceValues->LinkFlags) { sysroot = this->LinkerSysroot; } else { sysroot = this->CompilerSysroot; @@ -322,7 +322,7 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( if (!sysroot.empty() && !compilerOptionSysroot.empty()) { ret += " "; ret += compilerOptionSysroot; - ret += outputConverter->EscapeForShell(sysroot, true); + ret += this->OutputConverter->EscapeForShell(sysroot, true); } return ret; } @@ -331,13 +331,13 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( if (mapIt != this->VariableMappings.end()) { if (variable.find("_FLAG") == std::string::npos) { std::string ret = - outputConverter->ConvertToOutputForExisting(mapIt->second); + this->OutputConverter->ConvertToOutputForExisting(mapIt->second); - if (replaceValues.Launcher && variable == "CMAKE_LINKER") { + if (this->ReplaceValues->Launcher && variable == "CMAKE_LINKER") { // Add launcher as part of expansion so that it always appears // immediately before the command itself, regardless of whether the // overall rule template contains other content at the front. - ret = cmStrCat(replaceValues.Launcher, " ", ret); + ret = cmStrCat(this->ReplaceValues->Launcher, " ", ret); } return ret; @@ -351,47 +351,8 @@ void cmRulePlaceholderExpander::ExpandRuleVariables( cmOutputConverter* outputConverter, std::string& s, const RuleVariables& replaceValues) { - std::string::size_type start = s.find('<'); - // no variables to expand - if (start == std::string::npos) { - return; - } - std::string::size_type pos = 0; - std::string expandedInput; - while (start != std::string::npos && start < s.size() - 2) { - std::string::size_type end = s.find('>', start); - // if we find a < with no > we are done - if (end == std::string::npos) { - return; - } - char c = s[start + 1]; - // if the next char after the < is not A-Za-z then - // skip it and try to find the next < in the string - if (!isalpha(c)) { - start = s.find('<', start + 1); - } else { - // extract the var - std::string var = s.substr(start + 1, end - start - 1); - std::string replace = - this->ExpandRuleVariable(outputConverter, var, replaceValues); - expandedInput += s.substr(pos, start - pos); - - // Prevent consecutive whitespace in the output if the rule variable - // expands to an empty string. - bool consecutive = replace.empty() && start > 0 && s[start - 1] == ' ' && - end + 1 < s.size() && s[end + 1] == ' '; - if (consecutive) { - expandedInput.pop_back(); - } + this->OutputConverter = outputConverter; + this->ReplaceValues = &replaceValues; - expandedInput += replace; - - // move to next one - start = s.find('<', start + var.size() + 2); - pos = end + 1; - } - } - // add the rest of the input - expandedInput += s.substr(pos, s.size() - pos); - s = expandedInput; + this->ExpandVariables(s); } diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 852954f..23ec405 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -8,9 +8,11 @@ #include #include +#include "cmPlaceholderExpander.h" + class cmOutputConverter; -class cmRulePlaceholderExpander +class cmRulePlaceholderExpander : public cmPlaceholderExpander { public: cmRulePlaceholderExpander( @@ -76,16 +78,16 @@ public: std::string& string, const RuleVariables& replaceValues); - // Expand rule variables in a single string - std::string ExpandRuleVariable(cmOutputConverter* outputConverter, - std::string const& variable, - const RuleVariables& replaceValues); - private: + std::string ExpandVariable(std::string const& variable) override; + std::string TargetImpLib; std::map Compilers; std::map VariableMappings; std::string CompilerSysroot; std::string LinkerSysroot; + + cmOutputConverter* OutputConverter = nullptr; + RuleVariables const* ReplaceValues = nullptr; }; diff --git a/bootstrap b/bootstrap index e0791d5..98b5959 100755 --- a/bootstrap +++ b/bootstrap @@ -442,6 +442,7 @@ CMAKE_CXX_SOURCES="\ cmGccDepfileLexerHelper \ cmGccDepfileReader \ cmReturnCommand \ + cmPlaceholderExpander \ cmRulePlaceholderExpander \ cmRuntimeDependencyArchive \ cmScriptGenerator \ -- cgit v0.12 From 42965799b4747ab1e0afa6546be13444f68c1987 Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Mon, 1 Nov 2021 15:27:05 +0100 Subject: Genex: Add $ This generator expression offers the capability, for the link step, to decorate libraries with prefix/suffix flags and/or adding any specific flag for each library. Fixes: #22812, #18751, #20078, #22703 --- Help/manual/cmake-generator-expressions.7.rst | 69 ++++ Help/manual/cmake-variables.7.rst | 4 + Help/release/dev/Genex-LINK_LIBRARY.rst | 8 + Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst | 19 + .../CMAKE_LANG_LINK_USING_FEATURE_SUPPORTED.rst | 13 + Help/variable/CMAKE_LINK_USING_FEATURE.rst | 23 ++ Help/variable/CMAKE_LINK_USING_FEATURE.txt | 111 ++++++ .../CMAKE_LINK_USING_FEATURE_SUPPORTED.rst | 14 + Source/cmComputeLinkDepends.cxx | 177 ++++++++-- Source/cmComputeLinkDepends.h | 13 +- Source/cmComputeLinkInformation.cxx | 387 +++++++++++++++++++-- Source/cmComputeLinkInformation.h | 65 +++- Source/cmGeneratorExpressionNode.cxx | 63 ++++ Source/cmGeneratorTarget.cxx | 15 +- Source/cmGeneratorTarget.h | 3 +- Source/cmGlobalXCodeGenerator.cxx | 4 +- Source/cmLinkLibrariesCommand.cxx | 2 + Source/cmLinkLineComputer.cxx | 10 +- Source/cmLinkLineDeviceComputer.cxx | 8 +- Source/cmLocalVisualStudio7Generator.cxx | 4 +- Source/cmMakefile.cxx | 25 ++ Source/cmMakefile.h | 1 + Source/cmTarget.cxx | 140 +++++--- Source/cmTargetLinkLibrariesCommand.cxx | 3 + Source/cmVisualStudio10TargetGenerator.cxx | 6 +- Tests/RunCMake/CMakeLists.txt | 12 + Tests/RunCMake/GenEx-LINK_LIBRARY/CMakeLists.txt | 3 + .../RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake | 25 ++ .../add_custom_command-result.txt | 1 + .../add_custom_command-stderr.txt | 9 + .../GenEx-LINK_LIBRARY/add_custom_command.cmake | 4 + .../add_custom_target-result.txt | 1 + .../add_custom_target-stderr.txt | 9 + .../GenEx-LINK_LIBRARY/add_custom_target.cmake | 3 + .../GenEx-LINK_LIBRARY/add_link_options-result.txt | 1 + .../GenEx-LINK_LIBRARY/add_link_options-stderr.txt | 9 + .../GenEx-LINK_LIBRARY/add_link_options.cmake | 5 + .../GenEx-LINK_LIBRARY/bad-feature1-result.txt | 1 + .../GenEx-LINK_LIBRARY/bad-feature1-stderr.txt | 6 + .../RunCMake/GenEx-LINK_LIBRARY/bad-feature1.cmake | 6 + .../GenEx-LINK_LIBRARY/bad-feature2-result.txt | 1 + .../GenEx-LINK_LIBRARY/bad-feature2-stderr.txt | 5 + .../RunCMake/GenEx-LINK_LIBRARY/bad-feature2.cmake | 8 + .../GenEx-LINK_LIBRARY/bad-feature3-result.txt | 1 + .../GenEx-LINK_LIBRARY/bad-feature3-stderr.txt | 6 + .../RunCMake/GenEx-LINK_LIBRARY/bad-feature3.cmake | 9 + .../GenEx-LINK_LIBRARY/bad-feature4-result.txt | 1 + .../GenEx-LINK_LIBRARY/bad-feature4-stderr.txt | 6 + .../RunCMake/GenEx-LINK_LIBRARY/bad-feature4.cmake | 9 + .../GenEx-LINK_LIBRARY/bad-feature5-result.txt | 1 + .../GenEx-LINK_LIBRARY/bad-feature5-stderr.txt | 6 + .../RunCMake/GenEx-LINK_LIBRARY/bad-feature5.cmake | 9 + .../GenEx-LINK_LIBRARY/bad-feature6-result.txt | 1 + .../GenEx-LINK_LIBRARY/bad-feature6-stderr.txt | 6 + .../RunCMake/GenEx-LINK_LIBRARY/bad-feature6.cmake | 9 + .../GenEx-LINK_LIBRARY/bad-feature7-result.txt | 1 + .../GenEx-LINK_LIBRARY/bad-feature7-stderr.txt | 6 + .../RunCMake/GenEx-LINK_LIBRARY/bad-feature7.cmake | 9 + .../GenEx-LINK_LIBRARY/compatible-features.cmake | 15 + .../GenEx-LINK_LIBRARY/empty-arguments-result.txt | 1 + .../GenEx-LINK_LIBRARY/empty-arguments-stderr.txt | 8 + .../GenEx-LINK_LIBRARY/empty-arguments.cmake | 4 + Tests/RunCMake/GenEx-LINK_LIBRARY/empty.c | 0 .../feature-not-supported-result.txt | 1 + .../feature-not-supported-stderr.txt | 5 + .../GenEx-LINK_LIBRARY/feature-not-supported.cmake | 9 + .../forbidden-arguments-result.txt | 1 + .../forbidden-arguments-stderr.txt | 16 + .../GenEx-LINK_LIBRARY/forbidden-arguments.cmake | 6 + .../incompatible-features-result.txt | 1 + .../incompatible-features-stderr.txt | 6 + .../GenEx-LINK_LIBRARY/incompatible-features.cmake | 15 + .../GenEx-LINK_LIBRARY/library-ignored-stderr.txt | 14 + .../GenEx-LINK_LIBRARY/library-ignored.cmake | 15 + .../GenEx-LINK_LIBRARY/link_directories-result.txt | 1 + .../GenEx-LINK_LIBRARY/link_directories-stderr.txt | 9 + .../GenEx-LINK_LIBRARY/link_directories.cmake | 5 + .../nested-compatible-features.cmake | 11 + .../nested-incompatible-features-result.txt | 1 + .../nested-incompatible-features-stderr.txt | 8 + .../nested-incompatible-features.cmake | 14 + .../GenEx-LINK_LIBRARY/no-arguments-result.txt | 1 + .../GenEx-LINK_LIBRARY/no-arguments-stderr.txt | 8 + .../RunCMake/GenEx-LINK_LIBRARY/no-arguments.cmake | 4 + .../GenEx-LINK_LIBRARY/only-targets-result.txt | 1 + .../GenEx-LINK_LIBRARY/only-targets-stderr.txt | 13 + .../RunCMake/GenEx-LINK_LIBRARY/only-targets.cmake | 16 + .../target_link_directories-result.txt | 1 + .../target_link_directories-stderr.txt | 9 + .../target_link_directories.cmake | 4 + .../target_link_options-result.txt | 1 + .../target_link_options-stderr.txt | 9 + .../GenEx-LINK_LIBRARY/target_link_options.cmake | 4 + .../CMakeLists.txt | 3 + .../LINK_LIBRARY-group1-check.cmake | 4 + .../LINK_LIBRARY-group1-result.txt | 1 + .../LINK_LIBRARY-group2-check.cmake | 4 + .../LINK_LIBRARY-group2-result.txt | 1 + .../LINK_LIBRARY-link-items1-check.cmake | 4 + .../LINK_LIBRARY-link-items1-result.txt | 1 + .../LINK_LIBRARY-link-items2-check.cmake | 4 + .../LINK_LIBRARY-link-items2-result.txt | 1 + .../LINK_LIBRARY-link-items3-check.cmake | 4 + .../LINK_LIBRARY-link-items3-result.txt | 1 + .../LINK_LIBRARY-link-items4-check.cmake | 4 + .../LINK_LIBRARY-link-items4-result.txt | 1 + .../LINK_LIBRARY-mix-features1-check.cmake | 4 + .../LINK_LIBRARY-mix-features1-result.txt | 1 + .../LINK_LIBRARY-mix-features2-check.cmake | 4 + .../LINK_LIBRARY-mix-features2-result.txt | 1 + .../LINK_LIBRARY-mix-features3-check.cmake | 4 + .../LINK_LIBRARY-mix-features3-result.txt | 1 + .../LINK_LIBRARY-nested-feature1-check.cmake | 4 + .../LINK_LIBRARY-nested-feature1-result.txt | 1 + .../LINK_LIBRARY-nested-feature2-check.cmake | 4 + .../LINK_LIBRARY-nested-feature2-result.txt | 1 + .../LINK_LIBRARY-simple1-check.cmake | 4 + .../LINK_LIBRARY-simple1-result.txt | 1 + .../LINK_LIBRARY-simple2-check.cmake | 4 + .../LINK_LIBRARY-simple2-result.txt | 1 + .../LINK_LIBRARY.cmake | 81 +++++ .../RunCMakeTest.cmake | 73 ++++ .../target_link_libraries-LINK_LIBRARY/base.c | 9 + .../imported-target-result.txt | 1 + .../imported-target-stdout.txt | 18 + .../imported-target.cmake | 18 + .../target_link_libraries-LINK_LIBRARY/lib.c | 15 + .../target_link_libraries-LINK_LIBRARY/main.c | 18 + .../target_link_libraries-LINK_LIBRARY/unref.c | 8 + .../weak_library.cmake | 20 ++ .../whole_archive.cmake | 34 ++ 131 files changed, 1825 insertions(+), 151 deletions(-) create mode 100644 Help/release/dev/Genex-LINK_LIBRARY.rst create mode 100644 Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst create mode 100644 Help/variable/CMAKE_LANG_LINK_USING_FEATURE_SUPPORTED.rst create mode 100644 Help/variable/CMAKE_LINK_USING_FEATURE.rst create mode 100644 Help/variable/CMAKE_LINK_USING_FEATURE.txt create mode 100644 Help/variable/CMAKE_LINK_USING_FEATURE_SUPPORTED.rst create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/CMakeLists.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/empty.c create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/nested-compatible-features.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/CMakeLists.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/base.c create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-stdout.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/lib.c create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.c create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/unref.c create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/weak_library.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/whole_archive.cmake diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index df13dd0..b67d479 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1113,6 +1113,75 @@ Output-Related Expressions property, perhaps via the :command:`target_link_libraries` command, to specify private link dependencies without other usage requirements. +.. genex:: $ + + .. versionadded:: 3.24 + + Manage how libraries are specified during the link step. + This expression may be used to specify how to link libraries in a target. + For example: + + .. code-block:: cmake + + add_library(lib1 STATIC ...) + add_library(lib2 ...) + target_link_libraries(lib2 PRIVATE $) + + This specify to use the ``lib1`` target with feature ``whole_archive`` for + linking target ``lib2``. The feature must have be defined by + :variable:`CMAKE__LINK_USING_` variable or, if + :variable:`CMAKE__LINK_USING__SUPPORTED` is false, + by :variable:`CMAKE_LINK_USING_` variable. + + .. note:: + + The evaluation of this generator expression will use, for the following + variables, the values defined at the level of the creation of the target: + + * :variable:`CMAKE__LINK_USING__SUPPORTED` + * :variable:`CMAKE__LINK_USING_` + * :variable:`CMAKE_LINK_USING__SUPPORTED` + * :variable:`CMAKE_LINK_USING_` + + This expression can only be used to specify link libraries (i.e. part of + :command:`link_libraries` or :command:`target_link_libraries` commands and + :prop_tgt:`LINK_LIBRARIES` or :prop_tgt:`INTERFACE_LINK_LIBRARIES` target + properties). + + .. note:: + + If this expression appears in the :prop_tgt:`INTERFACE_LINK_LIBRARIES` + property of a target, it will be included in the imported target generated + by :command:`install(EXPORT)` command. It is the responsibility of the + environment consuming this import to define the link feature used by this + expression. + + The ``library-list`` argument can hold CMake targets or external libraries. + Any ``CMake`` target of type :ref:`OBJECT ` or + :ref:`INTERFACE ` will be ignored by this expression and + will be handled in the standard way. + + Each target or external library involved in the link step must have only one + kind of feature (the absence of feature is also incompatible with any + feature). For example: + + .. code-block:: cmake + + add_library(lib1 ...) + + add_library(lib2 ...) + target_link_libraries(lib2 PUBLIC $) + + add_library(lib3 ...) + target_link_libraries(lib3 PRIVATE lib1 lib2) + # an error will be raised here because lib1 has two different features + + .. note:: + + This expression does not guarantee that the list of specified libraries + will be kept grouped. So, constructs like ``start-group`` and + ``end-group``, as supported by ``GNU ld``, cannot be used. + .. genex:: $ Content of ``...`` when the property is exported using :command:`install(EXPORT)`, diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 59566b5..86e4d4c 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -440,6 +440,8 @@ Variables that Control the Build /variable/CMAKE_LANG_LINKER_LAUNCHER /variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG /variable/CMAKE_LANG_LINK_LIBRARY_FLAG + /variable/CMAKE_LANG_LINK_USING_FEATURE + /variable/CMAKE_LANG_LINK_USING_FEATURE_SUPPORTED /variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG /variable/CMAKE_LANG_VISIBILITY_PRESET /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY @@ -450,6 +452,8 @@ Variables that Control the Build /variable/CMAKE_LINK_INTERFACE_LIBRARIES /variable/CMAKE_LINK_LIBRARY_FILE_FLAG /variable/CMAKE_LINK_LIBRARY_FLAG + /variable/CMAKE_LINK_USING_FEATURE + /variable/CMAKE_LINK_USING_FEATURE_SUPPORTED /variable/CMAKE_LINK_WHAT_YOU_USE /variable/CMAKE_LINK_WHAT_YOU_USE_CHECK /variable/CMAKE_MACOSX_BUNDLE diff --git a/Help/release/dev/Genex-LINK_LIBRARY.rst b/Help/release/dev/Genex-LINK_LIBRARY.rst new file mode 100644 index 0000000..6b87a4f --- /dev/null +++ b/Help/release/dev/Genex-LINK_LIBRARY.rst @@ -0,0 +1,8 @@ +Genex-LINK_LIBRARY +------------------ + +* The :genex:`LINK_LIBRARY` generator expression was added to manage how + libraries are specified during the link step. The variables + :variable:`CMAKE__LINK_USING_` and + :variable:`CMAKE_LINK_USING_` are used to define features usable by + the :genex:`LINK_LIBRARY` generator expression. diff --git a/Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst b/Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst new file mode 100644 index 0000000..ff8b3d9 --- /dev/null +++ b/Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst @@ -0,0 +1,19 @@ +CMAKE__LINK_USING_ +--------------------------------- + +.. versionadded:: 3.24 + +This variable defines, for the specified ```` and the linker language +````, the expression expected by the linker when libraries are specified +using :genex:`LINK_LIBRARY` generator expression. + +.. note:: + + Feature names defined in all uppercase are reserved to CMake. + +See also the associated variable +:variable:`CMAKE__LINK_USING__SUPPORTED` and +:variable:`CMAKE_LINK_USING_` variable for the definition of features +independent from the link language. + +.. include:: CMAKE_LINK_USING_FEATURE.txt diff --git a/Help/variable/CMAKE_LANG_LINK_USING_FEATURE_SUPPORTED.rst b/Help/variable/CMAKE_LANG_LINK_USING_FEATURE_SUPPORTED.rst new file mode 100644 index 0000000..5794b15 --- /dev/null +++ b/Help/variable/CMAKE_LANG_LINK_USING_FEATURE_SUPPORTED.rst @@ -0,0 +1,13 @@ +CMAKE__LINK_USING__SUPPORTED +------------------------------------------- + +.. versionadded:: 3.24 + +Set to ``TRUE`` if the ````, as defined by variable +:variable:`CMAKE__LINK_USING_`, is supported for the linker +language ````. + +.. note:: + + This variable is evaluated before the more generic variable + :variable:`CMAKE_LINK_USING__SUPPORTED`. diff --git a/Help/variable/CMAKE_LINK_USING_FEATURE.rst b/Help/variable/CMAKE_LINK_USING_FEATURE.rst new file mode 100644 index 0000000..3d94461 --- /dev/null +++ b/Help/variable/CMAKE_LINK_USING_FEATURE.rst @@ -0,0 +1,23 @@ +CMAKE_LINK_USING_ +-------------------------- + +.. versionadded:: 3.24 + +This variable defines, for the specified ``FEATURE``, the expression expected +by the linker, regardless the linker language, when libraries are specified +using :genex:`LINK_LIBRARY` generator expression. + +.. note:: + + Feature names defined in all uppercase are reserved to CMake. + +See also the associated variable +:variable:`CMAKE_LINK_USING__SUPPORTED` and +:variable:`CMAKE__LINK_USING_` variable for the definition of +features dependent from the link language. + +This variable will be used by :genex:`LINK_LIBRARY` generator expression if, +for the linker language, the variable +:variable:`CMAKE__LINK_USING__SUPPORTED` is false or not set. + +.. include:: CMAKE_LINK_USING_FEATURE.txt diff --git a/Help/variable/CMAKE_LINK_USING_FEATURE.txt b/Help/variable/CMAKE_LINK_USING_FEATURE.txt new file mode 100644 index 0000000..92fc92d --- /dev/null +++ b/Help/variable/CMAKE_LINK_USING_FEATURE.txt @@ -0,0 +1,111 @@ + +It can contain one or three elements. + +:: + + [] [] + +When ```` and/or ```` are specified, they encapsulate the list +of libraries. + +.. note:: + + Even if ```` and ```` are specified, there is not guarantee + that the list of specified libraries, as part of :genex:`LINK_LIBRARY` + generator expression, will be kept grouped. So, constructs like + ``start-group`` and ``end-group``, as supported by ``GNU ld``, cannot be + used. + +```` is used to specify the decoration for each +library. For that purpose, the patterns ````, ````, and +```` are available: + +* ```` is expanded to the library as computed by CMake. +* ```` is expanded to the same expression as if the library was + specified in the standard way. +* ```` is equivalent to ```` for CMake targets and is + expanded to the item specified by the user for external libraries. + +Moreover, it is possible to have different decorations for paths (CMake targets +and external libraries specified with absolute paths) and other items specified +by name. For that purpose, ``PATH{}`` and ``NAME{}`` wrappers can be used. + +For all three elements of this variable, the ``LINKER:`` prefix can be used: + + .. include:: ../command/LINK_OPTIONS_LINKER.txt + :start-line: 3 + +Examples +^^^^^^^^ + +Loading a whole static library +"""""""""""""""""""""""""""""" + +A common need is the capability to load a whole static library. This capability +is offered by various environments but with a specific syntax: + +.. code-block:: cmake + + set(CMAKE_C_LINK_USING_whole_archive_SUPPORTED TRUE) + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_C_LINK_USING_whole_archive "-force_load ") + elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" + AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(CMAKE_C_LINK_USING_whole_archive "LINKER:--push-state,--whole-archive" + "" + "LINKER:--pop-state") + elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_C_LINK_USING_whole_archive "/WHOLEARCHIVE:") + else() + # feature not yet supported for the other environments + set(CMAKE_C_LINK_USING_whole_archive_SUPPORTED FALSE) + endif() + + add_library(lib1 STATIC ...) + + add_library(lib2 SHARED ...) + if(CMAKE_C_LINK_USING_whole_archive_SUPPORTED) + target_link_libraries(lib2 PRIVATE + $,libexternal.a,external>>) + else() + target_link_libraries(lib2 PRIVATE lib1 external) + endif() + +CMake will generate the following link expressions: + +* ``Clang``: ``-force_load /path/to/lib1.a -force_load libexternal.a`` +* ``GNU``: ``-Wl,--whole-archive /path/to/lib1.a -lexternal -Wl,--no-whole-archive`` +* ``MSVC``: ``/WHOLEARCHIVE:/path/to/lib1.lib /WHOLEARCHIVE:external.lib`` + +CMake will ensure, when possible, that ```` and ```` are +not repeated for each library. + +In case of ``Clang``, the pattern ```` is used because we need to +specify the library as defined by the user, not the name computed by CMake +(in that case ``external``). + +Linking a library as weak +""""""""""""""""""""""""" + +On MacOS, it is possible to link a library in weak mode (the library and all +references are marked as weak imports), but different flags must be used for a +library specified by path and by name. This constraint by be solved by using +``PATH{}`` and ``NAME{}`` wrappers: + +.. code-block:: cmake + + if (CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_LINK_USING_weak_library "PATH{-weak_library }NAME{LINKER:-weak-l}") + set(CMAKE_LINK_USING_weak_library_SUPPORTED TRUE) + endif() + + add_library(lib SHARED ...) + add_executable(main ...) + if(CMAKE_LINK_USING_weak_library_SUPPORTED) + target_link_libraries(main PRIVATE $) + else() + target_link_libraries(main PRIVATE lib external) + endif() + +CMake will generate the following link expression: +``-weak_library /path/to/lib -Xlinker -weak-lexternal`` diff --git a/Help/variable/CMAKE_LINK_USING_FEATURE_SUPPORTED.rst b/Help/variable/CMAKE_LINK_USING_FEATURE_SUPPORTED.rst new file mode 100644 index 0000000..31c3108 --- /dev/null +++ b/Help/variable/CMAKE_LINK_USING_FEATURE_SUPPORTED.rst @@ -0,0 +1,14 @@ +CMAKE_LINK_USING__SUPPORTED +------------------------------------ + +.. versionadded:: 3.24 + +Set to ``TRUE`` if the ````, as defined by variable +:variable:`CMAKE_LINK_USING_`, is supported regardless the linker +language. + +.. note:: + + This variable is evaluated if, and only if, the variable + :variable:`CMAKE__LINK_USING__SUPPORTED` evaluates to + ``FALSE``. diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 370ddff..c3367ac 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -11,6 +11,7 @@ #include #include +#include #include "cmComputeComponentGraph.h" #include "cmGeneratorTarget.h" @@ -18,6 +19,7 @@ #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmRange.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -174,8 +176,33 @@ items that we know the linker will re-use automatically (shared libs). */ +namespace { +const auto LL_BEGIN = "', LL_BEGIN.length()) - LL_BEGIN.length()); +} + +bool IsFeatureSupported(cmMakefile* makefile, std::string const& linkLanguage, + std::string const& feature) +{ + auto featureSupported = + cmStrCat("CMAKE_", linkLanguage, "_LINK_USING_", feature, "_SUPPORTED"); + if (makefile->GetDefinition(featureSupported).IsOn()) { + return true; + } + + featureSupported = cmStrCat("CMAKE_LINK_USING_", feature, "_SUPPORTED"); + return makefile->GetDefinition(featureSupported).IsOn(); +} +} + cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, - const std::string& config) + const std::string& config, + const std::string& linkLanguage) { // Store context information. this->Target = target; @@ -183,6 +210,7 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, this->GlobalGenerator = this->Target->GetLocalGenerator()->GetGlobalGenerator(); this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance(); + this->LinkLanguage = linkLanguage; // The configuration being linked. this->HasConfig = !config.empty(); @@ -249,7 +277,7 @@ cmComputeLinkDepends::Compute() } // Compute the final ordering. - this->OrderLinkEntires(); + this->OrderLinkEntries(); // Compute the final set of link entries. // Iterate in reverse order so we can keep only the last occurrence @@ -281,32 +309,33 @@ cmComputeLinkDepends::Compute() return this->FinalLinkEntries; } -std::map::iterator cmComputeLinkDepends::AllocateLinkEntry( - cmLinkItem const& item) +std::pair::iterator, bool> +cmComputeLinkDepends::AllocateLinkEntry(cmLinkItem const& item) { std::map::value_type index_entry( item, static_cast(this->EntryList.size())); - auto lei = this->LinkEntryIndex.insert(index_entry).first; - this->EntryList.emplace_back(); - this->InferredDependSets.emplace_back(); - this->EntryConstraintGraph.emplace_back(); + auto lei = this->LinkEntryIndex.insert(index_entry); + if (lei.second) { + this->EntryList.emplace_back(); + this->InferredDependSets.emplace_back(); + this->EntryConstraintGraph.emplace_back(); + } return lei; } -int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item) +std::pair cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item) { + // Allocate a spot for the item entry. + auto lei = this->AllocateLinkEntry(item); + // Check if the item entry has already been added. - auto lei = this->LinkEntryIndex.find(item); - if (lei != this->LinkEntryIndex.end()) { + if (!lei.second) { // Yes. We do not need to follow the item's dependencies again. - return lei->second; + return { lei.first->second, false }; } - // Allocate a spot for the item entry. - lei = this->AllocateLinkEntry(item); - // Initialize the item entry. - int index = lei->second; + int index = lei.first->second; LinkEntry& entry = this->EntryList[index]; entry.Item = BT(item.AsStr(), item.Backtrace); entry.Target = item.Target; @@ -332,22 +361,21 @@ int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item) } } - return index; + return { index, true }; } void cmComputeLinkDepends::AddLinkObject(cmLinkItem const& item) { + // Allocate a spot for the item entry. + auto lei = this->AllocateLinkEntry(item); + // Check if the item entry has already been added. - auto lei = this->LinkEntryIndex.find(item); - if (lei != this->LinkEntryIndex.end()) { + if (!lei.second) { return; } - // Allocate a spot for the item entry. - lei = this->AllocateLinkEntry(item); - // Initialize the item entry. - int index = lei->second; + int index = lei.first->second; LinkEntry& entry = this->EntryList[index]; entry.Item = BT(item.AsStr(), item.Backtrace); entry.IsObject = true; @@ -423,14 +451,14 @@ void cmComputeLinkDepends::QueueSharedDependencies( void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) { - // Check if the target already has an entry. - auto lei = this->LinkEntryIndex.find(dep.Item); - if (lei == this->LinkEntryIndex.end()) { - // Allocate a spot for the item entry. - lei = this->AllocateLinkEntry(dep.Item); + // Allocate a spot for the item entry. + auto lei = this->AllocateLinkEntry(dep.Item); + int index = lei.first->second; + // Check if the target does not already has an entry. + if (lei.second) { // Initialize the item entry. - LinkEntry& entry = this->EntryList[lei->second]; + LinkEntry& entry = this->EntryList[index]; entry.Item = BT(dep.Item.AsStr(), dep.Item.Backtrace); entry.Target = dep.Item.Target; @@ -441,7 +469,6 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) } // Get the link entry for this target. - int index = lei->second; LinkEntry& entry = this->EntryList[index]; // This shared library dependency must follow the item that listed @@ -541,6 +568,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, { // Track inferred dependency sets implied by this list. std::map dependSets; + std::string feature; // Loop over the libraries linked directly by the depender. for (T const& l : libs) { @@ -550,9 +578,86 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, if (item.AsStr() == this->Target->GetName() || item.AsStr().empty()) { continue; } + if (cmHasPrefix(item.AsStr(), LL_BEGIN) && + cmHasSuffix(item.AsStr(), '>')) { + feature = ExtractFeature(item.AsStr()); + // emit a warning if an undefined feature is used as part of + // an imported target + if (depender_index >= 0) { + const auto& depender = this->EntryList[depender_index]; + if (depender.Target != nullptr && depender.Target->IsImported() && + !IsFeatureSupported(this->Makefile, this->LinkLanguage, feature)) { + this->CMakeInstance->IssueMessage( + MessageType::AUTHOR_ERROR, + cmStrCat("The 'IMPORTED' target '", depender.Target->GetName(), + "' uses the generator-expression '$' with " + "the feature '", + feature, + "', which is undefined or unsupported.\nDid you miss to " + "define it by setting variables \"CMAKE_", + this->LinkLanguage, "_LINK_USING_", feature, + "\" and \"CMAKE_", this->LinkLanguage, "_LINK_USING_", + feature, "_SUPPORTED\"?"), + this->Target->GetBacktrace()); + } + } + continue; + } + if (cmHasPrefix(item.AsStr(), LL_END) && cmHasSuffix(item.AsStr(), '>')) { + feature.clear(); + continue; + } // Add a link entry for this item. - int dependee_index = this->AddLinkEntry(l); + auto ale = this->AddLinkEntry(item); + int dependee_index = ale.first; + LinkEntry& entry = this->EntryList[dependee_index]; + if (!feature.empty()) { + if (ale.second) { + // current item not yet defined + if (entry.Target != nullptr && + (entry.Target->GetType() == + cmStateEnums::TargetType::OBJECT_LIBRARY || + entry.Target->GetType() == + cmStateEnums::TargetType::INTERFACE_LIBRARY)) { + this->CMakeInstance->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat("The feature '", feature, + "', specified as part of a generator-expression " + "'$", + LL_BEGIN, feature, ">', will not be applied to the ", + (entry.Target->GetType() == + cmStateEnums::TargetType::OBJECT_LIBRARY + ? "OBJECT" + : "INTERFACE"), + " library '", entry.Item.Value, "'."), + this->Target->GetBacktrace()); + } else { + entry.Feature = feature; + } + } + } + + bool supportedItem = entry.Target == nullptr || + (entry.Target->GetType() != cmStateEnums::TargetType::OBJECT_LIBRARY && + entry.Target->GetType() != cmStateEnums::TargetType::INTERFACE_LIBRARY); + + if (supportedItem && entry.Feature != feature) { + // incompatibles features occurred + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Impossible to link target '", this->Target->GetName(), + "' because the link item '", entry.Item.Value, "', specified ", + (feature.empty() ? "without any feature" + : cmStrCat("with the feature '", feature, '\'')), + ", has already occurred ", + (entry.Feature.empty() + ? "without any feature" + : cmStrCat("with the feature '", entry.Feature, '\'')), + ", which is not allowed."), + this->Target->GetBacktrace()); + } // The dependee must come after the depender. if (depender_index >= 0) { @@ -667,7 +772,7 @@ void cmComputeLinkDepends::DisplayConstraintGraph() fprintf(stderr, "%s\n", e.str().c_str()); } -void cmComputeLinkDepends::OrderLinkEntires() +void cmComputeLinkDepends::OrderLinkEntries() { // Compute the DAG of strongly connected components. The algorithm // used by cmComputeComponentGraph should identify the components in @@ -869,10 +974,14 @@ void cmComputeLinkDepends::DisplayFinalEntries() fprintf(stderr, "target [%s] links to:\n", this->Target->GetName().c_str()); for (LinkEntry const& lei : this->FinalLinkEntries) { if (lei.Target) { - fprintf(stderr, " target [%s]\n", lei.Target->GetName().c_str()); + fprintf(stderr, " target [%s]", lei.Target->GetName().c_str()); } else { - fprintf(stderr, " item [%s]\n", lei.Item.Value.c_str()); + fprintf(stderr, " item [%s]", lei.Item.Value.c_str()); + } + if (!lei.Feature.empty()) { + fprintf(stderr, ", feature [%s]", lei.Feature.c_str()); } + fprintf(stderr, "\n"); } fprintf(stderr, "\n"); } diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 727c666..02bdf50 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -30,7 +30,8 @@ class cmComputeLinkDepends { public: cmComputeLinkDepends(cmGeneratorTarget const* target, - const std::string& config); + const std::string& config, + const std::string& linkLanguage); ~cmComputeLinkDepends(); cmComputeLinkDepends(const cmComputeLinkDepends&) = delete; @@ -51,6 +52,9 @@ public: bool IsSharedDep = false; bool IsFlag = false; bool IsObject = false; + // The following member is for the management of items specified + // through genex $ + std::string Feature; }; using EntryVector = std::vector; @@ -68,12 +72,13 @@ private: cmMakefile* Makefile; cmGlobalGenerator const* GlobalGenerator; cmake* CMakeInstance; + std::string LinkLanguage; std::string Config; EntryVector FinalLinkEntries; - std::map::iterator AllocateLinkEntry( + std::pair::iterator, bool> AllocateLinkEntry( cmLinkItem const& item); - int AddLinkEntry(cmLinkItem const& item); + std::pair AddLinkEntry(cmLinkItem const& item); void AddLinkObject(cmLinkItem const& item); void AddVarLinkEntries(int depender_index, const char* value); void AddDirectLinkEntries(); @@ -131,7 +136,7 @@ private: void DisplayConstraintGraph(); // Ordering algorithm. - void OrderLinkEntires(); + void OrderLinkEntries(); std::vector ComponentVisited; std::vector ComponentOrder; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 62a96dd..5c3a96d 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -19,6 +19,7 @@ #include "cmMessageType.h" #include "cmOrderDirectories.h" #include "cmOutputConverter.h" +#include "cmPlaceholderExpander.h" #include "cmPolicies.h" #include "cmState.h" #include "cmStateTypes.h" @@ -344,6 +345,27 @@ cmComputeLinkInformation::cmComputeLinkInformation( this->LinkWithRuntimePath = this->Makefile->IsOn(var); } + // Define some Feature descriptors to handle standard library and object link + if (!this->GetLibLinkFileFlag().empty()) { + this->LibraryFeatureDescriptors.emplace( + "__CMAKE_LINK_LIBRARY", + FeatureDescriptor{ "__CMAKE_LINK_LIBRARY", + cmStrCat(this->GetLibLinkFileFlag(), "") }); + } + if (!this->GetObjLinkFileFlag().empty()) { + this->LibraryFeatureDescriptors.emplace( + "__CMAKE_LINK_OBJECT", + FeatureDescriptor{ "__CMAKE_LINK_OBJECT", + cmStrCat(this->GetObjLinkFileFlag(), "") }); + } + if (!this->LoaderFlag->empty()) { + // Define a Feature descriptor for the link of an executable with exports + this->LibraryFeatureDescriptors.emplace( + "__CMAKE_LINK_EXECUTABLE", + FeatureDescriptor{ "__CMAKE_LINK_EXECUTABLE", + cmStrCat(this->LoaderFlag, "") }); + } + // Check the platform policy for missing soname case. this->NoSONameUsesPath = this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME"); @@ -510,12 +532,40 @@ bool cmComputeLinkInformation::Compute() } // Compute the ordered link line items. - cmComputeLinkDepends cld(this->Target, this->Config); + cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage); cld.SetOldLinkDirMode(this->OldLinkDirMode); cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute(); + FeatureDescriptor const* currentFeature = nullptr; // Add the link line items. for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) { + if (currentFeature != nullptr && + linkEntry.Feature != currentFeature->Name) { + // emit feature suffix, if any + if (!currentFeature->Suffix.empty()) { + this->Items.emplace_back( + BT{ currentFeature->Suffix, + this->Items.back().Value.Backtrace }, + ItemIsPath::No); + } + currentFeature = nullptr; + } + + if (!linkEntry.Feature.empty() && + (currentFeature == nullptr || + linkEntry.Feature != currentFeature->Name)) { + if (!this->AddLibraryFeature(linkEntry.Feature)) { + continue; + } + currentFeature = this->FindLibraryFeature(linkEntry.Feature); + // emit feature prefix, if any + if (!currentFeature->Prefix.empty()) { + this->Items.emplace_back( + BT{ currentFeature->Prefix, linkEntry.Item.Backtrace }, + ItemIsPath::No); + } + } + if (linkEntry.IsSharedDep) { this->AddSharedDepItem(linkEntry); } else { @@ -523,6 +573,16 @@ bool cmComputeLinkInformation::Compute() } } + if (currentFeature != nullptr) { + // emit feature suffix, if any + if (!currentFeature->Suffix.empty()) { + this->Items.emplace_back( + BT{ currentFeature->Suffix, + this->Items.back().Value.Backtrace }, + ItemIsPath::No); + } + } + // Restore the target link type so the correct system runtime // libraries are found. cmValue lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC"); @@ -575,6 +635,270 @@ bool cmComputeLinkInformation::Compute() return true; } +namespace { +void FinalizeFeatureFormat(std::string& format, const std::string& activeTag, + const std::string& otherTag) +{ + auto pos = format.find(otherTag); + if (pos != std::string::npos) { + format.erase(pos, format.find('}', pos) - pos + 1); + } + pos = format.find(activeTag); + if (pos != std::string::npos) { + format.erase(pos, activeTag.length()); + pos = format.find('}', pos); + if (pos != std::string::npos) { + format.erase(pos, 1); + } + } +} + +bool IsValidFeatureFormat(const std::string& format) +{ + return format.find("") != std::string::npos || + format.find("") != std::string::npos || + format.find("") != std::string::npos; +} +} + +bool cmComputeLinkInformation::AddLibraryFeature(std::string const& feature) +{ + auto it = this->LibraryFeatureDescriptors.find(feature); + if (it != this->LibraryFeatureDescriptors.end()) { + return it->second.Supported; + } + + auto featureName = + cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_USING_", feature); + cmValue featureSupported = + this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED")); + if (!featureSupported.IsOn()) { + featureName = cmStrCat("CMAKE_LINK_USING_", feature); + featureSupported = + this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED")); + } + if (!featureSupported.IsOn()) { + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Feature '", feature, + "', specified through generator-expression '$' to " + "link target '", + this->Target->GetName(), "', is not supported for the '", + this->LinkLanguage, "' link language."), + this->Target->GetBacktrace()); + + return false; + } + + cmValue langFeature = this->Makefile->GetDefinition(featureName); + if (!langFeature) { + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Feature '", feature, + "', specified through generator-expression '$' to " + "link target '", + this->Target->GetName(), "', is not defined for the '", + this->LinkLanguage, "' link language."), + this->Target->GetBacktrace()); + + return false; + } + + auto items = + cmExpandListWithBacktrace(langFeature, this->Target->GetBacktrace(), true); + + if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) || + (items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) { + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Feature '", feature, "', specified by variable '", featureName, + "', is malformed (\"\", \"\", or " + "\"\" patterns " + "are missing) and cannot be used to link target '", + this->Target->GetName(), "'."), + this->Target->GetBacktrace()); + + return false; + } + + // now, handle possible "PATH{}" and "NAME{}" patterns + if (items.size() == 1) { + items.push_back(items.front()); + FinalizeFeatureFormat(items[0].Value, "PATH{", "NAME{"); + FinalizeFeatureFormat(items[1].Value, "NAME{", "PATH{"); + } else if (items.size() == 3) { + items.insert(items.begin() + 1, items[1]); + FinalizeFeatureFormat(items[1].Value, "PATH{", "NAME{"); + FinalizeFeatureFormat(items[2].Value, "NAME{", "PATH{"); + } else { + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Feature '", feature, "', specified by variable '", featureName, + "', is malformed (wrong number of elements) and cannot be used " + "to link target '", + this->Target->GetName(), "'."), + this->Target->GetBacktrace()); + + return false; + } + if ((items.size() == 2 && !IsValidFeatureFormat(items[0].Value)) || + (items.size() == 4 && !IsValidFeatureFormat(items[1].Value))) { + // PATH{} has wrong format + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Feature '", feature, "', specified by variable '", featureName, + "', is malformed (\"\", \"\", or " + "\"\" patterns " + "are missing for \"PATH{}\" alternative) and cannot be used to " + "link target '", + this->Target->GetName(), "'."), + this->Target->GetBacktrace()); + + return false; + } + if ((items.size() == 2 && !IsValidFeatureFormat(items[1].Value)) || + (items.size() == 4 && !IsValidFeatureFormat(items[2].Value))) { + // NAME{} has wrong format + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Feature '", feature, "', specified by variable '", featureName, + "', is malformed (\"\", \"\", or " + "\"\" patterns " + "are missing for \"NAME{}\" alternative) and cannot be used to " + "link target '", + this->Target->GetName(), "'."), + this->Target->GetBacktrace()); + + return false; + } + + // replace LINKER: pattern + this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true); + + if (items.size() == 2) { + this->LibraryFeatureDescriptors.emplace( + feature, FeatureDescriptor{ feature, items[0].Value, items[1].Value }); + } else { + this->LibraryFeatureDescriptors.emplace( + feature, + FeatureDescriptor{ feature, items[0].Value, items[1].Value, + items[2].Value, items[3].Value }); + } + + return true; +} + +cmComputeLinkInformation::FeatureDescriptor const& +cmComputeLinkInformation::GetLibraryFeature(std::string const& feature) const +{ + return this->LibraryFeatureDescriptors.find(feature)->second; +} +cmComputeLinkInformation::FeatureDescriptor const* +cmComputeLinkInformation::FindLibraryFeature(std::string const& feature) const +{ + auto it = this->LibraryFeatureDescriptors.find(feature); + if (it == this->LibraryFeatureDescriptors.end()) { + return nullptr; + } + + return &it->second; +} + +namespace { +class FeaturePlaceHolderExpander : public cmPlaceholderExpander +{ +public: + FeaturePlaceHolderExpander(const std::string* library, + const std::string* libItem = nullptr, + const std::string* linkItem = nullptr) + : Library(library) + , LibItem(libItem) + , LinkItem(linkItem) + { + } + +private: + std::string ExpandVariable(std::string const& variable) override + { + if (this->Library != nullptr && variable == "LIBRARY") { + return *this->Library; + } + if (this->LibItem != nullptr && variable == "LIB_ITEM") { + return *this->LibItem; + } + if (this->LinkItem != nullptr && variable == "LINK_ITEM") { + return *this->LinkItem; + } + + return variable; + } + + const std::string* Library = nullptr; + const std::string* LibItem = nullptr; + const std::string* LinkItem = nullptr; +}; +} + +cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor( + std::string name, std::string itemFormat) + : Name(std::move(name)) + , Supported(true) + , ItemPathFormat(std::move(itemFormat)) + , ItemNameFormat(this->ItemPathFormat) +{ +} +cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor( + std::string name, std::string itemPathFormat, std::string itemNameFormat) + : Name(std::move(name)) + , Supported(true) + , ItemPathFormat(std::move(itemPathFormat)) + , ItemNameFormat(std::move(itemNameFormat)) +{ +} +cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor( + std::string name, std::string prefix, std::string itemPathFormat, + std::string itemNameFormat, std::string suffix) + : Name(std::move(name)) + , Supported(true) + , Prefix(std::move(prefix)) + , Suffix(std::move(suffix)) + , ItemPathFormat(std::move(itemPathFormat)) + , ItemNameFormat(std::move(itemNameFormat)) +{ +} + +std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem( + std::string const& library, ItemIsPath isPath) const +{ + auto format = + isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat; + + // replace , and patterns with library path + FeaturePlaceHolderExpander expander(&library, &library, &library); + return expander.ExpandVariables(format); +} +std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem( + std::string const& library, std::string const& libItem, + std::string const& linkItem, ItemIsPath isPath) const +{ + auto format = + isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat; + + // replace , and patterns + FeaturePlaceHolderExpander expander(&library, &libItem, &linkItem); + return expander.ExpandVariables(format); +} + void cmComputeLinkInformation::AddImplicitLinkInfo() { // The link closure lists all languages whose implicit info is needed. @@ -657,23 +981,21 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry) if (impexe && this->LoaderFlag) { // This link item is an executable that may provide symbols // used by this target. A special flag is needed on this - // platform. Add it now. - std::string linkItem = this->LoaderFlag; + // platform. Add it now using a special feature. cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config) ? cmStateEnums::ImportLibraryArtifact : cmStateEnums::RuntimeBinaryArtifact; - std::string exe = tgt->GetFullPath(config, artifact, true); - linkItem += exe; - this->Items.emplace_back(BT(linkItem, item.Backtrace), - ItemIsPath::Yes, ItemIsObject::No, tgt); + this->Items.emplace_back( + BT(exe, item.Backtrace), ItemIsPath::Yes, tgt, + this->FindLibraryFeature( + entry.Feature.empty() ? "__CMAKE_LINK_EXECUTABLE" : entry.Feature)); this->Depends.push_back(std::move(exe)); } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { // Add the interface library as an item so it can be considered as part // of COMPATIBLE_INTERFACE_ enforcement. The generators will ignore // this for the actual link line. - this->Items.emplace_back(std::string(), ItemIsPath::No, ItemIsObject::No, - tgt); + this->Items.emplace_back(std::string(), ItemIsPath::No, tgt); // Also add the item the interface specifies to be used in its place. std::string const& libName = tgt->GetImportedLibName(config); @@ -1098,7 +1420,10 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) } // Now add the full path to the library. - this->Items.emplace_back(item, ItemIsPath::Yes, ItemIsObject::No, target); + this->Items.emplace_back(item, ItemIsPath::Yes, target, + this->FindLibraryFeature(entry.Feature.empty() + ? "__CMAKE_LINK_LIBRARY" + : entry.Feature)); } void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry) @@ -1154,9 +1479,12 @@ void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry) } // Now add the full path to the library. - this->Items.emplace_back(item, ItemIsPath::Yes, - entry.IsObject ? ItemIsObject::Yes - : ItemIsObject::No); + this->Items.emplace_back( + item, ItemIsPath::Yes, nullptr, + this->FindLibraryFeature( + entry.Feature.empty() + ? (entry.IsObject ? "__CMAKE_LINK_OBJECT" : "__CMAKE_LINK_LIBRARY") + : entry.Feature)); } bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry) @@ -1221,8 +1549,6 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry) return true; } -// void cmComputeLinkInformation::AddUserItem(BT const& item, -// bool pathNotKnown) void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry, bool pathNotKnown) { @@ -1236,8 +1562,8 @@ void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry, BT const& item = entry.Item; - // Pass flags through untouched. if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') { + // Pass flags through untouched. // if this is a -l option then we might need to warn about // CMP0003 so put it in OldUserFlagItems, if it is not a -l // or -Wl,-l (-framework -pthread), then allow it without a @@ -1322,9 +1648,20 @@ void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry, } // Create an option to ask the linker to search for the library. - std::string out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix); - this->Items.emplace_back(BT(out, item.Backtrace), - ItemIsPath::No); + auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix); + + if (!entry.Feature.empty()) { + auto const& feature = this->GetLibraryFeature(entry.Feature); + this->Items.emplace_back( + BT( + feature.GetDecoratedItem(cmStrCat(lib, this->LibLinkSuffix), + item.Value, out, ItemIsPath::No), + item.Backtrace), + ItemIsPath::No); + } else { + this->Items.emplace_back(BT(out, item.Backtrace), + ItemIsPath::No); + } // Here we could try to find the library the linker will find and // add a runtime information entry for it. It would probably not be @@ -1374,10 +1711,10 @@ void cmComputeLinkInformation::DropDirectoryItem(BT const& item) // user. this->CMakeInstance->IssueMessage( MessageType::WARNING, - cmStrCat( - "Target \"", this->Target->GetName(), - "\" requests linking to directory \"", item.Value, - "\". Targets may link only to libraries. CMake is dropping the item."), + cmStrCat("Target \"", this->Target->GetName(), + "\" requests linking to directory \"", item.Value, + "\". Targets may link only to libraries. CMake is dropping " + "the item."), item.Backtrace); } @@ -1804,8 +2141,8 @@ void cmComputeLinkInformation::GetRPath(std::vector& runtimeDirs, // Add directories explicitly specified by user std::string build_rpath; if (this->Target->GetBuildRPATH(this->Config, build_rpath)) { - // This will not resolve entries to use $ORIGIN, the user is expected to - // do that if necessary. + // This will not resolve entries to use $ORIGIN, the user is expected + // to do that if necessary. cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted); } } diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 2edcd5f..ce9f393 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include +#include #include #include #include @@ -28,6 +29,9 @@ class cmake; */ class cmComputeLinkInformation { +private: + class FeatureDescriptor; + public: cmComputeLinkInformation(cmGeneratorTarget const* target, const std::string& config); @@ -43,28 +47,33 @@ public: Yes, }; - enum class ItemIsObject - { - No, - Yes, - }; - struct Item { - Item() = default; Item(BT v, ItemIsPath isPath, - ItemIsObject isObject = ItemIsObject::No, - cmGeneratorTarget const* target = nullptr) + cmGeneratorTarget const* target = nullptr, + FeatureDescriptor const* feature = nullptr) : Value(std::move(v)) , IsPath(isPath) - , IsObject(isObject) , Target(target) + , Feature(feature) { } BT Value; - ItemIsPath IsPath = ItemIsPath::Yes; - ItemIsObject IsObject = ItemIsObject::No; + ItemIsPath IsPath = ItemIsPath::No; cmGeneratorTarget const* Target = nullptr; + + bool HasFeature() const { return this->Feature != nullptr; } + + BT GetFormattedItem(std::string const& path) const + { + return { (this->Feature != nullptr) + ? this->Feature->GetDecoratedItem(path, this->IsPath) + : path, + Value.Backtrace }; + } + + private: + FeatureDescriptor const* Feature = nullptr; }; using ItemVector = std::vector; void AppendValues(std::string& result, std::vector>& values); @@ -237,4 +246,36 @@ private: void AddLibraryRuntimeInfo(std::string const& fullPath, const cmGeneratorTarget* target); void AddLibraryRuntimeInfo(std::string const& fullPath); + + class FeatureDescriptor + { + public: + FeatureDescriptor() = default; + FeatureDescriptor(std::string name, std::string itemFormat); + FeatureDescriptor(std::string name, std::string itemPathFormat, + std::string itemNameFormat); + FeatureDescriptor(std::string name, std::string prefix, + std::string itemPathFormat, std::string itemNameFormat, + std::string suffix); + + const std::string Name; + const bool Supported = false; + const std::string Prefix; + const std::string Suffix; + std::string GetDecoratedItem(std::string const& library, + ItemIsPath isPath) const; + std::string GetDecoratedItem(std::string const& library, + std::string const& linkItem, + std::string const& defaultValue, + ItemIsPath isPath) const; + + private: + std::string ItemPathFormat; + std::string ItemNameFormat; + }; + std::map LibraryFeatureDescriptors; + bool AddLibraryFeature(std::string const& feature); + FeatureDescriptor const& GetLibraryFeature(std::string const& feature) const; + FeatureDescriptor const* FindLibraryFeature( + std::string const& feature) const; }; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 396e9c9..b63b90b 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1198,6 +1198,68 @@ static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode } } linkLanguageAndIdNode; +static const struct LinkLibraryNode : public cmGeneratorExpressionNode +{ + LinkLibraryNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return OneOrMoreParameters; } + + std::string Evaluate( + const std::vector& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + if (!context->HeadTarget || !dagChecker || + !dagChecker->EvaluatingLinkLibraries()) { + reportError(context, content->GetOriginalExpression(), + "$ may only be used with binary targets " + "to specify link libraries."); + return std::string(); + } + + std::vector list; + cmExpandLists(parameters.begin(), parameters.end(), list); + if (list.empty()) { + reportError( + context, content->GetOriginalExpression(), + "$ expects a feature name as first argument."); + return std::string(); + } + if (list.size() == 1) { + // no libraries specified, ignore this genex + return std::string(); + } + + auto const& feature = list.front(); + const auto LL_BEGIN = cmStrCat("'); + const auto LL_END = cmStrCat("'); + + // filter out $ tags with same feature + // and raise an error for any different feature + cm::erase_if(list, [&](const std::string& item) -> bool { + return item == LL_BEGIN || item == LL_END; + }); + auto it = + std::find_if(list.cbegin() + 1, list.cend(), + [&feature](const std::string& item) -> bool { + return cmHasPrefix(item, "', 14) - 14) != feature; + }); + if (it != list.cend()) { + reportError( + context, content->GetOriginalExpression(), + "$ with different features cannot be nested."); + return std::string(); + } + + list.front() = LL_BEGIN; + list.push_back(LL_END); + + return cmJoin(list, ";"_s); + } +} linkLibraryNode; + static const struct HostLinkNode : public cmGeneratorExpressionNode { HostLinkNode() {} // NOLINT(modernize-use-equals-default) @@ -2668,6 +2730,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "COMPILE_LANGUAGE", &languageNode }, { "LINK_LANG_AND_ID", &linkLanguageAndIdNode }, { "LINK_LANGUAGE", &linkLanguageNode }, + { "LINK_LIBRARY", &linkLibraryNode }, { "HOST_LINK", &hostLinkNode }, { "DEVICE_LINK", &deviceLinkNode }, { "SHELL_PATH", &shellPathNode } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 9f1029e..58edefb 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -4625,7 +4625,8 @@ std::vector> cmGeneratorTarget::GetLinkOptions( } std::vector>& cmGeneratorTarget::ResolveLinkerWrapper( - std::vector>& result, const std::string& language) const + std::vector>& result, const std::string& language, + bool joinItems) const { // replace "LINKER:" prefixed elements by actual linker wrapper const std::string wrapper(this->Makefile->GetSafeDefinition( @@ -4684,7 +4685,14 @@ std::vector>& cmGeneratorTarget::ResolveLinkerWrapper( std::vector> options = wrapOptions( linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs); - result.insert(entry, options.begin(), options.end()); + if (joinItems) { + result.insert(entry, + cmJoin(cmRange( + options.cbegin(), options.cend()), + " "_s)); + } else { + result.insert(entry, options.begin(), options.end()); + } } return result; } @@ -6377,7 +6385,8 @@ bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role, std::string const& str = item.AsStr(); if (!str.empty() && (str[0] == '-' || str[0] == '$' || str[0] == '`' || - str.find_first_of("/\\") != std::string::npos)) { + str.find_first_of("/\\") != std::string::npos || + cmHasPrefix(str, ">& ResolveLinkerWrapper( - std::vector>& result, const std::string& language) const; + std::vector>& result, const std::string& language, + bool joinItems = false) const; void GetStaticLibraryLinkOptions(std::vector& result, const std::string& config, diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 203addd..489c7fb 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -3741,7 +3741,9 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } libPaths.Add("-framework " + this->XCodeEscapePath(fwName)); } else { - libPaths.Add(this->XCodeEscapePath(cleanPath)); + libPaths.Add( + libName.GetFormattedItem(this->XCodeEscapePath(cleanPath)) + .Value); } if ((!libName.Target || libName.Target->IsImported()) && IsLinkPhaseLibraryExtension(libPath)) { diff --git a/Source/cmLinkLibrariesCommand.cxx b/Source/cmLinkLibrariesCommand.cxx index 2b8f836..ed89e91 100644 --- a/Source/cmLinkLibrariesCommand.cxx +++ b/Source/cmLinkLibrariesCommand.cxx @@ -35,5 +35,7 @@ bool cmLinkLibrariesCommand(std::vector const& args, mf.AppendProperty("LINK_LIBRARIES", *i); } + mf.CheckProperty("LINK_LIBRARIES"); + return true; } diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx index 5646368..290642b 100644 --- a/Source/cmLinkLineComputer.cxx +++ b/Source/cmLinkLineComputer.cxx @@ -75,14 +75,8 @@ void cmLinkLineComputer::ComputeLinkLibs( BT linkLib; if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) { - if (item.IsObject == cmComputeLinkInformation::ItemIsObject::Yes) { - linkLib.Value += cli.GetObjLinkFileFlag(); - } else { - linkLib.Value += cli.GetLibLinkFileFlag(); - } - linkLib.Value += this->ConvertToOutputFormat( - this->ConvertToLinkReference(item.Value.Value)); - linkLib.Backtrace = item.Value.Backtrace; + linkLib = item.GetFormattedItem(this->ConvertToOutputFormat( + this->ConvertToLinkReference(item.Value.Value))); } else { linkLib = item.Value; } diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx index 43f161b..71f9f80 100644 --- a/Source/cmLinkLineDeviceComputer.cxx +++ b/Source/cmLinkLineDeviceComputer.cxx @@ -118,8 +118,10 @@ void cmLinkLineDeviceComputer::ComputeLinkLibraries( // can tolerate '.so' or '.dylib' it cannot tolerate '.so.1'. if (cmHasLiteralSuffix(item.Value.Value, ".a") || cmHasLiteralSuffix(item.Value.Value, ".lib")) { - linkLib.Value += this->ConvertToOutputFormat( - this->ConvertToLinkReference(item.Value.Value)); + linkLib.Value = item + .GetFormattedItem(this->ConvertToOutputFormat( + this->ConvertToLinkReference(item.Value.Value))) + .Value; } } else if (item.Value == "-framework") { // This is the first part of '-framework Name' where the framework @@ -127,7 +129,7 @@ void cmLinkLineDeviceComputer::ComputeLinkLibraries( skipItemAfterFramework = true; continue; } else if (cmLinkItemValidForDevice(item.Value.Value)) { - linkLib.Value += item.Value.Value; + linkLib.Value = item.Value.Value; } if (emitted.insert(linkLib.Value).second) { diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index ed7e888..f65add1 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1294,7 +1294,9 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries( for (auto const& lib : libs) { if (lib.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) { std::string rel = lg->MaybeRelativeToCurBinDir(lib.Value.Value); - fout << lg->ConvertToXMLOutputPath(rel) << " "; + rel = lg->ConvertToXMLOutputPath(rel); + fout << (lib.HasFeature() ? lib.GetFormattedItem(rel).Value : rel) + << " "; } else if (!lib.Target || lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { fout << lib.Value.Value << " "; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 4b1635b..6b17cc9 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3976,6 +3976,31 @@ std::vector cmMakefile::GetPropertyKeys() const return this->StateSnapshot.GetDirectory().GetPropertyKeys(); } +void cmMakefile::CheckProperty(const std::string& prop) const +{ + // Certain properties need checking. + if (prop == "LINK_LIBRARIES") { + if (cmValue value = this->GetProperty(prop)) { + // Look for internal pattern + static cmsys::RegularExpression linkLibrary( + "(^|;)(]*>)(;|$)"); + if (!linkLibrary.find(value)) { + return; + } + + // Report an error. + this->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Property ", prop, " contains the invalid item \"", + linkLibrary.match(2), "\". The ", prop, + " property may contain the generator-expression " + "\"$\" " + "which may be used to specify how the libraries are linked.")); + } + } +} + cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const { auto i = this->Targets.find(name); diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 85988b8..ecac95e 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -787,6 +787,7 @@ public: cmValue GetProperty(const std::string& prop, bool chain) const; bool GetPropertyAsBool(const std::string& prop) const; std::vector GetPropertyKeys() const; + void CheckProperty(const std::string& prop) const; //! Initialize a makefile from its parent void InitializeFromParent(cmMakefile* parent); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 87fce92..d40709f 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1779,69 +1779,93 @@ void cmTarget::InsertPrecompileHeader(BT 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 and internal tags + static cmsys::RegularExpression linkLibrary( + "(^|;)(]*>)(;|$)"); + if (!linkLibrary.find(value)) { return; } + // Report an error. + context->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Property ", property, " contains the invalid item \"", + linkLibrary.match(2), "\". The ", property, + " property may contain the generator-expression " + "\"$\" " + "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 << "_ 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 << "_ 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); +} - 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."; +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."; + + 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 = @@ -1857,6 +1881,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 @@ -1864,22 +1889,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); } } } diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index e15c941..0b96b2d 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -318,6 +318,9 @@ bool cmTargetLinkLibrariesCommand(std::vector const& args, target->SetProperty("LINK_INTERFACE_LIBRARIES", ""); } + target->CheckProperty("LINK_LIBRARIES", &mf); + target->CheckProperty("INTERFACE_LINK_LIBRARIES", &mf); + return true; } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 7b197fa..92d64fe 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -3677,7 +3677,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions( this->LocalGenerator->MaybeRelativeToCurBinDir(l.Value.Value); ConvertToWindowsSlash(path); if (!cmVS10IsTargetsFile(l.Value.Value)) { - libVec.push_back(path); + libVec.push_back(l.HasFeature() ? l.GetFormattedItem(path).Value + : path); } } else { libVec.push_back(l.Value.Value); @@ -4315,7 +4316,8 @@ void cmVisualStudio10TargetGenerator::AddLibraries( if (cmVS10IsTargetsFile(l.Value.Value)) { vsTargetVec.push_back(path); } else { - libVec.push_back(path); + libVec.push_back(l.HasFeature() ? l.GetFormattedItem(path).Value + : path); } } else if (!l.Target || l.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 1d7e632..d1a1ddd 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -312,6 +312,7 @@ add_RunCMake_test(GenEx-LINK_LANGUAGE) add_RunCMake_test(GenEx-LINK_LANG_AND_ID) add_RunCMake_test(GenEx-HOST_LINK) add_RunCMake_test(GenEx-DEVICE_LINK) +add_RunCMake_test(GenEx-LINK_LIBRARY) add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB}) add_RunCMake_test(GenEx-GENEX_EVAL) add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS) @@ -652,6 +653,17 @@ add_RunCMake_test(target_link_libraries) add_RunCMake_test(target_link_libraries-ALIAS) add_RunCMake_test(target_link_libraries-LINK_LANGUAGE) add_RunCMake_test(target_link_libraries-LINK_LANG_AND_ID) +add_RunCMake_test(target_link_libraries-LINK_LIBRARY -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} + -DMINGW=${MINGW} + -DMSYS=${MSYS} + -DCYGWIN=${CYGWIN} + -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} + -DMSVC_VERSION=${MSVC_VERSION} + -DCMAKE_SHARED_LIBRARY_PREFIX=${CMAKE_SHARED_LIBRARY_PREFIX} + -DCMAKE_SHARED_LIBRARY_SUFFIX=${CMAKE_SHARED_LIBRARY_SUFFIX} + -DCMAKE_IMPORT_LIBRARY_PREFIX=${CMAKE_IMPORT_LIBRARY_PREFIX} + -DCMAKE_IMPORT_LIBRARY_SUFFIX=${CMAKE_IMPORT_LIBRARY_SUFFIX} + -DCMAKE_LINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}) add_RunCMake_test(add_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}) add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} -DCMake_TEST_CUDA=${CMake_TEST_CUDA}) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/CMakeLists.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/CMakeLists.txt new file mode 100644 index 0000000..612169c --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.18...3.22) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake new file mode 100644 index 0000000..ab1ac37 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake @@ -0,0 +1,25 @@ +include(RunCMake) + +run_cmake(add_custom_target) +run_cmake(add_custom_command) +run_cmake(add_link_options) +run_cmake(link_directories) +run_cmake(target_link_options) +run_cmake(target_link_directories) +run_cmake(no-arguments) +run_cmake(empty-arguments) +run_cmake(forbidden-arguments) +run_cmake(bad-feature1) +run_cmake(bad-feature2) +run_cmake(bad-feature3) +run_cmake(bad-feature4) +run_cmake(bad-feature5) +run_cmake(bad-feature6) +run_cmake(bad-feature7) +run_cmake(feature-not-supported) +run_cmake(library-ignored) +run_cmake(compatible-features) +run_cmake(incompatible-features) +run_cmake(nested-compatible-features) +run_cmake(nested-incompatible-features) +run_cmake(only-targets) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-stderr.txt new file mode 100644 index 0000000..d8ff0eb --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at add_custom_command.cmake:[0-9]+ \(add_custom_command\): + Error evaluating generator expression: + + \$ + + \$ may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command.cmake new file mode 100644 index 0000000..3583a67 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command.cmake @@ -0,0 +1,4 @@ +add_custom_target(drive) +add_custom_command(TARGET drive PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "$" +) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-stderr.txt new file mode 100644 index 0000000..8ca384d --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at add_custom_target.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + \$ may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target.cmake new file mode 100644 index 0000000..ef00965 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target.cmake @@ -0,0 +1,3 @@ +add_custom_target(drive + COMMAND ${CMAKE_COMMAND} -E echo "$" +) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-stderr.txt new file mode 100644 index 0000000..399a413 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at add_link_options.cmake:[0-9]+ \(add_link_options\): + Error evaluating generator expression: + + \$ + + \$ may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options.cmake new file mode 100644 index 0000000..fdccf95 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options.cmake @@ -0,0 +1,5 @@ +enable_language(C) + +add_link_options("$") + +add_library(empty SHARED empty.c) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-stderr.txt new file mode 100644 index 0000000..0ff8aca --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature1.cmake:[0-9]+ \(add_library\): + Feature 'bad_feat', specified through generator-expression + '\$' to link target 'lib', is not supported for the 'C' link + language. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1.cmake new file mode 100644 index 0000000..5e540cf --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-stderr.txt new file mode 100644 index 0000000..9e878cc --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at bad-feature2.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified through generator-expression '\$' to + link target 'lib', is not defined for the 'C' link language. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2.cmake new file mode 100644 index 0000000..15b5ca0 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2.cmake @@ -0,0 +1,8 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat_SUPPORTED TRUE) + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-stderr.txt new file mode 100644 index 0000000..69963fe --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature3.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_USING_feat', is + malformed \("", "", or "" patterns are + missing\) and cannot be used to link target 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3.cmake new file mode 100644 index 0000000..7960465 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat "") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-stderr.txt new file mode 100644 index 0000000..7385115 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature4.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_USING_feat', is + malformed \("", "", or "" patterns are + missing\) and cannot be used to link target 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4.cmake new file mode 100644 index 0000000..b40cfaf --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat "-opt") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-stderr.txt new file mode 100644 index 0000000..9894577 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature5.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_USING_feat', is + malformed \(wrong number of elements\) and cannot be used to link target + 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5.cmake new file mode 100644 index 0000000..8ce1ecf --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat "-prefix" "") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-stderr.txt new file mode 100644 index 0000000..d8d0e19 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature6.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_USING_feat', is + malformed \("", "", or "" patterns are missing + for "PATH{}" alternative\) and cannot be used to link target 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6.cmake new file mode 100644 index 0000000..7b72ad5 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat "PATH{}NAME{}") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-stderr.txt new file mode 100644 index 0000000..2a498cd --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature7.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_USING_feat', is + malformed \("", "", or "" patterns are missing + for "NAME{}" alternative\) and cannot be used to link target 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7.cmake new file mode 100644 index 0000000..173f86c --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat "NAME{}PATH{}") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake new file mode 100644 index 0000000..e79764c --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat1 "") + +set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat2 "") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PRIVATE "$") + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-stderr.txt new file mode 100644 index 0000000..1530f61 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at empty-arguments.cmake:[0-9]+ \(target_link_libraries\): + Error evaluating generator expression: + + \$ + + \$ expects a feature name as first argument. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments.cmake new file mode 100644 index 0000000..c6e2260 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/empty.c b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty.c new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-stderr.txt new file mode 100644 index 0000000..6067bce --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at feature-not-supported.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified through generator-expression '\$' to + link target 'lib', is not supported for the 'C' link language. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported.cmake new file mode 100644 index 0000000..0666227 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat_SUPPORTED FALSE) +set(CMAKE_C_LINK_USING_feat "") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-stderr.txt new file mode 100644 index 0000000..5245dd8 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-stderr.txt @@ -0,0 +1,16 @@ +CMake Error at forbidden-arguments.cmake:[0-9]+ \(link_libraries\): + Property LINK_LIBRARIES contains the invalid item "". + The LINK_LIBRARIES property may contain the generator-expression + "\$" which may be used to specify how the libraries are + linked. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) + + +CMake Error at forbidden-arguments.cmake:[0-9]+ \(target_link_libraries\): + Property LINK_LIBRARIES contains the invalid item "". + The LINK_LIBRARIES property may contain the generator-expression + "\$" which may be used to specify how the libraries are + linked. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments.cmake new file mode 100644 index 0000000..1c51c44 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +link_libraries( foo ) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE foo ) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt new file mode 100644 index 0000000..22219a2 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at incompatible-features.cmake:[0-9]+ \(add_library\): + Impossible to link target 'lib' because the link item 'dep1', specified + with the feature 'feat1', has already occurred with the feature 'feat2', + which is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake new file mode 100644 index 0000000..d96b214 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat1 "") + +set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat2 "") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PUBLIC "$") + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt new file mode 100644 index 0000000..f9a99af --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt @@ -0,0 +1,14 @@ +CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\): + The feature 'feat', specified as part of a generator-expression + '\$', will not be applied to the INTERFACE library + 'front'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\): + The feature 'feat', specified as part of a generator-expression + '\$', will not be applied to the OBJECT library 'dep'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake new file mode 100644 index 0000000..e000b97 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat "") + +add_library(dep OBJECT empty.c) + +add_library(lib SHARED empty.c) + +add_library(front INTERFACE) +target_link_libraries(front INTERFACE lib) + + +add_library(lib2 SHARED empty.c) +target_link_libraries(lib2 PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-stderr.txt new file mode 100644 index 0000000..aeb32f2 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at link_directories.cmake:[0-9]+ \(link_directories\): + Error evaluating generator expression: + + \$ + + \$ may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories.cmake new file mode 100644 index 0000000..b6d9a36 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories.cmake @@ -0,0 +1,5 @@ +enable_language(C) + +link_directories("$") + +add_library(empty SHARED empty.c) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-compatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-compatible-features.cmake new file mode 100644 index 0000000..d3b04e8 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-compatible-features.cmake @@ -0,0 +1,11 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat1 "") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-stderr.txt new file mode 100644 index 0000000..3f6c504 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at nested-incompatible-features.cmake:[0-9]+ \(target_link_libraries\): + Error evaluating generator expression: + + \$> + + \$ with different features cannot be nested. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features.cmake new file mode 100644 index 0000000..8565fa9 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features.cmake @@ -0,0 +1,14 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat1 "") + +set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat2 "") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-stderr.txt new file mode 100644 index 0000000..af58fa0 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at no-arguments.cmake:[0-9]+ \(target_link_libraries\): + Error evaluating generator expression: + + \$ + + \$ expression requires at least one parameter. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments.cmake new file mode 100644 index 0000000..0645dc7 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-stderr.txt new file mode 100644 index 0000000..6b770f0 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-stderr.txt @@ -0,0 +1,13 @@ +CMake Error at only-targets.cmake:[0-9]+ \(target_link_libraries\): + Target "lib2" has LINK_LIBRARIES_ONLY_TARGETS enabled, but it links to: + + external + + which is not a target. Possible reasons include: + + \* There is a typo in the target name. + \* A find_package call is missing for an IMPORTED target. + \* An ALIAS target is missing. + +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets.cmake new file mode 100644 index 0000000..e29ad6c --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets.cmake @@ -0,0 +1,16 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat1 "") + +set(CMAKE_LINK_LIBRARIES_ONLY_TARGETS 1) + +add_library(dep1 SHARED empty.c) + +add_library(lib1 SHARED empty.c) +# accepted +target_link_libraries(lib1 PRIVATE "$") + +add_library(lib2 SHARED empty.c) +# invalid +target_link_libraries(lib2 PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-stderr.txt new file mode 100644 index 0000000..e0c60c4 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at target_link_directories.cmake:[0-9]+ \(target_link_directories\): + Error evaluating generator expression: + + \$ + + \$ may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories.cmake new file mode 100644 index 0000000..e8cc670 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(empty SHARED empty.c) +target_link_directories(empty PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-stderr.txt new file mode 100644 index 0000000..6c9aab1 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at target_link_options.cmake:[0-9]+ \(target_link_options\): + Error evaluating generator expression: + + \$ + + \$ may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options.cmake new file mode 100644 index 0000000..800124c --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(empty SHARED empty.c) +target_link_options(empty PRIVATE $) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/CMakeLists.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/CMakeLists.txt new file mode 100644 index 0000000..915fc41 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.1...3.22) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-check.cmake new file mode 100644 index 0000000..255c9a6 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG --LIBFLAG'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-check.cmake new file mode 100644 index 0000000..a8e0da7 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP --LIBGROUP --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-check.cmake new file mode 100644 index 0000000..54cef2c --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-check.cmake new file mode 100644 index 0000000..7c38134 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUPother${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP --LIBGROUP --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-check.cmake new file mode 100644 index 0000000..88b5cf6 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-ITEMFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAGother${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-ITEMFLAGother\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBFLAG --ITEMFLAG --LIBFLAG --ITEMFLAG --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-check.cmake new file mode 100644 index 0000000..c473637 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-ITEMFLAGother\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBFLAG --ITEMFLAG --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-check.cmake new file mode 100644 index 0000000..858dcfe --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP --LIBGROUP --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-check.cmake new file mode 100644 index 0000000..ab06726 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP --LIBGROUP --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-check.cmake new file mode 100644 index 0000000..62aa17c --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other2${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other1${LINK_EXTERN_LIBRARY_SUFFIX}") + set (RunCMake_TEST_FAILED "Not found expected ' --PREFIXGROUP --LIBGROUP --SUFFIXGROUP --PREFIXGROUP --LIBGROUP --SUFFIXGROUP '.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-check.cmake new file mode 100644 index 0000000..255c9a6 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG --LIBFLAG'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-check.cmake new file mode 100644 index 0000000..a8e0da7 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP --LIBGROUP --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-check.cmake new file mode 100644 index 0000000..32b58fe --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-check.cmake new file mode 100644 index 0000000..32b58fe --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake new file mode 100644 index 0000000..3223a95 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake @@ -0,0 +1,81 @@ + +enable_language(C) + +# ensure command line is always displayed and do not use any response file +set(CMAKE_VERBOSE_MAKEFILE TRUE) +set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES FALSE) + +if (CMAKE_GENERATOR MATCHES "Borland|NMake") + string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}") + string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}") +endif() + +add_library(base1 SHARED base.c) +add_library(base2 SHARED base.c) + +set(CMAKE_C_LINK_USING_feat1 "--LIBFLAG") +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) + +set(CMAKE_C_LINK_USING_feat1_1 "--LIBFLAG_C") +set(CMAKE_C_LINK_USING_feat1_1_SUPPORTED FALSE) +set(CMAKE_LINK_USING_feat1_1 "--LIBFLAG") +set(CMAKE_LINK_USING_feat1_1_SUPPORTED TRUE) + +set(CMAKE_C_LINK_USING_feat2 "--PREFIXGROUP" "--LIBGROUP" "--SUFFIXGROUP") +set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE) + +set(CMAKE_C_LINK_USING_feat3 "--PREFIXGROUP" "" "--SUFFIXGROUP") +set(CMAKE_C_LINK_USING_feat3_SUPPORTED TRUE) + +set(CMAKE_C_LINK_USING_feat4 "--PREFIXGROUP" "--LIBFLAG --ITEMFLAG" "--SUFFIXGROUP") +set(CMAKE_C_LINK_USING_feat4_SUPPORTED TRUE) + +set(CMAKE_C_LINK_USING_feat5 "--PREFIXGROUP" "PATH{--LIBFLAG}NAME{--ITEMFLAG}" "--SUFFIXGROUP") +set(CMAKE_C_LINK_USING_feat5_SUPPORTED TRUE) + +set(CMAKE_C_LINK_USING_feat6 "") +set(CMAKE_C_LINK_USING_feat6_SUPPORTED TRUE) + + +add_library(LinkLibrary_simple1 SHARED lib.c) +target_link_libraries(LinkLibrary_simple1 PRIVATE "$") + +add_library(LinkLibrary_simple2 SHARED lib.c) +target_link_libraries(LinkLibrary_simple2 PRIVATE "$") + +add_library(LinkLibrary_group1 SHARED lib.c) +target_link_libraries(LinkLibrary_group1 PRIVATE "$") + +add_library(LinkLibrary_group2 SHARED lib.c) +target_link_libraries(LinkLibrary_group2 PRIVATE "$") + +add_library(LinkLibrary_nested_feature1 SHARED lib.c) +target_link_libraries(LinkLibrary_nested_feature1 PRIVATE "$>") + +add_library(LinkLibrary_nested_feature2 SHARED lib.c) +target_link_libraries(LinkLibrary_nested_feature2 PRIVATE "$>") + +add_library(LinkLibrary_link_items1 SHARED lib.c) +target_link_libraries(LinkLibrary_link_items1 PRIVATE "$") + +add_library(LinkLibrary_link_items2 SHARED lib.c) +target_link_libraries(LinkLibrary_link_items2 PRIVATE "$") + +add_library(LinkLibrary_link_items3 SHARED lib.c) +target_link_libraries(LinkLibrary_link_items3 PRIVATE "$") + +add_library(LinkLibrary_link_items4 SHARED lib.c) +target_link_libraries(LinkLibrary_link_items4 PRIVATE "$") + +add_library(base3 SHARED base.c) +target_link_libraries(base3 PRIVATE "$") +add_library(LinkLibrary_mix_features1 SHARED lib.c) +target_link_libraries(LinkLibrary_mix_features1 PRIVATE "$") + +target_link_libraries(base3 INTERFACE "$") +add_library(LinkLibrary_mix_features2 SHARED lib.c) +target_link_libraries(LinkLibrary_mix_features2 PRIVATE "$") + +target_link_libraries(base3 INTERFACE other1) +add_library(LinkLibrary_mix_features3 SHARED lib.c) +target_link_libraries(LinkLibrary_mix_features3 PRIVATE base2 "$" other2) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake new file mode 100644 index 0000000..febada0 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake @@ -0,0 +1,73 @@ + +include(RunCMake) + +cmake_policy(SET CMP0054 NEW) + +macro(run_cmake_target test subtest target) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} --config Release --verbose ${ARGN}) + + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endmacro() + +# Some environments are excluded because they are not able to honor verbose mode +if ((RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Xcode" + OR (RunCMake_GENERATOR MATCHES "Visual Studio" AND MSVC_VERSION GREATER_EQUAL "1600")) + AND NOT CMAKE_C_COMPILER_ID STREQUAL "Intel") + + set(RunCMake_TEST_OUTPUT_MERGE TRUE) + if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release) + endif() + + if (CMAKE_SYSTEM_NAME STREQUAL "Windows" + OR CMAKE_SYSTEM_NAME STREQUAL "CYGWIN" + OR CMAKE_SYSTEM_NAME STREQUAL "MSYS") + set(LINK_SHARED_LIBRARY_PREFIX ${CMAKE_IMPORT_LIBRARY_PREFIX}) + set(LINK_SHARED_LIBRARY_SUFFIX ${CMAKE_IMPORT_LIBRARY_SUFFIX}) + else() + set(LINK_SHARED_LIBRARY_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) + set(LINK_SHARED_LIBRARY_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif() + if (MINGW OR MSYS OR CYGWIN) + set(LINK_EXTERN_LIBRARY_SUFFIX "") + else() + set(LINK_EXTERN_LIBRARY_SUFFIX "${CMAKE_IMPORT_LIBRARY_SUFFIX}") + endif() + + run_cmake(LINK_LIBRARY) + + run_cmake_target(LINK_LIBRARY simple1 LinkLibrary_simple1) + run_cmake_target(LINK_LIBRARY simple2 LinkLibrary_simple2) + run_cmake_target(LINK_LIBRARY group1 LinkLibrary_group1) + run_cmake_target(LINK_LIBRARY group2 LinkLibrary_group2) + run_cmake_target(LINK_LIBRARY nested-feature1 LinkLibrary_nested_feature1) + run_cmake_target(LINK_LIBRARY nested-feature2 LinkLibrary_nested_feature2) + run_cmake_target(LINK_LIBRARY link-items1 LinkLibrary_link_items1) + run_cmake_target(LINK_LIBRARY link-items2 LinkLibrary_link_items2) + run_cmake_target(LINK_LIBRARY link-items3 LinkLibrary_link_items3) + run_cmake_target(LINK_LIBRARY link-items4 LinkLibrary_link_items4) + run_cmake_target(LINK_LIBRARY mix-features1 LinkLibrary_mix_features1) + run_cmake_target(LINK_LIBRARY mix-features2 LinkLibrary_mix_features2) + run_cmake_target(LINK_LIBRARY mix-features3 LinkLibrary_mix_features3) + + run_cmake(imported-target) + + # tests using features as described in the documentation + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" + OR (CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER "1900") + OR (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")) + run_cmake(whole_archive) + run_cmake_target(whole_archive link-exe main) + endif() + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + run_cmake(weak_library) + run_cmake_target(weak_library link-exe main) + endif() + + unset(RunCMake_TEST_OPTIONS) + unset(RunCMake_TEST_OUTPUT_MERGE) + +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/base.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/base.c new file mode 100644 index 0000000..a5075d4 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/base.c @@ -0,0 +1,9 @@ + +#if !defined(STATIC_BASE) +# if defined(_WIN32) +__declspec(dllexport) +# endif +#endif + void base() +{ +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-stdout.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-stdout.txt new file mode 100644 index 0000000..b3a86cc --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-stdout.txt @@ -0,0 +1,18 @@ +CMake Warning \(dev\) at imported-target.cmake:[0-9]+ \(add_library\): + The 'IMPORTED' target 'NS::lib2' uses the generator-expression + '\$' with the feature 'whole_archive', which is undefined or + unsupported. + + Did you miss to define it by setting variables + "CMAKE_C_LINK_USING_whole_archive" and + "CMAKE_C_LINK_USING_whole_archive_SUPPORTED"\? +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error at imported-target.cmake:[0-9]+ \(add_library\): + Feature 'whole_archive', specified through generator-expression + '\$' to link target 'lib', is not supported for the 'C' link + language. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target.cmake new file mode 100644 index 0000000..9283054 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target.cmake @@ -0,0 +1,18 @@ + +enable_language(C) + +# Create imported target NS::lib +add_library(NS::lib STATIC IMPORTED) + +# Create imported target NS::lib2 +add_library(NS::lib2 SHARED IMPORTED) + +set_target_properties(NS::lib2 PROPERTIES + IMPORTED_LOCATION "/path/to/lib" + IMPORTED_IMPLIB "/path/to/import.lib" + INTERFACE_LINK_LIBRARIES "$" +) + + +add_library(lib SHARED lib.c) +target_link_libraries(lib PRIVATE NS::lib2) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/lib.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/lib.c new file mode 100644 index 0000000..35ab367 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/lib.c @@ -0,0 +1,15 @@ + +#if !defined(STATIC_BASE) +# if defined(_WIN32) +__declspec(dllimport) +# endif +#endif + void base(); + +#if defined(_WIN32) +__declspec(dllexport) +#endif + void lib() +{ + base(); +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.c new file mode 100644 index 0000000..601bd96 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.c @@ -0,0 +1,18 @@ + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void lib(); + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void unref(); + +int main() +{ + lib(); + unref(); + + return 0; +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/unref.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/unref.c new file mode 100644 index 0000000..37c3206 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/unref.c @@ -0,0 +1,8 @@ + + +#if defined(_WIN32) +__declspec(dllexport) +#endif + void unref() +{ +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/weak_library.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/weak_library.cmake new file mode 100644 index 0000000..135326e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/weak_library.cmake @@ -0,0 +1,20 @@ + +enable_language(C) + +if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_LINK_USING_weak_library "PATH{-weak_library }NAME{LINKER:-weak-l}") + set(CMAKE_LINK_USING_weak_library_SUPPORTED TRUE) +else() + # feature not yet supported for the other environments + set(CMAKE_LINK_USING_whole_library_SUPPORTED FALSE) +endif() + +add_library(lib SHARED base.c lib.c unref.c) +set_property(TARGET lib PROPERTY OUTPUT_NAME base) + +add_executable(main main.c) +target_link_libraries(main PRIVATE "$") + +add_executable(main2 main.c) +target_link_directories(main2 PRIVATE "$") +target_link_libraries(main2 PRIVATE "$") diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/whole_archive.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/whole_archive.cmake new file mode 100644 index 0000000..5214565 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/whole_archive.cmake @@ -0,0 +1,34 @@ + +enable_language(C) + +set(CMAKE_C_LINK_USING_whole_archive_SUPPORTED TRUE) +if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_C_LINK_USING_whole_archive "-force_load ") +elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + execute_process(COMMAND "${CMAKE_LINKER}" --help + OUTPUT_VARIABLE linker_help + ERROR_VARIABLE linker_help) + if(linker_help MATCHES "--push-state" AND linker_help MATCHES "--pop-state") + set(CMAKE_C_LINK_USING_whole_archive "LINKER:--push-state,--whole-archive" + "" + "LINKER:--pop-state") + else() + set(CMAKE_C_LINK_USING_whole_archive "LINKER:--whole-archive" + "" + "LINKER:--no-whole-archive") + endif() +elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_C_LINK_USING_whole_archive "/WHOLEARCHIVE:") +else() + # feature not yet supported for the other environments + set(CMAKE_C_LINK_USING_whole_archive_SUPPORTED FALSE) +endif() + +add_library(base STATIC base.c unref.c) +target_compile_definitions(base PUBLIC STATIC_BASE) + +add_library(lib SHARED lib.c) +target_link_libraries(lib PRIVATE "$") + +add_executable(main main.c) +target_link_libraries(main PRIVATE lib) -- cgit v0.12 From 2a6b0415d71db893b6d8edd1c5058d42eb40fca6 Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Fri, 19 Nov 2021 19:08:30 +0100 Subject: $: Add LINK_LIBRARY_OVERRIDE target property To enable the management of incompatible $ declarations, add LINK_LIBRARY_OVERRIDE and LINK_LIBRARY_OVERRIDE_ target properties. --- Help/manual/cmake-generator-expressions.7.rst | 8 ++ Help/manual/cmake-properties.7.rst | 2 + Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst | 54 +++++++++++++ Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst | 45 +++++++++++ Help/release/dev/Genex-LINK_LIBRARY.rst | 5 +- Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst | 7 ++ Help/variable/CMAKE_LINK_USING_FEATURE.rst | 7 ++ Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt | 5 ++ Modules/CMakeGenericSystem.cmake | 6 ++ Source/cmComputeLinkDepends.cxx | 90 ++++++++++++++++++---- Source/cmComputeLinkDepends.h | 8 +- Source/cmComputeLinkInformation.cxx | 17 ++-- Source/cmGeneratorExpressionDAGChecker.cxx | 2 +- .../RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake | 11 ++- .../GenEx-LINK_LIBRARY/compatible-features.cmake | 10 ++- .../incompatible-features-result.txt | 1 - .../incompatible-features-stderr.txt | 6 -- .../GenEx-LINK_LIBRARY/incompatible-features.cmake | 15 ---- .../incompatible-features1-result.txt | 1 + .../incompatible-features1-stderr.txt | 6 ++ .../incompatible-features1.cmake | 15 ++++ .../incompatible-features2-result.txt | 1 + .../incompatible-features2-stderr.txt | 6 ++ .../incompatible-features2.cmake | 15 ++++ .../incompatible-features3-result.txt | 1 + .../incompatible-features3-stderr.txt | 6 ++ .../incompatible-features3.cmake | 15 ++++ .../GenEx-LINK_LIBRARY/override-features1.cmake | 4 + .../GenEx-LINK_LIBRARY/override-features2.cmake | 4 + .../GenEx-LINK_LIBRARY/override-features3.cmake | 7 ++ .../GenEx-LINK_LIBRARY/override-features4.cmake | 9 +++ .../GenEx-LINK_LIBRARY/override-features5.cmake | 7 ++ .../LINK_LIBRARY-override-features1-check.cmake | 4 + .../LINK_LIBRARY-override-features1-result.txt | 1 + .../LINK_LIBRARY-override-features2-check.cmake | 4 + .../LINK_LIBRARY-override-features2-result.txt | 1 + .../LINK_LIBRARY-override-features3-check.cmake | 4 + .../LINK_LIBRARY-override-features3-result.txt | 1 + .../LINK_LIBRARY-override-features4-check.cmake | 4 + .../LINK_LIBRARY-override-features4-result.txt | 1 + .../LINK_LIBRARY-override-with-DEFAULT-check.cmake | 4 + .../LINK_LIBRARY-override-with-DEFAULT-result.txt | 1 + .../LINK_LIBRARY.cmake | 27 ++++++- .../RunCMakeTest.cmake | 8 ++ 44 files changed, 404 insertions(+), 52 deletions(-) create mode 100644 Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst create mode 100644 Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst create mode 100644 Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt delete mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt delete mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt delete mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-stderr.txt create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/override-features1.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/override-features2.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/override-features3.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/override-features4.cmake create mode 100644 Tests/RunCMake/GenEx-LINK_LIBRARY/override-features5.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-check.cmake create mode 100644 Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index b67d479..7c34671 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1176,12 +1176,20 @@ Output-Related Expressions target_link_libraries(lib3 PRIVATE lib1 lib2) # an error will be raised here because lib1 has two different features + To resolve such incompatibilities, the :prop_tgt:`LINK_LIBRARY_OVERRIDE` + and :prop_tgt:`LINK_LIBRARY_OVERRIDE_` target properties can be + used. + .. note:: This expression does not guarantee that the list of specified libraries will be kept grouped. So, constructs like ``start-group`` and ``end-group``, as supported by ``GNU ld``, cannot be used. + ``CMake`` pre-defines some features of general interest: + + .. include:: ../variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt + .. genex:: $ Content of ``...`` when the property is exported using :command:`install(EXPORT)`, diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index f4efd3c..e8048b3 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -308,6 +308,8 @@ Properties on Targets /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG /prop_tgt/LINK_LIBRARIES /prop_tgt/LINK_LIBRARIES_ONLY_TARGETS + /prop_tgt/LINK_LIBRARY_OVERRIDE + /prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY /prop_tgt/LINK_OPTIONS /prop_tgt/LINK_SEARCH_END_STATIC /prop_tgt/LINK_SEARCH_START_STATIC diff --git a/Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst b/Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst new file mode 100644 index 0000000..e9c76b0 --- /dev/null +++ b/Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst @@ -0,0 +1,54 @@ +LINK_LIBRARY_OVERRIDE +--------------------- + +.. versionadded:: 3.24 + +To resolve incompatible features introduced by :genex:`LINK_LIBRARY` generator +expression, this property offers the possibility to override, per ``link-item`` +(``CMake`` target or external library) involved in the link step, any defined +features with a new one. + +This property takes a :ref:`;-list ` of override +declarations which have the following format: + +:: + + feature[,link-item]* + +For the list of ``link-item`` (``CMake`` target or external library) specified, +the feature ``feature`` will be used in place of any declared feature. For +example: + +.. code-block:: cmake + + add_library(lib1 ...) + target_link_libraries(lib1 PUBLIC $) + + add_library(lib2 ...) + target_link_libraries(lib2 PUBLIC $) + + add_library(lib3 ...) + target_link_libraries(lib3 PRIVATE lib1 lib2) + # Here, lib1 has two different features which prevents to link lib3 + # So, define LINK_LIBRARY_OVERRIDE property to ensure correct link + set_property(TARGET lib3 PROPERTY LINK_LIBRARY_OVERRIDE "feature2,lib1,external") + # The lib1 and external will be used with FEATURE2 to link lib3 + +It is also possible to override any feature with the pre-defined feature +``DEFAULT`` to get the standard behavior (i.e. no feature): + +.. code-block:: cmake + + set_property(TARGET lib3 PROPERTY LINK_LIBRARY_OVERRIDE "DEFAULT,lib1" + "feature2,external") + # The lib1 will be used without any feature and external will use feature2 to link lib3 + +Contents of ``LINK_LIBRARY_OVERRIDE`` may use +:manual:`generator expressions `. + +See also :prop_tgt:`LINK_LIBRARY_OVERRIDE_` target property for +a per linked target oriented approach to override features. + +For more information about features, see +:variable:`CMAKE__LINK_USING_` +and :variable:`CMAKE_LINK_USING_` variables. diff --git a/Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst b/Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst new file mode 100644 index 0000000..58141c9 --- /dev/null +++ b/Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst @@ -0,0 +1,45 @@ +LINK_LIBRARY_OVERRIDE_ +------------------------------- + +.. versionadded:: 3.24 + +To resolve incompatible features introduced by :genex:`LINK_LIBRARY` generator +expression, this property offers the possibility to override, for a +``link-item`` (``CMake`` target or external library) involved in the link step, +any defined features with a new one. + +This property takes a ``feature`` name which will be applied to the +``link-item`` specified by ```` suffix property. For example: + +.. code-block:: cmake + + add_library(lib1 ...) + target_link_libraries(lib1 PUBLIC $) + + add_library(lib2 ...) + target_link_libraries(lib2 PUBLIC $) + + add_library(lib3 ...) + target_link_libraries(lib3 PRIVATE lib1 lib2) + # Here, lib1 has two different features which prevents to link lib3 + # So, define LINK_LIBRARY_OVERRIDE_lib1 property to ensure correct link + set_property(TARGET lib3 PROPERTY LINK_LIBRARY_OVERRIDE_lib1 feature2) + # The lib1 will be used with feature2 to link lib3 + +It is also possible to override any feature with the pre-defined feature +``DEFAULT`` to get the standard behavior (i.e. no feature): + +.. code-block:: cmake + + set_property(TARGET lib3 PROPERTY LINK_LIBRARY_OVERRIDE_lib1 DEFAULT) + # The lib1 will be used without any feature to link lib3 + +Contents of ``LINK_LIBRARY_OVERRIDE_`` may use +:manual:`generator expressions `. + +This property takes precedence over :prop_tgt:`LINK_LIBRARY_OVERRIDE` +target property. + +For more information about features, see +:variable:`CMAKE__LINK_USING_` +and :variable:`CMAKE_LINK_USING_` variables. diff --git a/Help/release/dev/Genex-LINK_LIBRARY.rst b/Help/release/dev/Genex-LINK_LIBRARY.rst index 6b87a4f..3234acb 100644 --- a/Help/release/dev/Genex-LINK_LIBRARY.rst +++ b/Help/release/dev/Genex-LINK_LIBRARY.rst @@ -5,4 +5,7 @@ Genex-LINK_LIBRARY libraries are specified during the link step. The variables :variable:`CMAKE__LINK_USING_` and :variable:`CMAKE_LINK_USING_` are used to define features usable by - the :genex:`LINK_LIBRARY` generator expression. + the :genex:`LINK_LIBRARY` generator expression. Moreover, the + :prop_tgt:`LINK_LIBRARY_OVERRIDE` and + :prop_tgt:`LINK_LIBRARY_OVERRIDE_` target properties are available + to resolve incompatible features. diff --git a/Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst b/Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst index ff8b3d9..9d7f87a 100644 --- a/Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst +++ b/Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst @@ -17,3 +17,10 @@ See also the associated variable independent from the link language. .. include:: CMAKE_LINK_USING_FEATURE.txt + +Predefined Features +^^^^^^^^^^^^^^^^^^^ + +``CMake`` pre-defines some features of general interest: + +.. include:: LINK_LIBRARY_PREDEFINED_FEATURES.txt diff --git a/Help/variable/CMAKE_LINK_USING_FEATURE.rst b/Help/variable/CMAKE_LINK_USING_FEATURE.rst index 3d94461..0c9cadc 100644 --- a/Help/variable/CMAKE_LINK_USING_FEATURE.rst +++ b/Help/variable/CMAKE_LINK_USING_FEATURE.rst @@ -21,3 +21,10 @@ for the linker language, the variable :variable:`CMAKE__LINK_USING__SUPPORTED` is false or not set. .. include:: CMAKE_LINK_USING_FEATURE.txt + +Predefined Features +^^^^^^^^^^^^^^^^^^^ + +``CMake`` pre-defines some features of general interest: + +.. include:: LINK_LIBRARY_PREDEFINED_FEATURES.txt diff --git a/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt new file mode 100644 index 0000000..dd22e14 --- /dev/null +++ b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt @@ -0,0 +1,5 @@ +**Features available in all environments** + +* ``DEFAULT``: This feature enables default link expression. This is mainly + useful with :prop_tgt:`LINK_LIBRARY_OVERRIDE` and + :prop_tgt:`LINK_LIBRARY_OVERRIDE_` target properties. diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake index 649b6f7..9ae68c4 100644 --- a/Modules/CMakeGenericSystem.cmake +++ b/Modules/CMakeGenericSystem.cmake @@ -24,6 +24,12 @@ set(CMAKE_DL_LIBS "dl") set(CMAKE_FIND_LIBRARY_PREFIXES "lib") set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a") +# Define feature "DEFAULT" as supported. This special feature generates the +# default option to link a library +# This feature is intended to be used in LINK_LIBRARY_OVERRIDE and +# LINK_LIBRARY_OVERRIDE_ target properties +set(CMAKE_LINK_USING_DEFAULT_SUPPORTED TRUE) + set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON) set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON) if(NOT DEFINED CMAKE_AUTOMOC_PATH_PREFIX) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index c3367ac..e6073cb 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -11,9 +11,12 @@ #include #include +#include #include #include "cmComputeComponentGraph.h" +#include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmListFileCache.h" @@ -200,6 +203,8 @@ bool IsFeatureSupported(cmMakefile* makefile, std::string const& linkLanguage, } } +const std::string cmComputeLinkDepends::LinkEntry::DEFAULT = "DEFAULT"; + cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, const std::string& config, const std::string& linkLanguage) @@ -212,6 +217,49 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance(); this->LinkLanguage = linkLanguage; + // target oriented feature override property takes precedence over + // global override property + cm::string_view lloPrefix = "LINK_LIBRARY_OVERRIDE_"_s; + auto const& keys = this->Target->GetPropertyKeys(); + std::for_each( + keys.cbegin(), keys.cend(), + [this, &lloPrefix, &config, &linkLanguage](std::string const& key) { + if (cmHasPrefix(key, lloPrefix)) { + if (cmValue feature = this->Target->GetProperty(key)) { + if (!feature->empty() && key.length() > lloPrefix.length()) { + auto item = key.substr(lloPrefix.length()); + cmGeneratorExpressionDAGChecker dag{ this->Target->GetBacktrace(), + this->Target, + "LINK_LIBRARY_OVERRIDE", + nullptr, nullptr }; + auto overrideFeature = cmGeneratorExpression::Evaluate( + feature, this->Target->GetLocalGenerator(), config, this->Target, + &dag, this->Target, linkLanguage); + this->LinkLibraryOverride.emplace(item, overrideFeature); + } + } + } + }); + // global override property + if (cmValue linkLibraryOverride = + this->Target->GetProperty("LINK_LIBRARY_OVERRIDE")) { + cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, + "LINK_LIBRARY_OVERRIDE", nullptr, + nullptr }; + auto overrideValue = cmGeneratorExpression::Evaluate( + linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag, + target, linkLanguage); + + auto overrideList = cmTokenize(overrideValue, ","_s); + if (overrideList.size() >= 2) { + auto const& feature = overrideList.front(); + for_each(overrideList.cbegin() + 1, overrideList.cend(), + [this, &feature](std::string const& item) { + this->LinkLibraryOverride.emplace(item, feature); + }); + } + } + // The configuration being linked. this->HasConfig = !config.empty(); this->Config = (this->HasConfig) ? config : std::string(); @@ -309,6 +357,13 @@ cmComputeLinkDepends::Compute() return this->FinalLinkEntries; } +std::string const& cmComputeLinkDepends::GetCurrentFeature( + std::string const& item, std::string const& defaultFeature) const +{ + auto it = this->LinkLibraryOverride.find(item); + return it == this->LinkLibraryOverride.end() ? defaultFeature : it->second; +} + std::pair::iterator, bool> cmComputeLinkDepends::AllocateLinkEntry(cmLinkItem const& item) { @@ -568,7 +623,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, { // Track inferred dependency sets implied by this list. std::map dependSets; - std::string feature; + std::string feature = LinkEntry::DEFAULT; // Loop over the libraries linked directly by the depender. for (T const& l : libs) { @@ -604,7 +659,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, continue; } if (cmHasPrefix(item.AsStr(), LL_END) && cmHasSuffix(item.AsStr(), '>')) { - feature.clear(); + feature = LinkEntry::DEFAULT; continue; } @@ -612,7 +667,9 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, auto ale = this->AddLinkEntry(item); int dependee_index = ale.first; LinkEntry& entry = this->EntryList[dependee_index]; - if (!feature.empty()) { + auto const& itemFeature = + this->GetCurrentFeature(entry.Item.Value, feature); + if (itemFeature != LinkEntry::DEFAULT) { if (ale.second) { // current item not yet defined if (entry.Target != nullptr && @@ -633,7 +690,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, " library '", entry.Item.Value, "'."), this->Target->GetBacktrace()); } else { - entry.Feature = feature; + entry.Feature = itemFeature; } } } @@ -642,20 +699,21 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, (entry.Target->GetType() != cmStateEnums::TargetType::OBJECT_LIBRARY && entry.Target->GetType() != cmStateEnums::TargetType::INTERFACE_LIBRARY); - if (supportedItem && entry.Feature != feature) { + if (supportedItem && entry.Feature != itemFeature) { // incompatibles features occurred this->CMakeInstance->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat( - "Impossible to link target '", this->Target->GetName(), - "' because the link item '", entry.Item.Value, "', specified ", - (feature.empty() ? "without any feature" - : cmStrCat("with the feature '", feature, '\'')), - ", has already occurred ", - (entry.Feature.empty() - ? "without any feature" - : cmStrCat("with the feature '", entry.Feature, '\'')), - ", which is not allowed."), + cmStrCat("Impossible to link target '", this->Target->GetName(), + "' because the link item '", entry.Item.Value, + "', specified ", + (itemFeature == LinkEntry::DEFAULT + ? "without any feature or 'DEFAULT' feature" + : cmStrCat("with the feature '", itemFeature, '\'')), + ", has already occurred ", + (entry.Feature == LinkEntry::DEFAULT + ? "without any feature or 'DEFAULT' feature" + : cmStrCat("with the feature '", entry.Feature, '\'')), + ", which is not allowed."), this->Target->GetBacktrace()); } @@ -978,7 +1036,7 @@ void cmComputeLinkDepends::DisplayFinalEntries() } else { fprintf(stderr, " item [%s]", lei.Item.Value.c_str()); } - if (!lei.Feature.empty()) { + if (lei.Feature != LinkEntry::DEFAULT) { fprintf(stderr, ", feature [%s]", lei.Feature.c_str()); } fprintf(stderr, "\n"); diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 02bdf50..64603e0 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -47,6 +47,8 @@ public: { } + static const std::string DEFAULT; + BT Item; cmGeneratorTarget const* Target = nullptr; bool IsSharedDep = false; @@ -54,7 +56,7 @@ public: bool IsObject = false; // The following member is for the management of items specified // through genex $ - std::string Feature; + std::string Feature = std::string(DEFAULT); }; using EntryVector = std::vector; @@ -75,6 +77,10 @@ private: std::string LinkLanguage; std::string Config; EntryVector FinalLinkEntries; + std::map LinkLibraryOverride; + + std::string const& GetCurrentFeature( + std::string const& item, std::string const& defaultFeature) const; std::pair::iterator, bool> AllocateLinkEntry( cmLinkItem const& item); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 5c3a96d..15e9d60 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -431,6 +431,10 @@ cmComputeLinkInformation::cmComputeLinkInformation( cmComputeLinkInformation::~cmComputeLinkInformation() = default; +namespace { +const std::string& DEFAULT = cmComputeLinkDepends::LinkEntry::DEFAULT; +} + void cmComputeLinkInformation::AppendValues( std::string& result, std::vector>& values) { @@ -551,7 +555,7 @@ bool cmComputeLinkInformation::Compute() currentFeature = nullptr; } - if (!linkEntry.Feature.empty() && + if (linkEntry.Feature != DEFAULT && (currentFeature == nullptr || linkEntry.Feature != currentFeature->Name)) { if (!this->AddLibraryFeature(linkEntry.Feature)) { @@ -988,8 +992,9 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry) std::string exe = tgt->GetFullPath(config, artifact, true); this->Items.emplace_back( BT(exe, item.Backtrace), ItemIsPath::Yes, tgt, - this->FindLibraryFeature( - entry.Feature.empty() ? "__CMAKE_LINK_EXECUTABLE" : entry.Feature)); + this->FindLibraryFeature(entry.Feature == DEFAULT + ? "__CMAKE_LINK_EXECUTABLE" + : entry.Feature)); this->Depends.push_back(std::move(exe)); } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { // Add the interface library as an item so it can be considered as part @@ -1421,7 +1426,7 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) // Now add the full path to the library. this->Items.emplace_back(item, ItemIsPath::Yes, target, - this->FindLibraryFeature(entry.Feature.empty() + this->FindLibraryFeature(entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature)); } @@ -1482,7 +1487,7 @@ void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry) this->Items.emplace_back( item, ItemIsPath::Yes, nullptr, this->FindLibraryFeature( - entry.Feature.empty() + entry.Feature == DEFAULT ? (entry.IsObject ? "__CMAKE_LINK_OBJECT" : "__CMAKE_LINK_LIBRARY") : entry.Feature)); } @@ -1650,7 +1655,7 @@ void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry, // Create an option to ask the linker to search for the library. auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix); - if (!entry.Feature.empty()) { + if (entry.Feature != DEFAULT) { auto const& feature = this->GetLibraryFeature(entry.Feature); this->Items.emplace_back( BT( diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index d4b02a5..d35d428 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -167,7 +167,7 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const cm::string_view property(this->Top()->Property); return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s || - property == "LINK_DEPENDS"_s; + property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s; } bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake index ab1ac37..d5438b8 100644 --- a/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake @@ -19,7 +19,16 @@ run_cmake(bad-feature7) run_cmake(feature-not-supported) run_cmake(library-ignored) run_cmake(compatible-features) -run_cmake(incompatible-features) +run_cmake(incompatible-features1) +run_cmake(incompatible-features2) +run_cmake(incompatible-features3) run_cmake(nested-compatible-features) run_cmake(nested-incompatible-features) run_cmake(only-targets) + +# testing target propertes LINK_LIBRARY_OVERRIDE and LINK_LIBRARY_OVERRIDE_ +run_cmake(override-features1) +run_cmake(override-features2) +run_cmake(override-features3) +run_cmake(override-features4) +run_cmake(override-features5) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake index e79764c..2579a5f 100644 --- a/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake @@ -11,5 +11,11 @@ add_library(dep1 SHARED empty.c) add_library(dep2 SHARED empty.c) target_link_libraries(dep2 PRIVATE "$") -add_library(lib SHARED empty.c) -target_link_libraries(lib PRIVATE "$") +add_library(dep3 SHARED empty.c) +target_link_libraries(dep3 PUBLIC dep2) + +add_library(lib1 SHARED empty.c) +target_link_libraries(lib1 PRIVATE $) + +add_library(lib2 SHARED empty.c) +target_link_libraries(lib2 PRIVATE $) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt deleted file mode 100644 index 22219a2..0000000 --- a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt +++ /dev/null @@ -1,6 +0,0 @@ -CMake Error at incompatible-features.cmake:[0-9]+ \(add_library\): - Impossible to link target 'lib' because the link item 'dep1', specified - with the feature 'feat1', has already occurred with the feature 'feat2', - which is not allowed. -Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake deleted file mode 100644 index d96b214..0000000 --- a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake +++ /dev/null @@ -1,15 +0,0 @@ -enable_language(C) - -set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) -set(CMAKE_C_LINK_USING_feat1 "") - -set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE) -set(CMAKE_C_LINK_USING_feat2 "") - -add_library(dep1 SHARED empty.c) - -add_library(dep2 SHARED empty.c) -target_link_libraries(dep2 PUBLIC "$") - -add_library(lib SHARED empty.c) -target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt new file mode 100644 index 0000000..1b31faa --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at incompatible-features1.cmake:[0-9]+ \(add_library\): + Impossible to link target 'lib' because the link item 'dep1', specified + with the feature 'feat1', has already occurred with the feature 'feat2', + which is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake new file mode 100644 index 0000000..d96b214 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat1 "") + +set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat2 "") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PUBLIC "$") + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-stderr.txt new file mode 100644 index 0000000..0855481 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at incompatible-features2.cmake:[0-9]+ \(add_library\): + Impossible to link target 'lib' because the link item 'dep1', specified + without any feature or 'DEFAULT' feature, has already occurred with the + feature 'feat2', which is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2.cmake new file mode 100644 index 0000000..1845fdb --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat1 "") + +set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat2 "") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PUBLIC dep1) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE $) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-stderr.txt new file mode 100644 index 0000000..2f40a1d --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at incompatible-features3.cmake:[0-9]+ \(add_library\): + Impossible to link target 'lib' because the link item 'dep1', specified + with the feature 'feat1', has already occurred without any feature or + 'DEFAULT' feature, which is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3.cmake new file mode 100644 index 0000000..1198d91 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat1 "") + +set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat2 "") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PUBLIC $) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE dep1 dep2) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features1.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features1.cmake new file mode 100644 index 0000000..6306c5d --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features1.cmake @@ -0,0 +1,4 @@ + +include(incompatible-features1.cmake) + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat1,dep1") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features2.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features2.cmake new file mode 100644 index 0000000..aa6ee76 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features2.cmake @@ -0,0 +1,4 @@ + +include(incompatible-features1.cmake) + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat2,dep1") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features3.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features3.cmake new file mode 100644 index 0000000..7f010fd --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features3.cmake @@ -0,0 +1,7 @@ + +include(incompatible-features1.cmake) + +set(CMAKE_C_LINK_USING_feat3_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat3 "") + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat3,dep1") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features4.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features4.cmake new file mode 100644 index 0000000..405cc8a --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features4.cmake @@ -0,0 +1,9 @@ + +include(incompatible-features1.cmake) + + +set(CMAKE_C_LINK_USING_feat3_SUPPORTED TRUE) +set(CMAKE_C_LINK_USING_feat3 "") + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat3,dep1") +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE_dep1 feat1) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features5.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features5.cmake new file mode 100644 index 0000000..1406d2a --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features5.cmake @@ -0,0 +1,7 @@ + +include(incompatible-features1.cmake) + + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat1,dep1") +# next property will be ignored because no feature is specified +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE_dep1) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-check.cmake new file mode 100644 index 0000000..a9fba20 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other1") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG --LIBFLAG '.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-check.cmake new file mode 100644 index 0000000..58c117e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUPother1${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG --PREFIXGROUP --LIBGROUP --LIBGROUP --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-check.cmake new file mode 100644 index 0000000..a9fba20 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other1") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG --LIBFLAG '.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-check.cmake new file mode 100644 index 0000000..58c117e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUPother1${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG --PREFIXGROUP --LIBGROUP --LIBGROUP --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-check.cmake new file mode 100644 index 0000000..d022f7e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other1${LINK_EXTERN_LIBRARY_SUFFIX}\"?") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG '.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake index 3223a95..ced689e 100644 --- a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake @@ -1,4 +1,3 @@ - enable_language(C) # ensure command line is always displayed and do not use any response file @@ -78,4 +77,28 @@ target_link_libraries(LinkLibrary_mix_features2 PRIVATE "$" other2) +target_link_libraries(LinkLibrary_mix_features3 PRIVATE base2 $ other2) + +# testing LINK_LIBRARY_OVERRIDE property +add_library(LinkLibrary_override_features1 SHARED lib.c) +target_link_libraries(LinkLibrary_override_features1 PRIVATE $) +set_property(TARGET LinkLibrary_override_features1 PROPERTY LINK_LIBRARY_OVERRIDE "feat1,base1") + +add_library(LinkLibrary_override_features2 SHARED lib.c) +target_link_libraries(LinkLibrary_override_features2 PRIVATE $) +set_property(TARGET LinkLibrary_override_features2 PROPERTY LINK_LIBRARY_OVERRIDE "feat2,base1,other1") + +add_library(LinkLibrary_override_with_default SHARED lib.c) +target_link_libraries(LinkLibrary_override_with_default PRIVATE $) +set_property(TARGET LinkLibrary_override_with_default PROPERTY LINK_LIBRARY_OVERRIDE "$<$:DEFAULT,base1,other1>") + +# testing LINK_LIBRARY_OVERRIDE_ property +add_library(LinkLibrary_override_features3 SHARED lib.c) +target_link_libraries(LinkLibrary_override_features3 PRIVATE $) +set_property(TARGET LinkLibrary_override_features3 PROPERTY LINK_LIBRARY_OVERRIDE_base1 feat1) + +add_library(LinkLibrary_override_features4 SHARED lib.c) +target_link_libraries(LinkLibrary_override_features4 PRIVATE $) +set_property(TARGET LinkLibrary_override_features4 PROPERTY LINK_LIBRARY_OVERRIDE "feat3,base1,other1") +set_property(TARGET LinkLibrary_override_features4 PROPERTY LINK_LIBRARY_OVERRIDE_base1 feat2) +set_property(TARGET LinkLibrary_override_features4 PROPERTY LINK_LIBRARY_OVERRIDE_other1 feat2) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake index febada0..9ebbdb7 100644 --- a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake @@ -53,6 +53,14 @@ if ((RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Xcode" run_cmake_target(LINK_LIBRARY mix-features2 LinkLibrary_mix_features2) run_cmake_target(LINK_LIBRARY mix-features3 LinkLibrary_mix_features3) + # testing target property LINK_LIBRARY_OVERRIDE + run_cmake_target(LINK_LIBRARY override-features1 LinkLibrary_override_features1) + run_cmake_target(LINK_LIBRARY override-features2 LinkLibrary_override_features2) + run_cmake_target(LINK_LIBRARY override-with-DEFAULT LinkLibrary_override_with_default) + # testing target property LINK_LIBRARY_OVERRIDE_ + run_cmake_target(LINK_LIBRARY override-features3 LinkLibrary_override_features3) + run_cmake_target(LINK_LIBRARY override-features4 LinkLibrary_override_features4) + run_cmake(imported-target) # tests using features as described in the documentation -- cgit v0.12