Merge branch 'backport-3.30-custom-transitive-properties'

This commit is contained in:
Brad King 2025-02-23 08:33:12 -05:00
commit 478d6cfd9a
15 changed files with 199 additions and 69 deletions

View File

@ -647,13 +647,13 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
if (!feature->empty() && key.length() > lloPrefix.length()) {
auto item = key.substr(lloPrefix.length());
cmGeneratorExpressionDAGChecker dagChecker{
this->Target->GetBacktrace(),
this->Target,
"LINK_LIBRARY_OVERRIDE",
nullptr,
nullptr,
this->Target->GetLocalGenerator(),
config,
this->Target->GetBacktrace(),
};
auto overrideFeature = cmGeneratorExpression::Evaluate(
*feature, this->Target->GetLocalGenerator(), config,
@ -667,13 +667,13 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
if (cmValue linkLibraryOverride =
this->Target->GetProperty("LINK_LIBRARY_OVERRIDE")) {
cmGeneratorExpressionDAGChecker dagChecker{
target->GetBacktrace(),
target,
"LINK_LIBRARY_OVERRIDE",
nullptr,
nullptr,
target->GetLocalGenerator(),
config,
target->GetBacktrace(),
};
auto overrideValue = cmGeneratorExpression::Evaluate(
*linkLibraryOverride, target->GetLocalGenerator(), config, target,

View File

@ -19,34 +19,24 @@
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
cmGeneratorTarget const* target, std::string property,
const GeneratorExpressionContent* content,
GeneratorExpressionContent const* content,
cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG,
std::string const& contextConfig)
: cmGeneratorExpressionDAGChecker(cmListFileBacktrace(), target,
std::move(property), content, parent,
contextLG, contextConfig)
{
}
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
cmListFileBacktrace backtrace, cmGeneratorTarget const* target,
std::string property, const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG,
std::string const& contextConfig)
std::string const& contextConfig, cmListFileBacktrace backtrace,
ComputingLinkLibraries computingLinkLibraries)
: Parent(parent)
, Top(parent ? parent->Top : this)
, Target(target)
, Property(std::move(property))
, Content(content)
, Backtrace(std::move(backtrace))
, ComputingLinkLibraries_(computingLinkLibraries)
{
if (parent) {
this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty;
} else {
this->TopIsTransitiveProperty =
this->Target
->IsTransitiveProperty(this->Property, contextLG, contextConfig,
this->EvaluatingLinkLibraries())
->IsTransitiveProperty(this->Property, contextLG, contextConfig, this)
.has_value();
}
@ -204,6 +194,11 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkerLauncher() const
"_LINKER_LAUNCHER"_s;
}
bool cmGeneratorExpressionDAGChecker::IsComputingLinkLibraries() const
{
return this->Top->ComputingLinkLibraries_ == ComputingLinkLibraries::Yes;
}
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
cmGeneratorTarget const* tgt, ForGenex genex) const
{

View File

@ -17,19 +17,19 @@ class cmLocalGenerator;
struct cmGeneratorExpressionDAGChecker
{
cmGeneratorExpressionDAGChecker(cmListFileBacktrace backtrace,
cmGeneratorTarget const* target,
std::string property,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent,
cmLocalGenerator const* contextLG,
std::string const& contextConfig);
cmGeneratorExpressionDAGChecker(cmGeneratorTarget const* target,
std::string property,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent,
cmLocalGenerator const* contextLG,
std::string const& contextConfig);
enum class ComputingLinkLibraries
{
No,
Yes,
};
cmGeneratorExpressionDAGChecker(
cmGeneratorTarget const* target, std::string property,
GeneratorExpressionContent const* content,
cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG,
std::string const& contextConfig,
cmListFileBacktrace backtrace = cmListFileBacktrace(),
ComputingLinkLibraries computingLinkLibraries =
ComputingLinkLibraries::No);
enum Result
{
@ -52,6 +52,11 @@ struct cmGeneratorExpressionDAGChecker
bool EvaluatingLinkOptionsExpression() const;
bool EvaluatingLinkerLauncher() const;
/** Returns true only when computing the actual link dependency
graph for cmGeneratorTarget::GetLinkImplementationLibraries
or cmGeneratorTarget::GetLinkInterfaceLibraries. */
bool IsComputingLinkLibraries() const;
enum class ForGenex
{
ANY,
@ -85,4 +90,6 @@ private:
bool TransitivePropertiesOnly = false;
bool CMP0131 = false;
bool TopIsTransitiveProperty = false;
ComputingLinkLibraries const ComputingLinkLibraries_ =
ComputingLinkLibraries::No;
};

View File

@ -486,13 +486,13 @@ protected:
{
if (context->HeadTarget) {
cmGeneratorExpressionDAGChecker dagChecker{
context->Backtrace,
context->HeadTarget,
genexOperator + ":" + expression,
content,
dagCheckerParent,
context->LG,
context->Config,
context->Backtrace,
};
switch (dagChecker.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
@ -2957,8 +2957,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
target->IsTransitiveProperty(propertyName, context->LG,
context->Config,
evaluatingLinkLibraries)) {
context->Config, dagCheckerParent)) {
interfacePropertyName = std::string(transitiveProp->InterfaceName);
isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
usage = transitiveProp->Usage;
@ -2993,8 +2992,13 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
cmGeneratorExpressionDAGChecker dagChecker{
context->Backtrace, target, propertyName, content,
dagCheckerParent, context->LG, context->Config,
target,
propertyName,
content,
dagCheckerParent,
context->LG,
context->Config,
context->Backtrace,
};
switch (dagChecker.Check()) {

View File

@ -1001,7 +1001,8 @@ public:
cm::optional<TransitiveProperty> IsTransitiveProperty(
cm::string_view prop, cmLocalGenerator const* lg,
std::string const& config, bool evaluatingLinkLibraries) const;
std::string const& config,
cmGeneratorExpressionDAGChecker const* dagChecker) const;
bool HaveInstallTreeRPATH(const std::string& config) const;

View File

@ -48,8 +48,13 @@ std::string AddLangSpecificInterfaceIncludeDirectories(
cmGeneratorExpressionDAGChecker* context)
{
cmGeneratorExpressionDAGChecker dagChecker{
target->GetBacktrace(), target, propertyName, nullptr, context,
target->GetLocalGenerator(), config,
target,
propertyName,
nullptr,
context,
target->GetLocalGenerator(),
config,
target->GetBacktrace(),
};
switch (dagChecker.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
@ -101,8 +106,13 @@ void AddLangSpecificImplicitIncludeDirectories(
if (const auto* libraries =
target->GetLinkImplementationLibraries(config, UseTo::Compile)) {
cmGeneratorExpressionDAGChecker dagChecker{
target->GetBacktrace(), target, propertyName, nullptr, nullptr,
target->GetLocalGenerator(), config,
target,
propertyName,
nullptr,
nullptr,
target->GetLocalGenerator(),
config,
target->GetBacktrace(),
};
for (const cmLinkImplItem& library : libraries->Libraries) {

View File

@ -565,7 +565,14 @@ void cmGeneratorTarget::ExpandLinkItems(std::string const& prop,
}
// Keep this logic in sync with ComputeLinkImplementationLibraries.
cmGeneratorExpressionDAGChecker dagChecker{
this, prop, nullptr, nullptr, this->LocalGenerator, config,
this,
prop,
nullptr,
nullptr,
this->LocalGenerator,
config,
cmListFileBacktrace(),
cmGeneratorExpressionDAGChecker::ComputingLinkLibraries::Yes,
};
// The $<LINK_ONLY> expression may be in a link interface to specify
// private link dependencies that are otherwise excluded from usage
@ -1322,7 +1329,14 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
for (auto const& entry : entryRange) {
// Keep this logic in sync with ExpandLinkItems.
cmGeneratorExpressionDAGChecker dagChecker{
this, "LINK_LIBRARIES", nullptr, nullptr, this->LocalGenerator, config,
this,
"LINK_LIBRARIES",
nullptr,
nullptr,
this->LocalGenerator,
config,
cmListFileBacktrace(),
cmGeneratorExpressionDAGChecker::ComputingLinkLibraries::Yes,
};
// The $<LINK_ONLY> expression may be used to specify link dependencies
// that are otherwise excluded from usage requirements.

View File

@ -110,13 +110,13 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
// a subset of TargetPropertyNode::Evaluate without stringify/parse steps
// but sufficient for transitive interface properties.
cmGeneratorExpressionDAGChecker dagChecker{
context->Backtrace,
this,
prop,
nullptr,
dagCheckerParent,
this->LocalGenerator,
context->LG,
context->Config,
context->Backtrace,
};
switch (dagChecker.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
@ -183,10 +183,9 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
}
cm::optional<cmGeneratorTarget::TransitiveProperty>
cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop,
cmLocalGenerator const* lg,
std::string const& config,
bool evaluatingLinkLibraries) const
cmGeneratorTarget::IsTransitiveProperty(
cm::string_view prop, cmLocalGenerator const* lg, std::string const& config,
cmGeneratorExpressionDAGChecker const* dagChecker) const
{
cm::optional<TransitiveProperty> result;
static const cm::string_view kINTERFACE_ = "INTERFACE_"_s;
@ -215,7 +214,7 @@ cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop,
result = TransitiveProperty{ "INTERFACE_COMPILE_DEFINITIONS"_s,
UseTo::Compile };
}
} else if (!evaluatingLinkLibraries) {
} else if (!dagChecker || !dagChecker->IsComputingLinkLibraries()) {
// Honor TRANSITIVE_COMPILE_PROPERTIES and TRANSITIVE_LINK_PROPERTIES
// from the link closure when we are not evaluating the closure itself.
CustomTransitiveProperties const& ctp =

View File

@ -90,9 +90,22 @@ target_compile_definitions(CustomTransitiveProperties PRIVATE
$<TARGET_PROPERTY:CUSTOM_W>
)
# Test TRANSITIVE_LINK_PROPERTIES containing LINK_LIBRARIES itself.
add_library(iface10 INTERFACE)
set_property(TARGET iface10 PROPERTY TRANSITIVE_LINK_PROPERTIES "LINK_LIBRARIES")
add_library(iface11 INTERFACE)
target_link_libraries(iface11 INTERFACE iface10)
add_library(static10 STATIC static10.c)
target_link_libraries(static10 PRIVATE iface11)
add_library(static11 STATIC static11.c)
target_link_libraries(static11 PRIVATE static10 iface11)
add_executable(main10 main10.c)
target_link_libraries(main10 PRIVATE static11 static10)
# Test TRANSITIVE_*_PROPERTY evaluation outside of usage requirements.
add_executable(check-args check-args.c)
set(out "${CMAKE_CURRENT_BINARY_DIR}/out-$<CONFIG>.txt")
file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced:
set(in_CUSTOM [====[
iface1 CUSTOM_A: '$<TARGET_PROPERTY:iface1,CUSTOM_A>'
iface1 INTERFACE_CUSTOM_A: '$<TARGET_PROPERTY:iface1,INTERFACE_CUSTOM_A>'
iface2 CUSTOM_A: '$<TARGET_PROPERTY:iface2,CUSTOM_A>'
@ -125,10 +138,35 @@ main CUSTOM_V: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_V>'
main INTERFACE_CUSTOM_V: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_V>'
main CUSTOM_W: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_W>'
main INTERFACE_CUSTOM_W: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_W>'
]====])
set(in_LINK_LIBRARIES [====[
iface1 LINK_LIBRARIES: '$<TARGET_PROPERTY:iface1,LINK_LIBRARIES>'
iface1 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:iface1,INTERFACE_LINK_LIBRARIES>'
iface2 LINK_LIBRARIES: '$<TARGET_PROPERTY:iface2,LINK_LIBRARIES>'
iface2 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:iface2,INTERFACE_LINK_LIBRARIES>'
static1 LINK_LIBRARIES: '$<TARGET_PROPERTY:static1,LINK_LIBRARIES>'
static1 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:static1,INTERFACE_LINK_LIBRARIES>'
main LINK_LIBRARIES: '$<TARGET_PROPERTY:CustomTransitiveProperties,LINK_LIBRARIES>'
main INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_LINK_LIBRARIES>'
iface10 LINK_LIBRARIES: '$<TARGET_PROPERTY:iface10,LINK_LIBRARIES>'
iface10 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:iface10,INTERFACE_LINK_LIBRARIES>'
iface11 LINK_LIBRARIES: '$<TARGET_PROPERTY:iface11,LINK_LIBRARIES>'
iface11 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:iface11,INTERFACE_LINK_LIBRARIES>'
static10 LINK_LIBRARIES: '$<TARGET_PROPERTY:static10,LINK_LIBRARIES>'
static10 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:static10,INTERFACE_LINK_LIBRARIES>'
static11 LINK_LIBRARIES: '$<TARGET_PROPERTY:static11,LINK_LIBRARIES>'
static11 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:static11,INTERFACE_LINK_LIBRARIES>'
main10 LINK_LIBRARIES: '$<TARGET_PROPERTY:main10,LINK_LIBRARIES>'
main10 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:main10,INTERFACE_LINK_LIBRARIES>'
]====])
file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced:
${in_CUSTOM}
${in_LINK_LIBRARIES}
")
add_custom_target(check ALL VERBATIM
COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIG> -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
COMMAND CustomTransitiveProperties
COMMAND check-args
"$<TARGET_PROPERTY:static1,CUSTOM_A>" "CUSTOM_A_STATIC1;CUSTOM_A_IFACE2;CUSTOM_A_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_STATIC1"
"$<TARGET_PROPERTY:static1,CUSTOM_B>" "CUSTOM_B_STATIC1;CUSTOM_B_IFACE1"
"$<TARGET_PROPERTY:static1,CUSTOM_U>" "CUSTOM_U_STATIC1;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_STATIC1"
@ -143,4 +181,33 @@ add_custom_target(check ALL VERBATIM
"$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_U>" "CUSTOM_U_MAIN;CUSTOM_U_STATIC1_IFACE;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_EXECUTABLE;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_CUSTOMTRANSITIVEPROPERTIES;CUSTOM_U_OBJECT1_IFACE"
"$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_V>" "CUSTOM_V_MAIN;CUSTOM_V_STATIC1_IFACE;CUSTOM_V_IFACE1"
"$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_W>" "CUSTOM_W_MAIN;CUSTOM_W_IFACE1;CUSTOM_W_OBJECT1_IFACE"
COMMAND check-args
"$<TARGET_PROPERTY:iface1,LINK_LIBRARIES>" ""
"$<TARGET_PROPERTY:iface1,INTERFACE_LINK_LIBRARIES>" ""
"$<TARGET_PROPERTY:iface2,LINK_LIBRARIES>" ""
"$<TARGET_PROPERTY:iface2,INTERFACE_LINK_LIBRARIES>" "iface1"
"$<TARGET_PROPERTY:static1,LINK_LIBRARIES>" "iface2"
"$<TARGET_PROPERTY:static1,INTERFACE_LINK_LIBRARIES>" "$<LINK_ONLY:iface2$<ANGLE-R>"
"$<TARGET_PROPERTY:CustomTransitiveProperties,LINK_LIBRARIES>" "static1;object1"
"$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_LINK_LIBRARIES>" ""
COMMAND check-args
"$<TARGET_PROPERTY:iface10,LINK_LIBRARIES>" ""
"$<TARGET_PROPERTY:iface10,INTERFACE_LINK_LIBRARIES>" ""
"$<TARGET_PROPERTY:iface11,LINK_LIBRARIES>" ""
"$<TARGET_PROPERTY:iface11,INTERFACE_LINK_LIBRARIES>" "iface10"
"$<TARGET_PROPERTY:static10,LINK_LIBRARIES>" "iface11;iface10"
# _/ \__
# / \
# "static10[iface11];iface11[iface10]"
"$<TARGET_PROPERTY:static10,INTERFACE_LINK_LIBRARIES>" "iface11;iface10"
"$<TARGET_PROPERTY:static11,LINK_LIBRARIES>" "static10;iface11;iface11;iface10"
# __/ __/ \__ \__________
# / / \ \
# "static11[static10;iface11];static10[iface11;iface11[iface10]]"
"$<TARGET_PROPERTY:static11,INTERFACE_LINK_LIBRARIES>" "static10;iface11;iface11;iface10"
"$<TARGET_PROPERTY:main10,LINK_LIBRARIES>" "static11;static10;static10;iface11;iface11;iface10"
# _______/ _______/ | | \______ \______________
# / / | | \ \
# "main10[static11;static10];static11[static10;iface11;static10[iface11;iface11[iface10]]]"
"$<TARGET_PROPERTY:main10,INTERFACE_LINK_LIBRARIES>" ""
)

View File

@ -0,0 +1,16 @@
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
int result = 0;
int i;
for (i = 2; i < argc; i += 2) {
if (strcmp(argv[i - 1], argv[i]) != 0) {
fprintf(stderr, "Argument %d expected '%s' but got '%s'.\n", i, argv[i],
argv[i - 1]);
result = 1;
}
}
return result;
}

View File

@ -32,6 +32,25 @@ main CUSTOM_V: 'CUSTOM_V_MAIN;CUSTOM_V_STATIC1_IFACE;CUSTOM_V_IFACE1'
main INTERFACE_CUSTOM_V: ''
main CUSTOM_W: 'CUSTOM_W_MAIN;CUSTOM_W_IFACE1;CUSTOM_W_OBJECT1_IFACE'
main INTERFACE_CUSTOM_W: ''
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: ''
]])
string(REGEX REPLACE "\r\n" "\n" expect "${expect}")
string(REGEX REPLACE "\n+$" "" expect "${expect}")

View File

@ -1,6 +1,3 @@
#include <stdio.h>
#include <string.h>
#ifdef CUSTOM_A_IFACE1
# error "CUSTOM_A_IFACE1 incorrectly defined"
#endif
@ -117,21 +114,7 @@
extern int static1(void);
extern int object1(void);
int check_args(int argc, char** argv)
int main(void)
{
int result = 0;
int i;
for (i = 2; i < argc; i += 2) {
if (strcmp(argv[i - 1], argv[i]) != 0) {
fprintf(stderr, "Argument %d expected '%s' but got '%s'.\n", i, argv[i],
argv[i - 1]);
result = 1;
}
}
return result;
}
int main(int argc, char** argv)
{
return static1() + object1() + check_args(argc, argv);
return static1() + object1();
}

View File

@ -0,0 +1,7 @@
extern int static10(void);
extern int static11(void);
int main(void)
{
return static10() + static11();
}

View File

@ -0,0 +1,4 @@
int static10(void)
{
return 0;
}

View File

@ -0,0 +1,4 @@
int static11(void)
{
return 0;
}