From 314440c32077dc2a902a494a99b96437d93af5b4 Mon Sep 17 00:00:00 2001 From: Martin Duffy Date: Wed, 5 Feb 2025 13:43:30 -0500 Subject: [PATCH] instrumentation: Run preBuild and postBuild hooks before and after make Updates the preBuild and postBuild instrumentation hooks to run before and after make is invoked. --- Help/manual/cmake-instrumentation.7.rst | 4 +- Source/cmLocalUnixMakefileGenerator3.cxx | 61 ++++++++++++++++--- .../Instrumentation/RunCMakeTest.cmake | 6 +- ...s.cmake => check-make-program-hooks.cmake} | 0 .../Instrumentation/project/CMakeLists.txt | 1 + .../query/cmake-command-make-program.cmake | 7 +++ .../query/cmake-command-ninja.cmake | 6 -- 7 files changed, 66 insertions(+), 19 deletions(-) rename Tests/RunCMake/Instrumentation/{check-ninja-hooks.cmake => check-make-program-hooks.cmake} (100%) create mode 100644 Tests/RunCMake/Instrumentation/query/cmake-command-make-program.cmake delete mode 100644 Tests/RunCMake/Instrumentation/query/cmake-command-ninja.cmake diff --git a/Help/manual/cmake-instrumentation.7.rst b/Help/manual/cmake-instrumentation.7.rst index d3a161964c..c3ebc7596f 100644 --- a/Help/manual/cmake-instrumentation.7.rst +++ b/Help/manual/cmake-instrumentation.7.rst @@ -117,8 +117,8 @@ optional. should be one of the following: * ``postGenerate`` - * ``preBuild`` (called when ``ninja`` is invoked; unavailable on Windows) - * ``postBuild`` (called when ``ninja`` completes; unavailable on Windows) + * ``preBuild`` (called when ``ninja`` or ``make`` is invoked; unavailable on Windows) + * ``postBuild`` (called when ``ninja`` or ``make`` completes; unavailable on Windows) * ``preCMakeBuild`` (called when ``cmake --build`` is invoked) * ``postCMakeBuild`` (called when ``cmake --build`` completes) * ``postInstall`` diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 1256592b17..68c79ed334 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -28,6 +28,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmInstrumentation.h" #include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" @@ -71,6 +72,26 @@ std::string cmSplitExtension(std::string const& in, std::string& base) return ext; } +#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) +// Helper function to add the Start Instrumentation command +void addInstrumentationCommand(cmInstrumentation* instrumentation, + std::vector& commands) +{ + // FIXME(#26668) This does not work on Windows + if (instrumentation->HasPreOrPostBuildHook()) { + std::string instrumentationCommand = + "$(CTEST_COMMAND) --start-instrumentation $(CMAKE_BINARY_DIR)"; + /* + * On Unix systems, Make will prefix the command with `/bin/sh -c`. + * Use exec so that Make is the parent process of the command. + * Add a `;` to convince BSD make to not optimize out the shell. + */ + instrumentationCommand = cmStrCat("exec ", instrumentationCommand, " ;"); + commands.push_back(instrumentationCommand); + } +} +#endif + // Helper predicate for removing absolute paths that don't point to the // source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY // is set ON, to only consider in-project dependencies during the build. @@ -651,19 +672,35 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( #endif } + auto getShellCommand = [this](std::string command) -> std::string { + std::string shellCommand = this->MaybeConvertWatcomShellCommand(command); + return shellCommand.empty() + ? this->ConvertToOutputFormat(command, cmOutputConverter::SHELL) + : shellCommand; + }; + std::string cmakeShellCommand = - this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand()); - if (cmakeShellCommand.empty()) { - cmakeShellCommand = this->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); + getShellCommand(cmSystemTools::GetCMakeCommand()); + + makefileStream << "# The CMake executable.\n" + "CMAKE_COMMAND = " + << cmakeShellCommand << "\n"; + +#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) + // FIXME(#26668) This does not work on Windows + if (this->GetCMakeInstance() + ->GetInstrumentation() + ->HasPreOrPostBuildHook()) { + std::string ctestShellCommand = + getShellCommand(cmSystemTools::GetCTestCommand()); + makefileStream << "# The CTest executable.\n" + "CTEST_COMMAND = " + << ctestShellCommand << "\n"; } +#endif makefileStream - << "# The CMake executable.\n" - "CMAKE_COMMAND = " - << cmakeShellCommand << "\n" - "\n" "# The command to remove a file.\n" "RM = " << cmakeShellCommand @@ -811,6 +848,10 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( std::vector no_depends; commands.push_back(std::move(runRule)); +#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) + addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(), + commands); +#endif if (!this->IsRootMakefile()) { this->CreateCDCommand(commands, this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory()); @@ -1808,6 +1849,10 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL), " 1"); commands.push_back(std::move(runRule)); +#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) + addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(), + commands); +#endif } this->CreateCDCommand(commands, this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory()); diff --git a/Tests/RunCMake/Instrumentation/RunCMakeTest.cmake b/Tests/RunCMake/Instrumentation/RunCMakeTest.cmake index f98bb32c20..c270b714cd 100644 --- a/Tests/RunCMake/Instrumentation/RunCMakeTest.cmake +++ b/Tests/RunCMake/Instrumentation/RunCMakeTest.cmake @@ -117,8 +117,8 @@ instrument(cmake-command-parallel-install CHECK_SCRIPT check-data-dir.cmake) # FIXME(#26668) This does not work on Windows -if (UNIX AND ${RunCMake_GENERATOR} MATCHES "^Ninja") - instrument(cmake-command-ninja NO_WARN +if (UNIX) + instrument(cmake-command-make-program NO_WARN BUILD_MAKE_PROGRAM - CHECK_SCRIPT check-ninja-hooks.cmake) + CHECK_SCRIPT check-make-program-hooks.cmake) endif() diff --git a/Tests/RunCMake/Instrumentation/check-ninja-hooks.cmake b/Tests/RunCMake/Instrumentation/check-make-program-hooks.cmake similarity index 100% rename from Tests/RunCMake/Instrumentation/check-ninja-hooks.cmake rename to Tests/RunCMake/Instrumentation/check-make-program-hooks.cmake diff --git a/Tests/RunCMake/Instrumentation/project/CMakeLists.txt b/Tests/RunCMake/Instrumentation/project/CMakeLists.txt index 30b28c6b2b..0d90faff9f 100644 --- a/Tests/RunCMake/Instrumentation/project/CMakeLists.txt +++ b/Tests/RunCMake/Instrumentation/project/CMakeLists.txt @@ -13,6 +13,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E true OUTPUT output1 output2 ) +set_property(SOURCE output1 output2 PROPERTY SYMBOLIC 1) add_custom_target(customTarget ALL DEPENDS output1 ) diff --git a/Tests/RunCMake/Instrumentation/query/cmake-command-make-program.cmake b/Tests/RunCMake/Instrumentation/query/cmake-command-make-program.cmake new file mode 100644 index 0000000000..807d9915b5 --- /dev/null +++ b/Tests/RunCMake/Instrumentation/query/cmake-command-make-program.cmake @@ -0,0 +1,7 @@ +file(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}/../hook.cmake" hook_path) +cmake_instrumentation( + API_VERSION 1 + DATA_VERSION 1 + HOOKS preBuild postBuild + CALLBACK "\"${CMAKE_COMMAND}\" -P \"${hook_path}\" 0" +) diff --git a/Tests/RunCMake/Instrumentation/query/cmake-command-ninja.cmake b/Tests/RunCMake/Instrumentation/query/cmake-command-ninja.cmake deleted file mode 100644 index 60acebdcd6..0000000000 --- a/Tests/RunCMake/Instrumentation/query/cmake-command-ninja.cmake +++ /dev/null @@ -1,6 +0,0 @@ -cmake_instrumentation( - API_VERSION 1 - DATA_VERSION 1 - HOOKS preBuild postBuild - CALLBACK "\"${CMAKE_COMMAND}\" -P \"${CMAKE_SOURCE_DIR}/../hook.cmake\" 0" -)