|
|
@@ -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.
|