Genex: Optimize transitive TARGET_PROPERTY evaluation
In large projects the generation process spends a lot of time evaluating usage requirements through transitive interface properties on targets. This can be seen in a contrived example with deep dependencies:
set(prev "")
foreach(i RANGE 1 500)
add_library(a${i} a.c)
target_compile_definitions(a${i} PUBLIC A${i})
target_link_libraries(a${i} PUBLIC ${prev})
set(prev a${i})
endforeach()
For each build setting property (such as COMPILE_DEFINITIONS
or
INCLUDE_DIRECTORIES
), the value of $<TARGET_PROPERTY:target,prop>
includes the values of the corresponding INTERFACE_*
usage requirement
property from the transitive closure of link libraries of the target.
Previously we computed this by constructing a generator expression
string like $<TARGET_PROPERTY:lib,INTERFACE_COMPILE_DEFINITIONS>
and
recursively evaluating it with the generator expression engine. Avoid
the string construction and parsing by creating and using a dedicated
evaluation method cmGeneratorTarget::EvaluateInterfaceProperty
that
looks up the properties directly.
In cases that a target's transitive closure of dependencies does not depend on the target being linked (the "head" target), we can memoize whether or not a usage requirement property exists at all for that target. When a usage requirement does not exist for a target, we can skip evaluating it for every consuming target.
Informal local timings using the above example reduce total configure/generate time by about 70%.
Issue: #18964 (closed), #18965 (closed)