cmGeneratorExpressionEvaluator.cxx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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 "cmGeneratorExpressionEvaluator.h"
  4. #include <sstream>
  5. #ifndef CMAKE_BOOTSTRAP
  6. # include <cm3p/json/value.h>
  7. #endif
  8. #include "cmGenExEvaluation.h"
  9. #include "cmGeneratorExpressionNode.h"
  10. #include "cmLocalGenerator.h"
  11. #include "cmake.h"
  12. GeneratorExpressionContent::GeneratorExpressionContent(
  13. char const* startContent, size_t length)
  14. : StartContent(startContent)
  15. , ContentLength(length)
  16. {
  17. }
  18. GeneratorExpressionContent::~GeneratorExpressionContent() = default;
  19. std::string GeneratorExpressionContent::GetOriginalExpression() const
  20. {
  21. return std::string(this->StartContent, this->ContentLength);
  22. }
  23. std::string GeneratorExpressionContent::ProcessArbitraryContent(
  24. cmGeneratorExpressionNode const* node, std::string const& identifier,
  25. cm::GenEx::Evaluation* eval, cmGeneratorExpressionDAGChecker* dagChecker,
  26. std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit) const
  27. {
  28. std::string result;
  29. auto const pend = this->ParamChildren.end();
  30. for (; pit != pend; ++pit) {
  31. for (auto const& pExprEval : *pit) {
  32. if (node->RequiresLiteralInput()) {
  33. if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) {
  34. reportError(eval, this->GetOriginalExpression(),
  35. "$<" + identifier +
  36. "> expression requires literal input.");
  37. return std::string();
  38. }
  39. }
  40. result += pExprEval->Evaluate(eval, dagChecker);
  41. if (eval->HadError) {
  42. return std::string();
  43. }
  44. }
  45. if ((pit + 1) != pend) {
  46. result += ",";
  47. }
  48. }
  49. if (node->RequiresLiteralInput()) {
  50. std::vector<std::string> parameters;
  51. parameters.push_back(result);
  52. return node->Evaluate(parameters, eval, this, dagChecker);
  53. }
  54. return result;
  55. }
  56. std::string GeneratorExpressionContent::Evaluate(
  57. cm::GenEx::Evaluation* eval,
  58. cmGeneratorExpressionDAGChecker* dagChecker) const
  59. {
  60. #ifndef CMAKE_BOOTSTRAP
  61. auto evalProfilingRAII = eval->LG->GetCMakeInstance()->CreateProfilingEntry(
  62. "genex_eval", this->GetOriginalExpression());
  63. #endif
  64. std::string identifier;
  65. {
  66. for (auto const& pExprEval : this->IdentifierChildren) {
  67. identifier += pExprEval->Evaluate(eval, dagChecker);
  68. if (eval->HadError) {
  69. return std::string();
  70. }
  71. }
  72. }
  73. cmGeneratorExpressionNode const* node =
  74. cmGeneratorExpressionNode::GetNode(identifier);
  75. if (!node) {
  76. reportError(eval, this->GetOriginalExpression(),
  77. "Expression did not evaluate to a known generator expression");
  78. return std::string();
  79. }
  80. if (!node->GeneratesContent()) {
  81. if (node->NumExpectedParameters() == 1 &&
  82. node->AcceptsArbitraryContentParameter()) {
  83. if (this->ParamChildren.empty()) {
  84. reportError(eval, this->GetOriginalExpression(),
  85. "$<" + identifier + "> expression requires a parameter.");
  86. }
  87. } else {
  88. std::vector<std::string> parameters;
  89. this->EvaluateParameters(node, identifier, eval, dagChecker, parameters);
  90. }
  91. return std::string();
  92. }
  93. std::vector<std::string> parameters;
  94. this->EvaluateParameters(node, identifier, eval, dagChecker, parameters);
  95. if (eval->HadError) {
  96. return std::string();
  97. }
  98. {
  99. #ifndef CMAKE_BOOTSTRAP
  100. auto execProfilingRAII =
  101. eval->LG->GetCMakeInstance()->CreateProfilingEntry(
  102. "genex_exec", identifier, [&parameters]() -> Json::Value {
  103. Json::Value args = Json::objectValue;
  104. if (!parameters.empty()) {
  105. args["genexArgs"] = Json::arrayValue;
  106. for (auto const& parameter : parameters) {
  107. args["genexArgs"].append(parameter);
  108. }
  109. }
  110. return args;
  111. });
  112. #endif
  113. return node->Evaluate(parameters, eval, this, dagChecker);
  114. }
  115. }
  116. std::string GeneratorExpressionContent::EvaluateParameters(
  117. cmGeneratorExpressionNode const* node, std::string const& identifier,
  118. cm::GenEx::Evaluation* eval, cmGeneratorExpressionDAGChecker* dagChecker,
  119. std::vector<std::string>& parameters) const
  120. {
  121. int const numExpected = node->NumExpectedParameters();
  122. {
  123. auto pit = this->ParamChildren.begin();
  124. auto const pend = this->ParamChildren.end();
  125. bool const acceptsArbitraryContent =
  126. node->AcceptsArbitraryContentParameter();
  127. int counter = 1;
  128. for (; pit != pend; ++pit, ++counter) {
  129. if (acceptsArbitraryContent && counter == numExpected) {
  130. parameters.push_back(this->ProcessArbitraryContent(
  131. node, identifier, eval, dagChecker, pit));
  132. return std::string();
  133. }
  134. std::string parameter;
  135. if (node->ShouldEvaluateNextParameter(parameters, parameter)) {
  136. for (auto const& pExprEval : *pit) {
  137. parameter += pExprEval->Evaluate(eval, dagChecker);
  138. if (eval->HadError) {
  139. return std::string();
  140. }
  141. }
  142. }
  143. parameters.push_back(std::move(parameter));
  144. }
  145. }
  146. if ((numExpected > cmGeneratorExpressionNode::DynamicParameters &&
  147. static_cast<unsigned int>(numExpected) != parameters.size())) {
  148. if (numExpected == 0) {
  149. reportError(eval, this->GetOriginalExpression(),
  150. "$<" + identifier + "> expression requires no parameters.");
  151. } else if (numExpected == 1) {
  152. reportError(eval, this->GetOriginalExpression(),
  153. "$<" + identifier +
  154. "> expression requires "
  155. "exactly one parameter.");
  156. } else {
  157. std::ostringstream e;
  158. e << "$<" + identifier + "> expression requires " << numExpected
  159. << " comma separated parameters, but got " << parameters.size()
  160. << " instead.";
  161. reportError(eval, this->GetOriginalExpression(), e.str());
  162. }
  163. return std::string();
  164. }
  165. if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters &&
  166. parameters.empty()) {
  167. reportError(eval, this->GetOriginalExpression(),
  168. "$<" + identifier +
  169. "> expression requires at least one parameter.");
  170. } else if (numExpected == cmGeneratorExpressionNode::TwoOrMoreParameters &&
  171. parameters.size() < 2) {
  172. reportError(eval, this->GetOriginalExpression(),
  173. "$<" + identifier +
  174. "> expression requires at least two parameters.");
  175. } else if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
  176. parameters.size() > 1) {
  177. reportError(eval, this->GetOriginalExpression(),
  178. "$<" + identifier +
  179. "> expression requires one or zero parameters.");
  180. }
  181. return std::string();
  182. }