instrumentation: Revise Data Version format

Give data version the new format <major>.<minor>, so that
the version can be incremented with the introduction of new
features without bumping the major version.

Add support for loading instrumentation JSON queries of unknown
data versions without error.

Issue: #27833
This commit is contained in:
Martin Duffy
2026-05-29 11:39:26 -04:00
committed by Brad King
parent 90cbb00f1e
commit df36317176
31 changed files with 334 additions and 77 deletions

View File

@@ -19,10 +19,14 @@ This allows for configuring instrumentation at the project-level.
[CUSTOM_CONTENT <name> <type> <content>]
)
The ``API_VERSION`` and ``DATA_VERSION`` must always be given. Currently, the
only supported value for both fields is 1. See
:ref:`cmake-instrumentation API v1` for details of the ``API_VERSION`` and
:ref:`cmake-instrumentation Data Version` for details of the ``DATA_VERSION``.
The ``API_VERSION`` and ``DATA_VERSION`` must always be given.
``API_VERSION`` is an integer. Currently, the only supported value is ``1``.
See :ref:`cmake-instrumentation API v1` for details.
``DATA_VERSION`` is a version value of the form ``major`` or ``major.minor``.
Currently, the only supported version is ``1.0``. See
:ref:`cmake-instrumentation Data Version` for details.
Each of the optional keywords ``HOOKS``, ``OPTIONS``, and ``CALLBACK``
correspond to one of the parameters to the :ref:`cmake-instrumentation v1 Query Files`.
@@ -70,7 +74,7 @@ equivalent JSON query file.
cmake_instrumentation(
API_VERSION 1
DATA_VERSION 1
DATA_VERSION 1.0
HOOKS postGenerate preCMakeBuild postCMakeBuild
OPTIONS staticSystemInformation dynamicSystemInformation trace
CALLBACK ${CMAKE_COMMAND} -P /path/to/handle_data.cmake
@@ -91,7 +95,7 @@ equivalent JSON query file.
"staticSystemInformation", "dynamicSystemInformation", "trace"
],
"callbacks": [
"/path/to/cmake -P /path/to/handle_data.cmake"
"/path/to/cmake -P /path/to/handle_data.cmake",
"/path/to/cmake -P /path/to/handle_data_2.cmake"
]
}

View File

