mirror of
https://github.com/Kitware/CMake.git
synced 2025-05-09 23:08:18 +08:00
147 lines
4.5 KiB
C++
147 lines
4.5 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
#include "cmInstrumentationCommand.h"
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <cstdlib>
|
|
#include <functional>
|
|
#include <set>
|
|
|
|
#include <cmext/string_view>
|
|
|
|
#include "cmArgumentParser.h"
|
|
#include "cmArgumentParserTypes.h"
|
|
#include "cmExecutionStatus.h"
|
|
#include "cmExperimental.h"
|
|
#include "cmInstrumentation.h"
|
|
#include "cmInstrumentationQuery.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmake.h"
|
|
|
|
namespace {
|
|
|
|
bool isCharDigit(char ch)
|
|
{
|
|
return std::isdigit(static_cast<unsigned char>(ch));
|
|
}
|
|
bool validateVersion(std::string const& key, std::string const& versionString,
|
|
int& version, cmExecutionStatus& status)
|
|
{
|
|
if (!std::all_of(versionString.begin(), versionString.end(), isCharDigit)) {
|
|
status.SetError(cmStrCat("given a non-integer ", key, "."));
|
|
return false;
|
|
}
|
|
version = std::atoi(versionString.c_str());
|
|
if (version != 1) {
|
|
status.SetError(cmStrCat(
|
|
"QUERY subcommand given an unsupported ", key, " \"", versionString,
|
|
"\" (the only currently supported version is 1)."));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename E>
|
|
std::function<bool(std::string const&, E&)> EnumParser(
|
|
std::vector<std::string> const toString)
|
|
{
|
|
return [toString](std::string const& value, E& out) -> bool {
|
|
for (size_t i = 0; i < toString.size(); ++i) {
|
|
if (value == toString[i]) {
|
|
out = (E)i;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
}
|
|
}
|
|
|
|
bool cmInstrumentationCommand(std::vector<std::string> const& args,
|
|
cmExecutionStatus& status)
|
|
{
|
|
// if (status->GetMakefile().GetPropertyKeys) {
|
|
if (!cmExperimental::HasSupportEnabled(
|
|
status.GetMakefile(), cmExperimental::Feature::Instrumentation)) {
|
|
status.SetError(
|
|
"requires the experimental Instrumentation flag to be enabled");
|
|
return false;
|
|
}
|
|
|
|
if (args.empty()) {
|
|
status.SetError("must be called with arguments.");
|
|
return false;
|
|
}
|
|
|
|
struct Arguments : public ArgumentParser::ParseResult
|
|
{
|
|
ArgumentParser::NonEmpty<std::string> ApiVersion;
|
|
ArgumentParser::NonEmpty<std::string> DataVersion;
|
|
ArgumentParser::NonEmpty<std::vector<std::string>> Queries;
|
|
ArgumentParser::NonEmpty<std::vector<std::string>> Hooks;
|
|
ArgumentParser::NonEmpty<std::vector<std::vector<std::string>>> Callbacks;
|
|
};
|
|
|
|
static auto const parser = cmArgumentParser<Arguments>{}
|
|
.Bind("API_VERSION"_s, &Arguments::ApiVersion)
|
|
.Bind("DATA_VERSION"_s, &Arguments::DataVersion)
|
|
.Bind("QUERIES"_s, &Arguments::Queries)
|
|
.Bind("HOOKS"_s, &Arguments::Hooks)
|
|
.Bind("CALLBACK"_s, &Arguments::Callbacks);
|
|
|
|
std::vector<std::string> unparsedArguments;
|
|
Arguments const arguments = parser.Parse(args, &unparsedArguments);
|
|
|
|
if (arguments.MaybeReportError(status.GetMakefile())) {
|
|
return true;
|
|
}
|
|
if (!unparsedArguments.empty()) {
|
|
status.SetError("given unknown argument \"" + unparsedArguments.front() +
|
|
"\".");
|
|
return false;
|
|
}
|
|
int apiVersion;
|
|
int dataVersion;
|
|
if (!validateVersion("API_VERSION", arguments.ApiVersion, apiVersion,
|
|
status) ||
|
|
!validateVersion("DATA_VERSION", arguments.DataVersion, dataVersion,
|
|
status)) {
|
|
return false;
|
|
}
|
|
|
|
std::set<cmInstrumentationQuery::Query> queries;
|
|
auto queryParser = EnumParser<cmInstrumentationQuery::Query>(
|
|
cmInstrumentationQuery::QueryString);
|
|
for (auto const& arg : arguments.Queries) {
|
|
cmInstrumentationQuery::Query query;
|
|
if (!queryParser(arg, query)) {
|
|
status.SetError(
|
|
cmStrCat("given invalid argument to QUERIES \"", arg, "\""));
|
|
return false;
|
|
}
|
|
queries.insert(query);
|
|
}
|
|
|
|
std::set<cmInstrumentationQuery::Hook> hooks;
|
|
auto hookParser = EnumParser<cmInstrumentationQuery::Hook>(
|
|
cmInstrumentationQuery::HookString);
|
|
for (auto const& arg : arguments.Hooks) {
|
|
cmInstrumentationQuery::Hook hook;
|
|
if (!hookParser(arg, hook)) {
|
|
status.SetError(
|
|
cmStrCat("given invalid argument to HOOKS \"", arg, "\""));
|
|
return false;
|
|
}
|
|
hooks.insert(hook);
|
|
}
|
|
|
|
status.GetMakefile()
|
|
.GetCMakeInstance()
|
|
->GetInstrumentation()
|
|
->WriteJSONQuery(queries, hooks, arguments.Callbacks);
|
|
|
|
return true;
|
|
}
|