diff options
25 files changed, 192 insertions, 18 deletions
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index eceeac7..2118031 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -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 diff --git a/Help/policy/CMP0099.rst b/Help/policy/CMP0099.rst new file mode 100644 index 0000000..c897e7b --- /dev/null +++ b/Help/policy/CMP0099.rst @@ -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 diff --git a/Help/release/dev/Link-properties-transitive.rst b/Help/release/dev/Link-properties-transitive.rst new file mode 100644 index 0000000..535b40c --- /dev/null +++ b/Help/release/dev/Link-properties-transitive.rst @@ -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`. diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index d0b5f9e..29593d9 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -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); diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 336c91f..761e58a 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -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>>; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index da32204..ecf892b 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -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 diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt index 6d72fac..9a1e027 100644 --- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt +++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt @@ -28,6 +28,7 @@ \* CMP0081 \* CMP0083 \* CMP0095 + \* CMP0099 Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-check.cmake b/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-check.cmake new file mode 100644 index 0000000..2fffddd --- /dev/null +++ b/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "DIR_INTERFACE") + string (APPEND RunCMake_TEST_FAILED "\nNot found expected 'DIR_INTERFACE'.") +endif() diff --git a/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-result.txt b/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake b/Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake new file mode 100644 index 0000000..17dd68e --- /dev/null +++ b/Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake @@ -0,0 +1,4 @@ + +cmake_policy(SET CMP0099 NEW) + +include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake) diff --git a/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-check.cmake b/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-check.cmake new file mode 100644 index 0000000..16573a7 --- /dev/null +++ b/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-check.cmake @@ -0,0 +1,4 @@ + +if (actual_stdout MATCHES "DIR_INTERFACE") + string (APPEND RunCMake_TEST_FAILED "\nFound unexpected 'DIR_INTERFACE'.") +endif() diff --git a/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-result.txt b/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake b/Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake new file mode 100644 index 0000000..193a4c7 --- /dev/null +++ b/Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake @@ -0,0 +1,4 @@ + +cmake_policy(SET CMP0099 OLD) + +include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake) diff --git a/Tests/RunCMake/target_link_directories/CMP0099.cmake b/Tests/RunCMake/target_link_directories/CMP0099.cmake new file mode 100644 index 0000000..a2be279 --- /dev/null +++ b/Tests/RunCMake/target_link_directories/CMP0099.cmake @@ -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) diff --git a/Tests/RunCMake/target_link_directories/RunCMakeTest.cmake b/Tests/RunCMake/target_link_directories/RunCMakeTest.cmake index b67c598..a74ee25 100644 --- a/Tests/RunCMake/target_link_directories/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_link_directories/RunCMakeTest.cmake @@ -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() diff --git a/Tests/RunCMake/target_link_directories/exe.c b/Tests/RunCMake/target_link_directories/exe.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/target_link_directories/exe.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/target_link_directories/lib.c b/Tests/RunCMake/target_link_directories/lib.c new file mode 100644 index 0000000..9bbd24c --- /dev/null +++ b/Tests/RunCMake/target_link_directories/lib.c @@ -0,0 +1,7 @@ +#if defined(_WIN32) +__declspec(dllexport) +#endif + int flags_lib(void) +{ + return 0; +} diff --git a/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-check.cmake b/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-check.cmake new file mode 100644 index 0000000..555bc37 --- /dev/null +++ b/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "BADFLAG_INTERFACE") + string (APPEND RunCMake_TEST_FAILED "\nNot found expected 'BADFLAG_INTERFACE'.") +endif() diff --git a/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-result.txt b/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_options/CMP0099-NEW.cmake b/Tests/RunCMake/target_link_options/CMP0099-NEW.cmake new file mode 100644 index 0000000..17dd68e --- /dev/null +++ b/Tests/RunCMake/target_link_options/CMP0099-NEW.cmake @@ -0,0 +1,4 @@ + +cmake_policy(SET CMP0099 NEW) + +include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake) diff --git a/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-check.cmake b/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-check.cmake new file mode 100644 index 0000000..4f159f1 --- /dev/null +++ b/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-check.cmake @@ -0,0 +1,4 @@ + +if (actual_stdout MATCHES "BADFLAG_INTERFACE") + string (APPEND RunCMake_TEST_FAILED "\nFound unexpected 'BADFLAG_INTERFACE'.") +endif() diff --git a/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-result.txt b/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_options/CMP0099-OLD.cmake b/Tests/RunCMake/target_link_options/CMP0099-OLD.cmake new file mode 100644 index 0000000..193a4c7 --- /dev/null +++ b/Tests/RunCMake/target_link_options/CMP0099-OLD.cmake @@ -0,0 +1,4 @@ + +cmake_policy(SET CMP0099 OLD) + +include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake) diff --git a/Tests/RunCMake/target_link_options/CMP0099.cmake b/Tests/RunCMake/target_link_options/CMP0099.cmake new file mode 100644 index 0000000..9dee964 --- /dev/null +++ b/Tests/RunCMake/target_link_options/CMP0099.cmake @@ -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) diff --git a/Tests/RunCMake/target_link_options/RunCMakeTest.cmake b/Tests/RunCMake/target_link_options/RunCMakeTest.cmake index 1d9ef8b..cdfdd7b 100644 --- a/Tests/RunCMake/target_link_options/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_link_options/RunCMakeTest.cmake @@ -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() |