Browse Source

Merge topic 'ctest-chrono'

e6a80ccf Make use of std::chrono throughout every component
ff62b005 CTest: add safe conversion from cmDuration to integer types
695951bc CTest: introduce cmDuration

Acked-by: Kitware Robot <[email protected]>
Merge-request: !1592
Brad King 7 years ago
parent
commit
f343106b19
38 changed files with 272 additions and 212 deletions
  1. 3 0
      Source/CMakeLists.txt
  2. 7 6
      Source/CPack/IFW/cmCPackIFWGenerator.cxx
  3. 4 3
      Source/CPack/cmCPackDragNDropGenerator.cxx
  4. 6 4
      Source/CPack/cmCPackGenerator.cxx
  5. 10 9
      Source/CPack/cmCPackNSISGenerator.cxx
  6. 4 3
      Source/CPack/cmCPackOSXX11Generator.cxx
  7. 6 4
      Source/CPack/cmCPackPackageMakerGenerator.cxx
  8. 4 3
      Source/CPack/cmCPackProductBuildGenerator.cxx
  9. 7 7
      Source/CTest/cmCTestBuildAndTestHandler.cxx
  10. 2 2
      Source/CTest/cmCTestBuildAndTestHandler.h
  11. 3 2
      Source/CTest/cmCTestBuildHandler.cxx
  12. 2 2
      Source/CTest/cmCTestBuildHandler.h
  13. 4 3
      Source/CTest/cmCTestConfigureHandler.cxx
  14. 11 10
      Source/CTest/cmCTestCoverageHandler.cxx
  15. 11 12
      Source/CTest/cmCTestMemCheckHandler.cxx
  16. 16 25
      Source/CTest/cmCTestRunTest.cxx
  17. 2 3
      Source/CTest/cmCTestRunTest.h
  18. 22 20
      Source/CTest/cmCTestScriptHandler.cxx
  19. 2 1
      Source/CTest/cmCTestScriptHandler.h
  20. 2 1
      Source/CTest/cmCTestSubmitHandler.cxx
  21. 4 3
      Source/CTest/cmCTestTestCommand.cxx
  22. 8 9
      Source/CTest/cmCTestTestHandler.cxx
  23. 5 4
      Source/CTest/cmCTestTestHandler.h
  24. 5 5
      Source/CTest/cmProcess.cxx
  25. 6 5
      Source/CTest/cmProcess.h
  26. 20 28
      Source/cmCTest.cxx
  27. 11 15
      Source/cmCTest.h
  28. 27 0
      Source/cmDuration.cxx
  29. 24 0
      Source/cmDuration.h
  30. 3 2
      Source/cmGlobalGenerator.cxx
  31. 4 3
      Source/cmGlobalGenerator.h
  32. 3 2
      Source/cmQtAutoGenInitializer.cxx
  33. 8 5
      Source/cmSystemTools.cxx
  34. 4 3
      Source/cmSystemTools.h
  35. 2 2
      Source/cmTryRunCommand.cxx
  36. 3 2
      Source/cmake.cxx
  37. 5 2
      Source/cmakexbuild.cxx
  38. 2 2
      Source/cmcmd.cxx

+ 3 - 0
Source/CMakeLists.txt

@@ -602,6 +602,9 @@ set(SRCS
   cm_codecvt.hxx
   cm_codecvt.cxx
   cm_thread.hxx
+
+  cmDuration.h
+  cmDuration.cxx
   )
 
 SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS

+ 7 - 6
Source/CPack/IFW/cmCPackIFWGenerator.cxx

@@ -9,6 +9,7 @@
 #include "cmCPackIFWPackage.h"
 #include "cmCPackIFWRepository.h"
 #include "cmCPackLog.h" // IWYU pragma: keep
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSystemTools.h"
 
@@ -84,9 +85,9 @@ int cmCPackIFWGenerator::PackageFiles()
     std::string output;
     int retVal = 1;
     cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl);
-    bool res = cmSystemTools::RunSingleCommand(ifwCmd.c_str(), &output,
-                                               &output, &retVal, nullptr,
-                                               this->GeneratorVerbose, 0);
+    bool res = cmSystemTools::RunSingleCommand(
+      ifwCmd.c_str(), &output, &output, &retVal, nullptr,
+      this->GeneratorVerbose, cmDuration::zero());
     if (!res || retVal) {
       cmGeneratedFileStream ofs(ifwTmpFile.c_str());
       ofs << "# Run command: " << ifwCmd << std::endl
@@ -194,9 +195,9 @@ int cmCPackIFWGenerator::PackageFiles()
     std::string output;
     int retVal = 1;
     cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl);
