Link properties: must be transitive over private dependency on static library
Fixes: #20022
This commit is contained in:
parent
a2c0c2d024
commit
bbba701899
@ -57,6 +57,7 @@ Policies Introduced by CMake 3.17
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
CMP0099: Link properties are transitive over private dependency on static libraries. </policy/CMP0099>
|
||||
CMP0098: FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0098>
|
||||
|
||||
Policies Introduced by CMake 3.16
|
||||
|
24
Help/policy/CMP0099.rst
Normal file
24
Help/policy/CMP0099.rst
Normal file
@ -0,0 +1,24 @@
|
||||
CMP0099
|
||||
-------
|
||||
|
||||
Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
|
||||
:prop_tgt:`INTERFACE_LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DEPENDS`
|
||||
are now transitive over private dependencies of static libraries.
|
||||
|
||||
In CMake 3.16 and below the interface link properties attached to libraries
|
||||
are not propagated for private dependencies of static libraries.
|
||||
Only the libraries themselves are propagated to link the dependent binary.
|
||||
CMake 3.17 and later prefer to propagate all interface link properties.
|
||||
This policy provides compatibility for projects that have not been updated
|
||||
to expect the new behavior.
|
||||
|
||||
The ``OLD`` behavior for this policy is to not propagate interface link
|
||||
properties. The ``NEW`` behavior of this policy is to propagate interface link
|
||||
properties.
|
||||
|
||||
This policy was introduced in CMake version 3.17. Use the
|
||||
:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
|
||||
Unlike many policies, CMake version |release| does *not* warn
|
||||
when this policy is not set and simply uses ``OLD`` behavior.
|
||||
|
||||
.. include:: DEPRECATED.txt
|
8
Help/release/dev/Link-properties-transitive.rst
Normal file
8
Help/release/dev/Link-properties-transitive.rst
Normal file
@ -0,0 +1,8 @@
|
||||
Link-properties-transitive
|
||||
--------------------------
|
||||
|
||||
* Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
|
||||
:prop_tgt:`INTERFACE_LINK_DIRECTORIES` and
|
||||
:prop_tgt:`INTERFACE_LINK_DEPENDS` are now transitive over private
|
||||
dependency on static libraries.
|
||||
See policy :policy:`CMP0099`.
|
@ -1116,7 +1116,8 @@ bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
|
||||
std::string const& prop, cmGeneratorExpressionContext* context) const
|
||||
std::string const& prop, cmGeneratorExpressionContext* context,
|
||||
bool usage_requirements_only) const
|
||||
{
|
||||
std::string const key = prop + '@' + context->Config;
|
||||
auto i = this->MaybeInterfacePropertyExists.find(key);
|
||||
@ -1135,7 +1136,7 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
|
||||
context->HeadTarget ? context->HeadTarget : this;
|
||||
if (cmLinkInterfaceLibraries const* iface =
|
||||
this->GetLinkInterfaceLibraries(context->Config, headTarget,
|
||||
true)) {
|
||||
usage_requirements_only)) {
|
||||
if (iface->HadHeadSensitiveCondition) {
|
||||
// With a different head target we may get to a library with
|
||||
// this interface property.
|
||||
@ -1145,7 +1146,8 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
|
||||
// head target, so we can follow them.
|
||||
for (cmLinkItem const& lib : iface->Libraries) {
|
||||
if (lib.Target &&
|
||||
lib.Target->MaybeHaveInterfaceProperty(prop, context)) {
|
||||
lib.Target->MaybeHaveInterfaceProperty(
|
||||
prop, context, usage_requirements_only)) {
|
||||
maybeInterfaceProp = true;
|
||||
break;
|
||||
}
|
||||
@ -1159,12 +1161,14 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
|
||||
|
||||
std::string cmGeneratorTarget::EvaluateInterfaceProperty(
|
||||
std::string const& prop, cmGeneratorExpressionContext* context,
|
||||
cmGeneratorExpressionDAGChecker* dagCheckerParent) const
|
||||
cmGeneratorExpressionDAGChecker* dagCheckerParent,
|
||||
bool usage_requirements_only) const
|
||||
{
|
||||
std::string result;
|
||||
|
||||
// If the property does not appear transitively at all, we are done.
|
||||
if (!this->MaybeHaveInterfaceProperty(prop, context)) {
|
||||
if (!this->MaybeHaveInterfaceProperty(prop, context,
|
||||
usage_requirements_only)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1196,8 +1200,8 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
|
||||
p, context->LG, context, headTarget, &dagChecker, this);
|
||||
}
|
||||
|
||||
if (cmLinkInterfaceLibraries const* iface =
|
||||
this->GetLinkInterfaceLibraries(context->Config, headTarget, true)) {
|
||||
if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(
|
||||
context->Config, headTarget, usage_requirements_only)) {
|
||||
for (cmLinkItem const& lib : iface->Libraries) {
|
||||
// Broken code can have a target in its own link interface.
|
||||
// Don't follow such link interface entries so as not to create a
|
||||
@ -1240,7 +1244,8 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget,
|
||||
std::string const& config, std::string const& prop,
|
||||
std::string const& lang,
|
||||
cmGeneratorExpressionDAGChecker* dagChecker,
|
||||
std::vector<EvaluatedTargetPropertyEntry>& entries)
|
||||
std::vector<EvaluatedTargetPropertyEntry>& entries,
|
||||
bool usage_requirements_only = true)
|
||||
{
|
||||
if (cmLinkImplementationLibraries const* impl =
|
||||
headTarget->GetLinkImplementationLibraries(config)) {
|
||||
@ -1253,9 +1258,9 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget,
|
||||
cmGeneratorExpressionContext context(
|
||||
headTarget->GetLocalGenerator(), config, false, headTarget,
|
||||
headTarget, true, lib.Backtrace, lang);
|
||||
cmExpandList(
|
||||
lib.Target->EvaluateInterfaceProperty(prop, &context, dagChecker),
|
||||
ee.Values);
|
||||
cmExpandList(lib.Target->EvaluateInterfaceProperty(
|
||||
prop, &context, dagChecker, usage_requirements_only),
|
||||
ee.Values);
|
||||
ee.ContextDependent = context.HadContextSensitiveCondition;
|
||||
entries.emplace_back(std::move(ee));
|
||||
}
|
||||
@ -3663,7 +3668,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
|
||||
this->LinkOptionsEntries);
|
||||
|
||||
AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language,
|
||||
&dagChecker, entries);
|
||||
&dagChecker, entries,
|
||||
this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
|
||||
|
||||
processOptions(this, entries, result, uniqueOptions, debugOptions,
|
||||
"link options", OptionsParse::Shell);
|
||||
@ -3918,7 +3924,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
|
||||
this->LinkDirectoriesEntries);
|
||||
|
||||
AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language,
|
||||
&dagChecker, entries);
|
||||
&dagChecker, entries,
|
||||
this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
|
||||
|
||||
processLinkDirectories(this, entries, result, uniqueDirectories,
|
||||
debugDirectories);
|
||||
@ -3956,7 +3963,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
|
||||
}
|
||||
}
|
||||
AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language,
|
||||
&dagChecker, entries);
|
||||
&dagChecker, entries,
|
||||
this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
|
||||
|
||||
processOptions(this, entries, result, uniqueOptions, false, "link depends",
|
||||
OptionsParse::None);
|
||||
|
@ -707,7 +707,8 @@ public:
|
||||
|
||||
std::string EvaluateInterfaceProperty(
|
||||
std::string const& prop, cmGeneratorExpressionContext* context,
|
||||
cmGeneratorExpressionDAGChecker* dagCheckerParent) const;
|
||||
cmGeneratorExpressionDAGChecker* dagCheckerParent,
|
||||
bool usage_requirements_only = true) const;
|
||||
|
||||
bool HaveInstallTreeRPATH(const std::string& config) const;
|
||||
|
||||
@ -886,7 +887,8 @@ private:
|
||||
|
||||
mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists;
|
||||
bool MaybeHaveInterfaceProperty(std::string const& prop,
|
||||
cmGeneratorExpressionContext* context) const;
|
||||
cmGeneratorExpressionContext* context,
|
||||
bool usage_requirements_only) const;
|
||||
|
||||
using TargetPropertyEntryVector =
|
||||
std::vector<std::unique_ptr<TargetPropertyEntry>>;
|
||||
|
@ -293,7 +293,11 @@ class cmMakefile;
|
||||
3, 16, 0, cmPolicies::WARN) \
|
||||
SELECT(POLICY, CMP0098, \
|
||||
"FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing.", 3, \
|
||||
17, 0, cmPolicies::WARN)
|
||||
17, 0, cmPolicies::WARN) \
|
||||
SELECT(POLICY, CMP0099, \
|
||||
"Link properties are transitive over private dependency on static " \
|
||||
"libraries.", \
|
||||
3, 17, 0, cmPolicies::WARN)
|
||||
|
||||
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
|
||||
#define CM_FOR_EACH_POLICY_ID(POLICY) \
|
||||
@ -322,7 +326,8 @@ class cmMakefile;
|
||||
F(CMP0076) \
|
||||
F(CMP0081) \
|
||||
F(CMP0083) \
|
||||
F(CMP0095)
|
||||
F(CMP0095) \
|
||||
F(CMP0099)
|
||||
|
||||
/** \class cmPolicies
|
||||
* \brief Handles changes in CMake behavior and policies
|
||||
|
@ -28,6 +28,7 @@
|
||||
\* CMP0081
|
||||
\* CMP0083
|
||||
\* CMP0095
|
||||
\* CMP0099
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -0,0 +1,4 @@
|
||||
|
||||
if (NOT actual_stdout MATCHES "DIR_INTERFACE")
|
||||
string (APPEND RunCMake_TEST_FAILED "\nNot found expected 'DIR_INTERFACE'.")
|
||||
endif()
|
@ -0,0 +1 @@
|
||||
.*
|
4
Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake
Normal file
4
Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
cmake_policy(SET CMP0099 NEW)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake)
|
@ -0,0 +1,4 @@
|
||||
|
||||
if (actual_stdout MATCHES "DIR_INTERFACE")
|
||||
string (APPEND RunCMake_TEST_FAILED "\nFound unexpected 'DIR_INTERFACE'.")
|
||||
endif()
|
@ -0,0 +1 @@
|
||||
.*
|
4
Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake
Normal file
4
Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
cmake_policy(SET CMP0099 OLD)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake)
|
14
Tests/RunCMake/target_link_directories/CMP0099.cmake
Normal file
14
Tests/RunCMake/target_link_directories/CMP0099.cmake
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
enable_language(C)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE TRUE)
|
||||
set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES FALSE)
|
||||
|
||||
add_library(LinkDirs_interface INTERFACE)
|
||||
target_link_directories (LinkDirs_interface INTERFACE "/DIR_INTERFACE"})
|
||||
|
||||
add_library(LinkDirs_static STATIC lib.c)
|
||||
target_link_libraries (LinkDirs_static PRIVATE LinkDirs_interface)
|
||||
|
||||
add_executable(LinkDirs_exe exe.c)
|
||||
target_link_libraries (LinkDirs_exe PRIVATE LinkDirs_static)
|
@ -1,3 +1,33 @@
|
||||
include(RunCMake)
|
||||
|
||||
macro(run_cmake_target test subtest target)
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} ${ARGN})
|
||||
|
||||
unset(RunCMake_TEST_BINARY_DIR)
|
||||
unset(RunCMake_TEST_NO_CLEAN)
|
||||
endmacro()
|
||||
|
||||
run_cmake(empty_keyword_args)
|
||||
|
||||
if(RunCMake_GENERATOR MATCHES "(Ninja|Makefiles)" AND
|
||||
NOT RunCMake_GENERATOR MATCHES "(NMake|Borland)")
|
||||
set(RunCMake_TEST_OUTPUT_MERGE TRUE)
|
||||
if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
|
||||
endif()
|
||||
if (RunCMake_GENERATOR MATCHES "Ninja")
|
||||
set(VERBOSE -- -v)
|
||||
endif()
|
||||
|
||||
run_cmake(CMP0099-NEW)
|
||||
run_cmake_target(CMP0099-NEW basic LinkDirs_exe ${VERBOSE})
|
||||
|
||||
|
||||
run_cmake(CMP0099-OLD)
|
||||
run_cmake_target(CMP0099-OLD basic LinkDirs_exe ${VERBOSE})
|
||||
|
||||
unset(RunCMake_TEST_OPTIONS)
|
||||
unset(RunCMake_TEST_OUTPUT_MERGE)
|
||||
endif()
|
||||
|
4
Tests/RunCMake/target_link_directories/exe.c
Normal file
4
Tests/RunCMake/target_link_directories/exe.c
Normal file
@ -0,0 +1,4 @@
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
7
Tests/RunCMake/target_link_directories/lib.c
Normal file
7
Tests/RunCMake/target_link_directories/lib.c
Normal file
@ -0,0 +1,7 @@
|
||||
#if defined(_WIN32)
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int flags_lib(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
|
||||
if (NOT actual_stdout MATCHES "BADFLAG_INTERFACE")
|
||||
string (APPEND RunCMake_TEST_FAILED "\nNot found expected 'BADFLAG_INTERFACE'.")
|
||||
endif()
|
@ -0,0 +1 @@
|
||||
.*
|
4
Tests/RunCMake/target_link_options/CMP0099-NEW.cmake
Normal file
4
Tests/RunCMake/target_link_options/CMP0099-NEW.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
cmake_policy(SET CMP0099 NEW)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake)
|
@ -0,0 +1,4 @@
|
||||
|
||||
if (actual_stdout MATCHES "BADFLAG_INTERFACE")
|
||||
string (APPEND RunCMake_TEST_FAILED "\nFound unexpected 'BADFLAG_INTERFACE'.")
|
||||
endif()
|
@ -0,0 +1 @@
|
||||
.*
|
4
Tests/RunCMake/target_link_options/CMP0099-OLD.cmake
Normal file
4
Tests/RunCMake/target_link_options/CMP0099-OLD.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
cmake_policy(SET CMP0099 OLD)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake)
|
16
Tests/RunCMake/target_link_options/CMP0099.cmake
Normal file
16
Tests/RunCMake/target_link_options/CMP0099.cmake
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
enable_language(C)
|
||||
|
||||
set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
|
||||
if(BORLAND)
|
||||
set(pre -)
|
||||
endif()
|
||||
|
||||
add_library(LinkOptions_interface INTERFACE)
|
||||
target_link_options (LinkOptions_interface INTERFACE ${pre}BADFLAG_INTERFACE${obj})
|
||||
|
||||
add_library(LinkOptions_static STATIC LinkOptionsLib.c)
|
||||
target_link_libraries (LinkOptions_static PRIVATE LinkOptions_interface)
|
||||
|
||||
add_executable(LinkOptions_exe LinkOptionsExe.c)
|
||||
target_link_libraries (LinkOptions_exe PRIVATE LinkOptions_static)
|
@ -41,3 +41,21 @@ if(RunCMake_GENERATOR MATCHES "(Ninja|Makefile)")
|
||||
endif()
|
||||
|
||||
run_cmake(empty_keyword_args)
|
||||
|
||||
if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
|
||||
# Intel compiler does not reject bad flags or objects!
|
||||
set(RunCMake_TEST_OUTPUT_MERGE TRUE)
|
||||
if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
|
||||
endif()
|
||||
|
||||
run_cmake(CMP0099-NEW)
|
||||
run_cmake_target(CMP0099-NEW basic LinkOptions_exe)
|
||||
|
||||
|
||||
run_cmake(CMP0099-OLD)
|
||||
run_cmake_target(CMP0099-OLD basic LinkOptions_exe)
|
||||
|
||||
unset(RunCMake_TEST_OPTIONS)
|
||||
unset(RunCMake_TEST_OUTPUT_MERGE)
|
||||
endif()
|
||||
|
Loading…
Reference in New Issue
Block a user