@@ -229,9 +229,11 @@ request a specific Data Version, and `v1 Data Files`_ of the corresponding
version will be generated and sent to the user `Callbacks`_ defined in that
query.
Currently, the only supported version is ``1``. A new version number will be
created whenever previously included data is removed or reformatted such that
scripts written to parse this data may become incompatible with the new format.
Currently, the only supported version is ``1.0``. A new major version number
will be created whenever previously included data is removed or reformatted such
that scripts written to parse this data may become incompatible with the new
format. A new minor version number will be created whenever new data becomes
available.
.. _`cmake-instrumentation v1 Query Files`:
@@ -245,8 +247,17 @@ These files must contain a JSON object with the following keys. The ``version``
key is required, but all other fields are optional.
``version``
The `Data Version`_ of snippet file to generate, an integer. Currently the only
supported version is ``1``.
The `Data Version`_ of snippet files to generate.
In query files, this may be specified either as an integer major version or
as an object with ``major`` and ``minor`` members. For example, ``1`` and
``{ "major": 1, "minor": 0 }`` both request version ``1.0``. Specifying a
minor version is optional. CMake will always generate instrumentation data
for the most recent minor version, even if an earlier minor version is
requested.
Currently, the only supported version is ``1.0``. Query files with an unknown
data version will be ignored.
``callbacks``
A list of command-line strings for `Callbacks`_ to handle collected
@@ -402,8 +413,8 @@ Snippet files have a filename with the syntax
``<role>-<hash>-<timestamp>.json`` and contain the following data:
``version``
The `Data Version`_ of the snippet file, an integer. Currently the version is
always ``1``.
The `Data Version`_ of the snippet file. Currently the version is
always ``{ "major": 1, "minor": 0 }``.
``command``
The full command executed. Excluded when ``role`` is ``build``.
@@ -507,7 +518,10 @@ Example:
.. code-block:: json
{
"version": 1,
"version": {
"major": 1,
"minor": 0
},
"command" : "\"/usr/bin/c++\" \"-MD\" \"-MT\" \"CMakeFiles/main.dir/main.cxx.o\" \"-MF\" \"CMakeFiles/main.dir/main.cxx.o.d\" \"-o\" \"CMakeFiles/main.dir/main.cxx.o\" \"-c\" \"<src>/main.cxx\"",
"role" : "compile",
"result" : 1,
@@ -538,8 +552,8 @@ generated whenever `Indexing`_ occurs and deleted after any user-specified
`Callbacks`_ are executed.
``version``
The `Data Version`_ of the index file, an integer. Currently the version is
always ``1``.
The `Data Version`_ of the index file. Currently this is always written as:
``{ "major": 1, "minor": 0 }``.
``buildDir``
The build directory of the CMake project.
@@ -604,7 +618,10 @@ Example:
.. code-block:: json
{
"version": 1,
"version": {
"major": 1,
"minor": 0
},
"hook": "manual",
"buildDir": "<build>",
"dataDir": "<build>/.cmake/instrumentation/v1/data",
@@ -633,6 +650,10 @@ corresponding to the CMake invocation responsible for generating its command.
Each CMake content file contains the following:
``version``
The `Data Version`_ of the content file. Currently the version is
always ``{ "major": 1, "minor": 0 }``.
``project``
The value of :variable:`CMAKE_PROJECT_NAME`.

View File

@@ -4,10 +4,29 @@
"required": ["version"],
"properties": {
"version": {
"type": "integer",
"description": "The data version of snippet file to generate.",
"enum": [
1
"oneOf": [
{
"type": "integer",
"const": 1
},
{
"type": "object",
"required": [
"major"
],
"properties": {
"major": {
"type": "integer",
"const": 1
},
"minor": {
"type": "integer",
"const": 0
}
},
"additionalProperties": false
}
]
},
"callbacks": {

View File

@@ -44,6 +44,11 @@
using LoadQueriesAfter = cmInstrumentation::LoadQueriesAfter;
namespace {
cmInstrumentationQuery::Version latestDataVersion =
cmInstrumentationQuery::LatestDataVersion();
}
std::map<std::string, std::string> cmInstrumentation::cdashSnippetsMap = {
{
"configure",
@@ -145,7 +150,7 @@ void cmInstrumentation::CheckCDashVariable()
options_.insert(cmInstrumentationQuery::Option::CDashVerbose);
}
std::set<cmInstrumentationQuery::Hook> hooks_;
this->WriteJSONQuery(options_, hooks_, {});
this->WriteJSONQuery(latestDataVersion, options_, hooks_, {});
}
}
@@ -198,12 +203,12 @@ bool cmInstrumentation::HasErrors() const
}
void cmInstrumentation::WriteJSONQuery(
cmInstrumentationQuery::Version dataVersion,
std::set<cmInstrumentationQuery::Option> const& options_,
std::set<cmInstrumentationQuery::Hook> const& hooks_,
std::vector<std::vector<std::string>> const& callbacks_)
{
Json::Value root;
root["version"] = 1;
root["options"] = Json::arrayValue;
for (auto const& option : options_) {
root["options"].append(cmInstrumentationQuery::OptionString[option]);
@@ -217,7 +222,7 @@ void cmInstrumentation::WriteJSONQuery(
root["callbacks"].append(cmInstrumentation::GetCommandStr(callback));
}
this->WriteInstrumentationJson(
root, "query/generated",
dataVersion, root, "query/generated",
cmStrCat("query-", this->writtenJsonQueries++, ".json"));
}
@@ -236,7 +241,7 @@ void cmInstrumentation::WriteCMakeContent(
root["project"] =
gg->GetCMakeInstance()->GetCacheDefinition("CMAKE_PROJECT_NAME").GetCStr();
this->WriteInstrumentationJson(
root, "data/content",
latestDataVersion, root, "data/content",
cmStrCat("cmake-", this->ComputeSuffixTime(), ".json"));
}
@@ -362,6 +367,8 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
cmsys::Directory d;
std::string last_index_name =
this->GetFileByTimestamp(LatestOrOldest::Latest, "index", index_name);
std::string last_index_path =
cmStrCat(this->dataDir, "/index/", last_index_name);
if (d.Load(this->dataDir)) {
for (unsigned int i = 0; i < d.GetNumberOfFiles(); i++) {
std::string fpath = d.GetFilePath(i);
@@ -379,18 +386,16 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
index["hook"] = cmInstrumentationQuery::HookString[hook];
index["dataDir"] = this->dataDir;
index["buildDir"] = this->binaryDir;
index["version"] = 1;
if (this->HasOption(
cmInstrumentationQuery::Option::StaticSystemInformation)) {
this->InsertStaticSystemInformation(index);
}
for (auto const& file : files) {
if (last_index_name.empty()) {
index["snippets"].append(file.first);
} else {
int compare;
std::string last_index_path =
cmStrCat(this->dataDir, "/index/", last_index_name);
cmSystemTools::FileTimeCompare(file.second, last_index_path, &compare);
if (compare == 1) {
index["snippets"].append(file.first);
@@ -406,13 +411,14 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
}
// Write index file
this->WriteInstrumentationJson(index, "data/index", index_name);
this->WriteInstrumentationJson(latestDataVersion, index, "data/index",
index_name);
// Execute callbacks
for (auto& cb : this->callbacks) {
cmSystemTools::RunSingleCommand(cmStrCat(cb, " \"", index_path, '"'),
nullptr, nullptr, nullptr, nullptr,
cmSystemTools::OUTPUT_PASSTHROUGH);
for (auto const& cb : this->callbacks) {
cmSystemTools::RunSingleCommand(
cmStrCat(cb.Command, " \"", index_path, '"'), nullptr, nullptr, nullptr,
nullptr, cmSystemTools::OUTPUT_PASSTHROUGH);
}
// Special case for CDash collation
@@ -545,10 +551,14 @@ Json::Value cmInstrumentation::ReadJsonSnippet(std::string const& file_name)
return snippetData;
}
void cmInstrumentation::WriteInstrumentationJson(Json::Value& root,
std::string const& subdir,
std::string const& file_name)
void cmInstrumentation::WriteInstrumentationJson(
cmInstrumentationQuery::Version version, Json::Value& root,
std::string const& subdir, std::string const& file_name)
{
root["version"] = Json::objectValue;
root["version"]["major"] = version.Major;
root["version"]["minor"] = version.Minor;
Json::StreamWriterBuilder wbuilder;
wbuilder["indentation"] = "\t";
std::unique_ptr<Json::StreamWriter> JsonWriter =
@@ -581,7 +591,6 @@ std::string cmInstrumentation::InstrumentTest(
// Store command info
Json::Value root(this->preTestStats);
std::string command_str = cmStrCat(command, ' ', GetCommandStr(args));
root["version"] = 1;
root["command"] = command_str;
root["role"] = "test";
root["testName"] = name;
@@ -603,7 +612,7 @@ std::string cmInstrumentation::InstrumentTest(
"test-",
this->ComputeSuffixHash(cmStrCat(command_str, info.GetProcessId())), '-',
this->ComputeSuffixTime(endTime), ".json");
this->WriteInstrumentationJson(root, "data", file_name);
this->WriteInstrumentationJson(latestDataVersion, root, "data", file_name);
return file_name;
}
@@ -637,7 +646,6 @@ int cmInstrumentation::InstrumentCommand(
if (!command_str.empty()) {
root["command"] = command_str;
}
root["version"] = 1;
// Pre-Command
auto steady_start = std::chrono::steady_clock::now();
@@ -759,11 +767,12 @@ int cmInstrumentation::InstrumentCommand(
} else {
addCMakeContent(it->second);
}
this->WriteInstrumentationJson(it->second, "data", it->first);
this->WriteInstrumentationJson(latestDataVersion, it->second, "data",
it->first);
}
this->configureSnippetData.clear();
}
this->WriteInstrumentationJson(root, "data", file_name);
this->WriteInstrumentationJson(latestDataVersion, root, "data", file_name);
}
return ret;
}

View File

@@ -31,6 +31,8 @@ class cmGlobalGenerator;
class cmInstrumentation
{
public:
using Callback = cmInstrumentationQuery::Callback;
enum class LoadQueriesAfter
{
Yes,
@@ -60,7 +62,8 @@ public:
bool HasHook(cmInstrumentationQuery::Hook hook) const;
bool ReadJSONQueries(std::string const& directory);
void ReadJSONQuery(std::string const& file);
void WriteJSONQuery(std::set<cmInstrumentationQuery::Option> const& options,
void WriteJSONQuery(cmInstrumentationQuery::Version dataVersion,
std::set<cmInstrumentationQuery::Option> const& options,
std::set<cmInstrumentationQuery::Hook> const& hooks,
std::vector<std::vector<std::string>> const& callback);
void AddCustomContent(std::string const& name, Json::Value const& contents);
@@ -90,7 +93,8 @@ private:
Json::Value ReadJsonSnippet(std::string const& file_name);
bool AcquireLock(std::string const& lock_file, cmFileLock& lock,
unsigned long timeout);
void WriteInstrumentationJson(Json::Value& index,
void WriteInstrumentationJson(cmInstrumentationQuery::Version version,
Json::Value& index,
std::string const& directory,
std::string const& file_name);
void InsertStaticSystemInformation(Json::Value& index);
@@ -122,7 +126,7 @@ private:
std::string dataDir;
std::set<cmInstrumentationQuery::Option> options;
std::set<cmInstrumentationQuery::Hook> hooks;
std::vector<std::string> callbacks;
std::vector<Callback> callbacks;
std::vector<std::string> queryFiles;
static std::map<std::string, std::string> cdashSnippetsMap;
Json::Value preTestStats;

View File

@@ -29,6 +29,8 @@ file LICENSE.rst or https://cmake.org/licensing for details. */
namespace {
using Version = cmInstrumentationQuery::Version;
bool validateVersion(std::string const& key, std::string const& versionString,
int& version, cmExecutionStatus& status)
{
@@ -47,6 +49,45 @@ bool validateVersion(std::string const& key, std::string const& versionString,
return true;
}
bool validateDataVersion(std::string const& versionString, Version& version,
cmExecutionStatus& status)
{
char const* vStart = versionString.c_str();
if (!std::all_of(versionString.begin(), versionString.end(), [](char c) {
return cmsysString_isdigit(c) || c == '.';
})) {
status.SetError(
cmStrCat("given a malformed DATA_VERSION \"", versionString,
"\". A numeric major or major.minor version is required."));
return false;
}
version.Major = std::atoi(vStart);
version.Minor = 0;
std::string::size_type pos = versionString.find('.');
if (pos != std::string::npos) {
vStart += pos + 1;
version.Minor = std::atoi(vStart);
}
if (version.Major < 1 || version.Minor < 0) {
status.SetError(
cmStrCat("given a malformed DATA_VERSION \"", versionString,
"\". A numeric major or major.minor version is required."));
return false;
}
if (!cmInstrumentationQuery::ValidDataVersion(version)) {
status.SetError(
cmStrCat("given an unsupported DATA_VERSION \"", versionString,
"\" (the only currently supported version is 1.0)."));
return false;
}
return true;
}
template <typename E>
std::function<bool(std::string const&, E&)> EnumParser(
std::vector<std::string> const toString)
@@ -110,11 +151,10 @@ bool cmInstrumentationCommand(std::vector<std::string> const& args,
return false;
}
int apiVersion;
int dataVersion;
Version dataVersion;
if (!validateVersion("API_VERSION", arguments.ApiVersion, apiVersion,
status) ||
!validateVersion("DATA_VERSION", arguments.DataVersion, dataVersion,
status)) {
!validateDataVersion(arguments.DataVersion, dataVersion, status)) {
return false;
}
@@ -182,7 +222,8 @@ bool cmInstrumentationCommand(std::vector<std::string> const& args,
}
// Write query file
instrumentation->WriteJSONQuery(options, hooks, arguments.Callbacks);
instrumentation->WriteJSONQuery(dataVersion, options, hooks,
arguments.Callbacks);
return true;
}

View File

@@ -3,7 +3,6 @@
#include <algorithm>
#include <ctime>
#include <functional>
#include <iostream>
#include <iterator>
#include <set>
#include <vector>
@@ -47,6 +46,7 @@ JsonErrors::ErrorGenerator InvalidRootQueryObject(
};
using JSONHelperBuilder = cmJSONHelperBuilder;
using Version = cmInstrumentationQuery::Version;
template <typename E>
static std::function<bool(E&, Json::Value const*, cmJSONState*)> EnumHelper(
@@ -67,7 +67,7 @@ static std::function<bool(E&, Json::Value const*, cmJSONState*)> EnumHelper(
}
static auto const OptionHelper = EnumHelper<cmInstrumentationQuery::Option>(
cmInstrumentationQuery::OptionString, "option");
static auto const QueryListHelper =
static auto const OptionListHelper =
JSONHelperBuilder::Vector<cmInstrumentationQuery::Option>(
ErrorMessages::InvalidArray, OptionHelper);
static auto const HookHelper = EnumHelper<cmInstrumentationQuery::Hook>(
@@ -78,7 +78,36 @@ static auto const HookListHelper =
static auto const CallbackHelper = JSONHelperBuilder::String();
static auto const CallbackListHelper = JSONHelperBuilder::Vector<std::string>(
ErrorMessages::InvalidArray, CallbackHelper);
static auto const VersionHelper = JSONHelperBuilder::Int();
JsonErrors::ErrorGenerator InvalidVersionObject(
JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields)
{
return JsonErrors::INVALID_NAMED_OBJECT(
[](Json::Value const*, cmJSONState*) -> std::string {
return "version object";
})(errorType, extraFields);
}
static auto const VersionObjectHelper =
JSONHelperBuilder::Object<Version>(InvalidVersionObject, false)
.Bind("major"_s, &Version::Major, JSONHelperBuilder::Int(), true)
.Bind("minor"_s, &Version::Minor, JSONHelperBuilder::Int(), false);
bool VersionHelper(Version& out, Json::Value const* value, cmJSONState* state)
{
out.Minor = 0;
if (value->isInt()) {
out.Major = value->asInt();
} else if (value->isObject()) {
if (!VersionObjectHelper(out, value, state)) {
return false;
}
} else {
state->AddErrorAtValue("Version must be an integer or object", value);
return false;
}
return true;
}
using QueryRoot = cmInstrumentationQuery::QueryJSONRoot;
@@ -86,22 +115,35 @@ static auto const QueryRootHelper =
JSONHelperBuilder::Object<QueryRoot>(ErrorMessages::InvalidRootQueryObject,
false)
.Bind("version"_s, &QueryRoot::version, VersionHelper, true)
.Bind("options"_s, &QueryRoot::options, QueryListHelper, false)
.Bind("options"_s, &QueryRoot::options, OptionListHelper, false)
.Bind("hooks"_s, &QueryRoot::hooks, HookListHelper, false)
.Bind("callbacks"_s, &QueryRoot::callbacks, CallbackListHelper, false);
static auto const QueryRootVersionOnlyHelper =
JSONHelperBuilder::Object<QueryRoot>(ErrorMessages::InvalidRootQueryObject,
true)
.Bind("version"_s, &QueryRoot::version, VersionHelper, true);
bool cmInstrumentationQuery::ReadJSON(std::string const& filename,
std::string& errorMessage,
std::set<Option>& options,
std::set<Hook>& hooks,
std::vector<std::string>& callbacks)
std::vector<Callback>& callbacks)
{
Json::Value root;
this->parseState = cmJSONState(filename, &root);
if (!this->parseState.errors.empty()) {
std::cerr << this->parseState.GetErrorMessage(true) << std::endl;
errorMessage = this->parseState.GetErrorMessage(true);
return false;
}
if (!QueryRootVersionOnlyHelper(this->queryRoot, &root, &this->parseState)) {
errorMessage = this->parseState.GetErrorMessage(true);
return false;
}
if (!ValidDataVersion(this->queryRoot.version)) {
// Ignore invalid data versions
return true;
}
if (!QueryRootHelper(this->queryRoot, &root, &this->parseState)) {
errorMessage = this->parseState.GetErrorMessage(true);
return false;
@@ -110,7 +152,22 @@ bool cmInstrumentationQuery::ReadJSON(std::string const& filename,
std::inserter(options, options.end()));
std::move(this->queryRoot.hooks.begin(), this->queryRoot.hooks.end(),
std::inserter(hooks, hooks.end()));
std::move(this->queryRoot.callbacks.begin(), this->queryRoot.callbacks.end(),
std::back_inserter(callbacks));
for (auto const& callback : this->queryRoot.callbacks) {
callbacks.push_back({ callback, this->queryRoot.version });
}
return true;
}
bool cmInstrumentationQuery::ValidDataVersion(Version version)
{
auto const latest = LatestDataVersion();
return version.Major == latest.Major && version.Minor == latest.Minor;
}
Version cmInstrumentationQuery::LatestDataVersion()
{
Version latest;
latest.Major = 1;
latest.Minor = 0;
return latest;
}

View File

@@ -37,18 +37,32 @@ public:
};
static std::vector<std::string> const HookString;
struct Version
{
int Major = 0;
int Minor = 0;
};
struct Callback
{
std::string Command;
Version DataVersion;
};
struct QueryJSONRoot
{
std::vector<cmInstrumentationQuery::Option> options;
std::vector<cmInstrumentationQuery::Hook> hooks;
std::vector<std::string> callbacks;
int version;
Version version;
};
cmInstrumentationQuery() = default;
bool ReadJSON(std::string const& file, std::string& errorMessage,
std::set<Option>& options, std::set<Hook>& hooks,
std::vector<std::string>& callbacks);
std::vector<Callback>& callbacks);
QueryJSONRoot queryRoot;
cmJSONState parseState;
static Version LatestDataVersion();
static bool ValidDataVersion(Version version);
};

View File

@@ -63,7 +63,7 @@ function(instrument test)
if (EXISTS ${query})
file(MAKE_DIRECTORY ${v1}/query)
configure_file(${query} ${v1}/query/${test}.json)
else ()
else()
if (NOT EXISTS ${cmake_file} AND NOT EXISTS ${cmake_file}.in)
set(cmake_file ${query_dir}/default.cmake)
endif()
@@ -195,6 +195,18 @@ instrument(empty BAD_QUERY
instrument(bad-version BAD_QUERY
CHECK_SCRIPT check-query-dir.cmake
)
instrument(bad-version-major BAD_QUERY
CHECK_SCRIPT check-query-dir.cmake
)
instrument(bad-version-minor BAD_QUERY
CHECK_SCRIPT check-query-dir.cmake
)
instrument(bad-version-object BAD_QUERY
CHECK_SCRIPT check-query-dir.cmake
)
instrument(hooks-invalid-version-ignored BUILD
CHECK_SCRIPT check-hooks-invalid-version-ignored.cmake
)
# Verify Hooks Run and Index File
instrument(hooks-1 BUILD INSTALL TEST STATIC_QUERY
@@ -236,6 +248,7 @@ instrument(cmake-command-data
)
instrument(cmake-command-bad-api-version)
instrument(cmake-command-bad-data-version)
instrument(cmake-command-unsupported-data-version)
instrument(cmake-command-missing-version)
instrument(cmake-command-bad-arg)
instrument(cmake-command-parallel-install

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
^CMake Error: Could not load instrumentation queries from [^
]+:
bad-version-object\.json:4: Invalid extra field "patch" in version object
"patch": 0
\^

View File

@@ -15,6 +15,11 @@ set(firstFile "")
foreach(content_file IN LISTS content_files)
read_json("${content_file}" contents)
# Check version
string(JSON version GET "${contents}" version)
json_assert_key("${content_file}" "${version}" major "1")
json_assert_key("${content_file}" "${version}" minor "0")
# Check project name
json_assert_key("${content_file}" "${contents}" project "instrumentation")

View File

@@ -0,0 +1,4 @@
if (EXISTS ${v1}/postCMakeBuild.hook)
string(APPEND RunCMake_TEST_FAILED
"Invalid-version query should have been ignored, but postCMakeBuild hook ran\n")
endif()

View File

@@ -1,5 +1,6 @@
CMake Error at [^
]*\(cmake_instrumentation\):
cmake_instrumentation given a non-integer DATA_VERSION\.
cmake_instrumentation given a malformed DATA_VERSION "NOT_AN_INT"\. A
numeric major or major\.minor version is required\.
Call Stack \(most recent call first\):
CMakeLists\.txt:5 \(include\)

View File

@@ -1,6 +1,6 @@
CMake Error at [^
]*\(cmake_instrumentation\):
cmake_instrumentation given an unsupported DATA_VERSION "" \(the only
currently supported version is 1\)\.
cmake_instrumentation given a malformed DATA_VERSION ""\. A numeric major
or major\.minor version is required\.
Call Stack \(most recent call first\):
CMakeLists\.txt:5 \(include\)

View File

@@ -0,0 +1,6 @@
CMake Error at [^
]*\(cmake_instrumentation\):
cmake_instrumentation given an unsupported DATA_VERSION "1\.1" \(the only
currently supported version is 1\.0\)\.
Call Stack \(most recent call first\):
CMakeLists\.txt:5 \(include\)

View File

@@ -6,18 +6,22 @@ include(${CMAKE_CURRENT_LIST_DIR}/verify-trace.cmake)
# Test CALLBACK script. Prints output information and verifies index file
# Called as: cmake -P hook.cmake [CheckForStaticQuery?] [CheckForTrace?] [index.json]
set(index ${CMAKE_ARGV5})
if (NOT ${CMAKE_ARGV3})
set(hasStaticInfo "UNEXPECTED")
endif()
if (NOT ${CMAKE_ARGV4})
set(hasTrace "UNEXPECTED")
endif()
set(index ${CMAKE_ARGV5})
cmake_path(GET index PARENT_PATH indexDir)
cmake_path(GET indexDir PARENT_PATH dataDir)
cmake_path(GET dataDir PARENT_PATH v1)
read_json("${index}" contents)
string(JSON hook GET "${contents}" hook)
# Output is verified by *-stdout.txt files that the HOOK is run
message(STATUS ${hook})
# Not a check-*.cmake script, this is called as an instrumentation CALLBACK
set(ERROR_MESSAGE "")
function(add_error error)
@@ -26,14 +30,17 @@ function(add_error error)
endfunction()
json_has_key("${index}" "${contents}" version)
string(JSON version_major GET "${contents}" version major)
string(JSON version_minor GET "${contents}" version minor)
if (NOT version_major EQUAL 1 OR NOT version_minor EQUAL 0)
add_error("Version must be 1.0, got: ${version_major}.${version_minor}")
endif()
json_has_key("${index}" "${contents}" buildDir)
json_has_key("${index}" "${contents}" dataDir)
json_has_key("${index}" "${contents}" snippets)
if (NOT version EQUAL 1)
add_error("Version must be 1, got: ${version}")
endif()
string(JSON n_snippets LENGTH "${snippets}")
math(EXPR snippets_range "${n_snippets}-1")
@@ -159,7 +166,6 @@ if (NOT hasStaticInfo STREQUAL UNEXPECTED)
endforeach()
endif()
get_filename_component(v1 ${dataDir} DIRECTORY)
if (EXISTS ${v1}/${hook}.hook)
add_error("Received multiple triggers of the same hook: ${hook}")
endif()

View File

@@ -0,0 +1,3 @@
{
"version": 2
}

View File

@@ -0,0 +1,6 @@
{
"version": {
"major": 1,
"minor": 1
}
}

View File

@@ -0,0 +1,6 @@
{
"version": {
"major": 1,
"patch": 0
}
}

View File

@@ -1,3 +1,6 @@
{
"version": 0
"version": {
"major": 1,
"minor": 1
}
}

View File

@@ -1,5 +1,8 @@
{
"version": 1,
"version": {
"major": 1,
"minor": 0
},
"options": [
"staticSystemInformation",
"dynamicSystemInformation"

View File

@@ -0,0 +1,4 @@
cmake_instrumentation(
API_VERSION 1
DATA_VERSION 1.1
)

View File

@@ -14,7 +14,7 @@
# Query 2
cmake_instrumentation(
API_VERSION 1
DATA_VERSION 1
DATA_VERSION 1.0
HOOKS postCMakeBuild
OPTIONS staticSystemInformation dynamicSystemInformation trace
CALLBACK ${CMAKE_COMMAND} -E echo callback2

View File

@@ -2,5 +2,9 @@
"callbacks" : [],
"hooks" : [],
"options" : [],
"version": 1
"version" :
{
"major" : 1,
"minor" : 0
}
}

View File

@@ -11,5 +11,9 @@
"cdashSubmit",
"cdashVerbose"
],
"version" : 1
"version" :
{
"major" : 1,
"minor" : 0
}
}

View File

@@ -14,5 +14,9 @@
"dynamicSystemInformation",
"trace"
],
"version": 1
"version" :
{
"major" : 1,
"minor" : 0
}
}

View File

@@ -1,5 +1,5 @@
{
"version": 1,
"version": { "major": 1 },
"hooks": ["postGenerate", "postCMakeBuild", "postCTest"],
"callbacks": ["@GET_HOOK@"]
}

View File

@@ -0,0 +1,8 @@
{
"version": {
"major": 1,
"minor": 1
},
"hooks": ["postCMakeBuild"],
"callbacks": ["@GET_HOOK@"]
}

View File

@@ -75,9 +75,10 @@ endfunction()
function(verify_snippet_data snippet contents)
snippet_has_fields("${snippet}" "${contents}")
snippet_valid_timing("${contents}")
string(JSON version GET "${contents}" version)
if (NOT version EQUAL 1)
json_error("${snippet}" "Version must be 1, got: ${version}")
string(JSON version_major GET "${contents}" version major)
string(JSON version_minor GET "${contents}" version minor)
if (NOT version_major EQUAL 1 OR NOT version_minor EQUAL 0)
json_error("${snippet}" "Version must be 1.0, got: ${version_major}.${version_minor}")
endif()
get_filename_component(filename "${snippet}" NAME)
string(JSON result GET "${contents}" result)