cmGeneratorExpressionDAGChecker.cxx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2012 Stephen Kelly <[email protected]>
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmGeneratorExpressionDAGChecker.h"
  11. #include "cmMakefile.h"
  12. //----------------------------------------------------------------------------
  13. cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
  14. const cmListFileBacktrace &backtrace,
  15. const std::string &target,
  16. const std::string &property,
  17. const GeneratorExpressionContent *content,
  18. cmGeneratorExpressionDAGChecker *parent)
  19. : Parent(parent), Target(target), Property(property),
  20. Content(content), Backtrace(backtrace)
  21. {
  22. const cmGeneratorExpressionDAGChecker *top = this;
  23. const cmGeneratorExpressionDAGChecker *p = this->Parent;
  24. while (p)
  25. {
  26. top = p;
  27. p = p->Parent;
  28. }
  29. this->CheckResult = this->checkGraph();
  30. #define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) \
  31. top->METHOD () ||
  32. if (CheckResult == DAG && (
  33. CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(TEST_TRANSITIVE_PROPERTY_METHOD)
  34. false)
  35. )
  36. {
  37. std::map<cmStdString, std::set<cmStdString> >::const_iterator it
  38. = top->Seen.find(target);
  39. if (it != top->Seen.end())
  40. {
  41. const std::set<cmStdString> &propSet = it->second;
  42. const std::set<cmStdString>::const_iterator i = propSet.find(property);
  43. if (i != propSet.end())
  44. {
  45. this->CheckResult = ALREADY_SEEN;
  46. return;
  47. }
  48. }
  49. const_cast<cmGeneratorExpressionDAGChecker *>(top)
  50. ->Seen[target].insert(property);
  51. }
  52. }
  53. //----------------------------------------------------------------------------
  54. cmGeneratorExpressionDAGChecker::Result
  55. cmGeneratorExpressionDAGChecker::check() const
  56. {
  57. return this->CheckResult;
  58. }
  59. //----------------------------------------------------------------------------
  60. void cmGeneratorExpressionDAGChecker::reportError(
  61. cmGeneratorExpressionContext *context,
  62. const std::string &expr)
  63. {
  64. if (this->CheckResult == DAG)
  65. {
  66. return;
  67. }
  68. context->HadError = true;
  69. if (context->Quiet)
  70. {
  71. return;
  72. }
  73. const cmGeneratorExpressionDAGChecker *parent = this->Parent;
  74. if (parent && !parent->Parent)
  75. {
  76. cmOStringStream e;
  77. e << "Error evaluating generator expression:\n"
  78. << " " << expr << "\n"
  79. << "Self reference on target \""
  80. << context->HeadTarget->GetName() << "\".\n";
  81. context->Makefile->GetCMakeInstance()
  82. ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
  83. parent->Backtrace);
  84. return;
  85. }
  86. {
  87. cmOStringStream e;
  88. e << "Error evaluating generator expression:\n"
  89. << " " << expr << "\n"
  90. << "Dependency loop found.";
  91. context->Makefile->GetCMakeInstance()
  92. ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
  93. context->Backtrace);
  94. }
  95. int loopStep = 1;
  96. while (parent)
  97. {
  98. cmOStringStream e;
  99. e << "Loop step " << loopStep << "\n"
  100. << " "
  101. << (parent->Content ? parent->Content->GetOriginalExpression() : expr)
  102. << "\n";
  103. context->Makefile->GetCMakeInstance()
  104. ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
  105. parent->Backtrace);
  106. parent = parent->Parent;
  107. ++loopStep;
  108. }
  109. }
  110. //----------------------------------------------------------------------------
  111. cmGeneratorExpressionDAGChecker::Result
  112. cmGeneratorExpressionDAGChecker::checkGraph() const
  113. {
  114. const cmGeneratorExpressionDAGChecker *parent = this->Parent;
  115. while (parent)
  116. {
  117. if (this->Target == parent->Target && this->Property == parent->Property)
  118. {
  119. return (parent == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
  120. }
  121. parent = parent->Parent;
  122. }
  123. return DAG;
  124. }
  125. //----------------------------------------------------------------------------
  126. bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries()
  127. {
  128. const cmGeneratorExpressionDAGChecker *top = this;
  129. const cmGeneratorExpressionDAGChecker *parent = this->Parent;
  130. while (parent)
  131. {
  132. top = parent;
  133. parent = parent->Parent;
  134. }
  135. const char *prop = top->Property.c_str();
  136. return (strcmp(prop, "LINK_LIBRARIES") == 0
  137. || strcmp(prop, "LINK_INTERFACE_LIBRARIES") == 0
  138. || strcmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES") == 0
  139. || strncmp(prop, "LINK_INTERFACE_LIBRARIES_", 25) == 0
  140. || strncmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_", 34) == 0);
  141. }
  142. //----------------------------------------------------------------------------
  143. bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories() const
  144. {
  145. const char *prop = this->Property.c_str();
  146. return (strcmp(prop, "INCLUDE_DIRECTORIES") == 0
  147. || strcmp(prop, "INTERFACE_INCLUDE_DIRECTORIES") == 0 );
  148. }
  149. //----------------------------------------------------------------------------
  150. bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions() const
  151. {
  152. const char *prop = this->Property.c_str();
  153. return (strcmp(prop, "COMPILE_DEFINITIONS") == 0
  154. || strcmp(prop, "INTERFACE_COMPILE_DEFINITIONS") == 0
  155. || strncmp(prop, "COMPILE_DEFINITIONS_", 20) == 0);
  156. }
  157. //----------------------------------------------------------------------------
  158. bool cmGeneratorExpressionDAGChecker::EvaluatingCompileOptions() const
  159. {
  160. const char *prop = this->Property.c_str();
  161. return (strcmp(prop, "COMPILE_OPTIONS") == 0
  162. || strcmp(prop, "INTERFACE_COMPILE_OPTIONS") == 0 );
  163. }