Merge topic 'LINK_LIBRARY-Feature-properties'

6e5e7968c3 GenEx $<LINK_LIBRARY>: Add the support of properties attached to features

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !9510
This commit is contained in:
Brad King
2024-05-16 15:27:05 +00:00
committed by Kitware Robot
43 changed files with 452 additions and 41 deletions

View File

@@ -467,6 +467,7 @@ Variables that Control the Build
/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
/variable/CMAKE_LANG_LINK_GROUP_USING_FEATURE
/variable/CMAKE_LANG_LINK_GROUP_USING_FEATURE_SUPPORTED
/variable/CMAKE_LANG_LINK_LIBRARY_FEATURE_PROPERTIES
/variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG
/variable/CMAKE_LANG_LINK_LIBRARY_FLAG
/variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE
@@ -485,6 +486,7 @@ Variables that Control the Build
/variable/CMAKE_LINK_GROUP_USING_FEATURE
/variable/CMAKE_LINK_GROUP_USING_FEATURE_SUPPORTED
/variable/CMAKE_LINK_INTERFACE_LIBRARIES
/variable/CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES
/variable/CMAKE_LINK_LIBRARY_FILE_FLAG
/variable/CMAKE_LINK_LIBRARY_FLAG
/variable/CMAKE_LINK_LIBRARY_USING_FEATURE

View File

@@ -0,0 +1,7 @@
GenEx-LINK_LIBRARY-feature-properties
-------------------------------------
* Link features, as used with the :genex:`LINK_LIBRARY` generator expression,
gained the ability to have properties that describe their behavior by
specifying the :variable:`CMAKE_LINK_LIBRARY_<FEATURE>_PROPERTIES` or
:variable:`CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_PROPERTIES` variables.

View File

@@ -0,0 +1,12 @@
CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_PROPERTIES
----------------------------------------------
.. versionadded:: 3.30
This variable defines the semantics of the specified ``<FEATURE>`` for the
language ``<LANG>`` (as described by the
:variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` or
:variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variables) used for the link
command generation.
.. include:: CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.txt

View File

@@ -0,0 +1,14 @@
CMAKE_LINK_LIBRARY_<FEATURE>_PROPERTIES
---------------------------------------
.. versionadded:: 3.30
This variable defines the semantics of the specified ``<FEATURE>`` (as
described by the :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` or
:variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variables) used for the link
command generation.
This variable will be considered only if the
:variable:`CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_PROPERTIES` is not defined.
.. include:: CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.txt

View File

@@ -0,0 +1,87 @@
Feature Properties Definition
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A feature properties definition is a
:ref:`semicolon-separated list <CMake Language Lists>` of ``property=value(s)``
items. In the case of multiple values can be specified, they are separated by
a comma.
The following properties are supported:
``LIBRARY_TYPE=<library_type-list>``
Specify which library types are supported by this feature. The possible
values are: ``STATIC``, ``SHARED``, ``MODULE`` or ``EXECUTABLE``.
If this property is not specified, the default is
``LIBRARY_TYPE=STATIC,SHARED,MODULE,EXECUTABLE``.
If the feature is used with an unsupported library type, CMake will emit a
developer warning and the feature will be ignored.
``OVERRIDE=<feature-list>``
Specify which features will be replaced by this one in the event of a
conflict. This override mechanism is superseded by any
:prop_tgt:`LINK_LIBRARY_OVERRIDE` or
:prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target properties definitions.
If this property is not specified, the default is an empty list.
``UNICITY=YES|NO|DEFAULT``
Manage the strategy of de-duplication for the libraries using this feature.
``YES``
Libraries are de-duplicated regardless the default strategy applied by
CMake.
``NO``
Libraries are not de-duplicated regardless the default strategy applied
by CMake.
``DEFAULT``
Apply the default CMake strategy.
If this property is not specified, ``DEFAULT`` will be used.
Example
^^^^^^^
A common need is the loading of a full archive as part of the creation of a
shared library or an executable. For that purpose, the ``WHOLE_ARCHIVE``
feature can be used.
Currently, the associated properties with this feature are defined as follows:
.. code-block:: cmake
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC
OVERRIDE=DEFAULT
UNICITY=YES)
``LIBRARY_TYPE=STATIC``
Obviously, this feature is only meaningful for static libraries.
``OVERRIDE=DEFAULT``
The ``DEFAULT`` feature will be overridden by the ``WHOLE_ARCHIVE`` feature
because they are compatible and enhance the user's experience: standard
library specification and ``$<LINK_LIBRARY:WHOLE_ARCHIVE>`` can be used
freely.
``UNICITY=YES``
When this feature is used, all symbols from the static library are loaded
by the linker, so there is no need to duplicate the library on the link
command.
A typical usage of the ``WHOLE_ARCHIVE`` can be:
.. code-block:: cmake
add_library(A STATIC ...)
add_library(B STATIC ...)
target_link_libraries(B PUBLIC A)
target_link_libraries(A PUBLIC B)
add_library(global SHARED ...)
target_link_libraries(global PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,A>)
The resulting link command will only have one iteration of the ``A`` library
specified with the needed linker flags to ensure the load of all the symbols
of the library.

