Merge topic 'instrumentation-build-hooks'

2680f30caf instrumentation: Allow multiple CALLBACK arguments
fc1d55f6a5 instrumentation: Add preBuild and postBuild hooks for ninja
f62a4ab2ee instrumentation: Refactor cmInstrumentation constructor and usage
c57d1752d4 cmUVProcessChain: Add Detached option for spawning daemons

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !10230
This commit is contained in:
Brad King
2025-02-05 14:08:17 +00:00
committed by Kitware Robot
19 changed files with 253 additions and 73 deletions

View File

@@ -23,8 +23,8 @@ only supported value for both fields is 1. See :ref:`cmake-instrumentation v1`
for details of the data output content and location.
Each of the optional keywords ``HOOKS``, ``QUERIES``, and ``CALLBACK``
correspond to one of the parameters to the :ref:`cmake-instrumentation v1 Query Files`. Note that the
``CALLBACK`` keyword only accepts a single callback.
correspond to one of the parameters to the :ref:`cmake-instrumentation v1 Query Files`.
The ``CALLBACK`` keyword can be provided multiple times to create multiple callbacks.
Whenever ``cmake_instrumentation`` is invoked, a query file is generated in
``<build>/.cmake/timing/v1/query/generated`` to enable instrumentation
@@ -43,7 +43,8 @@ equivalent JSON query file.
DATA_VERSION 1
HOOKS postGenerate preCMakeBuild postCMakeBuild
QUERIES staticSystemInformation dynamicSystemInformation
CALLBACK "${CMAKE_COMMAND} -P /path/to/handle_data.cmake"
CALLBACK ${CMAKE_COMMAND} -P /path/to/handle_data.cmake
CALLBACK ${CMAKE_COMMAND} -P /path/to/handle_data_2.cmake
)
.. code-block:: json
@@ -58,5 +59,6 @@ equivalent JSON query file.
],
"callbacks": [
"/path/to/cmake -P /path/to/handle_data.cmake"
"/path/to/cmake -P /path/to/handle_data_2.cmake"
]
}

View File

@@ -117,8 +117,10 @@ optional.
should be one of the following:
* ``postGenerate``
* ``preCMakeBuild``
* ``postCMakeBuild``
* ``preBuild`` (:ref:`Ninja Generators`. only, when ``ninja`` is invoked)
* ``postBuild`` (:ref:`Ninja Generators`. only, when ``ninja`` completes)
* ``preCMakeBuild`` (when ``cmake --build`` is invoked)
* ``postCMakeBuild`` (when ``cmake --build`` completes)
* ``postInstall``
* ``postTest``

View File

