浏览代码

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
Brad King 3 周之前
父节点
当前提交
deb7b4b658

+ 3 - 1
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
 This policy provides compatibility for projects that have not been updated to
 expect the new behavior.  It takes effect during buildsystem generation.
 expect the new behavior.  It takes effect during buildsystem generation.
 Generator expressions are evaluated in each directory using the policy setting
 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
 The ``OLD`` behavior of this policy is for :genex:`TARGET_PROPERTY` to not
 evaluate :prop_tgt:`LINK_LIBRARIES` and :prop_tgt:`INTERFACE_LINK_LIBRARIES`
 evaluate :prop_tgt:`LINK_LIBRARIES` and :prop_tgt:`INTERFACE_LINK_LIBRARIES`

+ 9 - 0
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.
 * This version made no changes to documented features or interfaces.
   Some implementation updates were made to support ecosystem changes
   Some implementation updates were made to support ecosystem changes
   and/or fix regressions.
   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.

+ 18 - 0
Source/cmGenExContext.cxx

@@ -4,6 +4,11 @@
 
 
 #include <utility>
 #include <utility>
 
 
+#include <cm/optional>
+
+#include "cmLocalGenerator.h"
+#include "cmPolicies.h"
+
 namespace cm {
 namespace cm {
 namespace GenEx {
 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);
+}
+
 }
 }
 }
 }

+ 10 - 0
Source/cmGenExContext.h

@@ -4,6 +4,10 @@
 
 
 #include <string>
 #include <string>
 
 
+#include <cm/optional>
+
+#include "cmPolicies.h"
+
 class cmLocalGenerator;
 class cmLocalGenerator;
 
 
 namespace cm {
 namespace cm {
@@ -17,6 +21,12 @@ struct Context final
   cmLocalGenerator const* LG;
   cmLocalGenerator const* LG;
   std::string Config;
   std::string Config;
   std::string Language;
   std::string Language;
+
+  void SetCMP0189(cmPolicies::PolicyStatus cmp0189);
+  cmPolicies::PolicyStatus GetCMP0189() const;
+
+private:
+  cm::optional<cmPolicies::PolicyStatus> CMP0189;
 };
 };
 
 
 }
 }

+ 5 - 1
Source/cmGeneratorExpressionEvaluationFile.cxx

@@ -23,7 +23,8 @@ cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
   std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
   std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
   std::unique_ptr<cmCompiledGeneratorExpression> condition,
   std::unique_ptr<cmCompiledGeneratorExpression> condition,
   bool inputIsContent, std::string newLineCharacter, mode_t permissions,
   bool inputIsContent, std::string newLineCharacter, mode_t permissions,
-  cmPolicies::PolicyStatus policyStatusCMP0070)
+  cmPolicies::PolicyStatus policyStatusCMP0070,
+  cmPolicies::PolicyStatus policyStatusCMP0189)
   : Input(std::move(input))
   : Input(std::move(input))
   , Target(std::move(target))
   , Target(std::move(target))
   , OutputFileExpr(std::move(outputFileExpr))
   , OutputFileExpr(std::move(outputFileExpr))
@@ -31,6 +32,7 @@ cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
   , InputIsContent(inputIsContent)
   , InputIsContent(inputIsContent)
   , NewLineCharacter(std::move(newLineCharacter))
   , NewLineCharacter(std::move(newLineCharacter))
   , PolicyStatusCMP0070(policyStatusCMP0070)
   , PolicyStatusCMP0070(policyStatusCMP0070)
+  , PolicyStatusCMP0189(policyStatusCMP0189)
   , Permissions(permissions)
   , Permissions(permissions)
 {
 {
 }
 }
@@ -41,6 +43,7 @@ void cmGeneratorExpressionEvaluationFile::Generate(
   std::map<std::string, std::string>& outputFiles, mode_t perm)
   std::map<std::string, std::string>& outputFiles, mode_t perm)
 {
 {
   cm::GenEx::Context context(lg, config, lang);
   cm::GenEx::Context context(lg, config, lang);
+  context.SetCMP0189(this->PolicyStatusCMP0189);
   std::string rawCondition = this->Condition->GetInput();
   std::string rawCondition = this->Condition->GetInput();
   cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target);
   cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target);
   if (!rawCondition.empty()) {
   if (!rawCondition.empty()) {
@@ -126,6 +129,7 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
 
 
   for (std::string const& lang : enabledLanguages) {
   for (std::string const& lang : enabledLanguages) {
     cm::GenEx::Context context(lg, config, lang);
     cm::GenEx::Context context(lg, config, lang);
+    context.SetCMP0189(this->PolicyStatusCMP0189);
     std::string const name = this->GetOutputFileName(context, target);
     std::string const name = this->GetOutputFileName(context, target);
     cmSourceFile* sf = lg->GetMakefile()->GetOrCreateGeneratedSource(name);
     cmSourceFile* sf = lg->GetMakefile()->GetOrCreateGeneratedSource(name);
 
 

+ 3 - 1
Source/cmGeneratorExpressionEvaluationFile.h

@@ -31,7 +31,8 @@ public:
     std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
     std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
     std::unique_ptr<cmCompiledGeneratorExpression> condition,
     std::unique_ptr<cmCompiledGeneratorExpression> condition,
     bool inputIsContent, std::string newLineCharacter, mode_t permissions,
     bool inputIsContent, std::string newLineCharacter, mode_t permissions,
-    cmPolicies::PolicyStatus policyStatusCMP0070);
+    cmPolicies::PolicyStatus policyStatusCMP0070,
+    cmPolicies::PolicyStatus policyStatusCMP0189);
 
 
   void Generate(cmLocalGenerator* lg);
   void Generate(cmLocalGenerator* lg);
 
 
@@ -64,5 +65,6 @@ private:
   bool const InputIsContent;
   bool const InputIsContent;
   std::string const NewLineCharacter;
   std::string const NewLineCharacter;
   cmPolicies::PolicyStatus PolicyStatusCMP0070;
   cmPolicies::PolicyStatus PolicyStatusCMP0070;
+  cmPolicies::PolicyStatus PolicyStatusCMP0189;
   mode_t Permissions;
   mode_t Permissions;
 };
 };

