Bläddra i källkod

$<LINK_LIBRARY>: Add LINK_LIBRARY_OVERRIDE target property

To enable the management of incompatible $<LINK_LIBRARY> declarations,
add LINK_LIBRARY_OVERRIDE and LINK_LIBRARY_OVERRIDE_<LIBRARY> target
properties.
Marc Chevrier 4 år sedan
förälder
incheckning
2a6b0415d7
41 ändrade filer med 383 tillägg och 31 borttagningar
  1. 8 0
      Help/manual/cmake-generator-expressions.7.rst
  2. 2 0
      Help/manual/cmake-properties.7.rst
  3. 54 0
      Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst
  4. 45 0
      Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst
  5. 4 1
      Help/release/dev/Genex-LINK_LIBRARY.rst
  6. 7 0
      Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst
  7. 7 0
      Help/variable/CMAKE_LINK_USING_FEATURE.rst
  8. 5 0
      Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
  9. 6 0
      Modules/CMakeGenericSystem.cmake
  10. 74 16
      Source/cmComputeLinkDepends.cxx
  11. 7 1
      Source/cmComputeLinkDepends.h
  12. 11 6
      Source/cmComputeLinkInformation.cxx
  13. 1 1
      Source/cmGeneratorExpressionDAGChecker.cxx
  14. 10 1
      Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake
  15. 8 2
      Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake
  16. 0 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt
  17. 1 1
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt
  18. 0 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake
  19. 1 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt
  20. 6 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-stderr.txt
  21. 15 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2.cmake
  22. 1 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt
  23. 6 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-stderr.txt
  24. 15 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3.cmake
  25. 4 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/override-features1.cmake
  26. 4 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/override-features2.cmake
  27. 7 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/override-features3.cmake
  28. 9 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/override-features4.cmake
  29. 7 0
      Tests/RunCMake/GenEx-LINK_LIBRARY/override-features5.cmake
  30. 4 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-check.cmake
  31. 1 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt
  32. 4 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-check.cmake
  33. 1 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt
  34. 4 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-check.cmake
  35. 1 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt
  36. 4 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-check.cmake
  37. 1 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt
  38. 4 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-check.cmake
  39. 1 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt
  40. 25 2
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake
  41. 8 0
      Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake

+ 8 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -1176,12 +1176,20 @@ Output-Related Expressions
     target_link_libraries(lib3 PRIVATE lib1 lib2)
     target_link_libraries(lib3 PRIVATE lib1 lib2)
     # an error will be raised here because lib1 has two different features
     # 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_<LIBRARY>` target properties can be
+  used.
+
   .. note::
   .. note::
 
 
     This expression does not guarantee that the list of specified libraries
     This expression does not guarantee that the list of specified libraries
     will be kept grouped. So, constructs like ``start-group`` and
     will be kept grouped. So, constructs like ``start-group`` and
     ``end-group``, as supported by ``GNU ld``, cannot be used.
     ``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:: $<INSTALL_INTERFACE:...>
 .. genex:: $<INSTALL_INTERFACE:...>
 
 
   Content of ``...`` when the property is exported using :command:`install(EXPORT)`,
   Content of ``...`` when the property is exported using :command:`install(EXPORT)`,

+ 2 - 0
Help/manual/cmake-properties.7.rst

@@ -308,6 +308,8 @@ Properties on Targets
    /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG
    /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG
    /prop_tgt/LINK_LIBRARIES
    /prop_tgt/LINK_LIBRARIES
    /prop_tgt/LINK_LIBRARIES_ONLY_TARGETS
    /prop_tgt/LINK_LIBRARIES_ONLY_TARGETS
+   /prop_tgt/LINK_LIBRARY_OVERRIDE
+   /prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY
    /prop_tgt/LINK_OPTIONS
    /prop_tgt/LINK_OPTIONS
    /prop_tgt/LINK_SEARCH_END_STATIC
    /prop_tgt/LINK_SEARCH_END_STATIC
    /prop_tgt/LINK_SEARCH_START_STATIC
    /prop_tgt/LINK_SEARCH_START_STATIC

