cmGeneratorExpressionEvaluator.cxx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. if (node->ShouldEvaluateNextParameter(parameters, parameter)) {
  140. for (const auto& pExprEval : *pit) {
  141. parameter += pExprEval->Evaluate(context, dagChecker);
  142. if (context->HadError) {
  143. return std::string();
  144. }
  145. }
  146. }
  147. parameters.push_back(std::move(parameter));
  148. }
  149. }
  150. if ((numExpected > cmGeneratorExpressionNode::DynamicParameters &&
  151. static_cast<unsigned int>(numExpected) != parameters.size())) {
  152. if (numExpected == 0) {
  153. reportError(context, this->GetOriginalExpression(),
  154. "$<" + identifier + "> expression requires no parameters.");
  155. } else if (numExpected == 1) {
  156. reportError(context, this->GetOriginalExpression(),
  157. "$<" + identifier +
  158. "> expression requires "
  159. "exactly one parameter.");
  160. } else {
  161. std::ostringstream e;
  162. e << "$<" + identifier + "> expression requires " << numExpected
  163. << " comma separated parameters, but got " << parameters.size()
  164. << " instead.";
  165. reportError(context, this->GetOriginalExpression(), e.str());
  166. }
  167. return std::string();
  168. }
  169. if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters &&
  170. parameters.empty()) {
  171. reportError(context, this->GetOriginalExpression(),
  172. "$<" + identifier +
  173. "> expression requires at least one parameter.");
  174. } else if (numExpected == cmGeneratorExpressionNode::TwoOrMoreParameters &&
  175. parameters.size() < 2) {
  176. reportError(context, this->GetOriginalExpression(),
  177. "$<" + identifier +
  178. "> expression requires at least two parameters.");
  179. } else if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
  180. parameters.size() > 1) {
  181. reportError(context, this->GetOriginalExpression(),
  182. "$<" + identifier +
  183. "> expression requires one or zero parameters.");
  184. }
  185. return std::string();
  186. }