-    bool res = cmSystemTools::RunSingleCommand(ifwCmd.c_str(), &output,
-                                               &output, &retVal, nullptr,
-                                               this->GeneratorVerbose, 0);
+    bool res = cmSystemTools::RunSingleCommand(
+      ifwCmd.c_str(), &output, &output, &retVal, nullptr,
+      this->GeneratorVerbose, cmDuration::zero());
     if (!res || retVal) {
       cmGeneratedFileStream ofs(ifwTmpFile.c_str());
       ofs << "# Run command: " << ifwCmd << std::endl

+ 4 - 3
Source/CPack/cmCPackDragNDropGenerator.cxx

@@ -4,6 +4,7 @@
 
 #include "cmCPackGenerator.h"
 #include "cmCPackLog.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSystemTools.h"
 
@@ -242,9 +243,9 @@ bool cmCPackDragNDropGenerator::RunCommand(std::ostringstream& command,
 {
   int exit_code = 1;
 
-  bool result = cmSystemTools::RunSingleCommand(command.str().c_str(), output,
-                                                output, &exit_code, nullptr,
-                                                this->GeneratorVerbose, 0);
+  bool result = cmSystemTools::RunSingleCommand(
+    command.str().c_str(), output, output, &exit_code, nullptr,
+    this->GeneratorVerbose, cmDuration::zero());
 
   if (!result || exit_code) {
     cmCPackLogger(cmCPackLog::LOG_ERROR, "Error executing: " << command.str()

+ 6 - 4
Source/CPack/cmCPackGenerator.cxx

@@ -12,6 +12,7 @@
 #include "cmCPackComponentGroup.h"
 #include "cmCPackLog.h"
 #include "cmCryptoHash.h"
+#include "cmDuration.h"
 #include "cmFSPermissions.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
@@ -277,9 +278,9 @@ int cmCPackGenerator::InstallProjectViaInstallCommands(
       cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ic << std::endl);
       std::string output;
       int retVal = 1;
-      bool resB =
-        cmSystemTools::RunSingleCommand(ic.c_str(), &output, &output, &retVal,
-                                        nullptr, this->GeneratorVerbose, 0);
+      bool resB = cmSystemTools::RunSingleCommand(
+        ic.c_str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+        cmDuration::zero());
       if (!resB || retVal) {
         std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
         tmpFile += "/InstallOutput.log";
@@ -601,7 +602,8 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
         int retVal = 1;
         bool resB = cmSystemTools::RunSingleCommand(
           buildCommand.c_str(), &output, &output, &retVal,
-          installDirectory.c_str(), this->GeneratorVerbose, 0);
+          installDirectory.c_str(), this->GeneratorVerbose,
+          cmDuration::zero());
         if (!resB || retVal) {
           std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
           tmpFile += "/PreinstallOutput.log";

+ 10 - 9
Source/CPack/cmCPackNSISGenerator.cxx

@@ -5,6 +5,7 @@
 #include "cmCPackComponentGroup.h"
 #include "cmCPackGenerator.h"
 #include "cmCPackLog.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSystemTools.h"
 
@@ -301,9 +302,9 @@ int cmCPackNSISGenerator::PackageFiles()
   cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd << std::endl);
   std::string output;
   int retVal = 1;
-  bool res =
-    cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output, &output, &retVal,
-                                    nullptr, this->GeneratorVerbose, 0);
+  bool res = cmSystemTools::RunSingleCommand(
+    nsisCmd.c_str(), &output, &output, &retVal, nullptr,
+    this->GeneratorVerbose, cmDuration::zero());
   if (!res || retVal) {
     cmGeneratedFileStream ofs(tmpFile.c_str());
     ofs << "# Run command: " << nsisCmd << std::endl
@@ -400,9 +401,9 @@ int cmCPackNSISGenerator::InitializeInternal()
                                                                << std::endl);
   std::string output;
   int retVal = 1;
-  bool resS =
-    cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output, &output, &retVal,
-                                    nullptr, this->GeneratorVerbose, 0);
+  bool resS = cmSystemTools::RunSingleCommand(
+    nsisCmd.c_str(), &output, &output, &retVal, nullptr,
+    this->GeneratorVerbose, cmDuration::zero());
   cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
   cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs");
   if (!resS || retVal ||
@@ -737,9 +738,9 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
                                       zipListFileName.c_str());
     std::string output;
     int retVal = -1;
-    int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, &output,
-                                              &retVal, dirName.c_str(),
-                                              cmSystemTools::OUTPUT_NONE, 0);
+    int res = cmSystemTools::RunSingleCommand(
+      cmd.c_str(), &output, &output, &retVal, dirName.c_str(),
+      cmSystemTools::OUTPUT_NONE, cmDuration::zero());
     if (!res || retVal) {
       std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
       tmpFile += "/CompressZip.log";

+ 4 - 3
Source/CPack/cmCPackOSXX11Generator.cxx

@@ -6,6 +6,7 @@
 
 #include "cmCPackGenerator.h"
 #include "cmCPackLog.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSystemTools.h"
 #include "cm_sys_stat.h"
@@ -154,9 +155,9 @@ int cmCPackOSXX11Generator::PackageFiles()
   int numTries = 10;
   bool res = false;
   while (numTries > 0) {
-    res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output,
-                                          &output, &retVal, nullptr,
-                                          this->GeneratorVerbose, 0);
+    res = cmSystemTools::RunSingleCommand(
+      dmgCmd.str().c_str(), &output, &output, &retVal, nullptr,
+      this->GeneratorVerbose, cmDuration::zero());
     if (res && !retVal) {
       numTries = -1;
       break;

+ 6 - 4
Source/CPack/cmCPackPackageMakerGenerator.cxx

@@ -13,6 +13,7 @@
 
 #include "cmCPackComponentGroup.h"
 #include "cmCPackLog.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSystemTools.h"
 #include "cmXMLWriter.h"
@@ -295,9 +296,9 @@ int cmCPackPackageMakerGenerator::PackageFiles()
   int numTries = 10;
   bool res = false;
   while (numTries > 0) {
-    res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output,
-                                          &output, &retVal, nullptr,
-                                          this->GeneratorVerbose, 0);
+    res = cmSystemTools::RunSingleCommand(
+      dmgCmd.str().c_str(), &output, &output, &retVal, nullptr,
+      this->GeneratorVerbose, cmDuration::zero());
     if (res && !retVal) {
       numTries = -1;
       break;
@@ -467,7 +468,8 @@ bool cmCPackPackageMakerGenerator::RunPackageMaker(const char* command,
   std::string output;
   int retVal = 1;
   bool res = cmSystemTools::RunSingleCommand(
-    command, &output, &output, &retVal, nullptr, this->GeneratorVerbose, 0);
+    command, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+    cmDuration::zero());
   cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running package maker"
                   << std::endl);
   if (!res || retVal) {

+ 4 - 3
Source/CPack/cmCPackProductBuildGenerator.cxx

@@ -8,6 +8,7 @@
 
 #include "cmCPackComponentGroup.h"
 #include "cmCPackLog.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSystemTools.h"
 
@@ -145,9 +146,9 @@ bool cmCPackProductBuildGenerator::RunProductBuild(const std::string& command)
   cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);
   std::string output, error_output;
   int retVal = 1;
-  bool res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
-                                             &error_output, &retVal, nullptr,
-                                             this->GeneratorVerbose, 0);
+  bool res = cmSystemTools::RunSingleCommand(
+    command.c_str(), &output, &error_output, &retVal, nullptr,
+    this->GeneratorVerbose, cmDuration::zero());
   cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl);
   if (!res || retVal) {
     cmGeneratedFileStream ofs(tmpFile.c_str());

+ 7 - 7
Source/CTest/cmCTestBuildAndTestHandler.cxx

@@ -19,7 +19,7 @@ cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
   this->BuildTwoConfig = false;
   this->BuildNoClean = false;
   this->BuildNoCMake = false;
-  this->Timeout = std::chrono::duration<double>::zero();
+  this->Timeout = cmDuration::zero();
 }
 
 void cmCTestBuildAndTestHandler::Initialize()
@@ -224,8 +224,8 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
     this->BuildTargets.push_back("");
   }
   for (std::string const& tar : this->BuildTargets) {
-    std::chrono::duration<double> remainingTime = std::chrono::seconds(0);
-    if (this->Timeout > std::chrono::duration<double>::zero()) {
+    cmDuration remainingTime = std::chrono::seconds(0);
+    if (this->Timeout > cmDuration::zero()) {
       remainingTime =
         this->Timeout - (std::chrono::steady_clock::now() - clock_start);
       if (remainingTime <= std::chrono::seconds(0)) {
@@ -251,7 +251,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
     int retVal = cm.GetGlobalGenerator()->Build(
       this->SourceDir, this->BinaryDir, this->BuildProject, tar, output,
       this->BuildMakeProgram, config, !this->BuildNoClean, false, false,
-      remainingTime.count());
+      remainingTime);
     out << output;
     // if the build failed then return
     if (retVal) {
@@ -323,8 +323,8 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
   out << "\n";
 
   // how much time is remaining
-  std::chrono::duration<double> remainingTime = std::chrono::seconds(0);
-  if (this->Timeout > std::chrono::duration<double>::zero()) {
+  cmDuration remainingTime = std::chrono::seconds(0);
+  if (this->Timeout > cmDuration::zero()) {
     remainingTime =
       this->Timeout - (std::chrono::steady_clock::now() - clock_start);
     if (remainingTime <= std::chrono::seconds(0)) {
@@ -395,7 +395,7 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
   }
   if (currentArg.find("--test-timeout", 0) == 0 && idx < allArgs.size() - 1) {
     idx++;
-    this->Timeout = std::chrono::duration<double>(atof(allArgs[idx].c_str()));
+    this->Timeout = cmDuration(atof(allArgs[idx].c_str()));
   }
   if (currentArg == "--build-generator" && idx < allArgs.size() - 1) {
     idx++;

+ 2 - 2
Source/CTest/cmCTestBuildAndTestHandler.h

@@ -6,8 +6,8 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include "cmCTestGenericHandler.h"
+#include "cmDuration.h"
 
-#include <chrono>
 #include <sstream>
 #include <stddef.h>
 #include <string>
@@ -68,7 +68,7 @@ protected:
   std::vector<std::string> TestCommandArgs;
   std::vector<std::string> BuildTargets;
   bool BuildNoCMake;
-  std::chrono::duration<double> Timeout;
+  cmDuration Timeout;
 };
 
 #endif

+ 3 - 2
Source/CTest/cmCTestBuildHandler.cxx

@@ -4,6 +4,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmCTest.h"
+#include "cmDuration.h"
 #include "cmFileTimeComparison.h"
 #include "cmGeneratedFileStream.h"
 #include "cmMakefile.h"
@@ -633,8 +634,8 @@ void cmCTestBuildHandler::GenerateXMLLogScraped(cmXMLWriter& xml)
   }
 }
 
-void cmCTestBuildHandler::GenerateXMLFooter(
-  cmXMLWriter& xml, std::chrono::duration<double> elapsed_build_time)
+void cmCTestBuildHandler::GenerateXMLFooter(cmXMLWriter& xml,
+                                            cmDuration elapsed_build_time)
 {
   xml.StartElement("Log");
   xml.Attribute("Encoding", "base64");

+ 2 - 2
Source/CTest/cmCTestBuildHandler.h

@@ -7,6 +7,7 @@
 
 #include "cmCTestGenericHandler.h"
 
+#include "cmDuration.h"
 #include "cmProcessOutput.h"
 #include "cmsys/RegularExpression.hxx"
 #include <chrono>
@@ -87,8 +88,7 @@ private:
   void GenerateXMLHeader(cmXMLWriter& xml);
   void GenerateXMLLaunched(cmXMLWriter& xml);
   void GenerateXMLLogScraped(cmXMLWriter& xml);
-  void GenerateXMLFooter(cmXMLWriter& xml,
-                         std::chrono::duration<double> elapsed_build_time);
+  void GenerateXMLFooter(cmXMLWriter& xml, cmDuration elapsed_build_time);
   bool IsLaunchedErrorFile(const char* fname);
   bool IsLaunchedWarningFile(const char* fname);
 

+ 4 - 3
Source/CTest/cmCTestConfigureHandler.cxx

@@ -3,6 +3,7 @@
 #include "cmCTestConfigureHandler.h"
 
 #include "cmCTest.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmXMLWriter.h"
 
@@ -62,9 +63,9 @@ int cmCTestConfigureHandler::ProcessHandler()
     cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                        "Configure with command: " << cCommand << std::endl,
                        this->Quiet);
-    res = this->CTest->RunMakeCommand(
-      cCommand.c_str(), output, &retVal, buildDirectory.c_str(),
-      std::chrono::duration<double>::zero(), ofs);
+    res = this->CTest->RunMakeCommand(cCommand.c_str(), output, &retVal,
+                                      buildDirectory.c_str(),
+                                      cmDuration::zero(), ofs);
 
     if (ofs) {
       ofs.close();

+ 11 - 10
Source/CTest/cmCTestCoverageHandler.cxx

@@ -3,6 +3,7 @@
 #include "cmCTestCoverageHandler.h"
 
 #include "cmCTest.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmParseBlanketJSCoverage.h"
 #include "cmParseCacheCoverage.h"
@@ -40,7 +41,7 @@ public:
   {
     this->Process = cmsysProcess_New();
     this->PipeState = -1;
-    this->TimeOut = std::chrono::duration<double>(-1);
+    this->TimeOut = cmDuration(-1);
   }
   ~cmCTestRunProcess()
   {
@@ -64,7 +65,7 @@ public:
     }
   }
   void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
-  void SetTimeout(std::chrono::duration<double> t) { this->TimeOut = t; }
+  void SetTimeout(cmDuration t) { this->TimeOut = t; }
   bool StartProcess()
   {
     std::vector<const char*> args;
@@ -79,7 +80,7 @@ public:
     }
 
     cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
-    if (this->TimeOut >= std::chrono::duration<double>::zero()) {
+    if (this->TimeOut >= cmDuration::zero()) {
       cmsysProcess_SetTimeout(this->Process, this->TimeOut.count());
     }
     cmsysProcess_Execute(this->Process);
@@ -108,7 +109,7 @@ private:
   cmsysProcess* Process;
   std::vector<std::string> CommandLineStrings;
   std::string WorkingDirectory;
-  std::chrono::duration<double> TimeOut;
+  cmDuration TimeOut;
 };
 
 cmCTestCoverageHandler::cmCTestCoverageHandler()
@@ -1022,9 +1023,9 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
     int retVal = 0;
     *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
     *cont->OFS << "  Command: " << command << std::endl;
-    int res = this->CTest->RunCommand(
-      covargs, &output, &errors, &retVal, tempDir.c_str(),
-      std::chrono::duration<double>::zero() /*this->TimeOut*/);
+    int res = this->CTest->RunCommand(covargs, &output, &errors, &retVal,
+                                      tempDir.c_str(),
+                                      cmDuration::zero() /*this->TimeOut*/);
 
     *cont->OFS << "  Output: " << output << std::endl;
     *cont->OFS << "  Errors: " << errors << std::endl;
@@ -1387,9 +1388,9 @@ int cmCTestCoverageHandler::HandleLCovCoverage(
     int retVal = 0;
     *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
     *cont->OFS << "  Command: " << command << std::endl;
-    int res = this->CTest->RunCommand(
-      covargs, &output, &errors, &retVal, fileDir.c_str(),
-      std::chrono::duration<double>::zero() /*this->TimeOut*/);
+    int res = this->CTest->RunCommand(covargs, &output, &errors, &retVal,
+                                      fileDir.c_str(),
+                                      cmDuration::zero() /*this->TimeOut*/);
 
     *cont->OFS << "  Output: " << output << std::endl;
     *cont->OFS << "  Errors: " << errors << std::endl;

+ 11 - 12
Source/CTest/cmCTestMemCheckHandler.cxx

@@ -3,6 +3,7 @@
 #include "cmCTestMemCheckHandler.h"
 
 #include "cmCTest.h"
+#include "cmDuration.h"
 #include "cmSystemTools.h"
 #include "cmXMLParser.h"
 #include "cmXMLWriter.h"
@@ -920,12 +921,11 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
       break; // stop the copy of output if we are full
     }
   }
-  cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: "
-                       << std::chrono::duration_cast<std::chrono::seconds>(
-                            std::chrono::steady_clock::now() - sttime)
-                            .count()
-                       << "s)" << std::endl,
-                     this->Quiet);
+  cmCTestOptionalLog(
+    this->CTest, DEBUG, "End test (elapsed: "
+      << cmDurationTo<unsigned int>(std::chrono::steady_clock::now() - sttime)
+      << "s)" << std::endl,
+    this->Quiet);
   log = ostr.str();
   this->DefectCount += defects;
   return defects == 0;
@@ -966,12 +966,11 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
     results[err]++;
     defects++;
   }
-  cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: "
-                       << std::chrono::duration_cast<std::chrono::seconds>(
-                            std::chrono::steady_clock::now() - sttime)
-                            .count()
-                       << "s)" << std::endl,
-                     this->Quiet);
+  cmCTestOptionalLog(
+    this->CTest, DEBUG, "End test (elapsed: "
+      << cmDurationTo<unsigned int>(std::chrono::steady_clock::now() - sttime)
+      << "s)" << std::endl,
+    this->Quiet);
   if (defects) {
     // only put the output of Bounds Checker if there were
     // errors or leaks detected

+ 16 - 25
Source/CTest/cmCTestRunTest.cxx

@@ -25,7 +25,7 @@ cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler)
 {
   this->CTest = multiHandler.CTest;
   this->TestHandler = multiHandler.TestHandler;
-  this->TestResult.ExecutionTime = std::chrono::duration<double>::zero();
+  this->TestResult.ExecutionTime = cmDuration::zero();
   this->TestResult.ReturnValue = 0;
   this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
   this->TestResult.TestCount = 0;
@@ -400,7 +400,7 @@ bool cmCTestRunTest::StartTest(size_t total)
   // Return immediately if test is disabled
   if (this->TestProperties->Disabled) {
     this->TestResult.Properties = this->TestProperties;
-    this->TestResult.ExecutionTime = std::chrono::duration<double>::zero();
+    this->TestResult.ExecutionTime = cmDuration::zero();
     this->TestResult.CompressOutput = false;
     this->TestResult.ReturnValue = -1;
     this->TestResult.CompletionStatus = "Disabled";
@@ -415,7 +415,7 @@ bool cmCTestRunTest::StartTest(size_t total)
   }
 
   this->TestResult.Properties = this->TestProperties;
-  this->TestResult.ExecutionTime = std::chrono::duration<double>::zero();
+  this->TestResult.ExecutionTime = cmDuration::zero();
   this->TestResult.CompressOutput = false;
   this->TestResult.ReturnValue = -1;
   this->TestResult.CompletionStatus = "Failed to start";
@@ -590,8 +590,7 @@ void cmCTestRunTest::DartProcessing()
   }
 }
 
-bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut,
-                                 bool explicitTimeout,
+bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
                                  std::vector<std::string>* environment)
 {
   this->TestProcess = cm::make_unique<cmProcess>(*this);
@@ -602,39 +601,31 @@ bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut,
   this->TestProcess->SetCommandArguments(this->Arguments);
 
   // determine how much time we have
-  std::chrono::duration<double> timeout =
-    this->CTest->GetRemainingTimeAllowed();
+  cmDuration timeout = this->CTest->GetRemainingTimeAllowed();
   if (timeout != cmCTest::MaxDuration()) {
     timeout -= std::chrono::minutes(2);
   }
-  if (this->CTest->GetTimeOut() > std::chrono::duration<double>::zero() &&
+  if (this->CTest->GetTimeOut() > cmDuration::zero() &&
       this->CTest->GetTimeOut() < timeout) {
     timeout = this->CTest->GetTimeOut();
   }
-  if (testTimeOut > std::chrono::duration<double>::zero() &&
+  if (testTimeOut > cmDuration::zero() &&
       testTimeOut < this->CTest->GetRemainingTimeAllowed()) {
     timeout = testTimeOut;
   }
   // always have at least 1 second if we got to here
-  if (timeout <= std::chrono::duration<double>::zero()) {
+  if (timeout <= cmDuration::zero()) {
     timeout = std::chrono::seconds(1);
   }
   // handle timeout explicitly set to 0
-  if (testTimeOut == std::chrono::duration<double>::zero() &&
-      explicitTimeout) {
-    timeout = std::chrono::duration<double>::zero();
-  }
-  cmCTestOptionalLog(
-    this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
-      << ": "
-      << "Test timeout computed to be: "
-      << (timeout == cmCTest::MaxDuration()
-            ? std::string("infinite")
-            : std::to_string(
-                std::chrono::duration_cast<std::chrono::seconds>(timeout)
-                  .count()))
-      << "\n",
-    this->TestHandler->GetQuiet());
+  if (testTimeOut == cmDuration::zero() && explicitTimeout) {
+    timeout = cmDuration::zero();
+  }
+  cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
+                       << ": "
+                       << "Test timeout computed to be: "
+                       << cmDurationTo<unsigned int>(timeout) << "\n",
+                     this->TestHandler->GetQuiet());
 
   this->TestProcess->SetTimeout(timeout);
 

+ 2 - 3
Source/CTest/cmCTestRunTest.h

@@ -5,13 +5,13 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include <chrono>
 #include <set>
 #include <stddef.h>
 #include <string>
 #include <vector>
 
 #include "cmCTestTestHandler.h"
+#include "cmDuration.h"
 #include "cmProcess.h" // IWYU pragma: keep (for unique_ptr)
 
 class cmCTest;
@@ -82,8 +82,7 @@ private:
   bool NeedsToRerun();
   void DartProcessing();
   void ExeNotFound(std::string exe);
-  bool ForkProcess(std::chrono::duration<double> testTimeOut,
-                   bool explicitTimeout,
+  bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
                    std::vector<std::string>* environment);
   void WriteLogOutputTop(size_t completed, size_t total);
   // Run post processing of the process output for MemCheck

+ 22 - 20
Source/CTest/cmCTestScriptHandler.cxx

@@ -27,6 +27,7 @@
 #include "cmCTestTestCommand.h"
 #include "cmCTestUpdateCommand.h"
 #include "cmCTestUploadCommand.h"
+#include "cmDuration.h"
 #include "cmFunctionBlocker.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
@@ -159,9 +160,9 @@ void cmCTestScriptHandler::UpdateElapsedTime()
 {
   if (this->Makefile) {
     // set the current elapsed time
-    auto itime = std::chrono::duration_cast<std::chrono::seconds>(
-      std::chrono::steady_clock::now() - this->ScriptStartTime);
-    auto timeString = std::to_string(itime.count());
+    auto itime = cmDurationTo<unsigned int>(std::chrono::steady_clock::now() -
+                                            this->ScriptStartTime);
+    auto timeString = std::to_string(itime);
     this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString.c_str());
   }
 }
@@ -206,7 +207,8 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
   std::vector<char> out;
   std::vector<char> err;
   std::string line;
-  int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err);
+  int pipe =
+    cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
   while (pipe != cmsysProcess_Pipe_None) {
     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: " << line
                                                                << "\n");
@@ -215,7 +217,8 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
     } else if (pipe == cmsysProcess_Pipe_STDOUT) {
       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
     }