+ 54 - 0
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 <CMake Language Lists>` 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 $<LINK_LIBRARY:feature1,external>)
+
+  add_library(lib2 ...)
+  target_link_libraries(lib2 PUBLIC $<LINK_LIBRARY:feature2,lib1>)
+
+  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 <cmake-generator-expressions(7)>`.
+
+See also :prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target property for
+a per linked target oriented approach to override features.
+
+For more information about features, see
+:variable:`CMAKE_<LANG>_LINK_USING_<FEATURE>`
+and :variable:`CMAKE_LINK_USING_<FEATURE>` variables.

+ 45 - 0
Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst

@@ -0,0 +1,45 @@
+LINK_LIBRARY_OVERRIDE_<LIBRARY>
+-------------------------------
+
+.. 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 ``<LIBRARY>`` suffix property. For example:
+
+.. code-block:: cmake
+
+  add_library(lib1 ...)
+  target_link_libraries(lib1 PUBLIC $<LINK_LIBRARY:feature1,external>)
+
+  add_library(lib2 ...)
+  target_link_libraries(lib2 PUBLIC $<LINK_LIBRARY:feature2,lib1>)
+
+  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_<LIBRARY>`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property takes precedence over :prop_tgt:`LINK_LIBRARY_OVERRIDE`
+target property.
+
+For more information about features, see
+:variable:`CMAKE_<LANG>_LINK_USING_<FEATURE>`
+and :variable:`CMAKE_LINK_USING_<FEATURE>` variables.

+ 4 - 1
Help/release/dev/Genex-LINK_LIBRARY.rst

@@ -5,4 +5,7 @@ Genex-LINK_LIBRARY
   libraries are specified during the link step. The variables
   libraries are specified during the link step. The variables
   :variable:`CMAKE_<LANG>_LINK_USING_<FEATURE>` and
   :variable:`CMAKE_<LANG>_LINK_USING_<FEATURE>` and
   :variable:`CMAKE_LINK_USING_<FEATURE>` are used to define features usable by
   :variable:`CMAKE_LINK_USING_<FEATURE>` 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_<LIBRARY>` target properties are available
+  to resolve incompatible features.

+ 7 - 0
Help/variable/CMAKE_LANG_LINK_USING_FEATURE.rst

@@ -17,3 +17,10 @@ See also the associated variable
 independent from the link language.
 independent from the link language.
 
 
 .. include:: CMAKE_LINK_USING_FEATURE.txt
 .. include:: CMAKE_LINK_USING_FEATURE.txt
+
+Predefined Features
+^^^^^^^^^^^^^^^^^^^
+
+``CMake`` pre-defines some features of general interest:
+
+.. include:: LINK_LIBRARY_PREDEFINED_FEATURES.txt

+ 7 - 0
Help/variable/CMAKE_LINK_USING_FEATURE.rst

@@ -21,3 +21,10 @@ for the linker language, the variable
 :variable:`CMAKE_<LANG>_LINK_USING_<FEATURE>_SUPPORTED` is false or not set.
 :variable:`CMAKE_<LANG>_LINK_USING_<FEATURE>_SUPPORTED` is false or not set.
 
 
 .. include:: CMAKE_LINK_USING_FEATURE.txt
 .. include:: CMAKE_LINK_USING_FEATURE.txt
+
+Predefined Features
+^^^^^^^^^^^^^^^^^^^
+
+``CMake`` pre-defines some features of general interest:
+
+.. include:: LINK_LIBRARY_PREDEFINED_FEATURES.txt

