cmGeneratorExpressionEvaluator.cxx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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 "cmGeneratorExpressionEvaluator.h"
  4. #include <sstream>
  5. #ifndef CMAKE_BOOTSTRAP
  6. # include <cm3p/json/value.h>
  7. #endif
  8. #include "cmGeneratorExpressionContext.h"
  9. #include "cmGeneratorExpressionNode.h"
  10. #include "cmLocalGenerator.h"
  11. #include "cmake.h"
  12. GeneratorExpressionContent::GeneratorExpressionContent(
  13. const char* 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. const cmGeneratorExpressionNode* node, const std::string& identifier,
  25. cmGeneratorExpressionContext* context,
  26. cmGeneratorExpressionDAGChecker* dagChecker,
  27. std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit) const
  28. {
  29. std::string result;
  30. const auto pend = this->ParamChildren.end();
  31. for (; pit != pend; ++pit) {
  32. for (const auto& pExprEval : *pit) {
  33. if (node->RequiresLiteralInput()) {
  34. if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) {
  35. reportError(context, this->GetOriginalExpression(),
  36. "$<" + identifier +
  37. "> expression requires literal input.");
  38. return std::string();
  39. }
  40. }
  41. result += pExprEval->Evaluate(context, dagChecker);
  42. if (context->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, context, this, dagChecker);
  54. }
  55. return result;
  56. }
  57. std::string GeneratorExpressionContent::Evaluate(
  58. cmGeneratorExpressionContext* context,
  59. cmGeneratorExpressionDAGChecker* dagChecker) const
  60. {
  61. #ifndef CMAKE_BOOTSTRAP
  62. auto evalProfilingRAII =
  63. context->LG->GetCMakeInstance()->CreateProfilingEntry(
  64. "genex_eval", this->GetOriginalExpression());
  65. #endif
  66. std::string identifier;
  67. {
  68. for (const auto& pExprEval : this->IdentifierChildren) {
  69. identifier += pExprEval->Evaluate(context, dagChecker);
  70. if (context->HadError) {
  71. return std::string();
  72. }
  73. }
  74. }
  75. const cmGeneratorExpressionNode* node =
  76. cmGeneratorExpressionNode::GetNode(identifier);
  77. if (!node) {
  78. reportError(context, 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(context, this->GetOriginalExpression(),
  87. "$<" + identifier + "> expression requires a parameter.");
  88. }
  89. } else {
  90. std::vector<std::string> parameters;
  91. this->EvaluateParameters(node, identifier, context, dagChecker,
  92. parameters);
  93. }
  94. return std::string();
  95. }
  96. std::vector<std::string> parameters;
  97. this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
  98. if (context->HadError) {
  99. return std::string();
  100. }
  101. {
  102. #ifndef CMAKE_BOOTSTRAP
  103. auto execProfilingRAII =
  104. context->LG->GetCMakeInstance()->CreateProfilingEntry(
  105. "genex_exec", identifier, [&parameters]() -> Json::Value {
  106. Json::Value args = Json::objectValue;
  107. if (!parameters.empty()) {
  108. args["genexArgs"] = Json::arrayValue;
  109. for (auto const& parameter : parameters) {
  110. args["genexArgs"].append(parameter);
  111. }
  112. }
  113. return args;
  114. });
  115. #endif
  116. return node->Evaluate(parameters, context, this, dagChecker);
  117. }
  118. }
  119. std::string GeneratorExpressionContent::EvaluateParameters(
  120. const cmGeneratorExpressionNode* node, const std::string& identifier,
  121. cmGeneratorExpressionContext* context,
  122. cmGeneratorExpressionDAGChecker* dagChecker,
  123. std::vector<std::string>& parameters) const
  124. {
  125. const int numExpected = node->NumExpectedParameters();
  126. {
  127. auto pit = this->ParamChildren.begin();
  128. const auto pend = this->ParamChildren.end();
  129. const bool acceptsArbitraryContent =
  130. node->AcceptsArbitraryContentParameter();
  131. int counter = 1;
  132. for (; pit != pend; ++pit, ++counter) {
  133. if (acceptsArbitraryContent && counter == numExpected) {
  134. parameters.push_back(this->ProcessArbitraryContent(
  135. node, identifier, context, dagChecker, pit));
  136. return std::string();
  137. }
  138. std::string parameter;
  139. for (const auto& pExprEval : *pit) {
  140. parameter += pExprEval->Evaluate(context, dagChecker);
  141. if (context->HadError) {
  142. return std::string();
  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(context, this->GetOriginalExpression(),
  152. "$<" + identifier + "> expression requires no parameters.");
  153. } else if (numExpected == 1) {
  154. reportError(context, 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(context, this->GetOriginalExpression(), e.str());
  164. }
  165. return std::string();
  166. }
  167. if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters &&
  168. parameters.empty()) {
  169. reportError(context, this->GetOriginalExpression(),
  170. "$<" + identifier +
  171. "> expression requires at least one parameter.");
  172. } else if (numExpected == cmGeneratorExpressionNode::TwoOrMoreParameters &&
  173. parameters.size() < 2) {
  174. reportError(context, this->GetOriginalExpression(),
  175. "$<" + identifier +
  176. "> expression requires at least two parameters.");
  177. } else if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
  178. parameters.size() > 1) {
  179. reportError(context, this->GetOriginalExpression(),
  180. "$<" + identifier +
  181. "> expression requires one or zero parameters.");
  182. }
  183. return std::string();
  184. }