1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-20 04:24:36 +08:00

instrumentation: Support preBuild and postBuild hooks on Windows

* Use `uv_disable_stdio_inheritance` to resolve the deadlock between the
parent build system process and `ctest
--wait-and-collect-instrumentation` on Windows.
* Remove Windows gating from preBuild and postBuild indexing and update
tests and documentation accordingly.

Fixes: #26668
This commit is contained in:
Tyler Yankee
2025-07-07 13:43:55 -04:00
committed by Brad King
parent 6d6c8303f9
commit 7dbe092d77
6 changed files with 36 additions and 18 deletions

View File

@@ -189,8 +189,8 @@ key is required, but all other fields are optional.
should be one of the following: should be one of the following:
* ``postGenerate`` * ``postGenerate``
* ``preBuild`` (called when ``ninja`` or ``make`` is invoked; unavailable on Windows) * ``preBuild`` (called when ``ninja`` or ``make`` is invoked)
* ``postBuild`` (called when ``ninja`` or ``make`` completes; unavailable on Windows) * ``postBuild`` (called when ``ninja`` or ``make`` completes)
* ``preCMakeBuild`` (called when ``cmake --build`` is invoked) * ``preCMakeBuild`` (called when ``cmake --build`` is invoked)
* ``postCMakeBuild`` (called when ``cmake --build`` completes) * ``postCMakeBuild`` (called when ``cmake --build`` completes)
* ``postInstall`` * ``postInstall``

View File

