cmCMakeLanguageCommand.cxx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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 "cmCMakeLanguageCommand.h"
  4. #include <algorithm>
  5. #include <array>
  6. #include <cstddef>
  7. #include <memory>
  8. #include <string>
  9. #include <cm/string_view>
  10. #include <cmext/string_view>
  11. #include "cmExecutionStatus.h"
  12. #include "cmListFileCache.h"
  13. #include "cmMakefile.h"
  14. #include "cmRange.h"
  15. #include "cmStringAlgorithms.h"
  16. #include "cmSystemTools.h"
  17. namespace {
  18. std::array<cm::static_string_view, 12> InvalidCommands{
  19. { // clang-format off
  20. "function"_s, "endfunction"_s,
  21. "macro"_s, "endmacro"_s,
  22. "if"_s, "elseif"_s, "else"_s, "endif"_s,
  23. "while"_s, "endwhile"_s,
  24. "foreach"_s, "endforeach"_s
  25. } // clang-format on
  26. };
  27. bool cmCMakeLanguageCommandEVAL(std::vector<cmListFileArgument> const& args,
  28. cmExecutionStatus& status)
  29. {
  30. cmMakefile& makefile = status.GetMakefile();
  31. cmListFileContext context = makefile.GetBacktrace().Top();
  32. std::vector<std::string> expandedArgs;
  33. makefile.ExpandArguments(args, expandedArgs);
  34. if (expandedArgs.size() < 2) {
  35. status.SetError("called with incorrect number of arguments");
  36. return false;
  37. }
  38. if (expandedArgs[1] != "CODE") {
  39. auto code_iter =
  40. std::find(expandedArgs.begin() + 2, expandedArgs.end(), "CODE");
  41. if (code_iter == expandedArgs.end()) {
  42. status.SetError("called without CODE argument");
  43. } else {
  44. status.SetError(
  45. "called with unsupported arguments between EVAL and CODE arguments");
  46. }
  47. return false;
  48. }
  49. const std::string code =
  50. cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " ");
  51. return makefile.ReadListFileAsString(
  52. code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL"));
  53. }
  54. }
  55. bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
  56. cmExecutionStatus& status)
  57. {
  58. if (args.empty()) {
  59. status.SetError("called with incorrect number of arguments");
  60. return false;
  61. }
  62. cmMakefile& makefile = status.GetMakefile();
  63. cmListFileContext context = makefile.GetBacktrace().Top();
  64. bool result = false;
  65. std::vector<std::string> dispatchExpandedArgs;
  66. std::vector<cmListFileArgument> dispatchArgs;
  67. dispatchArgs.emplace_back(args[0]);
  68. makefile.ExpandArguments(dispatchArgs, dispatchExpandedArgs);
  69. if (dispatchExpandedArgs.empty()) {
  70. status.SetError("called with incorrect number of arguments");
  71. return false;
  72. }
  73. if (dispatchExpandedArgs[0] == "CALL") {
  74. if ((args.size() == 1 && dispatchExpandedArgs.size() != 2) ||
  75. dispatchExpandedArgs.size() > 2) {
  76. status.SetError("called with incorrect number of arguments");
  77. return false;
  78. }
  79. // First argument is the name of the function to call
  80. std::string callCommand;
  81. size_t startArg;
  82. if (dispatchExpandedArgs.size() == 1) {
  83. std::vector<std::string> functionExpandedArg;
  84. std::vector<cmListFileArgument> functionArg;
  85. functionArg.emplace_back(args[1]);
  86. makefile.ExpandArguments(functionArg, functionExpandedArg);
  87. if (functionExpandedArg.size() != 1) {
  88. status.SetError("called with incorrect number of arguments");
  89. return false;
  90. }
  91. callCommand = functionExpandedArg[0];
  92. startArg = 2;
  93. } else {
  94. callCommand = dispatchExpandedArgs[1];
  95. startArg = 1;
  96. }
  97. // ensure specified command is valid
  98. // start/end flow control commands are not allowed
  99. auto cmd = cmSystemTools::LowerCase(callCommand);
  100. if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) !=
  101. InvalidCommands.cend()) {
  102. status.SetError(cmStrCat("invalid command specified: "_s, callCommand));
  103. return false;
  104. }
  105. cmListFileFunction func;
  106. func.Name = callCommand;
  107. func.Line = context.Line;
  108. // The rest of the arguments are passed to the function call above
  109. for (size_t i = startArg; i < args.size(); ++i) {
  110. cmListFileArgument lfarg;
  111. lfarg.Delim = args[i].Delim;
  112. lfarg.Line = context.Line;
  113. lfarg.Value = args[i].Value;
  114. func.Arguments.emplace_back(lfarg);
  115. }
  116. result = makefile.ExecuteCommand(func, status);
  117. } else if (dispatchExpandedArgs[0] == "EVAL") {
  118. return cmCMakeLanguageCommandEVAL(args, status);
  119. } else {
  120. status.SetError("called with unknown meta-operation");
  121. }
  122. return result;
  123. }