View File

@@ -2,6 +2,9 @@ Feature names are case-sensitive and may only contain letters, numbers
and underscores. Feature names defined in all uppercase are reserved for
CMake's own built-in features (see `Predefined Features`_ further below).
The feature behavior can be described using the
:variable:`CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_PROPERTIES` or
:variable:`CMAKE_LINK_LIBRARY_<FEATURE>_PROPERTIES` variables.
Feature Definitions
^^^^^^^^^^^^^^^^^^^

View File

@@ -19,6 +19,7 @@ macro(__apple_compiler_clang lang)
set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK "-framework <LIBRARY>")
set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE)
set(CMAKE_${lang}_LINK_LIBRARY_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
# linker selection
set(CMAKE_${lang}_USING_LINKER_SYSTEM "-fuse-ld=ld")

View File

@@ -17,6 +17,7 @@ macro(__apple_compiler_gnu lang)
set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK "-framework <LIBRARY>")
set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
set(CMAKE_${lang}_USING_LINKER_SYSTEM "")
set(CMAKE_${lang}_USING_LINKER_APPLE_CLASSIC "LINKER:-ld_classic")

View File

@@ -40,6 +40,7 @@ else()
"LINKER:--no-whole-archive")
endif()
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
macro(__cygwin_compiler_gnu lang)

View File