@@ -1772,8 +1772,7 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
this->WriteTargetRebuildManifest(os); this->WriteTargetRebuildManifest(os);
this->WriteTargetClean(os); this->WriteTargetClean(os);
this->WriteTargetHelp(os); this->WriteTargetHelp(os);
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) #ifndef CMAKE_BOOTSTRAP
// FIXME(#26668) This does not work on Windows
if (this->GetCMakeInstance() if (this->GetCMakeInstance()
->GetInstrumentation() ->GetInstrumentation()
->HasPreOrPostBuildHook()) { ->HasPreOrPostBuildHook()) {
@@ -1854,8 +1853,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
} }
reBuild.ImplicitDeps.push_back(this->CMakeCacheFile); reBuild.ImplicitDeps.push_back(this->CMakeCacheFile);
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) #ifndef CMAKE_BOOTSTRAP
// FIXME(#26668) This does not work on Windows
if (this->GetCMakeInstance() if (this->GetCMakeInstance()
->GetInstrumentation() ->GetInstrumentation()
->HasPreOrPostBuildHook()) { ->HasPreOrPostBuildHook()) {
@@ -2208,8 +2206,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
} }
} }
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) #ifndef CMAKE_BOOTSTRAP
// FIXME(#26668) This does not work on Windows
void cmGlobalNinjaGenerator::WriteTargetInstrument(std::ostream& os) void cmGlobalNinjaGenerator::WriteTargetInstrument(std::ostream& os)
{ {
// Write rule // Write rule
@@ -2218,11 +2215,13 @@ void cmGlobalNinjaGenerator::WriteTargetInstrument(std::ostream& os)
rule.Command = cmStrCat( rule.Command = cmStrCat(
'"', cmSystemTools::GetCTestCommand(), "\" --start-instrumentation \"", '"', cmSystemTools::GetCTestCommand(), "\" --start-instrumentation \"",
this->GetCMakeInstance()->GetHomeOutputDirectory(), '"'); this->GetCMakeInstance()->GetHomeOutputDirectory(), '"');
# ifndef _WIN32
/* /*
* On Unix systems, Ninja will prefix the command with `/bin/sh -c`. * On Unix systems, Ninja will prefix the command with `/bin/sh -c`.
* Use exec so that Ninja is the parent process of the command. * Use exec so that Ninja is the parent process of the command.
*/ */
rule.Command = cmStrCat("exec ", rule.Command); rule.Command = cmStrCat("exec ", rule.Command);
# endif
rule.Description = "Collecting build metrics"; rule.Description = "Collecting build metrics";
rule.Comment = "Rule to initialize instrumentation daemon."; rule.Comment = "Rule to initialize instrumentation daemon.";
rule.Restat = "1"; rule.Restat = "1";

View File

@@ -535,8 +535,7 @@ private:
void WriteTargetRebuildManifest(std::ostream& os); void WriteTargetRebuildManifest(std::ostream& os);
bool WriteTargetCleanAdditional(std::ostream& os); bool WriteTargetCleanAdditional(std::ostream& os);
void WriteTargetClean(std::ostream& os); void WriteTargetClean(std::ostream& os);
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) #ifndef CMAKE_BOOTSTRAP
// FIXME(#26668) This does not work on Windows
void WriteTargetInstrument(std::ostream& os); void WriteTargetInstrument(std::ostream& os);
#endif #endif
void WriteTargetHelp(std::ostream& os); void WriteTargetHelp(std::ostream& os);

View File

@@ -621,6 +621,10 @@ std::string cmInstrumentation::ComputeSuffixTime()
*/ */
int cmInstrumentation::SpawnBuildDaemon() int cmInstrumentation::SpawnBuildDaemon()
{ {
// Do not inherit handles from the parent process, so that the daemon is
// fully detached. This helps prevent deadlock between the two.
uv_disable_stdio_inheritance();
// preBuild Hook // preBuild Hook
this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild); this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild);

View File

@@ -74,21 +74,22 @@ std::string cmSplitExtension(std::string const& in, std::string& base)
return ext; return ext;
} }
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) #ifndef CMAKE_BOOTSTRAP
// Helper function to add the Start Instrumentation command // Helper function to add the Start Instrumentation command
void addInstrumentationCommand(cmInstrumentation* instrumentation, void addInstrumentationCommand(cmInstrumentation* instrumentation,
std::vector<std::string>& commands) std::vector<std::string>& commands)
{ {
// FIXME(#26668) This does not work on Windows
if (instrumentation->HasPreOrPostBuildHook()) { if (instrumentation->HasPreOrPostBuildHook()) {
std::string instrumentationCommand = std::string instrumentationCommand =
"$(CTEST_COMMAND) --start-instrumentation $(CMAKE_BINARY_DIR)"; "$(CTEST_COMMAND) --start-instrumentation $(CMAKE_BINARY_DIR)";
# ifndef _WIN32
/* /*
* On Unix systems, Make will prefix the command with `/bin/sh -c`. * On Unix systems, Make will prefix the command with `/bin/sh -c`.
* Use exec so that Make is the parent process of the command. * Use exec so that Make is the parent process of the command.
* Add a `;` to convince BSD make to not optimize out the shell. * Add a `;` to convince BSD make to not optimize out the shell.
*/ */
instrumentationCommand = cmStrCat("exec ", instrumentationCommand, " ;"); instrumentationCommand = cmStrCat("exec ", instrumentationCommand, " ;");
# endif
commands.push_back(instrumentationCommand); commands.push_back(instrumentationCommand);
} }
} }
@@ -687,8 +688,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables(
"CMAKE_COMMAND = " "CMAKE_COMMAND = "
<< cmakeShellCommand << "\n"; << cmakeShellCommand << "\n";
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) #ifndef CMAKE_BOOTSTRAP
// FIXME(#26668) This does not work on Windows
if (this->GetCMakeInstance() if (this->GetCMakeInstance()
->GetInstrumentation() ->GetInstrumentation()
->HasPreOrPostBuildHook()) { ->HasPreOrPostBuildHook()) {
@@ -849,7 +849,7 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
std::vector<std::string> no_depends; std::vector<std::string> no_depends;
commands.push_back(std::move(runRule)); commands.push_back(std::move(runRule));
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) #ifndef CMAKE_BOOTSTRAP
addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(), addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(),
commands); commands);
#endif #endif
@@ -1855,7 +1855,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL), this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
" 1"); " 1");
commands.push_back(std::move(runRule)); commands.push_back(std::move(runRule));
#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) #ifndef CMAKE_BOOTSTRAP
addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(), addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(),
commands); commands);
#endif #endif

View File

@@ -129,8 +129,24 @@ instrument(cmake-command-resets-generated NO_WARN
CHECK_SCRIPT check-data-dir.cmake CHECK_SCRIPT check-data-dir.cmake
) )
# FIXME(#26668) This does not work on Windows if(RunCMake_GENERATOR STREQUAL "NMake Makefiles")
if (UNIX) execute_process(
COMMAND "${RunCMake_MAKE_PROGRAM}" -?
OUTPUT_VARIABLE nmake_out
ERROR_VARIABLE nmake_out
RESULT_VARIABLE nmake_res
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(nmake_res EQUAL 0 AND nmake_out MATCHES "Program Maintenance Utility[^\n]+Version ([1-9][0-9.]+)")
set(nmake_version "${CMAKE_MATCH_1}")
else()
message(FATAL_ERROR "'nmake -?' reported:\n${nmake_out}")
endif()
if(nmake_version VERSION_LESS 9)
set(Skip_BUILD_MAKE_PROGRAM_Case 1)
endif()
endif()
if(NOT Skip_BUILD_MAKE_PROGRAM_Case)
instrument(cmake-command-make-program NO_WARN instrument(cmake-command-make-program NO_WARN
BUILD_MAKE_PROGRAM BUILD_MAKE_PROGRAM
CHECK_SCRIPT check-make-program-hooks.cmake) CHECK_SCRIPT check-make-program-hooks.cmake)