cmGeneratorExpressionEvaluator.cxx 6.6 KB

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