diff options
author | Brad King <brad.king@kitware.com> | 2019-07-23 14:01:13 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2019-07-23 14:44:19 (GMT) |
commit | 1d3841b6003d4f1a45e79f6b9e6d6357514905f1 (patch) | |
tree | 750424fd2e4726f489c8f5c894300ffc65da3db4 /Source/cmGeneratorTarget.cxx | |
parent | b5460f99315f8e6a6bdc985ebc0ca18dd8a294a8 (diff) | |
download | CMake-1d3841b6003d4f1a45e79f6b9e6d6357514905f1.zip CMake-1d3841b6003d4f1a45e79f6b9e6d6357514905f1.tar.gz CMake-1d3841b6003d4f1a45e79f6b9e6d6357514905f1.tar.bz2 |
Genex: Memoize usage requirement TARGET_PROPERTY existence
For each usage requirement (such as `INTERFACE_COMPILE_DEFINITIONS` or
`INTERFACE_INCLUDE_DIRECTORIES`), the value of the generator expression
`$<TARGET_PROPERTY:target,prop>` includes the values of the same
property from the transitive closure of link libraries of the target.
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.
Fixes: #18964, #18965
Diffstat (limited to 'Source/cmGeneratorTarget.cxx')
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index b22d8b6..7c41045 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1143,12 +1143,59 @@ bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const return this->Target->GetPropertyAsBool(prop); } +bool cmGeneratorTarget::MaybeHaveInterfaceProperty( + std::string const& prop, cmGeneratorExpressionContext* context) const +{ + std::string const key = prop + '@' + context->Config; + auto i = this->MaybeInterfacePropertyExists.find(key); + if (i == this->MaybeInterfacePropertyExists.end()) { + // Insert an entry now in case there is a cycle. + i = this->MaybeInterfacePropertyExists.emplace(key, false).first; + bool& maybeInterfaceProp = i->second; + + // If this target itself has a non-empty property value, we are done. + const char* p = this->GetProperty(prop); + maybeInterfaceProp = p && *p; + + // Otherwise, recurse to interface dependencies. + if (!maybeInterfaceProp) { + cmGeneratorTarget const* headTarget = + context->HeadTarget ? context->HeadTarget : this; + if (cmLinkInterfaceLibraries const* iface = + this->GetLinkInterfaceLibraries(context->Config, headTarget, + true)) { + if (iface->HadHeadSensitiveCondition) { + // With a different head target we may get to a library with + // this interface property. + maybeInterfaceProp = true; + } else { + // The transitive interface libraries do not depend on the + // head target, so we can follow them. + for (cmLinkItem const& lib : iface->Libraries) { + if (lib.Target && + lib.Target->MaybeHaveInterfaceProperty(prop, context)) { + maybeInterfaceProp = true; + break; + } + } + } + } + } + } + return i->second; +} + std::string cmGeneratorTarget::EvaluateInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagCheckerParent) const { std::string result; + // If the property does not appear transitively at all, we are done. + if (!this->MaybeHaveInterfaceProperty(prop, context)) { + return result; + } + // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is // a subset of TargetPropertyNode::Evaluate without stringify/parse steps // but sufficient for transitive interface properties. |