@@ -114,29 +114,37 @@ set(CMAKE_CREATE_TEXT_STUBS "<CMAKE_TAPI> stubify -isysroot <CMAKE_OSX_SYSROOT>
# Defines LINK_LIBRARY features for frameworks
set(CMAKE_LINK_LIBRARY_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
set(CMAKE_LINK_LIBRARY_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_NEEDED_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
set(CMAKE_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_REEXPORT_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
set(CMAKE_LINK_LIBRARY_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_WEAK_FRAMEWORK_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WEAK_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
# Defines LINK_LIBRARY features for libraries
set(CMAKE_LINK_LIBRARY_USING_NEEDED_LIBRARY "PATH{LINKER:-needed_library,<LIBRARY>}NAME{LINKER:-needed-l<LIBRARY>}")
set(CMAKE_LINK_LIBRARY_USING_NEEDED_LIBRARY_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_NEEDED_LIBRARY_PROPERTIES LIBRARY_TYPE=SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
set(CMAKE_LINK_LIBRARY_USING_REEXPORT_LIBRARY "PATH{LINKER:-reexport_library,<LIBRARY>}NAME{LINKER:-reexport-l<LIBRARY>}")
set(CMAKE_LINK_LIBRARY_USING_REEXPORT_LIBRARY_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_REEXPORT_LIBRARY_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
set(CMAKE_LINK_LIBRARY_USING_WEAK_LIBRARY "PATH{LINKER:-weak_library,<LIBRARY>}NAME{LINKER:-weak-l<LIBRARY>}")
set(CMAKE_LINK_LIBRARY_USING_WEAK_LIBRARY_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WEAK_LIBRARY_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
# Defines LINK_LIBRARY feature to Force loading of all members of an archive
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE "LINKER:-force_load,<LIB_ITEM>")
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
# default to searching for frameworks first
if(NOT DEFINED CMAKE_FIND_FRAMEWORK)

View File

@@ -51,6 +51,7 @@ else()
"LINKER:--no-whole-archive")
endif()
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
# Features for LINK_GROUP generator expression

View File

@@ -44,6 +44,7 @@ else()
"LINKER:--no-whole-archive")
endif()
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
# Features for LINK_GROUP generator expression
## RESCAN: request the linker to rescan static libraries until there is

View File

@@ -37,6 +37,7 @@ else()
"LINKER:--no-whole-archive")
endif()
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
# Features for LINK_GROUP generator expression

View File

@@ -20,6 +20,7 @@ else()
"LINKER:-z,defaultextract")
endif()
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
# Features for LINK_GROUP generator expression

View File

@@ -140,6 +140,7 @@ macro(__windows_compiler_clang_gnu lang)
## WHOLE_ARCHIVE: Force loading all members of an archive
set(CMAKE_${lang}_LINK_LIBRARY_USING_WHOLE_ARCHIVE "LINKER:/WHOLEARCHIVE:<LIBRARY>")
set(CMAKE_${lang}_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_${lang}_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
endif()
enable_language(RC)

View File

@@ -88,6 +88,7 @@ else()
"LINKER:--no-whole-archive")
endif()
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
# Features for LINK_GROUP generator expression
## RESCAN: request the linker to rescan static libraries until there is

View File

@@ -37,6 +37,7 @@ macro(__windows_compiler_intel lang)
## WHOLE_ARCHIVE: Force loading all members of an archive
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE "LINKER:/WHOLEARCHIVE:<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
endif()
set(CMAKE_${lang}_LINK_EXECUTABLE

View File

@@ -358,6 +358,7 @@ if(MSVC_VERSION GREATER "1900")
## WHOLE_ARCHIVE: Force loading all members of an archive
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE "/WHOLEARCHIVE:<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
endif()

View File

@@ -30,6 +30,7 @@
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmRange.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmTarget.h"
@@ -201,6 +202,113 @@ bool IsFeatureSupported(cmMakefile* makefile, std::string const& linkLanguage,
return makefile->GetDefinition(featureSupported).IsOn();
}
// LINK_LIBRARY feature properties management
struct LinkLibraryFeaturePropertySet
{
std::set<cmStateEnums::TargetType> LibraryTypes = {
cmStateEnums::EXECUTABLE, cmStateEnums::STATIC_LIBRARY,
cmStateEnums::SHARED_LIBRARY, cmStateEnums::MODULE_LIBRARY,
cmStateEnums::UNKNOWN_LIBRARY
};
std::set<std::string> Override;
enum UnicityKind
{
Default,
Yes,
No
};
UnicityKind Unicity = Default;
};
std::map<std::string, LinkLibraryFeaturePropertySet>
LinkLibraryFeatureProperties;
const LinkLibraryFeaturePropertySet& GetLinkLibraryFeatureProperties(
cmMakefile* makefile, std::string const& linkLanguage,
const std::string& feature)
{
auto it = LinkLibraryFeatureProperties.find(feature);
if (it != LinkLibraryFeatureProperties.end()) {
return it->second;
}
auto featurePropertiesVariable =
cmStrCat("CMAKE_", linkLanguage, "_LINK_LIBRARY_", feature, "_PROPERTIES");
auto featurePropertiesValues =
makefile->GetDefinition(featurePropertiesVariable);
if (featurePropertiesValues.IsEmpty()) {
// try language agnostic definition
featurePropertiesVariable =
cmStrCat("CMAKE_LINK_LIBRARY_", feature, "_PROPERTIES");
featurePropertiesValues =
makefile->GetDefinition(featurePropertiesVariable);
}
if (!featurePropertiesValues.IsEmpty()) {
LinkLibraryFeaturePropertySet featureProperties;
cmsys::RegularExpression processingOption{
"^(LIBRARY_TYPE|UNICITY|OVERRIDE)=((STATIC|SHARED|MODULE|EXECUTABLE)(,("
"STATIC|"
"SHARED|MODULE|EXECUTABLE)"
")*|YES|NO|DEFAULT|[A-Za-z0-9_]+(,[A-Za-z0-9_]+)*)$"
};
std::string errorMessage;
for (auto const& option : cmList{ featurePropertiesValues }) {
if (processingOption.find(option)) {
if (processingOption.match(1) == "LIBRARY_TYPE") {
featureProperties.LibraryTypes.clear();
for (auto const& value :
cmTokenize(processingOption.match(2), ","_s)) {
if (value == "STATIC") {
featureProperties.LibraryTypes.emplace(
cmStateEnums::STATIC_LIBRARY);
} else if (value == "SHARED") {
featureProperties.LibraryTypes.emplace(
cmStateEnums::SHARED_LIBRARY);
} else if (value == "MODULE") {
featureProperties.LibraryTypes.emplace(
cmStateEnums::MODULE_LIBRARY);
} else if (value == "EXECUTABLE") {
featureProperties.LibraryTypes.emplace(cmStateEnums::EXECUTABLE);
} else {
errorMessage += cmStrCat(" ", option, '\n');
break;
}
}
// Always add UNKNOWN type
featureProperties.LibraryTypes.emplace(
cmStateEnums::UNKNOWN_LIBRARY);
} else if (processingOption.match(1) == "UNICITY") {
if (processingOption.match(2) == "YES") {
featureProperties.Unicity = LinkLibraryFeaturePropertySet::Yes;
} else if (processingOption.match(2) == "NO") {
featureProperties.Unicity = LinkLibraryFeaturePropertySet::No;
} else if (processingOption.match(2) == "DEFAULT") {
featureProperties.Unicity = LinkLibraryFeaturePropertySet::Default;
} else {
errorMessage += cmStrCat(" ", option, '\n');
}
} else if (processingOption.match(1) == "OVERRIDE") {
featureProperties.Override.clear();
auto values = cmTokenize(processingOption.match(2), ","_s);
featureProperties.Override.insert(values.begin(), values.end());
}
} else {
errorMessage += cmStrCat(" ", option, '\n');
}
}
if (!errorMessage.empty()) {
makefile->GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Erroneous option(s) for '", featurePropertiesVariable,
"':\n", errorMessage));
}
return LinkLibraryFeatureProperties.emplace(feature, featureProperties)
.first->second;
}
return LinkLibraryFeatureProperties
.emplace(feature, LinkLibraryFeaturePropertySet{})
.first->second;
}
// LINK_GROUP helpers
const auto LG_BEGIN = "<LINK_GROUP:"_s;
const auto LG_END = "</LINK_GROUP:"_s;
@@ -235,7 +343,9 @@ public:
EntriesProcessing(const cmGeneratorTarget* target,
const std::string& linkLanguage, EntryVector& entries,
EntryVector& finalEntries)
: Entries(entries)
: Target(target)
, LinkLanguage(linkLanguage)
, Entries(entries)
, FinalEntries(finalEntries)
{
const auto* makefile = target->Makefile;
@@ -398,6 +508,18 @@ private:
bool IncludeEntry(LinkEntry const& entry) const
{
if (entry.Feature != cmComputeLinkDepends::LinkEntry::DEFAULT) {
auto const& featureProperties = GetLinkLibraryFeatureProperties(
this->Target->Makefile, this->LinkLanguage, entry.Feature);
if ((entry.Target == nullptr ||
featureProperties.LibraryTypes.find(entry.Target->GetType()) !=
featureProperties.LibraryTypes.end()) &&
featureProperties.Unicity !=
LinkLibraryFeaturePropertySet::Default) {
return featureProperties.Unicity == LinkLibraryFeaturePropertySet::No;
}
}
return this->Unicity == None ||
(this->Unicity == Shared &&
(entry.Target == nullptr ||
@@ -418,6 +540,8 @@ private:
OrderKind Order = Reverse;
UnicityKind Unicity = Shared;
const cmGeneratorTarget* Target;
const std::string& LinkLanguage;
EntryVector& Entries;
EntryVector& FinalEntries;
std::set<size_t> Emitted;
@@ -973,12 +1097,14 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index,
auto ale = this->AddLinkEntry(item, groupIndex.first);
dependee_index = ale.first;
LinkEntry& entry = this->EntryList[dependee_index];
bool supportedItem = true;
auto const& itemFeature =
this->GetCurrentFeature(entry.Item.Value, item.Feature);
if (inGroup && ale.second && entry.Target != nullptr &&
(entry.Target->GetType() == cmStateEnums::TargetType::OBJECT_LIBRARY ||
entry.Target->GetType() ==
cmStateEnums::TargetType::INTERFACE_LIBRARY)) {
supportedItem = false;
const auto& groupFeature = this->EntryList[groupIndex.first].Feature;
this->CMakeInstance->IssueMessage(
MessageType::AUTHOR_WARNING,
@@ -995,30 +1121,27 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index,
}
if (ale.second) {
// current item not yet defined
if (itemFeature != LinkEntry::DEFAULT && 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 '", itemFeature,
"', specified as part of a generator-expression "
"'$<LINK_LIBRARY:",
itemFeature, ">', will not be applied to the ",
(entry.Target->GetType() ==
cmStateEnums::TargetType::OBJECT_LIBRARY
? "OBJECT"
: "INTERFACE"),
" library '", entry.Item.Value, "'."),
this->Target->GetBacktrace());
}
entry.Feature = itemFeature;
}
bool supportedItem = entry.Target == nullptr ||
(entry.Target->GetType() != cmStateEnums::TargetType::OBJECT_LIBRARY &&
entry.Target->GetType() != cmStateEnums::TargetType::INTERFACE_LIBRARY);
if (itemFeature != LinkEntry::DEFAULT && entry.Target != nullptr) {
auto const& featureProperties = GetLinkLibraryFeatureProperties(
this->Makefile, this->LinkLanguage, itemFeature);
if (featureProperties.LibraryTypes.find(entry.Target->GetType()) ==
featureProperties.LibraryTypes.end()) {
supportedItem = false;
entry.Feature = LinkEntry::DEFAULT;
this->CMakeInstance->IssueMessage(
MessageType::AUTHOR_WARNING,
cmStrCat("The feature '", itemFeature,
"', specified as part of a generator-expression "
"'$<LINK_LIBRARY:",
itemFeature, ">', will not be applied to the ",
cmState::GetTargetTypeName(entry.Target->GetType()), " '",
entry.Item.Value, "'."),
this->Target->GetBacktrace());
}
}
}
if (supportedItem) {
if (inGroup) {
@@ -1043,21 +1166,41 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index,
}
}
if (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 ",
(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());
bool incompatibleFeatures = true;
// check if an override is possible
auto const& entryFeatureProperties = GetLinkLibraryFeatureProperties(
this->Makefile, this->LinkLanguage, entry.Feature);
auto const& itemFeatureProperties = GetLinkLibraryFeatureProperties(
this->Makefile, this->LinkLanguage, itemFeature);
if (entryFeatureProperties.Override.empty() &&
!itemFeatureProperties.Override.empty() &&
itemFeatureProperties.Override.find(entry.Feature) !=
itemFeatureProperties.Override.end()) {
entry.Feature = itemFeature;
incompatibleFeatures = false;
} else if (!entryFeatureProperties.Override.empty() &&
itemFeatureProperties.Override.empty() &&
entryFeatureProperties.Override.find(itemFeature) !=
entryFeatureProperties.Override.end()) {
incompatibleFeatures = false;
}
if (incompatibleFeatures) {
// 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 ",
(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());
}
}
}

View File

@@ -35,3 +35,10 @@ run_cmake(override-features2)
run_cmake(override-features3)
run_cmake(override-features4)
run_cmake(override-features5)
# testing feature properties specification
run_cmake(bad-feature-properties1)
run_cmake(bad-feature-properties2)
run_cmake(bad-feature-properties3)
run_cmake(bad-feature-properties4)
run_cmake(bad-feature-properties5)

View File

@@ -0,0 +1,4 @@
CMake Error:
Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
BAD_PROPERTY=XXX

View File

@@ -0,0 +1,10 @@
enable_language(C)
set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_feature_PROPERTIES BAD_PROPERTY=XXX)
add_library(dep SHARED empty.c)
add_library(lib SHARED empty.c)
target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")

View File

@@ -0,0 +1,4 @@
CMake Error:
Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
BAD_PROPERTY=XXX

View File

@@ -0,0 +1,10 @@
enable_language(C)
set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_feature_PROPERTIES LIBRARY_TYPE=STATIC BAD_PROPERTY=XXX UNICITY=YES)
add_library(dep SHARED empty.c)
add_library(lib SHARED empty.c)
target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")

View File

@@ -0,0 +1,4 @@
CMake Error:
Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
LIBRARY_TYPE=STATIC,BAD_TYPE

View File

@@ -0,0 +1,10 @@
enable_language(C)
set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_feature_PROPERTIES LIBRARY_TYPE=STATIC,BAD_TYPE)
add_library(dep SHARED empty.c)
add_library(lib SHARED empty.c)
target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")

