mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-17 15:32:10 +08:00
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
This commit is contained in:
@@ -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`
|
||||||
|
@@ -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.
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
@@ -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 &&
|
context.GetCMP0189() != cmPolicies::NEW && prop == "LINK_LIBRARIES"_s) {
|
||||||
prop == "LINK_LIBRARIES"_s) {
|
|
||||||
i = BuiltinTransitiveProperties.end();
|
i = BuiltinTransitiveProperties.end();
|
||||||
}
|
}
|
||||||
if (i != BuiltinTransitiveProperties.end()) {
|
if (i != BuiltinTransitiveProperties.end()) {
|
||||||
|
@@ -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&
|
||||||
|
@@ -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>" ""
|
||||||
|
32
Tests/CustomTransitiveProperties/CMP0189/check-OLD.cmake
Normal file
32
Tests/CustomTransitiveProperties/CMP0189/check-OLD.cmake
Normal file
@@ -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)
|
Reference in New Issue
Block a user