mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-16 12:11:04 -06:00
$<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.
This commit is contained in:
@@ -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_<LIBRARY>` 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:: $<INSTALL_INTERFACE:...>
|
||||
|
||||
Content of ``...`` when the property is exported using :command:`install(EXPORT)`,
|
||||
|
||||
@@ -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
|
||||
|
||||
54
Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst
Normal file
54
Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst
Normal file
@@ -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
Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst
Normal file
45
Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst
Normal file
@@ -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.
|
||||
@@ -5,4 +5,7 @@ Genex-LINK_LIBRARY
|
||||
libraries are specified during the link step. The variables
|
||||
:variable:`CMAKE_<LANG>_LINK_USING_<FEATURE>` and
|
||||
: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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,3 +21,10 @@ for the linker language, the variable
|
||||
:variable:`CMAKE_<LANG>_LINK_USING_<FEATURE>_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
|
||||
|
||||
5
Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
Normal file
5
Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
Normal file
@@ -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.
|
||||
@@ -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_<LIBRARY> 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)
|
||||
|
||||
@@ -11,9 +11,12 @@
|
||||
#include <utility>
|
||||
|
||||
#include <cm/memory>
|
||||
#include <cm/string_view>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#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<std::map<cmLinkItem, int>::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<int, DependSet> 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");
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
static const std::string DEFAULT;
|
||||
|
||||
BT<std::string> 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 $<LINK_LIBRARY:...>
|
||||
std::string Feature;
|
||||
std::string Feature = std::string(DEFAULT);
|
||||
};
|
||||
|
||||
using EntryVector = std::vector<LinkEntry>;
|
||||
@@ -75,6 +77,10 @@ private:
|
||||
std::string LinkLanguage;
|
||||
std::string Config;
|
||||
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(
|
||||
cmLinkItem const& item);
|
||||
|
||||
@@ -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<BT<std::string>>& 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<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));
|
||||
} 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<std::string>(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_<LIBRARY>
|
||||
run_cmake(override-features1)
|
||||
run_cmake(override-features2)
|
||||
run_cmake(override-features3)
|
||||
run_cmake(override-features4)
|
||||
run_cmake(override-features5)
|
||||
|
||||
@@ -11,5 +11,11 @@ add_library(dep1 SHARED empty.c)
|
||||
add_library(dep2 SHARED empty.c)
|
||||
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>)
|
||||
|
||||
@@ -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
|
||||
with the feature 'feat1', has already occurred with the feature 'feat2',
|
||||
which is not allowed.
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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\)
|
||||
@@ -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>)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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\)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
include(incompatible-features1.cmake)
|
||||
|
||||
set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat1,dep1")
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
include(incompatible-features1.cmake)
|
||||
|
||||
set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat2,dep1")
|
||||
@@ -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")
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
@@ -0,0 +1 @@
|
||||
.*
|
||||
@@ -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()
|
||||
@@ -0,0 +1 @@
|
||||
.*
|
||||
@@ -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()
|
||||
@@ -0,0 +1 @@
|
||||
.*
|
||||
@@ -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()
|
||||
@@ -0,0 +1 @@
|
||||
.*
|
||||
@@ -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()
|
||||
@@ -0,0 +1 @@
|
||||
.*
|
||||
@@ -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 "$<LINK_LIBRARY:feat2,ba
|
||||
|
||||
target_link_libraries(base3 INTERFACE other1)
|
||||
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)
|
||||
|
||||
@@ -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_<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)
|
||||
|
||||
# tests using features as described in the documentation
|
||||
|
||||
Reference in New Issue
Block a user