-    pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
+    pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
+                                      err);
   }
 
   // Properly handle output of the build command
@@ -558,8 +561,8 @@ int cmCTestScriptHandler::RunCurrentScript()
   // for a continuous, do we ned to run it more than once?
   if (this->ContinuousDuration >= 0) {
     this->UpdateElapsedTime();
-    auto ending_time = std::chrono::steady_clock::now() +
-      std::chrono::duration<double>(this->ContinuousDuration);
+    auto ending_time =
+      std::chrono::steady_clock::now() + cmDuration(this->ContinuousDuration);
     if (this->EmptyBinDirOnce) {
       this->EmptyBinDir = true;
     }
@@ -567,13 +570,11 @@ int cmCTestScriptHandler::RunCurrentScript()
       auto startOfInterval = std::chrono::steady_clock::now();
       result = this->RunConfigurationDashboard();
       auto interval = std::chrono::steady_clock::now() - startOfInterval;
-      auto minimumInterval =
-        std::chrono::duration<double>(this->MinimumInterval);
+      auto minimumInterval = cmDuration(this->MinimumInterval);
       if (interval < minimumInterval) {
-        auto sleepTime = std::chrono::duration_cast<std::chrono::seconds>(
-                           minimumInterval - interval)
-                           .count();
-        this->SleepInSeconds(static_cast<unsigned int>(sleepTime));
+        auto sleepTime =
+          cmDurationTo<unsigned int>(minimumInterval - interval);
+        this->SleepInSeconds(sleepTime);
       }
       if (this->EmptyBinDirOnce) {
         this->EmptyBinDir = false;
@@ -603,7 +604,8 @@ int cmCTestScriptHandler::CheckOutSourceDir()
                "Run cvs: " << this->CVSCheckOut << std::endl);
     res = cmSystemTools::RunSingleCommand(
       this->CVSCheckOut.c_str(), &output, &output, &retVal,
-      this->CTestRoot.c_str(), this->HandlerVerbose, 0 /*this->TimeOut*/);
+      this->CTestRoot.c_str(), this->HandlerVerbose,
+      cmDuration::zero() /*this->TimeOut*/);
     if (!res || retVal != 0) {
       cmSystemTools::Error("Unable to perform cvs checkout:\n",
                            output.c_str());
@@ -670,7 +672,7 @@ int cmCTestScriptHandler::PerformExtraUpdates()
                  "Run Update: " << fullCommand << std::endl);
       res = cmSystemTools::RunSingleCommand(
         fullCommand.c_str(), &output, &output, &retVal, cvsArgs[0].c_str(),
-        this->HandlerVerbose, 0 /*this->TimeOut*/);
+        this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
       if (!res || retVal != 0) {
         cmSystemTools::Error("Unable to perform extra updates:\n", eu.c_str(),
                              "\nWith output:\n", output.c_str());
@@ -774,7 +776,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
                "Run cmake command: " << command << std::endl);
     res = cmSystemTools::RunSingleCommand(
       command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
-      this->HandlerVerbose, 0 /*this->TimeOut*/);
+      this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
 
     if (!this->CMOutFile.empty()) {
       std::string cmakeOutputFile = this->CMOutFile;
@@ -813,7 +815,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
                "Run ctest command: " << command << std::endl);
     res = cmSystemTools::RunSingleCommand(
       command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
-      this->HandlerVerbose, 0 /*this->TimeOut*/);
+      this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
 
     // did something critical fail in ctest
     if (!res || cmakeFailed || retVal & cmCTest::BUILD_ERRORS) {
@@ -960,7 +962,7 @@ bool cmCTestScriptHandler::TryToRemoveBinaryDirectoryOnce(
   return cmSystemTools::RemoveADirectory(directoryPath);
 }
 
-std::chrono::duration<double> cmCTestScriptHandler::GetRemainingTimeAllowed()
+cmDuration cmCTestScriptHandler::GetRemainingTimeAllowed()
 {
   if (!this->Makefile) {
     return cmCTest::MaxDuration();
@@ -972,9 +974,9 @@ std::chrono::duration<double> cmCTestScriptHandler::GetRemainingTimeAllowed()
     return cmCTest::MaxDuration();
   }
 
-  auto timelimit = std::chrono::duration<double>(atof(timelimitS));
+  auto timelimit = cmDuration(atof(timelimitS));
 
-  auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(
+  auto duration = std::chrono::duration_cast<cmDuration>(
     std::chrono::steady_clock::now() - this->ScriptStartTime);
   return (timelimit - duration);
 }

+ 2 - 1
Source/CTest/cmCTestScriptHandler.h

@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include "cmCTestGenericHandler.h"
+#include "cmDuration.h"
 
 #include <chrono>
 #include <string>
@@ -96,7 +97,7 @@ public:
    * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has
    * not been set it returns a very large value.
    */
-  std::chrono::duration<double> GetRemainingTimeAllowed();
+  cmDuration GetRemainingTimeAllowed();
 
   cmCTestScriptHandler();
   ~cmCTestScriptHandler() override;

+ 2 - 1
Source/CTest/cmCTestSubmitHandler.cxx

@@ -16,6 +16,7 @@
 #include "cmCTestScriptHandler.h"
 #include "cmCryptoHash.h"
 #include "cmCurl.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmProcessOutput.h"
 #include "cmState.h"
@@ -497,7 +498,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix,
           ? ""
           : this->GetOption("RetryCount");
 
-        auto delay = std::chrono::duration<double>(
+        auto delay = cmDuration(
           retryDelay.empty()
             ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryDelay")
                      .c_str())

+ 4 - 3
Source/CTest/cmCTestTestCommand.cxx

@@ -4,6 +4,7 @@
 
 #include "cmCTest.h"
 #include "cmCTestGenericHandler.h"
+#include "cmDuration.h"
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
 
@@ -37,12 +38,12 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   const char* ctestTimeout =
     this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
 
-  std::chrono::duration<double> timeout;
+  cmDuration timeout;
   if (ctestTimeout) {
-    timeout = std::chrono::duration<double>(atof(ctestTimeout));
+    timeout = cmDuration(atof(ctestTimeout));
   } else {
     timeout = this->CTest->GetTimeOut();
-    if (timeout <= std::chrono::duration<double>::zero()) {
+    if (timeout <= cmDuration::zero()) {
       // By default use timeout of 10 minutes
       timeout = std::chrono::minutes(10);
     }

+ 8 - 9
Source/CTest/cmCTestTestHandler.cxx

@@ -21,6 +21,7 @@
 #include "cmCTest.h"
 #include "cmCTestMultiProcessHandler.h"
 #include "cmCommand.h"
+#include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
@@ -346,7 +347,7 @@ void cmCTestTestHandler::Initialize()
 {
   this->Superclass::Initialize();
 
-  this->ElapsedTestingTime = std::chrono::duration<double>();
+  this->ElapsedTestingTime = cmDuration();
 
   this->TestResults.clear();
 
@@ -539,7 +540,7 @@ int cmCTestTestHandler::ProcessHandler()
       this->PrintLabelOrSubprojectSummary(false);
     }
     char realBuf[1024];
-    std::chrono::duration<double> durationInSecs = clock_finish - clock_start;
+    cmDuration durationInSecs = clock_finish - clock_start;
     sprintf(realBuf, "%6.2f sec", durationInSecs.count());
     cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
                        "\nTotal Test time (real) = " << realBuf << "\n",
@@ -1235,9 +1236,8 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed,
       p.Cost = static_cast<float>(rand());
     }
 
-    if (p.Timeout == std::chrono::duration<double>::zero() &&
-        this->CTest->GetGlobalTimeout() !=
-          std::chrono::duration<double>::zero()) {
+    if (p.Timeout == cmDuration::zero() &&
+        this->CTest->GetGlobalTimeout() != cmDuration::zero()) {
       p.Timeout = this->CTest->GetGlobalTimeout();
     }
 
@@ -2140,7 +2140,7 @@ bool cmCTestTestHandler::SetTestsProperties(
             rt.FixturesRequired.insert(lval.begin(), lval.end());
           }
           if (key == "TIMEOUT") {
-            rt.Timeout = std::chrono::duration<double>(atof(val.c_str()));
+            rt.Timeout = cmDuration(atof(val.c_str()));
             rt.ExplicitTimeout = true;
           }
           if (key == "COST") {
@@ -2220,8 +2220,7 @@ bool cmCTestTestHandler::SetTestsProperties(
                          "TIMEOUT_AFTER_MATCH expects two arguments, found "
                            << propArgs.size() << std::endl);
             } else {
-              rt.AlternateTimeout =
-                std::chrono::duration<double>(atof(propArgs[0].c_str()));
+              rt.AlternateTimeout = cmDuration(atof(propArgs[0].c_str()));
               std::vector<std::string> lval;
               cmSystemTools::ExpandListArgument(propArgs[1], lval);
               for (std::string const& cr : lval) {
@@ -2339,7 +2338,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
   test.WillFail = false;
   test.Disabled = false;
   test.RunSerial = false;
-  test.Timeout = std::chrono::duration<double>::zero();
+  test.Timeout = cmDuration::zero();
   test.ExplicitTimeout = false;
   test.Cost = 0;
   test.Processors = 1;

+ 5 - 4
Source/CTest/cmCTestTestHandler.h

@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include "cmCTestGenericHandler.h"
+#include "cmDuration.h"
 
 #include "cmsys/RegularExpression.hxx"
 #include <chrono>
@@ -123,9 +124,9 @@ public:
     float Cost;
     int PreviousRuns;
     bool RunSerial;
-    std::chrono::duration<double> Timeout;
+    cmDuration Timeout;
     bool ExplicitTimeout;
-    std::chrono::duration<double> AlternateTimeout;
+    cmDuration AlternateTimeout;
     int Index;
     // Requested number of process slots
     int Processors;
@@ -146,7 +147,7 @@ public:
     std::string Path;
     std::string Reason;
     std::string FullCommandLine;
-    std::chrono::duration<double> ExecutionTime;
+    cmDuration ExecutionTime;
     int ReturnValue;
     int Status;
     std::string ExceptionStatus;
@@ -198,7 +199,7 @@ protected:
   //! Clean test output to specified length
   bool CleanTestOutput(std::string& output, size_t length);
 
-  std::chrono::duration<double> ElapsedTestingTime;
+  cmDuration ElapsedTestingTime;
 
   typedef std::vector<cmCTestTestResult> TestResultsVector;
   TestResultsVector TestResults;

+ 5 - 5
Source/CTest/cmProcess.cxx

@@ -62,8 +62,8 @@ cmProcess::cmProcess(cmCTestRunTest& runner)
   : Runner(runner)
   , Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE)
 {
-  this->Timeout = std::chrono::duration<double>::zero();
-  this->TotalTime = std::chrono::duration<double>::zero();
+  this->Timeout = cmDuration::zero();
+  this->TotalTime = cmDuration::zero();
   this->ExitValue = 0;
   this->Id = 0;
   this->StartTime = std::chrono::steady_clock::time_point();
@@ -344,8 +344,8 @@ void cmProcess::OnExit(int64_t exit_status, int term_signal)
   // negative. If someone changed the system clock while the process was
   // running this may be even more. Make sure not to report a negative
   // duration here.
-  if (this->TotalTime <= std::chrono::duration<double>::zero()) {
-    this->TotalTime = std::chrono::duration<double>::zero();
+  if (this->TotalTime <= cmDuration::zero()) {
+    this->TotalTime = cmDuration::zero();
   }
 
   this->ProcessHandleClosed = true;
@@ -360,7 +360,7 @@ cmProcess::State cmProcess::GetProcessStatus()
   return this->ProcessState;
 }
 
-void cmProcess::ChangeTimeout(std::chrono::duration<double> t)
+void cmProcess::ChangeTimeout(cmDuration t)
 {
   this->Timeout = t;
   this->StartTimer();

+ 6 - 5
Source/CTest/cmProcess.h

@@ -4,6 +4,7 @@
 #define cmProcess_h
 
 #include "cmConfigure.h" // IWYU pragma: keep
+#include "cmDuration.h"
 
 #include "cmProcessOutput.h"
 #include "cmUVHandlePtr.h"
@@ -31,8 +32,8 @@ public:
   void SetCommand(const char* command);
   void SetCommandArguments(std::vector<std::string> const& arg);
   void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
-  void SetTimeout(std::chrono::duration<double> t) { this->Timeout = t; }
-  void ChangeTimeout(std::chrono::duration<double> t);
+  void SetTimeout(cmDuration t) { this->Timeout = t; }
+  void ChangeTimeout(cmDuration t);
   void ResetStartTime();
   // Return true if the process starts
   bool StartProcess(uv_loop_t& loop);
@@ -53,7 +54,7 @@ public:
   int GetId() { return this->Id; }
   void SetId(int id) { this->Id = id; }
   int GetExitValue() { return this->ExitValue; }
-  std::chrono::duration<double> GetTotalTime() { return this->TotalTime; }
+  cmDuration GetTotalTime() { return this->TotalTime; }
 
   enum class Exception
   {
@@ -69,9 +70,9 @@ public:
   std::string GetExitExceptionString();
 
 private:
-  std::chrono::duration<double> Timeout;
+  cmDuration Timeout;
   std::chrono::steady_clock::time_point StartTime;
-  std::chrono::duration<double> TotalTime;
+  cmDuration TotalTime;
   bool ReadHandleClosed = false;
   bool ProcessHandleClosed = false;
 

+ 20 - 28
Source/cmCTest.cxx

@@ -277,8 +277,8 @@ cmCTest::cmCTest()
   this->TestModel = cmCTest::EXPERIMENTAL;
   this->MaxTestNameWidth = 30;
   this->InteractiveDebugMode = true;
-  this->TimeOut = std::chrono::duration<double>::zero();
-  this->GlobalTimeout = std::chrono::duration<double>::zero();
+  this->TimeOut = cmDuration::zero();
+  this->GlobalTimeout = cmDuration::zero();
   this->CompressXMLFiles = false;
   this->ScheduleType.clear();
   this->OutputLogFile = nullptr;
@@ -954,8 +954,7 @@ int cmCTest::GetTestModelFromString(const char* str)
 //######################################################################
 
 int cmCTest::RunMakeCommand(const char* command, std::string& output,
-                            int* retVal, const char* dir,
-                            std::chrono::duration<double> timeout,
+                            int* retVal, const char* dir, cmDuration timeout,
                             std::ostream& ofs, Encoding encoding)
 {
   // First generate the command and arguments
@@ -1071,38 +1070,33 @@ int cmCTest::RunMakeCommand(const char* command, std::string& output,
 //######################################################################
 
 int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
-                     int* retVal, std::ostream* log,
-                     std::chrono::duration<double> testTimeOut,
+                     int* retVal, std::ostream* log, cmDuration testTimeOut,
                      std::vector<std::string>* environment, Encoding encoding)
 {
   bool modifyEnv = (environment && !environment->empty());
 
   // determine how much time we have
-  std::chrono::duration<double> timeout = this->GetRemainingTimeAllowed();
+  cmDuration timeout = this->GetRemainingTimeAllowed();
   if (timeout != cmCTest::MaxDuration()) {
     timeout -= std::chrono::minutes(2);
   }
-  if (this->TimeOut > std::chrono::duration<double>::zero() &&
-      this->TimeOut < timeout) {
+  if (this->TimeOut > cmDuration::zero() && this->TimeOut < timeout) {
     timeout = this->TimeOut;
   }
-  if (testTimeOut > std::chrono::duration<double>::zero() &&
+  if (testTimeOut > cmDuration::zero() &&
       testTimeOut < this->GetRemainingTimeAllowed()) {
     timeout = testTimeOut;
   }
 
   // always have at least 1 second if we got to here
-  if (timeout <= std::chrono::duration<double>::zero()) {
+  if (timeout <= cmDuration::zero()) {
     timeout = std::chrono::seconds(1);
   }
-  cmCTestLog(
-    this, HANDLER_VERBOSE_OUTPUT, "Test timeout computed to be: "
-      << (timeout == cmCTest::MaxDuration()
-            ? std::string("infinite")
-            : std::to_string(
-                std::chrono::duration_cast<std::chrono::seconds>(timeout)
-                  .count()))
-      << "\n");
+  cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Test timeout computed to be: "
+               << (timeout == cmCTest::MaxDuration()
+                     ? std::string("infinite")
+                     : std::to_string(cmDurationTo<unsigned int>(timeout)))
+               << "\n");
   if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) &&
       !this->ForceNewCTestProcess) {
     cmCTest inst;
@@ -1121,11 +1115,10 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
         // good place to check for it, and to add the arguments in
         if (strcmp(i, "--build-generator") == 0 &&
             timeout != cmCTest::MaxDuration() &&
-            timeout > std::chrono::duration<double>::zero()) {
+            timeout > cmDuration::zero()) {
           args.push_back("--test-timeout");
           std::ostringstream msg;
-          msg << std::chrono::duration_cast<std::chrono::seconds>(timeout)
-                   .count();
+          msg << cmDurationTo<unsigned int>(timeout);
           args.push_back(msg.str());
         }
         args.push_back(i);
@@ -1772,7 +1765,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
 
   if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) {
     i++;
-    auto timeout = std::chrono::duration<double>(atof(args[i].c_str()));
+    auto timeout = cmDuration(atof(args[i].c_str()));
     this->GlobalTimeout = timeout;
   }
 
@@ -2575,8 +2568,7 @@ bool cmCTest::SetCTestConfigurationFromCMakeVariable(
 
 bool cmCTest::RunCommand(std::vector<std::string> const& args,
                          std::string* stdOut, std::string* stdErr, int* retVal,
-                         const char* dir,
-                         std::chrono::duration<double> timeout,
+                         const char* dir, cmDuration timeout,
                          Encoding encoding)
 {
   std::vector<const char*> argv;
@@ -2788,7 +2780,7 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
   }
 }
 
-std::chrono::duration<double> cmCTest::GetRemainingTimeAllowed()
+cmDuration cmCTest::GetRemainingTimeAllowed()
 {
   if (!this->GetHandler("script")) {
     return cmCTest::MaxDuration();
@@ -2800,9 +2792,9 @@ std::chrono::duration<double> cmCTest::GetRemainingTimeAllowed()
   return ch->GetRemainingTimeAllowed();
 }
 
-std::chrono::duration<double> cmCTest::MaxDuration()
+cmDuration cmCTest::MaxDuration()
 {
-  return std::chrono::duration<double>(1.0e7);
+  return cmDuration(1.0e7);
 }
 
 void cmCTest::OutputTestErrors(std::vector<char> const& process_output)

+ 11 - 15
Source/cmCTest.h

@@ -5,6 +5,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include "cmDuration.h"
 #include "cmProcessOutput.h"
 #include "cmsys/String.hxx"
 #include <chrono>
@@ -140,13 +141,10 @@ public:
 
   /** what is the configuraiton type, e.g. Debug, Release etc. */
   std::string const& GetConfigType();
-  std::chrono::duration<double> GetTimeOut() { return this->TimeOut; }
-  void SetTimeOut(std::chrono::duration<double> t) { this->TimeOut = t; }
+  cmDuration GetTimeOut() { return this->TimeOut; }
+  void SetTimeOut(cmDuration t) { this->TimeOut = t; }
 
-  std::chrono::duration<double> GetGlobalTimeout()
-  {
-    return this->GlobalTimeout;
-  }
+  cmDuration GetGlobalTimeout() { return this->GlobalTimeout; }
 
   /** how many test to run at the same time */
   int GetParallelLevel() { return this->ParallelLevel; }
@@ -206,9 +204,9 @@ public:
    * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has
    * not been set it returns a very large duration.
    */
-  std::chrono::duration<double> GetRemainingTimeAllowed();
+  cmDuration GetRemainingTimeAllowed();
 
-  static std::chrono::duration<double> MaxDuration();
+  static cmDuration MaxDuration();
 
   /**
    * Open file in the output directory and set the stream
@@ -258,8 +256,7 @@ public:
   bool RunCommand(std::vector<std::string> const& args, std::string* stdOut,
                   std::string* stdErr, int* retVal = nullptr,
                   const char* dir = nullptr,
-                  std::chrono::duration<double> timeout =
-                    std::chrono::duration<double>::zero(),
+                  cmDuration timeout = cmDuration::zero(),
                   Encoding encoding = cmProcessOutput::Auto);
 
   /**
@@ -279,8 +276,7 @@ public:
    * and retVal is return value or exception.
    */
   int RunMakeCommand(const char* command, std::string& output, int* retVal,
-                     const char* dir, std::chrono::duration<double> timeout,
-                     std::ostream& ofs,
+                     const char* dir, cmDuration timeout, std::ostream& ofs,
                      Encoding encoding = cmProcessOutput::Auto);
 
   /** Return the current tag */
@@ -327,7 +323,7 @@ public:
    * environment variables are restored to their previous values.
    */
   int RunTest(std::vector<const char*> args, std::string* output, int* retVal,
-              std::ostream* logfile, std::chrono::duration<double> testTimeOut,
+              std::ostream* logfile, cmDuration testTimeOut,
               std::vector<std::string>* environment,
               Encoding encoding = cmProcessOutput::Auto);
 
@@ -508,9 +504,9 @@ private:
   int TestModel;
   std::string SpecificTrack;
 
-  std::chrono::duration<double> TimeOut;
+  cmDuration TimeOut;
 
-  std::chrono::duration<double> GlobalTimeout;
+  cmDuration GlobalTimeout;
 
   int MaxTestNameWidth;
 

+ 27 - 0
Source/cmDuration.cxx

@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#define CMDURATION_CPP
+#include "cmDuration.h"
+
+template <typename T>
+T cmDurationTo(const cmDuration& duration)
+{
+  /* This works because the comparison operators for duration rely on
+   * std::common_type.
+   * So for example duration<int>::max() gets promoted to a duration<double>,
+   * which can then be safely compared.
+   */
+  if (duration >= std::chrono::duration<T>::max()) {
+    return std::chrono::duration<T>::max().count();
+  }
+  if (duration <= std::chrono::duration<T>::min()) {
+    return std::chrono::duration<T>::min().count();
+  }
+  // Ensure number of seconds by defining ratio<1>
+  return std::chrono::duration_cast<std::chrono::duration<T, std::ratio<1>>>(
+           duration)
+    .count();
+}
+
+template int cmDurationTo<int>(const cmDuration&);
+template unsigned int cmDurationTo<unsigned int>(const cmDuration&);

+ 24 - 0
Source/cmDuration.h

@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <chrono>
+#include <ratio>
+
+typedef std::chrono::duration<double, std::ratio<1>> cmDuration;
+
+/*
+ * This function will return number of seconds in the requested type T.
+ *
+ * A duration_cast from duration<double> to duration<T> will not yield what
+ * one might expect if the double representation does not fit into type T.
+ * This function aims to safely convert, by clamping the double value between
+ * the permissible valid values for T.
+ */
+template <typename T>
+T cmDurationTo(const cmDuration& duration);
+
+#ifndef CMDURATION_CPP
+extern template int cmDurationTo<int>(const cmDuration&);
+extern template unsigned int cmDurationTo<unsigned int>(const cmDuration&);
+#endif

+ 3 - 2
Source/cmGlobalGenerator.cxx

@@ -21,6 +21,7 @@
 #include "cmComputeTargetDepends.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
+#include "cmDuration.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmExternalMakefileProjectGenerator.h"
 #include "cmGeneratedFileStream.h"
@@ -87,7 +88,7 @@ cmGlobalGenerator::cmGlobalGenerator(cmake* cm)
   this->InstallTargetEnabled = false;
 
   // how long to let try compiles run
-  this->TryCompileTimeout = 0;
+  this->TryCompileTimeout = cmDuration::zero();
 
   this->ExtraGenerator = nullptr;
   this->CurrentConfigureMakefile = nullptr;
@@ -1801,7 +1802,7 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/,
                              const std::string& target, std::string& output,
                              const std::string& makeCommandCSTR,
                              const std::string& config, bool clean, bool fast,
-                             bool verbose, double timeout,
+                             bool verbose, cmDuration timeout,
                              cmSystemTools::OutputOption outputflag,
                              std::vector<std::string> const& nativeOptions)
 {

+ 4 - 3
Source/cmGlobalGenerator.h

@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "cmCustomCommandLines.h"
+#include "cmDuration.h"
 #include "cmExportSetMap.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
@@ -160,8 +161,8 @@ public:
             const std::string& projectName, const std::string& targetName,
             std::string& output, const std::string& makeProgram,
             const std::string& config, bool clean, bool fast, bool verbose,
-            double timeout, cmSystemTools::OutputOption outputflag =
-                              cmSystemTools::OUTPUT_NONE,
+            cmDuration timeout, cmSystemTools::OutputOption outputflag =
+                                  cmSystemTools::OUTPUT_NONE,
             std::vector<std::string> const& nativeOptions =
               std::vector<std::string>());
 
@@ -233,7 +234,7 @@ public:
 
   void EnableInstallTarget();
 
-  int TryCompileTimeout;
+  cmDuration TryCompileTimeout;
 
   bool GetForceUnixPaths() const { return this->ForceUnixPaths; }
   bool GetToolSupportsColor() const { return this->ToolSupportsColor; }

+ 3 - 2
Source/cmQtAutoGenInitializer.cxx

@@ -6,6 +6,7 @@
 #include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
+#include "cmDuration.h"
 #include "cmFilePathChecksum.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -410,7 +411,7 @@ void cmQtAutoGenInitializer::InitCustomTargets()
       int retVal = 0;
       bool result = cmSystemTools::RunSingleCommand(
         command, &rccStdOut, &rccStdErr, &retVal, nullptr,
-        cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto);
+        cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
       if (result && retVal == 0 &&
           rccStdOut.find("--list") != std::string::npos) {
         this->RccListOptions.push_back("--list");
@@ -1417,7 +1418,7 @@ bool cmQtAutoGenInitializer::RccListInputs(std::string const& fileName,
       cmd.push_back(fileNameName);
       result = cmSystemTools::RunSingleCommand(
         cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
-        cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto);
+        cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
     }
     if (!result || retVal) {
       error = "rcc list process failed for:\n  ";

+ 8 - 5
Source/cmSystemTools.cxx

@@ -3,6 +3,7 @@
 #include "cmSystemTools.h"
 
 #include "cmAlgorithms.h"
+#include "cmDuration.h"
 #include "cmProcessOutput.h"
 #include "cm_sys_stat.h"
 
@@ -701,7 +702,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
                                      std::string* captureStdOut,
                                      std::string* captureStdErr, int* retVal,
                                      const char* dir, OutputOption outputflag,
-                                     double timeout, Encoding encoding)
+                                     cmDuration timeout, Encoding encoding)
 {
   std::vector<const char*> argv;
   argv.reserve(command.size() + 1);
@@ -729,7 +730,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
   }
   assert(!captureStdErr || captureStdErr != captureStdOut);
 
-  cmsysProcess_SetTimeout(cp, timeout);
+  cmsysProcess_SetTimeout(cp, timeout.count());
   cmsysProcess_Execute(cp);
 
   std::vector<char> tempStdOut;
@@ -842,7 +843,7 @@ bool cmSystemTools::RunSingleCommand(const char* command,
                                      std::string* captureStdOut,
                                      std::string* captureStdErr, int* retVal,
                                      const char* dir, OutputOption outputflag,
-                                     double timeout)
+                                     cmDuration timeout)
 {
   if (s_DisableRunCommandOutput) {
     outputflag = OUTPUT_NONE;
@@ -1828,7 +1829,7 @@ bool cmSystemTools::ListTar(const char* outFileName, bool verbose)
 }
 
 int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
-                               double timeout, std::vector<char>& out,
+                               cmDuration timeout, std::vector<char>& out,
                                std::vector<char>& err)
 {
   line.clear();
@@ -1876,7 +1877,9 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
     // No newlines found.  Wait for more data from the process.
     int length;
     char* data;
-    int pipe = cmsysProcess_WaitForData(process, &data, &length, &timeout);
+    double timeoutAsDbl = timeout.count();
+    int pipe =
+      cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl);
     if (pipe == cmsysProcess_Pipe_Timeout) {
       // Timeout has been exceeded.
       return pipe;

+ 4 - 3
Source/cmSystemTools.h

@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include "cmCryptoHash.h"
+#include "cmDuration.h"
 #include "cmProcessOutput.h"
 #include "cmsys/Process.h"
 #include "cmsys/SystemTools.hxx" // IWYU pragma: export
@@ -225,7 +226,7 @@ public:
                                int* retVal = nullptr,
                                const char* dir = nullptr,
                                OutputOption outputflag = OUTPUT_MERGE,
-                               double timeout = 0.0);
+                               cmDuration timeout = cmDuration::zero());
   /**
    * In this version of RunSingleCommand, command[0] should be
    * the command to run, and each argument to the command should
@@ -237,7 +238,7 @@ public:
                                int* retVal = nullptr,
                                const char* dir = nullptr,
                                OutputOption outputflag = OUTPUT_MERGE,
-                               double timeout = 0.0,
+                               cmDuration timeout = cmDuration::zero(),
                                Encoding encoding = cmProcessOutput::Auto);
 
   static std::string PrintSingleCommand(std::vector<std::string> const&);
@@ -343,7 +344,7 @@ public:
 
   /** a general output handler for cmsysProcess  */
   static int WaitForLine(cmsysProcess* process, std::string& line,
-                         double timeout, std::vector<char>& out,
+                         cmDuration timeout, std::vector<char>& out,
                          std::vector<char>& err);
 
   /** Split a string on its newlines into multiple lines.  Returns

+ 2 - 2
Source/cmTryRunCommand.cxx

@@ -5,6 +5,7 @@
 #include "cmsys/FStream.hxx"
 #include <stdio.h>
 
+#include "cmDuration.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
@@ -185,10 +186,9 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs,
   if (!runArgs.empty()) {
     finalCommand += runArgs;
   }
-  int timeout = 0;
   bool worked = cmSystemTools::RunSingleCommand(
     finalCommand.c_str(), out, out, &retVal, nullptr,
-    cmSystemTools::OUTPUT_NONE, timeout);
+    cmSystemTools::OUTPUT_NONE, cmDuration::zero());
   // set the run var
   char retChar[16];
   const char* retStr;

+ 3 - 2
Source/cmake.cxx

@@ -7,6 +7,7 @@
 #include "cmDocumentation.h"
 #include "cmDocumentationEntry.h"
 #include "cmDocumentationFormatter.h"
+#include "cmDuration.h"
 #include "cmExternalMakefileProjectGenerator.h"
 #include "cmFileTimeComparison.h"
 #include "cmGeneratorTarget.h"
@@ -2465,8 +2466,8 @@ int cmake::Build(const std::string& dir, const std::string& target,
 #endif
 
   return gen->Build("", dir, projName, target, output, "", config, clean,
-                    false, verbose, 0, cmSystemTools::OUTPUT_PASSTHROUGH,
-                    nativeOptions);
+                    false, verbose, cmDuration::zero(),
+                    cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions);
 }
 
 bool cmake::Open(const std::string& dir, bool dryRun)

+ 5 - 2
Source/cmakexbuild.cxx

@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "cmDuration.h"
 #include "cmSystemTools.h"
 
 // This is a wrapper program for xcodebuild
@@ -27,7 +28,8 @@ int RunXCode(std::vector<const char*>& argv, bool& hitbug)
   std::vector<char> out;
   std::vector<char> err;
   std::string line;
-  int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err);
+  int pipe =
+    cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
   while (pipe != cmsysProcess_Pipe_None) {
     if (line.find("/bin/sh: bad interpreter: Text file busy") !=
         std::string::npos) {
@@ -45,7 +47,8 @@ int RunXCode(std::vector<const char*>& argv, bool& hitbug)
         std::cout << line << "\n";
       }
     }
-    pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
+    pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
+                                      err);
   }
   cmsysProcess_WaitForExit(cp, nullptr);
   if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {

+ 2 - 2
Source/cmcmd.cxx

@@ -3,6 +3,7 @@
 #include "cmcmd.h"
 
 #include "cmAlgorithms.h"
+#include "cmDuration.h"
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -797,10 +798,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
       std::string command =
         cmWrap('"', cmMakeRange(args).advance(3), '"', " ");
       int retval = 0;
-      int timeout = 0;
       if (cmSystemTools::RunSingleCommand(
             command.c_str(), nullptr, nullptr, &retval, directory.c_str(),
-            cmSystemTools::OUTPUT_PASSTHROUGH, timeout)) {
+            cmSystemTools::OUTPUT_PASSTHROUGH, cmDuration::zero())) {
         return retval;
       }