cmMakefile: Add OnExecuteCommand callback

In cmCTestScriptHandler, port away from cmFunctionBlocker
and update the elapsed time with the new callback instead.
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 7a5b8d1..f8d9f1b 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -24,7 +24,6 @@
 #include "cmCTestUploadCommand.h"
 #include "cmCommand.h"
 #include "cmDuration.h"
-#include "cmFunctionBlocker.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
@@ -49,32 +48,8 @@
 #  include <unistd.h>
 #endif
 
-class cmExecutionStatus;
-struct cmListFileFunction;
-
 #define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log"
 
-// used to keep elapsed time up to date
-class cmCTestScriptFunctionBlocker : public cmFunctionBlocker
-{
-public:
-  bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf,
-                         cmExecutionStatus& /*status*/) override;
-  // virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf);
-  // virtual void ScopeEnded(cmMakefile &mf);
-
-  cmCTestScriptHandler* CTestScriptHandler;
-};
-
-// simply update the time and don't block anything
-bool cmCTestScriptFunctionBlocker::IsFunctionBlocked(
-  const cmListFileFunction& /*lff*/, cmMakefile& /*mf*/,
-  cmExecutionStatus& /*status*/)
-{
-  this->CTestScriptHandler->UpdateElapsedTime();
-  return false;
-}
-
 cmCTestScriptHandler::cmCTestScriptHandler()
 {
   this->Backup = false;
@@ -373,12 +348,8 @@
   this->Makefile->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
 #endif
 
-  // always add a function blocker to update the elapsed time
-  {
-    auto fb = cm::make_unique<cmCTestScriptFunctionBlocker>();
-    fb->CTestScriptHandler = this;
-    this->Makefile->AddFunctionBlocker(std::move(fb));
-  }
+  // set a callback function to update the elapsed time
+  this->Makefile->OnExecuteCommand([this] { this->UpdateElapsedTime(); });
 
   /* Execute CTestScriptMode.cmake, which loads CMakeDetermineSystem and
   CMakeSystemSpecificInformation, so
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 8188ffa..f297fdf 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -353,6 +353,11 @@
   cmMakefile* Makefile;
 };
 
+void cmMakefile::OnExecuteCommand(std::function<void()> callback)
+{
+  this->ExecuteCommandCallback = std::move(callback);
+}
+
 bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
                                 cmExecutionStatus& status)
 {
@@ -364,6 +369,10 @@
     return result;
   }
 
+  if (this->ExecuteCommandCallback) {
+    this->ExecuteCommandCallback();
+  }
+
   // Place this call on the call stack.
   cmMakefileCall stack_manager(this, lff, status);
   static_cast<void>(stack_manager);
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index dc196ac..941e335 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -628,6 +628,11 @@
   void PrintCommandTrace(const cmListFileFunction& lff) const;
 
   /**
+   * Set a callback that is invoked whenever ExecuteCommand is called.
+   */
+  void OnExecuteCommand(std::function<void()> callback);
+
+  /**
    * Execute a single CMake command.  Returns true if the command
    * succeeded or false if it failed.
    */
@@ -964,6 +969,7 @@
   bool EnforceUniqueDir(const std::string& srcPath,
                         const std::string& binPath) const;
 
+  std::function<void()> ExecuteCommandCallback;
   using FunctionBlockerPtr = std::unique_ptr<cmFunctionBlocker>;
   using FunctionBlockersType =
     std::stack<FunctionBlockerPtr, std::vector<FunctionBlockerPtr>>;