View File

@@ -0,0 +1,4 @@
CMake Error:
Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
LIBRARY_TYPE=STATIC,BAD_TYPE

View File

@@ -0,0 +1,10 @@
enable_language(C)
set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_feature_PROPERTIES UNICITY=YES LIBRARY_TYPE=STATIC,BAD_TYPE)
add_library(dep SHARED empty.c)
add_library(lib SHARED empty.c)
target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")

View File

@@ -0,0 +1,4 @@
CMake Error:
Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
UNICITY=YES,NO

View File

@@ -0,0 +1,10 @@
enable_language(C)
set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
set(CMAKE_LINK_LIBRARY_feature_PROPERTIES UNICITY=YES,NO)
add_library(dep SHARED empty.c)
add_library(lib SHARED empty.c)
target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")

View File

@@ -1,6 +1,6 @@
CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\):
The feature 'feat', specified as part of a generator-expression
'\$<LINK_LIBRARY:feat>', will not be applied to the INTERFACE library
'\$<LINK_LIBRARY:feat>', will not be applied to the INTERFACE_LIBRARY
'front'.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)
@@ -8,7 +8,14 @@ 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
'\$<LINK_LIBRARY:feat>', will not be applied to the OBJECT library 'dep'.
'\$<LINK_LIBRARY:feat>', 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.
CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\):
The feature 'feat', specified as part of a generator-expression
'\$<LINK_LIBRARY:feat>', will not be applied to the SHARED_LIBRARY 'lib'.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)
This warning is for project developers. Use -Wno-dev to suppress it.