@@ -260,7 +260,7 @@ void cmCTestLaunch::RunChild()
int cmCTestLaunch::Run()
{
auto instrumenter = cmInstrumentation(this->Reporter.OptionBuildDir);
auto instrumentation = cmInstrumentation(this->Reporter.OptionBuildDir);
std::map<std::string, std::string> options;
options["target"] = this->Reporter.OptionTargetName;
options["source"] = this->Reporter.OptionSource;
@@ -270,7 +270,7 @@ int cmCTestLaunch::Run()
std::map<std::string, std::string> arrayOptions;
arrayOptions["outputs"] = this->Reporter.OptionOutput;
arrayOptions["targetLabels"] = this->Reporter.OptionTargetLabels;
instrumenter.InstrumentCommand(
instrumentation.InstrumentCommand(
this->Reporter.OptionCommandType, this->RealArgV,
[this]() -> int {
this->RunChild();

View File

@@ -32,6 +32,7 @@
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmInstrumentation.h"
#include "cmLinkLineComputer.h"
#include "cmList.h"
#include "cmListFileCache.h"
@@ -1761,6 +1762,13 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
this->WriteTargetRebuildManifest(os);
this->WriteTargetClean(os);
this->WriteTargetHelp(os);
#if !defined(CMAKE_BOOTSTRAP)
if (this->GetCMakeInstance()
->GetInstrumentation()
->HasPreOrPostBuildHook()) {
this->WriteTargetInstrument(os);
}
#endif
for (std::string const& config : this->GetConfigNames()) {
this->WriteTargetDefault(*this->GetConfigFileStream(config));
@@ -1835,6 +1843,14 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
}
reBuild.ImplicitDeps.push_back(this->CMakeCacheFile);
#if !defined(CMAKE_BOOTSTRAP)
if (this->GetCMakeInstance()
->GetInstrumentation()
->HasPreOrPostBuildHook()) {
reBuild.ExplicitDeps.push_back(this->NinjaOutputPath("start_instrument"));
}
#endif
// Use 'console' pool to get non buffered output of the CMake re-run call
// Available since Ninja 1.5
if (this->SupportsDirectConsole()) {
@@ -2180,6 +2196,42 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
}
}
void cmGlobalNinjaGenerator::WriteTargetInstrument(std::ostream& os)
{
// Write rule
{
cmNinjaRule rule("START_INSTRUMENT");
rule.Command = cmStrCat(
"\"", cmSystemTools::GetCTestCommand(), "\" --start-instrumentation \"",
this->GetCMakeInstance()->GetHomeOutputDirectory(), "\"");
#ifndef _WIN32
/*
* On Unix systems, Ninja will prefix the command with `/bin/sh -c`.
* Use exec so that Ninja is the parent process of the command.
*/
rule.Command = cmStrCat("exec ", rule.Command);
#endif
rule.Description = "Collecting build metrics";
rule.Comment = "Rule to initialize instrumentation daemon.";
rule.Restat = "1";
WriteRule(*this->RulesFileStream, rule);
}
// Write build
{
cmNinjaBuild phony("phony");
phony.Comment = "Phony target to keep START_INSTRUMENTATION out of date.";
phony.Outputs.push_back(this->NinjaOutputPath("CMakeFiles/instrument"));
cmNinjaBuild instrument("START_INSTRUMENT");
instrument.Comment = "Start instrumentation daemon.";
instrument.Outputs.push_back(this->NinjaOutputPath("start_instrument"));
instrument.ExplicitDeps.push_back(
this->NinjaOutputPath("CMakeFiles/instrument"));
WriteBuild(os, phony);
WriteBuild(os, instrument);
}
}
void cmGlobalNinjaGenerator::InitOutputPathPrefix()
{
this->OutputPathPrefix =

View File

@@ -536,6 +536,7 @@ private:
void WriteTargetRebuildManifest(std::ostream& os);
bool WriteTargetCleanAdditional(std::ostream& os);
void WriteTargetClean(std::ostream& os);
void WriteTargetInstrument(std::ostream& os);
void WriteTargetHelp(std::ostream& os);
void ComputeTargetDependsClosure(

View File

@@ -11,6 +11,7 @@
#include <cm/optional>
#include <cm3p/json/writer.h>
#include <cm3p/uv.h>
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
@@ -22,9 +23,9 @@
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
#include "cmUVProcessChain.h"
cmInstrumentation::cmInstrumentation(std::string const& binary_dir,
bool clear_generated)
cmInstrumentation::cmInstrumentation(std::string const& binary_dir)
{
std::string const uuid =
cmExperimental::DataForFeature(cmExperimental::Feature::Instrumentation)
@@ -32,9 +33,6 @@ cmInstrumentation::cmInstrumentation(std::string const& binary_dir,
this->binaryDir = binary_dir;
this->timingDirv1 =
cmStrCat(this->binaryDir, "/.cmake/instrumentation-", uuid, "/v1");
if (clear_generated) {
this->ClearGeneratedQueries();
}
if (cm::optional<std::string> configDir =
cmSystemTools::GetCMakeConfigDirectory()) {
this->userTimingDirv1 =
@@ -57,24 +55,6 @@ void cmInstrumentation::LoadQueries()
}
}
cmInstrumentation::cmInstrumentation(
std::string const& binary_dir,
std::set<cmInstrumentationQuery::Query>& queries_,
std::set<cmInstrumentationQuery::Hook>& hooks_, std::string& callback)
{
this->binaryDir = binary_dir;
this->timingDirv1 = cmStrCat(
this->binaryDir, "/.cmake/instrumentation-",
cmExperimental::DataForFeature(cmExperimental::Feature::Instrumentation)
.Uuid,
"/v1");
this->queries = queries_;
this->hooks = hooks_;
if (!callback.empty()) {
this->callbacks.push_back(callback);
}
}
bool cmInstrumentation::ReadJSONQueries(std::string const& directory)
{
cmsys::Directory d;
@@ -99,21 +79,24 @@ void cmInstrumentation::ReadJSONQuery(std::string const& file)
this->callbacks);
}
void cmInstrumentation::WriteJSONQuery()
void cmInstrumentation::WriteJSONQuery(
std::set<cmInstrumentationQuery::Query> const& queries_,
std::set<cmInstrumentationQuery::Hook> const& hooks_,
std::vector<std::vector<std::string>> const& callbacks_)
{
Json::Value root;
root["version"] = 1;
root["queries"] = Json::arrayValue;
for (auto const& query : this->queries) {
for (auto const& query : queries_) {
root["queries"].append(cmInstrumentationQuery::QueryString[query]);
}
root["hooks"] = Json::arrayValue;
for (auto const& hook : this->hooks) {
for (auto const& hook : hooks_) {
root["hooks"].append(cmInstrumentationQuery::HookString[hook]);
}
root["callbacks"] = Json::arrayValue;
for (auto const& callback : this->callbacks) {
root["callbacks"].append(callback);
for (auto const& callback : callbacks_) {
root["callbacks"].append(cmInstrumentation::GetCommandStr(callback));
}
cmsys::Directory d;
int n = 0;
@@ -132,16 +115,27 @@ void cmInstrumentation::ClearGeneratedQueries()
}
}
bool cmInstrumentation::HasQuery()
bool cmInstrumentation::HasQuery() const
{
return this->hasQuery;
}
bool cmInstrumentation::HasQuery(cmInstrumentationQuery::Query query)
bool cmInstrumentation::HasQuery(cmInstrumentationQuery::Query query) const
{
return (this->queries.find(query) != this->queries.end());
}
bool cmInstrumentation::HasHook(cmInstrumentationQuery::Hook hook) const
{
return (this->hooks.find(hook) != this->hooks.end());
}
bool cmInstrumentation::HasPreOrPostBuildHook() const
{
return (this->HasHook(cmInstrumentationQuery::Hook::PreBuild) ||
this->HasHook(cmInstrumentationQuery::Hook::PostBuild));
}
int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
{
// Don't run collection if hook is disabled
@@ -462,7 +456,7 @@ std::string cmInstrumentation::GetCommandStr(
for (size_t i = 0; i < args.size(); ++i) {
command_str = cmStrCat(command_str, args[i]);
if (i < args.size() - 1) {
command_str = cmStrCat(command_str, " ");
command_str = cmStrCat(command_str, ' ');
}
}
return command_str;
@@ -494,3 +488,46 @@ std::string cmInstrumentation::ComputeSuffixTime()
<< std::setfill('0') << std::setw(4) << tms;
return ss.str();
}
/*
* Called by ctest --start-instrumentation as part of the START_INSTRUMENTATION
* rule when using the Ninja generator.
* This creates a detached process which waits for the Ninja process to die
* before running the postBuild hook. In this way, the postBuild hook triggers
* after every ninja invocation, regardless of whether the build passed or
* failed.
*/
int cmInstrumentation::SpawnBuildDaemon()
{
// preBuild Hook
this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild);
// postBuild Hook
if (this->HasHook(cmInstrumentationQuery::Hook::PostBuild)) {
auto ninja_pid = uv_os_getppid();
if (ninja_pid) {
std::vector<std::string> args;
args.push_back(cmSystemTools::GetCTestCommand());
args.push_back("--wait-and-collect-instrumentation");
args.push_back(this->binaryDir);
args.push_back(std::to_string(ninja_pid));
auto builder = cmUVProcessChainBuilder().SetDetached().AddCommand(args);
auto chain = builder.Start();
uv_run(&chain.GetLoop(), UV_RUN_DEFAULT);
}
}
return 0;
}
/*
* Always called by ctest --wait-and-collect-instrumentation in a detached
* process. Waits for the given PID to end before running the postBuild hook.
*
* See SpawnBuildDaemon()
*/
int cmInstrumentation::CollectTimingAfterBuild(int ppid)
{
while (0 == uv_kill(ppid, 0)) {
};
return this->CollectTimingData(cmInstrumentationQuery::Hook::PostBuild);
}

View File

@@ -21,14 +21,7 @@
class cmInstrumentation
{
public:
// Read Queries
cmInstrumentation(std::string const& binary_dir,
bool clear_generated = false);
// Create Query
cmInstrumentation(std::string const& binary_dir,
std::set<cmInstrumentationQuery::Query>& queries,
std::set<cmInstrumentationQuery::Hook>& hooks,
std::string& callback);
cmInstrumentation(std::string const& binary_dir);
int InstrumentCommand(
std::string command_type, std::vector<std::string> const& command,
std::function<int()> const& callback,
@@ -42,12 +35,19 @@ public:
std::chrono::system_clock::time_point systemStart);
void GetPreTestStats();
void LoadQueries();
bool HasQuery();
bool HasQuery(cmInstrumentationQuery::Query);
bool HasQuery() const;
bool HasQuery(cmInstrumentationQuery::Query) const;
bool HasHook(cmInstrumentationQuery::Hook) const;
bool HasPreOrPostBuildHook() const;
bool ReadJSONQueries(std::string const& directory);
void ReadJSONQuery(std::string const& file);
void WriteJSONQuery();
void WriteJSONQuery(std::set<cmInstrumentationQuery::Query> const& queries,
std::set<cmInstrumentationQuery::Hook> const& hooks,
std::vector<std::vector<std::string>> const& callback);
void ClearGeneratedQueries();
int CollectTimingData(cmInstrumentationQuery::Hook hook);
int SpawnBuildDaemon();
int CollectTimingAfterBuild(int ppid);
std::string errorMsg;
private:
@@ -61,7 +61,6 @@ private:
static void InsertTimingData(
Json::Value& root, std::chrono::steady_clock::time_point steadyStart,
std::chrono::system_clock::time_point systemStart);
void ClearGeneratedQueries();
bool HasQueryFile(std::string const& file);
static std::string GetCommandStr(std::vector<std::string> const& args);
static std::string ComputeSuffixHash(std::string const& command_str);

View File

@@ -18,6 +18,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstrumentationQuery.h"
#include "cmMakefile.h"
#include "cmStringAlgorithms.h"
#include "cmake.h"
namespace {
@@ -80,7 +81,7 @@ bool cmInstrumentationCommand(std::vector<std::string> const& args,
ArgumentParser::NonEmpty<std::string> DataVersion;
ArgumentParser::NonEmpty<std::vector<std::string>> Queries;
ArgumentParser::NonEmpty<std::vector<std::string>> Hooks;
ArgumentParser::NonEmpty<std::vector<std::string>> Callback;
ArgumentParser::NonEmpty<std::vector<std::vector<std::string>>> Callbacks;
};
static auto const parser = cmArgumentParser<Arguments>{}
@@ -88,7 +89,7 @@ bool cmInstrumentationCommand(std::vector<std::string> const& args,
.Bind("DATA_VERSION"_s, &Arguments::DataVersion)
.Bind("QUERIES"_s, &Arguments::Queries)
.Bind("HOOKS"_s, &Arguments::Hooks)
.Bind("CALLBACK"_s, &Arguments::Callback);
.Bind("CALLBACK"_s, &Arguments::Callbacks);
std::vector<std::string> unparsedArguments;
Arguments const arguments = parser.Parse(args, &unparsedArguments);
@@ -136,14 +137,10 @@ bool cmInstrumentationCommand(std::vector<std::string> const& args,
hooks.insert(hook);
}
std::string callback;
for (auto const& arg : arguments.Callback) {
callback = cmStrCat(callback, arg);
}
auto instrument = cmInstrumentation(
status.GetMakefile().GetHomeOutputDirectory(), queries, hooks, callback);
instrument.WriteJSONQuery();
status.GetMakefile()
.GetCMakeInstance()
->GetInstrumentation()
->WriteJSONQuery(queries, hooks, arguments.Callbacks);
return true;
}

View File

@@ -156,6 +156,12 @@ cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetWorkingDirectory(
return *this;
}
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetDetached()
{
this->Detached = true;
return *this;
}
uv_loop_t* cmUVProcessChainBuilder::GetLoop() const
{
return this->Loop;
@@ -337,6 +343,9 @@ void cmUVProcessChain::InternalData::SpawnProcess(
arguments.push_back(nullptr);
options.args = const_cast<char**>(arguments.data());
options.flags = UV_PROCESS_WINDOWS_HIDE;
if (this->Builder->Detached) {
options.flags |= UV_PROCESS_DETACHED;
}
#if UV_VERSION_MAJOR > 1 || \
(UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 48) || \
!defined(CMAKE_USE_SYSTEM_LIBUV)
@@ -380,6 +389,9 @@ void cmUVProcessChain::InternalData::SpawnProcess(
process.Process.spawn(*this->Loop, options, &process)) < 0) {
process.Finish();
}
if (this->Builder->Detached) {
uv_unref((uv_handle_t*)process.Process);
}
process.InputPipe.reset();
process.OutputPipe.reset();
}

View File

@@ -38,6 +38,7 @@ public:
cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd);
cmUVProcessChainBuilder& SetExternalStream(Stream stdio, FILE* stream);
cmUVProcessChainBuilder& SetWorkingDirectory(std::string dir);
cmUVProcessChainBuilder& SetDetached();
uv_loop_t* GetLoop() const;
@@ -68,6 +69,7 @@ private:
std::vector<ProcessConfiguration> Processes;
std::string WorkingDirectory;
bool MergedBuiltinStreams = false;
bool Detached = false;
uv_loop_t* Loop = nullptr;
};

View File

@@ -2611,21 +2611,24 @@ int cmake::ActualConfigure()
cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles"_s),
this->FileAPI->GetConfigureLogVersions());
}
this->Instrumentation =
cm::make_unique<cmInstrumentation>(this->State->GetBinaryDirectory());
this->Instrumentation->ClearGeneratedQueries();
#endif
// actually do the configure
auto startTime = std::chrono::steady_clock::now();
#if !defined(CMAKE_BOOTSTRAP)
cmInstrumentation instrumentation(this->State->GetBinaryDirectory(), true);
if (!instrumentation.errorMsg.empty()) {
cmSystemTools::Error(instrumentation.errorMsg);
if (!this->Instrumentation->errorMsg.empty()) {
cmSystemTools::Error(this->Instrumentation->errorMsg);
return 1;
}
std::function<int()> doConfigure = [this]() -> int {
this->GlobalGenerator->Configure();
return 0;
};
int ret = instrumentation.InstrumentCommand(
int ret = this->Instrumentation->InstrumentCommand(
"configure", this->cmdArgs, [doConfigure]() { return doConfigure(); },
cm::nullopt, cm::nullopt, true);
if (ret != 0) {
@@ -2670,8 +2673,8 @@ int cmake::ActualConfigure()
}
// Setup launchers for instrumentation
#if !defined(CMAKE_BOOTSTRAP)
instrumentation.LoadQueries();
if (instrumentation.HasQuery()) {
this->Instrumentation->LoadQueries();
if (this->Instrumentation->HasQuery()) {
std::string launcher;
if (mf->IsOn("CTEST_USE_LAUNCHERS")) {
launcher =
@@ -3016,7 +3019,6 @@ int cmake::Generate()
auto startTime = std::chrono::steady_clock::now();
#if !defined(CMAKE_BOOTSTRAP)
auto profilingRAII = this->CreateProfilingEntry("project", "generate");
cmInstrumentation instrumentation(this->State->GetBinaryDirectory());
std::function<int()> doGenerate = [this]() -> int {
if (!this->GlobalGenerator->Compute()) {
return -1;
@@ -3025,7 +3027,8 @@ int cmake::Generate()
return 0;
};
int ret = instrumentation.InstrumentCommand(
this->Instrumentation->LoadQueries();
int ret = this->Instrumentation->InstrumentCommand(
"generate", this->cmdArgs, [doGenerate]() { return doGenerate(); });
if (ret != 0) {
return ret;
@@ -3046,7 +3049,7 @@ int cmake::Generate()
this->UpdateProgress(msg.str(), -1);
}
#if !defined(CMAKE_BOOTSTRAP)
instrumentation.CollectTimingData(
this->Instrumentation->CollectTimingData(
cmInstrumentationQuery::Hook::PostGenerate);
#endif
if (!this->GraphVizFile.empty()) {

View File

@@ -49,6 +49,7 @@ class cmDebuggerAdapter;
class cmExternalMakefileProjectGeneratorFactory;
class cmFileAPI;
class cmInstrumentation;
class cmFileTimeCache;
class cmGlobalGenerator;
class cmMakefile;
@@ -663,6 +664,10 @@ public:
#if !defined(CMAKE_BOOTSTRAP)
cmFileAPI* GetFileAPI() const { return this->FileAPI.get(); }
cmInstrumentation* GetInstrumentation() const
{
return this->Instrumentation.get();
}
#endif
cmState* GetState() const { return this->State.get(); }
@@ -816,6 +821,7 @@ private:
#if !defined(CMAKE_BOOTSTRAP)
std::unique_ptr<cmVariableWatch> VariableWatch;
std::unique_ptr<cmFileAPI> FileAPI;
std::unique_ptr<cmInstrumentation> Instrumentation;
#endif
std::unique_ptr<cmState> State;

View File

@@ -189,6 +189,18 @@ int main(int argc, char const* const* argv)
return cmCTestLaunch::Main(argc, argv, cmCTestLaunch::Op::Instrument);
}
// Dispatch post-build instrumentation daemon for ninja
if (argc == 3 && strcmp(argv[1], "--start-instrumentation") == 0) {
return cmInstrumentation(argv[2]).SpawnBuildDaemon();
}
// Dispatch 'ctest --collect-instrumentation' once given PID finishes
if (argc == 4 &&
strcmp(argv[1], "--wait-and-collect-instrumentation") == 0) {
return cmInstrumentation(argv[2]).CollectTimingAfterBuild(
std::stoi(argv[3]));
}
// Dispatch 'ctest --collect-instrumentation' mode directly.
if (argc == 3 && strcmp(argv[1], "--collect-instrumentation") == 0) {
return cmInstrumentation(argv[2]).CollectTimingData(

View File

@@ -6,7 +6,7 @@ function(instrument test)
set(config "${CMAKE_CURRENT_LIST_DIR}/config")
set(ENV{CMAKE_CONFIG_DIR} ${config})
cmake_parse_arguments(ARGS
"BUILD;INSTALL;TEST;COPY_QUERIES;NO_WARN;STATIC_QUERY;DYNAMIC_QUERY;INSTALL_PARALLEL;MANUAL_HOOK"
"BUILD;BUILD_MAKE_PROGRAM;INSTALL;TEST;COPY_QUERIES;NO_WARN;STATIC_QUERY;DYNAMIC_QUERY;INSTALL_PARALLEL;MANUAL_HOOK"
"CHECK_SCRIPT;CONFIGURE_ARG" "" ${ARGN})
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test})
set(uuid "a37d1069-1972-4901-b9c9-f194aaf2b6e0")
@@ -58,6 +58,9 @@ function(instrument test)
if (ARGS_BUILD)
run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Debug)
endif()
if (ARGS_BUILD_MAKE_PROGRAM)
run_cmake_command(${test}-make-program ${RunCMake_MAKE_PROGRAM})
endif()
if (ARGS_INSTALL)
run_cmake_command(${test}-install ${CMAKE_COMMAND} --install . --prefix install --config Debug)
endif()
@@ -112,3 +115,8 @@ instrument(cmake-command-bad-arg NO_WARN)
instrument(cmake-command-parallel-install
BUILD INSTALL TEST NO_WARN INSTALL_PARALLEL DYNAMIC_QUERY
CHECK_SCRIPT check-data-dir.cmake)
if (UNIX AND ${RunCMake_GENERATOR} MATCHES "^Ninja")
instrument(cmake-command-ninja NO_WARN
BUILD_MAKE_PROGRAM
CHECK_SCRIPT check-ninja-hooks.cmake)
endif()

View File

@@ -0,0 +1,35 @@
set(NUM_TRIES 30)
set(DELAY 1)
if (NOT EXISTS ${v1}/preBuild.hook)
set(RunCMake_TEST_FAILED "preBuild hook did not run\n")
endif()
macro(hasPostBuildArtifacts)
if (NOT postBuildRan AND EXISTS ${v1}/postBuild.hook)
set(postBuildRan 1)
endif()
if (NOT dataDirClean)
file(GLOB snippets "${v1}/data/*")
if ("${snippets}" STREQUAL "")
set(dataDirClean 1)
endif()
endif()
endmacro()
set(postBuildRan 0)
set(dataDirClean 0)
foreach(_ RANGE ${NUM_TRIES})
hasPostBuildArtifacts()
if (postBuildRan AND dataDirClean)
break()
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${DELAY})
endforeach()
if (NOT postBuildRan)
string(APPEND RunCMake_TEST_FAILED "postBuild hook did not run\n")
endif()
if (NOT dataDirClean)
string(APPEND RunCMake_TEST_FAILED "Snippet files not fully removed post build\n")
endif()

View File

@@ -68,3 +68,7 @@ has_key(vendorString ${staticSystemInformation} ${hasStaticInfo})
if (NOT ERROR_MESSAGE MATCHES "^$")
message(FATAL_ERROR ${ERROR_MESSAGE})
endif()
get_filename_component(dataDir ${index} DIRECTORY)
get_filename_component(v1 ${dataDir} DIRECTORY)
file(TOUCH ${v1}/${hook}.hook)

View File

@@ -0,0 +1,6 @@
cmake_instrumentation(
API_VERSION 1
DATA_VERSION 1
HOOKS preBuild postBuild
CALLBACK "\"${CMAKE_COMMAND}\" -P \"${CMAKE_SOURCE_DIR}/../hook.cmake\" 0"
)

View File

@@ -8,7 +8,7 @@
API_VERSION 1
DATA_VERSION 1
HOOKS postGenerate
CALLBACK "\"${CMAKE_COMMAND}\" -E echo callback1"
CALLBACK \"${CMAKE_COMMAND}\" -E echo callback1
)
# Query 2
cmake_instrumentation(
@@ -16,5 +16,6 @@
DATA_VERSION 1
HOOKS postCMakeBuild
QUERIES staticSystemInformation dynamicSystemInformation
CALLBACK "\"${CMAKE_COMMAND}\" -E echo callback2"
CALLBACK \"${CMAKE_COMMAND}\" -E echo callback2
CALLBACK \"${CMAKE_COMMAND}\" -E echo callback3
)

View File

@@ -1,7 +1,8 @@
{
"callbacks" :
[
"\"@CMAKE_COMMAND@\" -E echo callback2"
"\"@CMAKE_COMMAND@\" -E echo callback2",
"\"@CMAKE_COMMAND@\" -E echo callback3"
],
"hooks" :
[