From deb7b4b6588f6d2b98e649a022a17fb4401ebed4 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 23 Sep 2025 11:27:53 -0400 Subject: [PATCH] file(GENERATE): Record CMP0189 at each call site Policy CMP0189, introduced by commit b3da9c6d60 (GenEx: Evaluate LINK_LIBRARIES target properties transitively, 2025-02-24, v4.1.0-rc1~731^2), takes effect at generation time, and so uses the policy value as of the end of each directory. However, some projects may rely on `file(GENERATE)` with the policy's OLD behavior in order to extract targets' *direct* dependencies from `LINK_LIBRARIES`. Pending a first-class solution to that problem, make it easier for projects to port to the policy's NEW behavior in general while retaining the OLD behavior in an isolated context. Fixes: #27220 --- Help/policy/CMP0189.rst | 4 ++- Help/release/4.1.rst | 9 ++++++ Source/cmGenExContext.cxx | 18 +++++++++++ Source/cmGenExContext.h | 10 ++++++ .../cmGeneratorExpressionEvaluationFile.cxx | 6 +++- Source/cmGeneratorExpressionEvaluationFile.h | 4 ++- .../cmGeneratorTarget_TransitiveProperty.cxx | 3 +- Source/cmMakefile.cxx | 3 +- .../CMP0189/CMakeLists.txt | 12 +++++-- .../CMP0189/{check.cmake => check-NEW.cmake} | 0 .../CMP0189/check-OLD.cmake | 32 +++++++++++++++++++ 11 files changed, 93 insertions(+), 8 deletions(-) rename Tests/CustomTransitiveProperties/CMP0189/{check.cmake => check-NEW.cmake} (100%) create mode 100644 Tests/CustomTransitiveProperties/CMP0189/check-OLD.cmake diff --git a/Help/policy/CMP0189.rst b/Help/policy/CMP0189.rst index c2a5893136..71d35200c7 100644 --- a/Help/policy/CMP0189.rst +++ b/Help/policy/CMP0189.rst @@ -18,7 +18,9 @@ target properties transitively because they are among the This policy provides compatibility for projects that have not been updated to expect the new behavior. It takes effect during buildsystem generation. Generator expressions are evaluated in each directory using the policy setting -as of the end of its ``CMakeLists.txt``. +as of the end of its ``CMakeLists.txt``. As an exception, generator +expressions evaluated by the :command:`file(GENERATE)` command use the +policy setting as of its call site. The ``OLD`` behavior of this policy is for :genex:`TARGET_PROPERTY` to not evaluate :prop_tgt:`LINK_LIBRARIES` and :prop_tgt:`INTERFACE_LINK_LIBRARIES` diff --git a/Help/release/4.1.rst b/Help/release/4.1.rst index 095526fd8d..a984269501 100644 --- a/Help/release/4.1.rst +++ b/Help/release/4.1.rst @@ -234,3 +234,12 @@ Changes made since CMake 4.1.0 include the following. * This version made no changes to documented features or interfaces. Some implementation updates were made to support ecosystem changes and/or fix regressions. + +4.1.2 +----- + +* The :command:`file(GENERATE)` command, when evaluating generator + expressions, now uses the value of policy :policy:`CMP0189` as of + each call site. Previously, it used the value as of the end of the + directory's ``CMakeLists.txt``, as all other generator expression + evaluations do. diff --git a/Source/cmGenExContext.cxx b/Source/cmGenExContext.cxx index 1089e5b35f..1699051ce8 100644 --- a/Source/cmGenExContext.cxx +++ b/Source/cmGenExContext.cxx @@ -4,6 +4,11 @@ #include +#include + +#include "cmLocalGenerator.h" +#include "cmPolicies.h" + namespace cm { namespace GenEx { @@ -15,5 +20,18 @@ Context::Context(cmLocalGenerator const* lg, std::string config, { } +void Context::SetCMP0189(cmPolicies::PolicyStatus cmp0189) +{ + this->CMP0189 = cmp0189; +} + +cmPolicies::PolicyStatus Context::GetCMP0189() const +{ + if (this->CMP0189.has_value()) { + return *this->CMP0189; + } + return this->LG->GetPolicyStatus(cmPolicies::CMP0189); +} + } } diff --git a/Source/cmGenExContext.h b/Source/cmGenExContext.h index 4e4e7c4dab..85c8ab2a29 100644 --- a/Source/cmGenExContext.h +++ b/Source/cmGenExContext.h @@ -4,6 +4,10 @@ #include +#include + +#include "cmPolicies.h" + class cmLocalGenerator; namespace cm { @@ -17,6 +21,12 @@ struct Context final cmLocalGenerator const* LG; std::string Config; std::string Language; + + void SetCMP0189(cmPolicies::PolicyStatus cmp0189); + cmPolicies::PolicyStatus GetCMP0189() const; + +private: + cm::optional CMP0189; }; } diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx index 7909fc0c42..38a320bf4f 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.cxx +++ b/Source/cmGeneratorExpressionEvaluationFile.cxx @@ -23,7 +23,8 @@ cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile( std::unique_ptr outputFileExpr, std::unique_ptr condition, bool inputIsContent, std::string newLineCharacter, mode_t permissions, - cmPolicies::PolicyStatus policyStatusCMP0070) + cmPolicies::PolicyStatus policyStatusCMP0070, + cmPolicies::PolicyStatus policyStatusCMP0189) : Input(std::move(input)) , Target(std::move(target)) , OutputFileExpr(std::move(outputFileExpr)) @@ -31,6 +32,7 @@ cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile( , InputIsContent(inputIsContent) , NewLineCharacter(std::move(newLineCharacter)) , PolicyStatusCMP0070(policyStatusCMP0070) + , PolicyStatusCMP0189(policyStatusCMP0189) , Permissions(permissions) { } @@ -41,6 +43,7 @@ void cmGeneratorExpressionEvaluationFile::Generate( std::map& outputFiles, mode_t perm) { cm::GenEx::Context context(lg, config, lang); + context.SetCMP0189(this->PolicyStatusCMP0189); std::string rawCondition = this->Condition->GetInput(); cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target); if (!rawCondition.empty()) { @@ -126,6 +129,7 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile( for (std::string const& lang : enabledLanguages) { cm::GenEx::Context context(lg, config, lang); + context.SetCMP0189(this->PolicyStatusCMP0189); std::string const name = this->GetOutputFileName(context, target); cmSourceFile* sf = lg->GetMakefile()->GetOrCreateGeneratedSource(name); diff --git a/Source/cmGeneratorExpressionEvaluationFile.h b/Source/cmGeneratorExpressionEvaluationFile.h index dab5f14ff9..01955bab9e 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.h +++ b/Source/cmGeneratorExpressionEvaluationFile.h @@ -31,7 +31,8 @@ public: std::unique_ptr outputFileExpr, std::unique_ptr condition, bool inputIsContent, std::string newLineCharacter, mode_t permissions, - cmPolicies::PolicyStatus policyStatusCMP0070); + cmPolicies::PolicyStatus policyStatusCMP0070, + cmPolicies::PolicyStatus policyStatusCMP0189); void Generate(cmLocalGenerator* lg); @@ -64,5 +65,6 @@ private: bool const InputIsContent; std::string const NewLineCharacter; cmPolicies::PolicyStatus PolicyStatusCMP0070; + cmPolicies::PolicyStatus PolicyStatusCMP0189; mode_t Permissions; }; diff --git a/Source/cmGeneratorTarget_TransitiveProperty.cxx b/Source/cmGeneratorTarget_TransitiveProperty.cxx index 85557f27b8..81072f28b9 100644 --- a/Source/cmGeneratorTarget_TransitiveProperty.cxx +++ b/Source/cmGeneratorTarget_TransitiveProperty.cxx @@ -192,8 +192,7 @@ cmGeneratorTarget::IsTransitiveProperty( if (i != BuiltinTransitiveProperties.end() && // Look up CMP0189 in the context where evaluation occurs, // not where the target was created. - context.LG->GetPolicyStatus(cmPolicies::CMP0189) != cmPolicies::NEW && - prop == "LINK_LIBRARIES"_s) { + context.GetCMP0189() != cmPolicies::NEW && prop == "LINK_LIBRARIES"_s) { i = BuiltinTransitiveProperties.end(); } if (i != BuiltinTransitiveProperties.end()) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 786ef74744..3c467e1fa8 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -941,7 +941,8 @@ void cmMakefile::AddEvaluationFile( cm::make_unique( inputFile, targetName, std::move(outputName), std::move(condition), inputIsContent, newLineCharacter, permissions, - this->GetPolicyStatus(cmPolicies::CMP0070))); + this->GetPolicyStatus(cmPolicies::CMP0070), + this->GetPolicyStatus(cmPolicies::CMP0189))); } std::vector> const& diff --git a/Tests/CustomTransitiveProperties/CMP0189/CMakeLists.txt b/Tests/CustomTransitiveProperties/CMP0189/CMakeLists.txt index 04fb1b4f63..8df28ccd7d 100644 --- a/Tests/CustomTransitiveProperties/CMP0189/CMakeLists.txt +++ b/Tests/CustomTransitiveProperties/CMP0189/CMakeLists.txt @@ -1,10 +1,18 @@ +set(out "${CMAKE_CURRENT_BINARY_DIR}/out-OLD-$.txt") +file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced: +${in_LINK_LIBRARIES} +") +add_custom_target(check-CMP0189-OLD ALL VERBATIM + COMMAND ${CMAKE_COMMAND} -Dconfig=$ -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check-OLD.cmake +) + cmake_policy(SET CMP0189 NEW) -set(out "${CMAKE_CURRENT_BINARY_DIR}/out-$.txt") +set(out "${CMAKE_CURRENT_BINARY_DIR}/out-NEW-$.txt") file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced: ${in_LINK_LIBRARIES} ") add_custom_target(check-CMP0189-NEW ALL VERBATIM - COMMAND ${CMAKE_COMMAND} -Dconfig=$ -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check.cmake + COMMAND ${CMAKE_COMMAND} -Dconfig=$ -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check-NEW.cmake COMMAND check-args "$" "" "$" "" diff --git a/Tests/CustomTransitiveProperties/CMP0189/check.cmake b/Tests/CustomTransitiveProperties/CMP0189/check-NEW.cmake similarity index 100% rename from Tests/CustomTransitiveProperties/CMP0189/check.cmake rename to Tests/CustomTransitiveProperties/CMP0189/check-NEW.cmake diff --git a/Tests/CustomTransitiveProperties/CMP0189/check-OLD.cmake b/Tests/CustomTransitiveProperties/CMP0189/check-OLD.cmake new file mode 100644 index 0000000000..94dd066829 --- /dev/null +++ b/Tests/CustomTransitiveProperties/CMP0189/check-OLD.cmake @@ -0,0 +1,32 @@ +set(expect [[ +# file\(GENERATE\) produced: +iface1 LINK_LIBRARIES: '' +iface1 INTERFACE_LINK_LIBRARIES: '' +iface2 LINK_LIBRARIES: '' +iface2 INTERFACE_LINK_LIBRARIES: 'iface1' +static1 LINK_LIBRARIES: 'iface2' +static1 INTERFACE_LINK_LIBRARIES: '\$' +main LINK_LIBRARIES: 'static1;object1' +main INTERFACE_LINK_LIBRARIES: '' +iface10 LINK_LIBRARIES: '' +iface10 INTERFACE_LINK_LIBRARIES: '' +iface11 LINK_LIBRARIES: '' +iface11 INTERFACE_LINK_LIBRARIES: 'iface10' +static10 LINK_LIBRARIES: 'iface11;iface10' +static10 INTERFACE_LINK_LIBRARIES: 'iface11;iface10' +static11 LINK_LIBRARIES: 'static10;iface11;iface11;iface10' +static11 INTERFACE_LINK_LIBRARIES: 'static10;iface11;iface11;iface10' +main10 LINK_LIBRARIES: 'static11;static10;static10;iface11;iface11;iface10' +main10 INTERFACE_LINK_LIBRARIES: '' +iface20 LINK_LIBRARIES: '' +iface20 INTERFACE_LINK_LIBRARIES: '' +iface21 LINK_LIBRARIES: '' +iface21 INTERFACE_LINK_LIBRARIES: 'iface20' +static20 LINK_LIBRARIES: 'iface21' +static20 INTERFACE_LINK_LIBRARIES: '\$' +static21 LINK_LIBRARIES: 'static20;iface21' +static21 INTERFACE_LINK_LIBRARIES: '\$;\$' +main20 LINK_LIBRARIES: 'static21;static20' +main20 INTERFACE_LINK_LIBRARIES: '' +]]) +include(${CMAKE_CURRENT_LIST_DIR}/../check-common.cmake)