| 104 | } |
| 105 | |
| 106 | std::string cmGeneratorTarget::EvaluateInterfaceProperty( |
| 107 | std::string const& prop, cm::GenEx::Evaluation* eval, |
| 108 | cmGeneratorExpressionDAGChecker* dagCheckerParent, UseTo usage) const |
| 109 | { |
| 110 | std::string result; |
| 111 | |
| 112 | // If the property does not appear transitively at all, we are done. |
| 113 | if (!this->MaybeHaveInterfaceProperty(prop, eval, usage)) { |
| 114 | return result; |
| 115 | } |
| 116 | |
| 117 | // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is |
| 118 | // a subset of TargetPropertyNode::Evaluate without stringify/parse steps |
| 119 | // but sufficient for transitive interface properties. |
| 120 | cmGeneratorExpressionDAGChecker dagChecker{ |
| 121 | this, prop, nullptr, dagCheckerParent, eval->Context, eval->Backtrace, |
| 122 | }; |
| 123 | switch (dagChecker.Check()) { |
| 124 | case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: |
| 125 | dagChecker.ReportError( |
| 126 | eval, cmStrCat("$<TARGET_PROPERTY:", this->GetName(), ',', prop, '>')); |
| 127 | return result; |
| 128 | case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: |
| 129 | // No error. We just skip cyclic references. |
| 130 | case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: |
| 131 | // No error. We have already seen this transitive property. |
| 132 | return result; |
| 133 | case cmGeneratorExpressionDAGChecker::DAG: |
| 134 | break; |
| 135 | } |
| 136 | |
| 137 | cmGeneratorTarget const* headTarget = |
| 138 | eval->HeadTarget ? eval->HeadTarget : this; |
| 139 | |
| 140 | if (cmValue p = this->GetProperty(prop)) { |
| 141 | result = cmGeneratorExpressionNode::EvaluateDependentExpression( |
| 142 | *p, eval, headTarget, &dagChecker, this); |
| 143 | } |
| 144 | |
| 145 | if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries( |
| 146 | eval->Context.Config, headTarget, usage)) { |
| 147 | eval->HadContextSensitiveCondition = eval->HadContextSensitiveCondition || |
| 148 | iface->HadContextSensitiveCondition; |
| 149 | for (cmLinkItem const& lib : iface->Libraries) { |
| 150 | // Broken code can have a target in its own link interface. |
| 151 | // Don't follow such link interface entries so as not to create a |
| 152 | // self-referencing loop. |
| 153 | if (lib.Target && lib.Target != this) { |
| 154 | // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the |
| 155 | // above property and hand-evaluate it as if it were compiled. |
| 156 | // Create a context as cmCompiledGeneratorExpression::Evaluate does. |
| 157 | cm::GenEx::Evaluation libEval(eval->Context, eval->Quiet, headTarget, |
| 158 | this, eval->EvaluateForBuildsystem, |
| 159 | eval->Backtrace); |
| 160 | std::string libResult = cmGeneratorExpression::StripEmptyListElements( |
| 161 | lib.Target->EvaluateInterfaceProperty(prop, &libEval, &dagChecker, |
| 162 | usage)); |
| 163 | if (!libResult.empty()) { |
no test coverage detected