View File

@@ -2,13 +2,14 @@ enable_language(C)
set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE)
set(CMAKE_C_LINK_LIBRARY_USING_feat "<LIBRARY>")
set(CMAKE_C_LINK_LIBRARY_feat_PROPERTIES "LIBRARY_TYPE=STATIC")
add_library(dep OBJECT empty.c)
add_library(lib SHARED empty.c)
add_library(front INTERFACE)
target_link_libraries(front INTERFACE lib)
target_link_libraries(front INTERFACE "$<LINK_LIBRARY:feat,lib>")
add_library(lib2 SHARED empty.c)

View File

@@ -135,4 +135,5 @@ if ((CMAKE_SYSTEM_NAME STREQUAL "Windows" AND
OR CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|visionOS|watchOS|Linux|BSD|MSYS|CYGWIN")
run_cmake(feature-WHOLE_ARCHIVE)
run_cmake_target(feature-WHOLE_ARCHIVE link-exe main)
run_cmake_target(feature-WHOLE_ARCHIVE circular-exe main_circular)
endif()

View File

@@ -0,0 +1,6 @@
void circular2(void);
void circular1(void)
{
circular2();
}

View File

@@ -0,0 +1,7 @@
void circular1(void);
void circular2(void)
{
circular1();
}

View File

@@ -0,0 +1 @@
(ld: warning: ignoring duplicate libraries:)?

View File

@@ -9,3 +9,13 @@ target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,base>")
add_executable(main main.c)
target_link_libraries(main PRIVATE lib)
add_library(circular1 STATIC circular1.c)
add_library(circular2 STATIC circular2.c)
target_link_libraries(circular1 PRIVATE circular2)
target_link_libraries(circular2 PRIVATE circular1)
add_executable(main_circular main_circular.c)
target_link_libraries(main_circular PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,circular1>)

View File

@@ -0,0 +1,9 @@
void circular1(void);
int main(void)
{
circular1();
return 0;
}