+ 5 - 0
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_<LIBRARY>` target properties.

+ 6 - 0
Modules/CMakeGenericSystem.cmake

@@ -24,6 +24,12 @@ set(CMAKE_DL_LIBS "dl")
 set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
 set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
 set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
 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_<LIBRARY> target properties
+set(CMAKE_LINK_USING_DEFAULT_SUPPORTED TRUE)
+
 set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON)
 set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON)
 set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON)
 set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON)
 if(NOT DEFINED CMAKE_AUTOMOC_PATH_PREFIX)
 if(NOT DEFINED CMAKE_AUTOMOC_PATH_PREFIX)

+ 74 - 16
Source/cmComputeLinkDepends.cxx

@@ -11,9 +11,12 @@
 #include <utility>
 #include <utility>
 
 
 #include <cm/memory>
 #include <cm/memory>
+#include <cm/string_view>
 #include <cmext/string_view>
 #include <cmext/string_view>
 
 
 #include "cmComputeComponentGraph.h"
 #include "cmComputeComponentGraph.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGenerator.h"
 #include "cmListFileCache.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,
 cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
                                            const std::string& config,
                                            const std::string& config,
                                            const std::string& linkLanguage)
                                            const std::string& linkLanguage)
@@ -212,6 +217,49 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
   this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance();
   this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance();
   this->LinkLanguage = linkLanguage;
   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.
   // The configuration being linked.
   this->HasConfig = !config.empty();
   this->HasConfig = !config.empty();
   this->Config = (this->HasConfig) ? config : std::string();
   this->Config = (this->HasConfig) ? config : std::string();
@@ -309,6 +357,13 @@ cmComputeLinkDepends::Compute()
   return this->FinalLinkEntries;
   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<std::map<cmLinkItem, int>::iterator, bool>
 std::pair<std::map<cmLinkItem, int>::iterator, bool>
 cmComputeLinkDepends::AllocateLinkEntry(cmLinkItem const& item)
 cmComputeLinkDepends::AllocateLinkEntry(cmLinkItem const& item)
 {
 {
@@ -568,7 +623,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
 {
 {
   // Track inferred dependency sets implied by this list.
   // Track inferred dependency sets implied by this list.
   std::map<int, DependSet> dependSets;
   std::map<int, DependSet> dependSets;
-  std::string feature;
+  std::string feature = LinkEntry::DEFAULT;
 
 
   // Loop over the libraries linked directly by the depender.
   // Loop over the libraries linked directly by the depender.
   for (T const& l : libs) {
   for (T const& l : libs) {
@@ -604,7 +659,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
       continue;
       continue;
     }
     }
     if (cmHasPrefix(item.AsStr(), LL_END) && cmHasSuffix(item.AsStr(), '>')) {
     if (cmHasPrefix(item.AsStr(), LL_END) && cmHasSuffix(item.AsStr(), '>')) {
-      feature.clear();
+      feature = LinkEntry::DEFAULT;
       continue;
       continue;
     }
     }
 
 
@@ -612,7 +667,9 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
     auto ale = this->AddLinkEntry(item);
     auto ale = this->AddLinkEntry(item);
     int dependee_index = ale.first;
     int dependee_index = ale.first;
     LinkEntry& entry = this->EntryList[dependee_index];
     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) {
       if (ale.second) {
         // current item not yet defined
         // current item not yet defined
         if (entry.Target != nullptr &&
         if (entry.Target != nullptr &&
@@ -633,7 +690,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
                      " library '", entry.Item.Value, "'."),
                      " library '", entry.Item.Value, "'."),
             this->Target->GetBacktrace());
             this->Target->GetBacktrace());
         } else {
         } 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::OBJECT_LIBRARY &&
        entry.Target->GetType() != cmStateEnums::TargetType::INTERFACE_LIBRARY);
        entry.Target->GetType() != cmStateEnums::TargetType::INTERFACE_LIBRARY);
 
 
-    if (supportedItem && entry.Feature != feature) {
+    if (supportedItem && entry.Feature != itemFeature) {
       // incompatibles features occurred
       // incompatibles features occurred
       this->CMakeInstance->IssueMessage(
       this->CMakeInstance->IssueMessage(
         MessageType::FATAL_ERROR,
         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());
         this->Target->GetBacktrace());
     }
     }
 
 
@@ -978,7 +1036,7 @@ void cmComputeLinkDepends::DisplayFinalEntries()
     } else {
     } else {
       fprintf(stderr, "  item [%s]", lei.Item.Value.c_str());
       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, ", feature [%s]", lei.Feature.c_str());
     }
     }
     fprintf(stderr, "\n");
     fprintf(stderr, "\n");

+ 7 - 1
Source/cmComputeLinkDepends.h

@@ -47,6 +47,8 @@ public:
     {
     {
     }
     }
 
 
+    static const std::string DEFAULT;
+
     BT<std::string> Item;
     BT<std::string> Item;
     cmGeneratorTarget const* Target = nullptr;
     cmGeneratorTarget const* Target = nullptr;
     bool IsSharedDep = false;
     bool IsSharedDep = false;
@@ -54,7 +56,7 @@ public:
     bool IsObject = false;
     bool IsObject = false;
     // The following member is for the management of items specified
     // The following member is for the management of items specified
     // through genex $<LINK_LIBRARY:...>
     // through genex $<LINK_LIBRARY:...>
-    std::string Feature;
+    std::string Feature = std::string(DEFAULT);
   };
   };
 
 
   using EntryVector = std::vector<LinkEntry>;
   using EntryVector = std::vector<LinkEntry>;
@@ -75,6 +77,10 @@ private:
   std::string LinkLanguage;
   std::string LinkLanguage;
   std::string Config;
   std::string Config;
   EntryVector FinalLinkEntries;
   EntryVector FinalLinkEntries;
+  std::map<std::string, std::string> LinkLibraryOverride;
+
+  std::string const& GetCurrentFeature(
+    std::string const& item, std::string const& defaultFeature) const;
 
 
   std::pair<std::map<cmLinkItem, int>::iterator, bool> AllocateLinkEntry(
   std::pair<std::map<cmLinkItem, int>::iterator, bool> AllocateLinkEntry(
     cmLinkItem const& item);
     cmLinkItem const& item);

+ 11 - 6
Source/cmComputeLinkInformation.cxx

@@ -431,6 +431,10 @@ cmComputeLinkInformation::cmComputeLinkInformation(
 
 
 cmComputeLinkInformation::~cmComputeLinkInformation() = default;
 cmComputeLinkInformation::~cmComputeLinkInformation() = default;
 
 
+namespace {
+const std::string& DEFAULT = cmComputeLinkDepends::LinkEntry::DEFAULT;
+}
+
 void cmComputeLinkInformation::AppendValues(
 void cmComputeLinkInformation::AppendValues(
   std::string& result, std::vector<BT<std::string>>& values)
   std::string& result, std::vector<BT<std::string>>& values)
 {
 {
@@ -551,7 +555,7 @@ bool cmComputeLinkInformation::Compute()
       currentFeature = nullptr;
       currentFeature = nullptr;
     }
     }
 
 
-    if (!linkEntry.Feature.empty() &&
+    if (linkEntry.Feature != DEFAULT &&
         (currentFeature == nullptr ||
         (currentFeature == nullptr ||
          linkEntry.Feature != currentFeature->Name)) {
          linkEntry.Feature != currentFeature->Name)) {
       if (!this->AddLibraryFeature(linkEntry.Feature)) {
       if (!this->AddLibraryFeature(linkEntry.Feature)) {
@@ -988,8 +992,9 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
       std::string exe = tgt->GetFullPath(config, artifact, true);
       std::string exe = tgt->GetFullPath(config, artifact, true);
       this->Items.emplace_back(
       this->Items.emplace_back(
         BT<std::string>(exe, item.Backtrace), ItemIsPath::Yes, tgt,
         BT<std::string>(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));
       this->Depends.push_back(std::move(exe));
     } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
     } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       // Add the interface library as an item so it can be considered as part
       // 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.
   // Now add the full path to the library.
   this->Items.emplace_back(item, ItemIsPath::Yes, target,
   this->Items.emplace_back(item, ItemIsPath::Yes, target,
-                           this->FindLibraryFeature(entry.Feature.empty()
+                           this->FindLibraryFeature(entry.Feature == DEFAULT
                                                       ? "__CMAKE_LINK_LIBRARY"
                                                       ? "__CMAKE_LINK_LIBRARY"
                                                       : entry.Feature));
                                                       : entry.Feature));
 }
 }
@@ -1482,7 +1487,7 @@ void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry)
   this->Items.emplace_back(
   this->Items.emplace_back(
     item, ItemIsPath::Yes, nullptr,
     item, ItemIsPath::Yes, nullptr,
     this->FindLibraryFeature(
     this->FindLibraryFeature(
-      entry.Feature.empty()
+      entry.Feature == DEFAULT
         ? (entry.IsObject ? "__CMAKE_LINK_OBJECT" : "__CMAKE_LINK_LIBRARY")
         ? (entry.IsObject ? "__CMAKE_LINK_OBJECT" : "__CMAKE_LINK_LIBRARY")
         : entry.Feature));
         : entry.Feature));
 }
 }
@@ -1650,7 +1655,7 @@ void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry,
   // Create an option to ask the linker to search for the library.
   // Create an option to ask the linker to search for the library.
   auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix);
   auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix);
 
 
-  if (!entry.Feature.empty()) {
+  if (entry.Feature != DEFAULT) {
     auto const& feature = this->GetLibraryFeature(entry.Feature);
     auto const& feature = this->GetLibraryFeature(entry.Feature);
     this->Items.emplace_back(
     this->Items.emplace_back(
       BT<std::string>(
       BT<std::string>(

+ 1 - 1
Source/cmGeneratorExpressionDAGChecker.cxx

@@ -167,7 +167,7 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
   cm::string_view property(this->Top()->Property);
   cm::string_view property(this->Top()->Property);
 
 
   return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s ||
   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
 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const

+ 10 - 1
Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake

@@ -19,7 +19,16 @@ run_cmake(bad-feature7)
 run_cmake(feature-not-supported)
 run_cmake(feature-not-supported)
 run_cmake(library-ignored)
 run_cmake(library-ignored)
 run_cmake(compatible-features)
 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-compatible-features)
 run_cmake(nested-incompatible-features)
 run_cmake(nested-incompatible-features)
 run_cmake(only-targets)
 run_cmake(only-targets)
+
+# testing target propertes LINK_LIBRARY_OVERRIDE and LINK_LIBRARY_OVERRIDE_<LIBRARY>
+run_cmake(override-features1)
+run_cmake(override-features2)
+run_cmake(override-features3)
+run_cmake(override-features4)
+run_cmake(override-features5)

+ 8 - 2
Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake

@@ -11,5 +11,11 @@ add_library(dep1 SHARED empty.c)
 add_library(dep2 SHARED empty.c)
 add_library(dep2 SHARED empty.c)
 target_link_libraries(dep2 PRIVATE "$<LINK_LIBRARY:feat1,dep1>")
 target_link_libraries(dep2 PRIVATE "$<LINK_LIBRARY:feat1,dep1>")
 
 
-add_library(lib SHARED empty.c)
-target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat2,dep1,dep2>")
+add_library(dep3 SHARED empty.c)
+target_link_libraries(dep3 PUBLIC dep2)
+
+add_library(lib1 SHARED empty.c)
+target_link_libraries(lib1 PRIVATE $<LINK_LIBRARY:feat2,dep1,dep2>)
+
+add_library(lib2 SHARED empty.c)
+target_link_libraries(lib2 PRIVATE $<LINK_LIBRARY:DEFAULT,dep2,dep3>)

+ 0 - 0
Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-result.txt → Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt


+ 1 - 1
Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features-stderr.txt → Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt

@@ -1,4 +1,4 @@
-CMake Error at incompatible-features.cmake:[0-9]+ \(add_library\):
+CMake Error at incompatible-features1.cmake:[0-9]+ \(add_library\):
   Impossible to link target 'lib' because the link item 'dep1', specified
   Impossible to link target 'lib' because the link item 'dep1', specified
   with the feature 'feat1', has already occurred with the feature 'feat2',
   with the feature 'feat1', has already occurred with the feature 'feat2',
   which is not allowed.
   which is not allowed.

+ 0 - 0
Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features.cmake → Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake


+ 1 - 0
Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
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\)

+ 15 - 0
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 "<LIBRARY>")
+
+set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE)
+set(CMAKE_C_LINK_USING_feat2 "<LIBRARY>")
+
+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 $<LINK_LIBRARY:feat2,dep1,dep2>)

+ 1 - 0
Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
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\)

+ 15 - 0
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 "<LIBRARY>")
+
+set(CMAKE_C_LINK_USING_feat2_SUPPORTED TRUE)
+set(CMAKE_C_LINK_USING_feat2 "<LIBRARY>")
+
+add_library(dep1 SHARED empty.c)
+
+add_library(dep2 SHARED empty.c)
+target_link_libraries(dep2 PUBLIC $<LINK_LIBRARY:feat1,dep1>)
+
+add_library(lib SHARED empty.c)
+target_link_libraries(lib PRIVATE dep1 dep2)

+ 4 - 0
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")

+ 4 - 0
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")

+ 7 - 0
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 "<LIBRARY>")
+
+set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat3,dep1")

+ 9 - 0
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 "<LIBRARY>")
+
+set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat3,dep1")
+set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE_dep1 feat1)

+ 7 - 0
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)

+ 4 - 0
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<base3> --LIBFLAG<base1> <other1>'.")
+endif()

+ 1 - 0
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt

@@ -0,0 +1 @@
+.*

+ 4 - 0
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<base3> --PREFIXGROUP --LIBGROUP<base1> --LIBGROUP<other1> --SUFFIXGROUP'.")
+endif()

+ 1 - 0
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt

@@ -0,0 +1 @@
+.*

+ 4 - 0
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<base3> --LIBFLAG<base1> <other1>'.")
+endif()

+ 1 - 0
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt

@@ -0,0 +1 @@
+.*

+ 4 - 0
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<base3> --PREFIXGROUP --LIBGROUP<base1> --LIBGROUP<other1> --SUFFIXGROUP'.")
+endif()

+ 1 - 0
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt

@@ -0,0 +1 @@
+.*

+ 4 - 0
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<base3> <base1> <other1>'.")
+endif()

+ 1 - 0
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt

@@ -0,0 +1 @@
+.*

+ 25 - 2
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake

@@ -1,4 +1,3 @@
-
 enable_language(C)
 enable_language(C)
 
 
 # ensure command line is always displayed and do not use any response file
 # ensure command line is always displayed and do not use any response file
@@ -78,4 +77,28 @@ target_link_libraries(LinkLibrary_mix_features2 PRIVATE "$<LINK_LIBRARY:feat2,ba
 
 
 target_link_libraries(base3 INTERFACE other1)
 target_link_libraries(base3 INTERFACE other1)
 add_library(LinkLibrary_mix_features3 SHARED lib.c)
 add_library(LinkLibrary_mix_features3 SHARED lib.c)
-target_link_libraries(LinkLibrary_mix_features3 PRIVATE base2 "$<LINK_LIBRARY:feat2,base1,base3>" other2)
+target_link_libraries(LinkLibrary_mix_features3 PRIVATE base2 $<LINK_LIBRARY:feat2,base1,base3> other2)
+
+# testing LINK_LIBRARY_OVERRIDE property
+add_library(LinkLibrary_override_features1 SHARED lib.c)
+target_link_libraries(LinkLibrary_override_features1 PRIVATE $<LINK_LIBRARY:feat1,base1,base3>)
+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 $<LINK_LIBRARY:feat1,base1,base3>)
+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 $<LINK_LIBRARY:feat1,base1,base3>)
+set_property(TARGET LinkLibrary_override_with_default PROPERTY LINK_LIBRARY_OVERRIDE "$<$<LINK_LANGUAGE:C>:DEFAULT,base1,other1>")
+
+# testing LINK_LIBRARY_OVERRIDE_<LIBRARY> property
+add_library(LinkLibrary_override_features3 SHARED lib.c)
+target_link_libraries(LinkLibrary_override_features3 PRIVATE $<LINK_LIBRARY:feat1,base1,base3>)
+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 $<LINK_LIBRARY:feat1,base1,base3>)
+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)

+ 8 - 0
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-features2 LinkLibrary_mix_features2)
   run_cmake_target(LINK_LIBRARY mix-features3 LinkLibrary_mix_features3)
   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_<LIBRARY>
+  run_cmake_target(LINK_LIBRARY override-features3 LinkLibrary_override_features3)
+  run_cmake_target(LINK_LIBRARY override-features4 LinkLibrary_override_features4)
+
   run_cmake(imported-target)
   run_cmake(imported-target)
 
 
   # tests using features as described in the documentation
   # tests using features as described in the documentation