Skip to content

Genex: Optimize transitive TARGET_PROPERTY evaluation

Brad King requested to merge brad.king/cmake:optimize-usage-requirements into master

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)

Edited by Brad King

Merge request reports