cmGeneratorExpressionDAGChecker.cxx 6.9 KB

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