cmIfCommand.cxx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmIfCommand.h"
  4. #include "cmOutputConverter.h"
  5. #include "cmStringCommand.h"
  6. #include "cmConditionEvaluator.h"
  7. #include <cmsys/RegularExpression.hxx>
  8. #include <list>
  9. #include <stdlib.h> // required for atof
  10. static std::string cmIfCommandError(
  11. std::vector<cmExpandedCommandArgument> const& args)
  12. {
  13. std::string err = "given arguments:\n ";
  14. for (std::vector<cmExpandedCommandArgument>::const_iterator i = args.begin();
  15. i != args.end(); ++i) {
  16. err += " ";
  17. err += cmOutputConverter::EscapeForCMake(i->GetValue());
  18. }
  19. err += "\n";
  20. return err;
  21. }
  22. //=========================================================================
  23. bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
  24. cmMakefile& mf,
  25. cmExecutionStatus& inStatus)
  26. {
  27. // we start by recording all the functions
  28. if (!cmSystemTools::Strucmp(lff.Name.c_str(), "if")) {
  29. this->ScopeDepth++;
  30. } else if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endif")) {
  31. this->ScopeDepth--;
  32. // if this is the endif for this if statement, then start executing
  33. if (!this->ScopeDepth) {
  34. // Remove the function blocker for this scope or bail.
  35. CM_AUTO_PTR<cmFunctionBlocker> fb(mf.RemoveFunctionBlocker(this, lff));
  36. if (!fb.get()) {
  37. return false;
  38. }
  39. // execute the functions for the true parts of the if statement
  40. cmExecutionStatus status;
  41. int scopeDepth = 0;
  42. for (unsigned int c = 0; c < this->Functions.size(); ++c) {
  43. // keep track of scope depth
  44. if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(), "if")) {
  45. scopeDepth++;
  46. }
  47. if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),
  48. "endif")) {
  49. scopeDepth--;
  50. }
  51. // watch for our state change
  52. if (scopeDepth == 0 &&
  53. !cmSystemTools::Strucmp(this->Functions[c].Name.c_str(), "else")) {
  54. this->IsBlocking = this->HasRun;
  55. this->HasRun = true;
  56. // if trace is enabled, print a (trivially) evaluated "else"
  57. // statement
  58. if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) {
  59. mf.PrintCommandTrace(this->Functions[c]);
  60. }
  61. } else if (scopeDepth == 0 &&
  62. !cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),
  63. "elseif")) {
  64. if (this->HasRun) {
  65. this->IsBlocking = true;
  66. } else {
  67. // if trace is enabled, print the evaluated "elseif" statement
  68. if (mf.GetCMakeInstance()->GetTrace()) {
  69. mf.PrintCommandTrace(this->Functions[c]);
  70. }
  71. std::string errorString;
  72. std::vector<cmExpandedCommandArgument> expandedArguments;
  73. mf.ExpandArguments(this->Functions[c].Arguments,
  74. expandedArguments);
  75. cmake::MessageType messType;
  76. cmListFileContext conditionContext =
  77. cmListFileContext::FromCommandContext(
  78. this->Functions[c], this->GetStartingContext().FilePath);
  79. cmConditionEvaluator conditionEvaluator(
  80. mf, conditionContext, mf.GetBacktrace(this->Functions[c]));
  81. bool isTrue = conditionEvaluator.IsTrue(expandedArguments,
  82. errorString, messType);
  83. if (!errorString.empty()) {
  84. std::string err = cmIfCommandError(expandedArguments);
  85. err += errorString;
  86. cmListFileBacktrace bt = mf.GetBacktrace(this->Functions[c]);
  87. mf.GetCMakeInstance()->IssueMessage(messType, err, bt);
  88. if (messType == cmake::FATAL_ERROR) {
  89. cmSystemTools::SetFatalErrorOccured();
  90. return true;
  91. }
  92. }
  93. if (isTrue) {
  94. this->IsBlocking = false;
  95. this->HasRun = true;
  96. }
  97. }
  98. }
  99. // should we execute?
  100. else if (!this->IsBlocking) {
  101. status.Clear();
  102. mf.ExecuteCommand(this->Functions[c], status);
  103. if (status.GetReturnInvoked()) {
  104. inStatus.SetReturnInvoked(true);
  105. return true;
  106. }
  107. if (status.GetBreakInvoked()) {
  108. inStatus.SetBreakInvoked(true);
  109. return true;
  110. }
  111. if (status.GetContinueInvoked()) {
  112. inStatus.SetContinueInvoked(true);
  113. return true;
  114. }
  115. }
  116. }
  117. return true;
  118. }
  119. }
  120. // record the command
  121. this->Functions.push_back(lff);
  122. // always return true
  123. return true;
  124. }
  125. //=========================================================================
  126. bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
  127. cmMakefile&)
  128. {
  129. if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endif")) {
  130. // if the endif has arguments, then make sure
  131. // they match the arguments of the matching if
  132. if (lff.Arguments.empty() || lff.Arguments == this->Args) {
  133. return true;
  134. }
  135. }
  136. return false;
  137. }
  138. //=========================================================================
  139. bool cmIfCommand::InvokeInitialPass(
  140. const std::vector<cmListFileArgument>& args, cmExecutionStatus&)
  141. {
  142. std::string errorString;
  143. std::vector<cmExpandedCommandArgument> expandedArguments;
  144. this->Makefile->ExpandArguments(args, expandedArguments);
  145. cmake::MessageType status;
  146. cmConditionEvaluator conditionEvaluator(
  147. *(this->Makefile), this->Makefile->GetExecutionContext(),
  148. this->Makefile->GetBacktrace());
  149. bool isTrue =
  150. conditionEvaluator.IsTrue(expandedArguments, errorString, status);
  151. if (!errorString.empty()) {
  152. std::string err = "if " + cmIfCommandError(expandedArguments);
  153. err += errorString;
  154. if (status == cmake::FATAL_ERROR) {
  155. this->Makefile->IssueMessage(cmake::FATAL_ERROR, err);
  156. cmSystemTools::SetFatalErrorOccured();
  157. return true;
  158. }
  159. this->Makefile->IssueMessage(status, err);
  160. }
  161. cmIfFunctionBlocker* f = new cmIfFunctionBlocker();
  162. // if is isn't true block the commands
  163. f->ScopeDepth = 1;
  164. f->IsBlocking = !isTrue;
  165. if (isTrue) {
  166. f->HasRun = true;
  167. }
  168. f->Args = args;
  169. this->Makefile->AddFunctionBlocker(f);
  170. return true;
  171. }