cmGeneratorExpressionDAGChecker.cxx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include "cmGeneratorExpressionDAGChecker.h"
  4. #include <sstream>
  5. #include <utility>
  6. #include <cm/optional>
  7. #include <cm/string_view>
  8. #include <cmext/string_view>
  9. #include "cmGenExContext.h"
  10. #include "cmGenExEvaluation.h"
  11. #include "cmGeneratorExpressionEvaluator.h"
  12. #include "cmGeneratorTarget.h"
  13. #include "cmLocalGenerator.h"
  14. #include "cmMessageType.h"
  15. #include "cmStringAlgorithms.h"
  16. #include "cmake.h"
  17. cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
  18. cmGeneratorTarget const* target, std::string property,
  19. GeneratorExpressionContent const* content,
  20. cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG,
  21. std::string const& contextConfig, cmListFileBacktrace backtrace,
  22. ComputingLinkLibraries computingLinkLibraries)
  23. : Parent(parent)
  24. , Top(parent ? parent->Top : this)
  25. , Target(target)
  26. , Property(std::move(property))
  27. , Content(content)
  28. , Backtrace(std::move(backtrace))
  29. , ComputingLinkLibraries_(computingLinkLibraries)
  30. {
  31. if (parent) {
  32. this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty;
  33. } else {
  34. this->TopIsTransitiveProperty =
  35. this->Target
  36. ->IsTransitiveProperty(this->Property, contextLG, contextConfig, this)
  37. .has_value();
  38. }
  39. this->CheckResult = this->CheckGraph();
  40. if (this->CheckResult == DAG && this->EvaluatingTransitiveProperty()) {
  41. auto const* top = this->Top;
  42. auto it = top->Seen.find(this->Target);
  43. if (it != top->Seen.end()) {
  44. std::set<std::string> const& propSet = it->second;
  45. if (propSet.find(this->Property) != propSet.end()) {
  46. this->CheckResult = ALREADY_SEEN;
  47. return;
  48. }
  49. }
  50. top->Seen[this->Target].insert(this->Property);
  51. }
  52. }
  53. cmGeneratorExpressionDAGChecker::Result
  54. cmGeneratorExpressionDAGChecker::Check() const
  55. {
  56. return this->CheckResult;
  57. }
  58. void cmGeneratorExpressionDAGChecker::ReportError(cm::GenEx::Evaluation* eval,
  59. std::string const& expr)
  60. {
  61. if (this->CheckResult == DAG) {
  62. return;
  63. }
  64. eval->HadError = true;
  65. if (eval->Quiet) {
  66. return;
  67. }
  68. cmGeneratorExpressionDAGChecker const* parent = this->Parent;
  69. if (parent && !parent->Parent) {
  70. std::ostringstream e;
  71. e << "Error evaluating generator expression:\n"
  72. << " " << expr << "\n"
  73. << "Self reference on target \"" << eval->HeadTarget->GetName()
  74. << "\".\n";
  75. eval->Context.LG->GetCMakeInstance()->IssueMessage(
  76. MessageType::FATAL_ERROR, e.str(), parent->Backtrace);
  77. return;
  78. }
  79. {
  80. std::ostringstream e;
  81. /* clang-format off */
  82. e << "Error evaluating generator expression:\n"
  83. << " " << expr << "\n"
  84. << "Dependency loop found.";
  85. /* clang-format on */
  86. eval->Context.LG->GetCMakeInstance()->IssueMessage(
  87. MessageType::FATAL_ERROR, e.str(), eval->Backtrace);
  88. }
  89. int loopStep = 1;
  90. while (parent) {
  91. std::ostringstream e;
  92. e << "Loop step " << loopStep << "\n"
  93. << " "
  94. << (parent->Content ? parent->Content->GetOriginalExpression() : expr)
  95. << "\n";
  96. eval->Context.LG->GetCMakeInstance()->IssueMessage(
  97. MessageType::FATAL_ERROR, e.str(), parent->Backtrace);
  98. parent = parent->Parent;
  99. ++loopStep;
  100. }
  101. }
  102. cmGeneratorExpressionDAGChecker::Result
  103. cmGeneratorExpressionDAGChecker::CheckGraph() const
  104. {
  105. cmGeneratorExpressionDAGChecker const* parent = this->Parent;
  106. while (parent) {
  107. if (this->Target == parent->Target && this->Property == parent->Property) {
  108. return (parent == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
  109. }
  110. parent = parent->Parent;
  111. }
  112. return DAG;
  113. }
  114. bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() const
  115. {
  116. return this->Top->TransitivePropertiesOnly;
  117. }
  118. bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnlyCMP0131()
  119. const
  120. {
  121. return this->Top->CMP0131;
  122. }
  123. bool cmGeneratorExpressionDAGChecker::EvaluatingTransitiveProperty() const
  124. {
  125. return this->TopIsTransitiveProperty;
  126. }
  127. bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const
  128. {
  129. // Corresponds to GenexEvaluator::EvaluateExpression.
  130. return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") ||
  131. cmHasLiteralPrefix(this->Property, "GENEX_EVAL:");
  132. }
  133. bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const
  134. {
  135. // Corresponds to checkInterfacePropertyCompatibility's special case
  136. // that evaluates the value of POSITION_INDEPENDENT_CODE as a genex.
  137. return this->Top->Property == "INTERFACE_POSITION_INDEPENDENT_CODE";
  138. }
  139. bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const
  140. {
  141. cm::string_view property(this->Top->Property);
  142. return property == "INCLUDE_DIRECTORIES"_s ||
  143. property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s;
  144. }
  145. bool cmGeneratorExpressionDAGChecker::EvaluatingSources() const
  146. {
  147. return this->Property == "SOURCES"_s ||
  148. this->Property == "INTERFACE_SOURCES"_s;
  149. }
  150. bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
  151. {
  152. cm::string_view property(this->Top->Property);
  153. return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s ||
  154. property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s ||
  155. property == "LINKER_TYPE"_s;
  156. }
  157. bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const
  158. {
  159. cm::string_view property(this->Top->Property);
  160. return property == "LINK_OPTIONS"_s || property == "LINKER_TYPE"_s;
  161. }
  162. bool cmGeneratorExpressionDAGChecker::EvaluatingLinkerLauncher() const
  163. {
  164. cm::string_view property(this->Top->Property);
  165. return property.length() > cmStrLen("_LINKER_LAUNCHER") &&
  166. property.substr(property.length() - cmStrLen("_LINKER_LAUNCHER")) ==
  167. "_LINKER_LAUNCHER"_s;
  168. }
  169. bool cmGeneratorExpressionDAGChecker::IsComputingLinkLibraries() const
  170. {
  171. return this->Top->ComputingLinkLibraries_ == ComputingLinkLibraries::Yes;
  172. }
  173. bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
  174. cmGeneratorTarget const* tgt, ForGenex genex) const
  175. {
  176. auto const* top = this->Top;
  177. cm::string_view prop(top->Property);
  178. if (tgt) {
  179. return top->Target == tgt && prop == "LINK_LIBRARIES"_s;
  180. }
  181. auto result = prop == "LINK_LIBRARIES"_s ||
  182. prop == "INTERFACE_LINK_LIBRARIES"_s ||
  183. prop == "INTERFACE_LINK_LIBRARIES_DIRECT"_s ||
  184. prop == "LINK_INTERFACE_LIBRARIES"_s ||
  185. prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s ||
  186. cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") ||
  187. cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_");
  188. return genex == ForGenex::LINK_LIBRARY || genex == ForGenex::LINK_GROUP
  189. ? result
  190. : (result || prop == "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s);
  191. }
  192. cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
  193. {
  194. return this->Top->Target;
  195. }