+ 1 - 2
Source/cmGeneratorTarget_TransitiveProperty.cxx

@@ -192,8 +192,7 @@ cmGeneratorTarget::IsTransitiveProperty(
   if (i != BuiltinTransitiveProperties.end() &&
   if (i != BuiltinTransitiveProperties.end() &&
       // Look up CMP0189 in the context where evaluation occurs,
       // Look up CMP0189 in the context where evaluation occurs,
       // not where the target was created.
       // 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();
     i = BuiltinTransitiveProperties.end();
   }
   }
   if (i != BuiltinTransitiveProperties.end()) {
   if (i != BuiltinTransitiveProperties.end()) {

+ 2 - 1
Source/cmMakefile.cxx

@@ -941,7 +941,8 @@ void cmMakefile::AddEvaluationFile(
     cm::make_unique<cmGeneratorExpressionEvaluationFile>(
     cm::make_unique<cmGeneratorExpressionEvaluationFile>(
       inputFile, targetName, std::move(outputName), std::move(condition),
       inputFile, targetName, std::move(outputName), std::move(condition),
       inputIsContent, newLineCharacter, permissions,
       inputIsContent, newLineCharacter, permissions,
-      this->GetPolicyStatus(cmPolicies::CMP0070)));
+      this->GetPolicyStatus(cmPolicies::CMP0070),
+      this->GetPolicyStatus(cmPolicies::CMP0189)));
 }
 }
 
 
 std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>> const&
 std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>> const&

+ 10 - 2
Tests/CustomTransitiveProperties/CMP0189/CMakeLists.txt

@@ -1,10 +1,18 @@
+set(out "${CMAKE_CURRENT_BINARY_DIR}/out-OLD-$<CONFIG>.txt")
+file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced:
+${in_LINK_LIBRARIES}
+")
+add_custom_target(check-CMP0189-OLD ALL VERBATIM
+  COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIG> -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check-OLD.cmake
+)
+
 cmake_policy(SET CMP0189 NEW)
 cmake_policy(SET CMP0189 NEW)
-set(out "${CMAKE_CURRENT_BINARY_DIR}/out-$<CONFIG>.txt")
+set(out "${CMAKE_CURRENT_BINARY_DIR}/out-NEW-$<CONFIG>.txt")
 file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced:
 file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced:
 ${in_LINK_LIBRARIES}
 ${in_LINK_LIBRARIES}
 ")
 ")
 add_custom_target(check-CMP0189-NEW ALL VERBATIM
 add_custom_target(check-CMP0189-NEW ALL VERBATIM
-  COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIG> -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
+  COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIG> -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check-NEW.cmake
   COMMAND check-args
   COMMAND check-args
   "$<TARGET_PROPERTY:iface1,LINK_LIBRARIES>" ""
   "$<TARGET_PROPERTY:iface1,LINK_LIBRARIES>" ""
   "$<TARGET_PROPERTY:iface1,INTERFACE_LINK_LIBRARIES>" ""
   "$<TARGET_PROPERTY:iface1,INTERFACE_LINK_LIBRARIES>" ""

+ 0 - 0
Tests/CustomTransitiveProperties/CMP0189/check.cmake → Tests/CustomTransitiveProperties/CMP0189/check-NEW.cmake


+ 32 - 0
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: '\$<LINK_ONLY:iface2>'
+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: '\$<LINK_ONLY:iface21>'
+static21 LINK_LIBRARIES: 'static20;iface21'
+static21 INTERFACE_LINK_LIBRARIES: '\$<LINK_ONLY:static20>;\$<LINK_ONLY:iface21>'
+main20 LINK_LIBRARIES: 'static21;static20'
+main20 INTERFACE_LINK_LIBRARIES: ''
+]])
+include(${CMAKE_CURRENT_LIST_DIR}/../check-common.cmake)