cmInstrumentationCommand.cxx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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 "cmInstrumentationCommand.h"
  4. #include <algorithm>
  5. #include <cctype>
  6. #include <cstdlib>
  7. #include <functional>
  8. #include <set>
  9. #include <cmext/string_view>
  10. #include "cmArgumentParser.h"
  11. #include "cmArgumentParserTypes.h"
  12. #include "cmExecutionStatus.h"
  13. #include "cmExperimental.h"
  14. #include "cmInstrumentation.h"
  15. #include "cmInstrumentationQuery.h"
  16. #include "cmMakefile.h"
  17. #include "cmStringAlgorithms.h"
  18. #include "cmake.h"
  19. namespace {
  20. bool isCharDigit(char ch)
  21. {
  22. return std::isdigit(static_cast<unsigned char>(ch));
  23. }
  24. bool validateVersion(std::string const& key, std::string const& versionString,
  25. int& version, cmExecutionStatus& status)
  26. {
  27. if (!std::all_of(versionString.begin(), versionString.end(), isCharDigit)) {
  28. status.SetError(cmStrCat("given a non-integer ", key, "."));
  29. return false;
  30. }
  31. version = std::atoi(versionString.c_str());
  32. if (version != 1) {
  33. status.SetError(cmStrCat(
  34. "QUERY subcommand given an unsupported ", key, " \"", versionString,
  35. "\" (the only currently supported version is 1)."));
  36. return false;
  37. }
  38. return true;
  39. }
  40. template <typename E>
  41. std::function<bool(std::string const&, E&)> EnumParser(
  42. std::vector<std::string> const toString)
  43. {
  44. return [toString](std::string const& value, E& out) -> bool {
  45. for (size_t i = 0; i < toString.size(); ++i) {
  46. if (value == toString[i]) {
  47. out = (E)i;
  48. return true;
  49. }
  50. }
  51. return false;
  52. };
  53. }
  54. }
  55. bool cmInstrumentationCommand(std::vector<std::string> const& args,
  56. cmExecutionStatus& status)
  57. {
  58. // if (status->GetMakefile().GetPropertyKeys) {
  59. if (!cmExperimental::HasSupportEnabled(
  60. status.GetMakefile(), cmExperimental::Feature::Instrumentation)) {
  61. status.SetError(
  62. "requires the experimental Instrumentation flag to be enabled");
  63. return false;
  64. }
  65. if (args.empty()) {
  66. status.SetError("must be called with arguments.");
  67. return false;
  68. }
  69. struct Arguments : public ArgumentParser::ParseResult
  70. {
  71. ArgumentParser::NonEmpty<std::string> ApiVersion;
  72. ArgumentParser::NonEmpty<std::string> DataVersion;
  73. ArgumentParser::NonEmpty<std::vector<std::string>> Queries;
  74. ArgumentParser::NonEmpty<std::vector<std::string>> Hooks;
  75. ArgumentParser::NonEmpty<std::vector<std::vector<std::string>>> Callbacks;
  76. };
  77. static auto const parser = cmArgumentParser<Arguments>{}
  78. .Bind("API_VERSION"_s, &Arguments::ApiVersion)
  79. .Bind("DATA_VERSION"_s, &Arguments::DataVersion)
  80. .Bind("QUERIES"_s, &Arguments::Queries)
  81. .Bind("HOOKS"_s, &Arguments::Hooks)
  82. .Bind("CALLBACK"_s, &Arguments::Callbacks);
  83. std::vector<std::string> unparsedArguments;
  84. Arguments const arguments = parser.Parse(args, &unparsedArguments);
  85. if (arguments.MaybeReportError(status.GetMakefile())) {
  86. return true;
  87. }
  88. if (!unparsedArguments.empty()) {
  89. status.SetError("given unknown argument \"" + unparsedArguments.front() +
  90. "\".");
  91. return false;
  92. }
  93. int apiVersion;
  94. int dataVersion;
  95. if (!validateVersion("API_VERSION", arguments.ApiVersion, apiVersion,
  96. status) ||
  97. !validateVersion("DATA_VERSION", arguments.DataVersion, dataVersion,
  98. status)) {
  99. return false;
  100. }
  101. std::set<cmInstrumentationQuery::Query> queries;
  102. auto queryParser = EnumParser<cmInstrumentationQuery::Query>(
  103. cmInstrumentationQuery::QueryString);
  104. for (auto const& arg : arguments.Queries) {
  105. cmInstrumentationQuery::Query query;
  106. if (!queryParser(arg, query)) {
  107. status.SetError(
  108. cmStrCat("given invalid argument to QUERIES \"", arg, "\""));
  109. return false;
  110. }
  111. queries.insert(query);
  112. }
  113. std::set<cmInstrumentationQuery::Hook> hooks;
  114. auto hookParser = EnumParser<cmInstrumentationQuery::Hook>(
  115. cmInstrumentationQuery::HookString);
  116. for (auto const& arg : arguments.Hooks) {
  117. cmInstrumentationQuery::Hook hook;
  118. if (!hookParser(arg, hook)) {
  119. status.SetError(
  120. cmStrCat("given invalid argument to HOOKS \"", arg, "\""));
  121. return false;
  122. }
  123. hooks.insert(hook);
  124. }
  125. status.GetMakefile()
  126. .GetCMakeInstance()
  127. ->GetInstrumentation()
  128. ->WriteJSONQuery(queries, hooks, arguments.Callbacks);
  129. return true;
  130. }