From ec124582acf966db9e6ddb226b53021fe6be591a Mon Sep 17 00:00:00 2001
From: Kyle Edwards <kyle.edwards@kitware.com>
Date: Thu, 8 Jun 2023 08:50:10 -0400
Subject: cmProcessTools::RunProcess(): Replace cmsysProcess with
 cmUVProcessChain

And convert the VCS code to std::vector<std::string>.
---
 Source/CTest/cmCTestBZR.cxx |  31 +++++------
 Source/CTest/cmCTestCVS.cxx |  18 +++---
 Source/CTest/cmCTestGIT.cxx | 130 ++++++++++++++++++++++----------------------
 Source/CTest/cmCTestHG.cxx  |  35 +++++-------
 Source/CTest/cmCTestP4.cxx  |  66 +++++++++-------------
 Source/CTest/cmCTestP4.h    |   2 +-
 Source/CTest/cmCTestSVN.cxx |  36 +++++-------
 Source/CTest/cmCTestSVN.h   |   2 +-
 Source/CTest/cmCTestVC.cxx  |  45 +++++++--------
 Source/CTest/cmCTestVC.h    |   9 +--
 Source/cmProcessTools.cxx   |  82 +++++++++++++++++-----------
 Source/cmProcessTools.h     |   8 ++-
 Source/cmcmd.cxx            |  33 ++++-------
 13 files changed, 233 insertions(+), 264 deletions(-)

diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index 246e811..36df344 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -135,14 +135,14 @@ private:
 std::string cmCTestBZR::LoadInfo()
 {
   // Run "bzr info" to get the repository info from the work tree.
-  const char* bzr = this->CommandLineTool.c_str();
-  const char* bzr_info[] = { bzr, "info", nullptr };
+  std::string bzr = this->CommandLineTool;
+  std::vector<std::string> bzr_info = { bzr, "info" };
   InfoParser iout(this, "info-out> ");
   OutputLogger ierr(this->Log, "info-err> ");
   this->RunChild(bzr_info, &iout, &ierr);
 
   // Run "bzr revno" to get the repository revision number from the work tree.
-  const char* bzr_revno[] = { bzr, "revno", nullptr };
+  std::vector<std::string> bzr_revno = { bzr, "revno" };
   std::string rev;
   RevnoParser rout(this, "revno-out> ", rev);
   OutputLogger rerr(this->Log, "revno-err> ");
@@ -372,22 +372,18 @@ bool cmCTestBZR::UpdateImpl()
   // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
 
   // Use "bzr pull" to update the working tree.
-  std::vector<char const*> bzr_update;
-  bzr_update.push_back(this->CommandLineTool.c_str());
+  std::vector<std::string> bzr_update;
+  bzr_update.push_back(this->CommandLineTool);
   bzr_update.push_back("pull");
 
-  for (std::string const& arg : args) {
-    bzr_update.push_back(arg.c_str());
-  }
-
-  bzr_update.push_back(this->URL.c_str());
+  cm::append(bzr_update, args);
 
-  bzr_update.push_back(nullptr);
+  bzr_update.push_back(this->URL);
 
   // For some reason bzr uses stderr to display the update status.
   OutputLogger out(this->Log, "pull-out> ");
   UpdateParser err(this, "pull-err> ");
-  return this->RunUpdateCommand(bzr_update.data(), &out, &err);
+  return this->RunUpdateCommand(bzr_update, &out, &err);
 }
 
 bool cmCTestBZR::LoadRevisions()
@@ -408,10 +404,9 @@ bool cmCTestBZR::LoadRevisions()
   }
 
   // Run "bzr log" to get all global revisions of interest.
-  const char* bzr = this->CommandLineTool.c_str();
-  const char* bzr_log[] = {
-    bzr, "log", "-v", "-r", revs.c_str(), "--xml", this->URL.c_str(), nullptr
-  };
+  std::string bzr = this->CommandLineTool;
+  std::vector<std::string> bzr_log = { bzr,  "log",   "-v",     "-r",
+                                       revs, "--xml", this->URL };
   {
     LogParser out(this, "log-out> ");
     OutputLogger err(this->Log, "log-err> ");
@@ -467,8 +462,8 @@ private:
 bool cmCTestBZR::LoadModifications()
 {
   // Run "bzr status" which reports local modifications.
-  const char* bzr = this->CommandLineTool.c_str();
-  const char* bzr_status[] = { bzr, "status", "-SV", nullptr };
+  std::string bzr = this->CommandLineTool;
+  std::vector<std::string> bzr_status = { bzr, "status", "-SV" };
   StatusParser out(this, "status-out> ");
   OutputLogger err(this->Log, "status-err> ");
   this->RunChild(bzr_status, &out, &err);
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
index 95e898c..ef95b25 100644
--- a/Source/CTest/cmCTestCVS.cxx
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -5,6 +5,7 @@
 #include <utility>
 
 #include <cm/string_view>
+#include <cmext/algorithm>
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
@@ -89,18 +90,15 @@ bool cmCTestCVS::UpdateImpl()
   }
 
   // Run "cvs update" to update the work tree.
-  std::vector<char const*> cvs_update;
-  cvs_update.push_back(this->CommandLineTool.c_str());
+  std::vector<std::string> cvs_update;
+  cvs_update.push_back(this->CommandLineTool);
   cvs_update.push_back("-z3");
   cvs_update.push_back("update");
-  for (std::string const& arg : args) {
-    cvs_update.push_back(arg.c_str());
-  }
-  cvs_update.push_back(nullptr);
+  cm::append(cvs_update, args);
 
   UpdateParser out(this, "up-out> ");
   UpdateParser err(this, "up-err> ");
-  return this->RunUpdateCommand(cvs_update.data(), &out, &err);
+  return this->RunUpdateCommand(cvs_update, &out, &err);
 }
 
 class cmCTestCVS::LogParser : public cmCTestVC::LineParser
@@ -221,10 +219,8 @@ void cmCTestCVS::LoadRevisions(std::string const& file, const char* branchFlag,
   cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
 
   // Run "cvs log" to get revisions of this file on this branch.
-  const char* cvs = this->CommandLineTool.c_str();
-  const char* cvs_log[] = {
-    cvs, "log", "-N", branchFlag, file.c_str(), nullptr
-  };
+  std::string cvs = this->CommandLineTool;
+  std::vector<std::string> cvs_log = { cvs, "log", "-N", branchFlag, file };
 
   LogParser out(this, "log-out> ", revisions);
   OutputLogger err(this->Log, "log-err> ");
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 5f8cb74..ca8659e 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -9,8 +9,9 @@
 #include <utility>
 #include <vector>
 
+#include <cmext/algorithm>
+
 #include "cmsys/FStream.hxx"
-#include "cmsys/Process.h"
 
 #include "cmCTest.h"
 #include "cmCTestVC.h"
@@ -18,6 +19,7 @@
 #include "cmProcessOutput.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
 #include "cmValue.h"
 
 static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major,
@@ -58,9 +60,9 @@ private:
 std::string cmCTestGIT::GetWorkingRevision()
 {
   // Run plumbing "git rev-list" to get work tree revision.
-  const char* git = this->CommandLineTool.c_str();
-  const char* git_rev_list[] = { git,    "rev-list", "-n",   "1",
-                                 "HEAD", "--",       nullptr };
+  std::string git = this->CommandLineTool;
+  std::vector<std::string> git_rev_list = { git, "rev-list", "-n",
+                                            "1", "HEAD",     "--" };
   std::string rev;
   OneLineParser out(this, "rl-out> ", rev);
   OutputLogger err(this->Log, "rl-err> ");
@@ -92,13 +94,13 @@ std::string cmCTestGIT::FindGitDir()
   std::string git_dir;
 
   // Run "git rev-parse --git-dir" to locate the real .git directory.
-  const char* git = this->CommandLineTool.c_str();
-  char const* git_rev_parse[] = { git, "rev-parse", "--git-dir", nullptr };
+  std::string git = this->CommandLineTool;
+  std::vector<std::string> git_rev_parse = { git, "rev-parse", "--git-dir" };
   std::string git_dir_line;
   OneLineParser rev_parse_out(this, "rev-parse-out> ", git_dir_line);
   OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
-  if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr,
-                     cmProcessOutput::UTF8)) {
+  if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err,
+                     std::string{}, cmProcessOutput::UTF8)) {
     git_dir = git_dir_line;
   }
   if (git_dir.empty()) {
@@ -117,11 +119,10 @@ std::string cmCTestGIT::FindGitDir()
     std::string cygpath_exe =
       cmStrCat(cmSystemTools::GetFilenamePath(git), "/cygpath.exe");
     if (cmSystemTools::FileExists(cygpath_exe)) {
-      char const* cygpath[] = { cygpath_exe.c_str(), "-w", git_dir.c_str(),
-                                0 };
+      std::vector<std::string> cygpath = { cygpath_exe, "-w", git_dir };
       OneLineParser cygpath_out(this, "cygpath-out> ", git_dir_line);
       OutputLogger cygpath_err(this->Log, "cygpath-err> ");
-      if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, nullptr,
+      if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, std::string{},
                          cmProcessOutput::UTF8)) {
         git_dir = git_dir_line;
       }
@@ -136,12 +137,12 @@ std::string cmCTestGIT::FindTopDir()
   std::string top_dir = this->SourceDirectory;
 
   // Run "git rev-parse --show-cdup" to locate the top of the tree.
-  const char* git = this->CommandLineTool.c_str();
-  char const* git_rev_parse[] = { git, "rev-parse", "--show-cdup", nullptr };
+  std::string git = this->CommandLineTool;
+  std::vector<std::string> git_rev_parse = { git, "rev-parse", "--show-cdup" };
   std::string cdup;
   OneLineParser rev_parse_out(this, "rev-parse-out> ", cdup);
   OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
-  if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr,
+  if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, "",
                      cmProcessOutput::UTF8) &&
       !cdup.empty()) {
     top_dir += "/";
@@ -153,10 +154,10 @@ std::string cmCTestGIT::FindTopDir()
 
 bool cmCTestGIT::UpdateByFetchAndReset()
 {
-  const char* git = this->CommandLineTool.c_str();
+  std::string git = this->CommandLineTool;
 
   // Use "git fetch" to get remote commits.
-  std::vector<char const*> git_fetch;
+  std::vector<std::string> git_fetch;
   git_fetch.push_back(git);
   git_fetch.push_back("fetch");
 
@@ -166,17 +167,12 @@ bool cmCTestGIT::UpdateByFetchAndReset()
     opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
   }
   std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
-  for (std::string const& arg : args) {
-    git_fetch.push_back(arg.c_str());
-  }
-
-  // Sentinel argument.
-  git_fetch.push_back(nullptr);
+  cm::append(git_fetch, args);
 
   // Fetch upstream refs.
   OutputLogger fetch_out(this->Log, "fetch-out> ");
   OutputLogger fetch_err(this->Log, "fetch-err> ");
-  if (!this->RunUpdateCommand(git_fetch.data(), &fetch_out, &fetch_err)) {
+  if (!this->RunUpdateCommand(git_fetch, &fetch_out, &fetch_err)) {
     return false;
   }
 
@@ -207,25 +203,22 @@ bool cmCTestGIT::UpdateByFetchAndReset()
   }
 
   // Reset the local branch to point at that tracked from upstream.
-  char const* git_reset[] = { git, "reset", "--hard", sha1.c_str(), nullptr };
+  std::vector<std::string> git_reset = { git, "reset", "--hard", sha1 };
   OutputLogger reset_out(this->Log, "reset-out> ");
   OutputLogger reset_err(this->Log, "reset-err> ");
-  return this->RunChild(&git_reset[0], &reset_out, &reset_err);
+  return this->RunChild(git_reset, &reset_out, &reset_err);
 }
 
 bool cmCTestGIT::UpdateByCustom(std::string const& custom)
 {
   cmList git_custom_command{ custom, cmList::EmptyElements::Yes };
-  std::vector<char const*> git_custom;
-  git_custom.reserve(git_custom_command.size() + 1);
-  for (std::string const& i : git_custom_command) {
-    git_custom.push_back(i.c_str());
-  }
-  git_custom.push_back(nullptr);
+  std::vector<std::string> git_custom;
+  git_custom.reserve(git_custom_command.size());
+  cm::append(git_custom, git_custom_command);
 
   OutputLogger custom_out(this->Log, "custom-out> ");
   OutputLogger custom_err(this->Log, "custom-err> ");
-  return this->RunUpdateCommand(git_custom.data(), &custom_out, &custom_err);
+  return this->RunUpdateCommand(git_custom, &custom_out, &custom_err);
 }
 
 bool cmCTestGIT::UpdateInternal()
@@ -244,13 +237,14 @@ bool cmCTestGIT::UpdateImpl()
   }
 
   std::string top_dir = this->FindTopDir();
-  const char* git = this->CommandLineTool.c_str();
-  const char* recursive = "--recursive";
-  const char* sync_recursive = "--recursive";
+  std::string git = this->CommandLineTool;
+  std::string recursive = "--recursive";
+  std::string sync_recursive = "--recursive";
 
   // Git < 1.6.5 did not support submodule --recursive
+  bool support_recursive = true;
   if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) {
-    recursive = nullptr;
+    support_recursive = false;
     // No need to require >= 1.6.5 if there are no submodules.
     if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) {
       this->Log << "Git < 1.6.5 cannot update submodules recursively\n";
@@ -258,8 +252,9 @@ bool cmCTestGIT::UpdateImpl()
   }
 
   // Git < 1.8.1 did not support sync --recursive
+  bool support_sync_recursive = true;
   if (this->GetGitVersion() < cmCTestGITVersion(1, 8, 1, 0)) {
-    sync_recursive = nullptr;
+    support_sync_recursive = false;
     // No need to require >= 1.8.1 if there are no submodules.
     if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) {
       this->Log << "Git < 1.8.1 cannot synchronize submodules recursively\n";
@@ -274,35 +269,39 @@ bool cmCTestGIT::UpdateImpl()
   std::string init_submodules =
     this->CTest->GetCTestConfiguration("GITInitSubmodules");
   if (cmIsOn(init_submodules)) {
-    char const* git_submodule_init[] = { git, "submodule", "init", nullptr };
+    std::vector<std::string> git_submodule_init = { git, "submodule", "init" };
     ret = this->RunChild(git_submodule_init, &submodule_out, &submodule_err,
-                         top_dir.c_str());
+                         top_dir);
 
     if (!ret) {
       return false;
     }
   }
 
-  char const* git_submodule_sync[] = { git, "submodule", "sync",
-                                       sync_recursive, nullptr };
+  std::vector<std::string> git_submodule_sync = { git, "submodule", "sync" };
+  if (support_sync_recursive) {
+    git_submodule_sync.push_back(sync_recursive);
+  }
   ret = this->RunChild(git_submodule_sync, &submodule_out, &submodule_err,
-                       top_dir.c_str());
+                       top_dir);
 
   if (!ret) {
     return false;
   }
 
-  char const* git_submodule[] = { git, "submodule", "update", recursive,
-                                  nullptr };
+  std::vector<std::string> git_submodule = { git, "submodule", "update" };
+  if (support_recursive) {
+    git_submodule.push_back(recursive);
+  }
   return this->RunChild(git_submodule, &submodule_out, &submodule_err,
-                        top_dir.c_str());
+                        top_dir);
 }
 
 unsigned int cmCTestGIT::GetGitVersion()
 {
   if (!this->CurrentGitVersion) {
-    const char* git = this->CommandLineTool.c_str();
-    char const* git_version[] = { git, "--version", nullptr };
+    std::string git = this->CommandLineTool;
+    std::vector<std::string> git_version = { git, "--version" };
     std::string version;
     OneLineParser version_out(this, "version-out> ", version);
     OutputLogger version_err(this->Log, "version-err> ");
@@ -605,50 +604,49 @@ bool cmCTestGIT::LoadRevisions()
 {
   // Use 'git rev-list ... | git diff-tree ...' to get revisions.
   std::string range = this->OldRevision + ".." + this->NewRevision;
-  const char* git = this->CommandLineTool.c_str();
-  const char* git_rev_list[] = { git,           "rev-list", "--reverse",
-                                 range.c_str(), "--",       nullptr };
-  const char* git_diff_tree[] = {
-    git,  "diff-tree",    "--stdin",          "--always", "-z",
-    "-r", "--pretty=raw", "--encoding=utf-8", nullptr
+  std::string git = this->CommandLineTool;
+  std::vector<std::string> git_rev_list = { git, "rev-list", "--reverse",
+                                            range, "--" };
+  std::vector<std::string> git_diff_tree = {
+    git,  "diff-tree", "--stdin",      "--always",
+    "-z", "-r",        "--pretty=raw", "--encoding=utf-8"
   };
   this->Log << cmCTestGIT::ComputeCommandLine(git_rev_list) << " | "
             << cmCTestGIT::ComputeCommandLine(git_diff_tree) << "\n";
 
-  cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_AddCommand(cp, git_rev_list);
-  cmsysProcess_AddCommand(cp, git_diff_tree);
-  cmsysProcess_SetWorkingDirectory(cp, this->SourceDirectory.c_str());
+  cmUVProcessChainBuilder builder;
+  builder.AddCommand(git_rev_list)
+    .AddCommand(git_diff_tree)
+    .SetWorkingDirectory(this->SourceDirectory);
 
   CommitParser out(this, "dt-out> ");
   OutputLogger err(this->Log, "dt-err> ");
-  cmCTestGIT::RunProcess(cp, &out, &err, cmProcessOutput::UTF8);
+  cmCTestGIT::RunProcess(builder, &out, &err, cmProcessOutput::UTF8);
 
   // Send one extra zero-byte to terminate the last record.
   out.Process("", 1);
 
-  cmsysProcess_Delete(cp);
   return true;
 }
 
 bool cmCTestGIT::LoadModifications()
 {
-  const char* git = this->CommandLineTool.c_str();
+  std::string git = this->CommandLineTool;
 
   // Use 'git update-index' to refresh the index w.r.t. the work tree.
-  const char* git_update_index[] = { git, "update-index", "--refresh",
-                                     nullptr };
+  std::vector<std::string> git_update_index = { git, "update-index",
+                                                "--refresh" };
   OutputLogger ui_out(this->Log, "ui-out> ");
   OutputLogger ui_err(this->Log, "ui-err> ");
-  this->RunChild(git_update_index, &ui_out, &ui_err, nullptr,
+  this->RunChild(git_update_index, &ui_out, &ui_err, "",
                  cmProcessOutput::UTF8);
 
   // Use 'git diff-index' to get modified files.
-  const char* git_diff_index[] = { git,    "diff-index", "-z",
-                                   "HEAD", "--",         nullptr };
+  std::vector<std::string> git_diff_index = { git, "diff-index", "-z", "HEAD",
+                                              "--" };
   DiffParser out(this, "di-out> ");
   OutputLogger err(this->Log, "di-err> ");
-  this->RunChild(git_diff_index, &out, &err, nullptr, cmProcessOutput::UTF8);
+  this->RunChild(git_diff_index, &out, &err, "", cmProcessOutput::UTF8);
 
   for (Change const& c : out.Changes) {
     this->DoModification(PathModified, c.Path);
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index 02837ba..e1a945d 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -95,8 +95,8 @@ private:
 std::string cmCTestHG::GetWorkingRevision()
 {
   // Run plumbing "hg identify" to get work tree revision.
-  const char* hg = this->CommandLineTool.c_str();
-  const char* hg_identify[] = { hg, "identify", "-i", nullptr };
+  std::string hg = this->CommandLineTool;
+  std::vector<std::string> hg_identify = { hg, "identify", "-i" };
   std::string rev;
   IdentifyParser out(this, "rev-out> ", rev);
   OutputLogger err(this->Log, "rev-err> ");
@@ -127,16 +127,16 @@ bool cmCTestHG::UpdateImpl()
 {
   // Use "hg pull" followed by "hg update" to update the working tree.
   {
-    const char* hg = this->CommandLineTool.c_str();
-    const char* hg_pull[] = { hg, "pull", "-v", nullptr };
+    std::string hg = this->CommandLineTool;
+    std::vector<std::string> hg_pull = { hg, "pull", "-v" };
     OutputLogger out(this->Log, "pull-out> ");
     OutputLogger err(this->Log, "pull-err> ");
-    this->RunChild(&hg_pull[0], &out, &err);
+    this->RunChild(hg_pull, &out, &err);
   }
 
   // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
 
-  std::vector<char const*> hg_update;
+  std::vector<std::string> hg_update;
   hg_update.push_back(this->CommandLineTool.c_str());
   hg_update.push_back("update");
   hg_update.push_back("-v");
@@ -147,16 +147,11 @@ bool cmCTestHG::UpdateImpl()
     opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
   }
   std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
-  for (std::string const& arg : args) {
-    hg_update.push_back(arg.c_str());
-  }
-
-  // Sentinel argument.
-  hg_update.push_back(nullptr);
+  cm::append(hg_update, args);
 
   OutputLogger out(this->Log, "update-out> ");
   OutputLogger err(this->Log, "update-err> ");
-  return this->RunUpdateCommand(hg_update.data(), &out, &err);
+  return this->RunUpdateCommand(hg_update, &out, &err);
 }
 
 class cmCTestHG::LogParser
@@ -277,8 +272,8 @@ bool cmCTestHG::LoadRevisions()
   // the project has spaces in the path.  Also, they may not have
   // proper XML escapes.
   std::string range = this->OldRevision + ":" + this->NewRevision;
-  const char* hg = this->CommandLineTool.c_str();
-  const char* hgXMLTemplate = "<logentry\n"
+  std::string hg = this->CommandLineTool;
+  std::string hgXMLTemplate = "<logentry\n"
                               "   revision=\"{node|short}\">\n"
                               "  <author>{author|person}</author>\n"
                               "  <email>{author|email}</email>\n"
@@ -288,10 +283,8 @@ bool cmCTestHG::LoadRevisions()
                               "  <file_adds>{file_adds}</file_adds>\n"
                               "  <file_dels>{file_dels}</file_dels>\n"
                               "</logentry>\n";
-  const char* hg_log[] = {
-    hg,           "log",         "--removed", "-r", range.c_str(),
-    "--template", hgXMLTemplate, nullptr
-  };
+  std::vector<std::string> hg_log = { hg,    "log",        "--removed",  "-r",
+                                      range, "--template", hgXMLTemplate };
 
   LogParser out(this, "log-out> ");
   out.Process("<?xml version=\"1.0\"?>\n"
@@ -305,8 +298,8 @@ bool cmCTestHG::LoadRevisions()
 bool cmCTestHG::LoadModifications()
 {
   // Use 'hg status' to get modified files.
-  const char* hg = this->CommandLineTool.c_str();
-  const char* hg_status[] = { hg, "status", nullptr };
+  std::string hg = this->CommandLineTool;
+  std::vector<std::string> hg_status = { hg, "status" };
   StatusParser out(this, "status-out> ");
   OutputLogger err(this->Log, "status-err> ");
   this->RunChild(hg_status, &out, &err);
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
index 0e002b9..5d71b84 100644
--- a/Source/CTest/cmCTestP4.cxx
+++ b/Source/CTest/cmCTestP4.cxx
@@ -149,17 +149,16 @@ cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
   auto it = this->Users.find(username);
 
   if (it == this->Users.end()) {
-    std::vector<char const*> p4_users;
+    std::vector<std::string> p4_users;
     this->SetP4Options(p4_users);
     p4_users.push_back("users");
     p4_users.push_back("-m");
     p4_users.push_back("1");
-    p4_users.push_back(username.c_str());
-    p4_users.push_back(nullptr);
+    p4_users.push_back(username);
 
     UserParser out(this, "users-out> ");
     OutputLogger err(this->Log, "users-err> ");
-    this->RunChild(p4_users.data(), &out, &err);
+    this->RunChild(p4_users, &out, &err);
 
     // The user should now be added to the map. Search again.
     it = this->Users.find(username);
@@ -303,10 +302,10 @@ private:
   }
 };
 
-void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
+void cmCTestP4::SetP4Options(std::vector<std::string>& CommandOptions)
 {
   if (this->P4Options.empty()) {
-    const char* p4 = this->CommandLineTool.c_str();
+    std::string p4 = this->CommandLineTool;
     this->P4Options.emplace_back(p4);
 
     // The CTEST_P4_CLIENT variable sets the P4 client used when issuing
@@ -328,15 +327,12 @@ void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
     cm::append(this->P4Options, cmSystemTools::ParseArguments(opts));
   }
 
-  CommandOptions.clear();
-  for (std::string const& o : this->P4Options) {
-    CommandOptions.push_back(o.c_str());
-  }
+  CommandOptions = this->P4Options;
 }
 
 std::string cmCTestP4::GetWorkingRevision()
 {
-  std::vector<char const*> p4_identify;
+  std::vector<std::string> p4_identify;
   this->SetP4Options(p4_identify);
 
   p4_identify.push_back("changes");
@@ -345,14 +341,13 @@ std::string cmCTestP4::GetWorkingRevision()
   p4_identify.push_back("-t");
 
   std::string source = this->SourceDirectory + "/...#have";
-  p4_identify.push_back(source.c_str());
-  p4_identify.push_back(nullptr);
+  p4_identify.push_back(source);
 
   std::string rev;
   IdentifyParser out(this, "p4_changes-out> ", rev);
   OutputLogger err(this->Log, "p4_changes-err> ");
 
-  bool result = this->RunChild(p4_identify.data(), &out, &err);
+  bool result = this->RunChild(p4_identify, &out, &err);
 
   // If there was a problem contacting the server return "<unknown>"
   if (!result) {
@@ -388,7 +383,7 @@ bool cmCTestP4::NoteNewRevision()
 
 bool cmCTestP4::LoadRevisions()
 {
-  std::vector<char const*> p4_changes;
+  std::vector<std::string> p4_changes;
   this->SetP4Options(p4_changes);
 
   // Use 'p4 changes ...@old,new' to get a list of changelists
@@ -409,38 +404,36 @@ bool cmCTestP4::LoadRevisions()
     .append(this->NewRevision);
 
   p4_changes.push_back("changes");
-  p4_changes.push_back(range.c_str());
-  p4_changes.push_back(nullptr);
+  p4_changes.push_back(range);
 
   ChangesParser out(this, "p4_changes-out> ");
   OutputLogger err(this->Log, "p4_changes-err> ");
 
   this->ChangeLists.clear();
-  this->RunChild(p4_changes.data(), &out, &err);
+  this->RunChild(p4_changes, &out, &err);
 
   if (this->ChangeLists.empty()) {
     return true;
   }
 
   // p4 describe -s ...@1111111,2222222
-  std::vector<char const*> p4_describe;
+  std::vector<std::string> p4_describe;
   for (std::string const& i : cmReverseRange(this->ChangeLists)) {
     this->SetP4Options(p4_describe);
     p4_describe.push_back("describe");
     p4_describe.push_back("-s");
-    p4_describe.push_back(i.c_str());
-    p4_describe.push_back(nullptr);
+    p4_describe.push_back(i);
 
     DescribeParser outDescribe(this, "p4_describe-out> ");
     OutputLogger errDescribe(this->Log, "p4_describe-err> ");
-    this->RunChild(p4_describe.data(), &outDescribe, &errDescribe);
+    this->RunChild(p4_describe, &outDescribe, &errDescribe);
   }
   return true;
 }
 
 bool cmCTestP4::LoadModifications()
 {
-  std::vector<char const*> p4_diff;
+  std::vector<std::string> p4_diff;
   this->SetP4Options(p4_diff);
 
   p4_diff.push_back("diff");
@@ -448,12 +441,11 @@ bool cmCTestP4::LoadModifications()
   // Ideally we would use -Od but not all clients support it
   p4_diff.push_back("-dn");
   std::string source = this->SourceDirectory + "/...";
-  p4_diff.push_back(source.c_str());
-  p4_diff.push_back(nullptr);
+  p4_diff.push_back(source);
 
   DiffParser out(this, "p4_diff-out> ");
   OutputLogger err(this->Log, "p4_diff-err> ");
-  this->RunChild(p4_diff.data(), &out, &err);
+  this->RunChild(p4_diff, &out, &err);
   return true;
 }
 
@@ -461,17 +453,14 @@ bool cmCTestP4::UpdateCustom(const std::string& custom)
 {
   cmList p4_custom_command{ custom, cmList::EmptyElements::Yes };
 
-  std::vector<char const*> p4_custom;
-  p4_custom.reserve(p4_custom_command.size() + 1);
-  for (std::string const& i : p4_custom_command) {
-    p4_custom.push_back(i.c_str());
-  }
-  p4_custom.push_back(nullptr);
+  std::vector<std::string> p4_custom;
+  p4_custom.reserve(p4_custom_command.size());
+  cm::append(p4_custom, p4_custom_command);
 
   OutputLogger custom_out(this->Log, "p4_customsync-out> ");
   OutputLogger custom_err(this->Log, "p4_customsync-err> ");
 
-  return this->RunUpdateCommand(p4_custom.data(), &custom_out, &custom_err);
+  return this->RunUpdateCommand(p4_custom, &custom_out, &custom_err);
 }
 
 bool cmCTestP4::UpdateImpl()
@@ -488,7 +477,7 @@ bool cmCTestP4::UpdateImpl()
     return false;
   }
 
-  std::vector<char const*> p4_sync;
+  std::vector<std::string> p4_sync;
   this->SetP4Options(p4_sync);
 
   p4_sync.push_back("sync");
@@ -499,9 +488,7 @@ bool cmCTestP4::UpdateImpl()
     opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
   }
   std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
-  for (std::string const& arg : args) {
-    p4_sync.push_back(arg.c_str());
-  }
+  cm::append(p4_sync, args);
 
   std::string source = this->SourceDirectory + "/...";
 
@@ -515,11 +502,10 @@ bool cmCTestP4::UpdateImpl()
     source.append("@\"").append(date).append("\"");
   }
 
-  p4_sync.push_back(source.c_str());
-  p4_sync.push_back(nullptr);
+  p4_sync.push_back(source);
 
   OutputLogger out(this->Log, "p4_sync-out> ");
   OutputLogger err(this->Log, "p4_sync-err> ");
 
-  return this->RunUpdateCommand(p4_sync.data(), &out, &err);
+  return this->RunUpdateCommand(p4_sync, &out, &err);
 }
diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h
index 1889520..827caa1 100644
--- a/Source/CTest/cmCTestP4.h
+++ b/Source/CTest/cmCTestP4.h
@@ -39,7 +39,7 @@ private:
   std::vector<std::string> P4Options;
 
   User GetUserData(const std::string& username);
-  void SetP4Options(std::vector<char const*>& options);
+  void SetP4Options(std::vector<std::string>& options);
 
   std::string GetWorkingRevision();
   bool NoteOldRevision() override;
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
index 91a1177..14bc510 100644
--- a/Source/CTest/cmCTestSVN.cxx
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -33,7 +33,7 @@ cmCTestSVN::~cmCTestSVN() = default;
 
 void cmCTestSVN::CleanupImpl()
 {
-  std::vector<const char*> svn_cleanup;
+  std::vector<std::string> svn_cleanup;
   svn_cleanup.push_back("cleanup");
   OutputLogger out(this->Log, "cleanup-out> ");
   OutputLogger err(this->Log, "cleanup-err> ");
@@ -88,9 +88,9 @@ static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2)
 std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo)
 {
   // Run "svn info" to get the repository info from the work tree.
-  std::vector<const char*> svn_info;
+  std::vector<std::string> svn_info;
   svn_info.push_back("info");
-  svn_info.push_back(svninfo.LocalPath.c_str());
+  svn_info.push_back(svninfo.LocalPath);
   std::string rev;
   InfoParser out(this, "info-out> ", rev, svninfo);
   OutputLogger err(this->Log, "info-err> ");
@@ -251,26 +251,24 @@ bool cmCTestSVN::UpdateImpl()
     args.push_back("-r{" + this->GetNightlyTime() + " +0000}");
   }
 
-  std::vector<char const*> svn_update;
+  std::vector<std::string> svn_update;
   svn_update.push_back("update");
-  for (std::string const& arg : args) {
-    svn_update.push_back(arg.c_str());
-  }
+  cm::append(svn_update, args);
 
   UpdateParser out(this, "up-out> ");
   OutputLogger err(this->Log, "up-err> ");
   return this->RunSVNCommand(svn_update, &out, &err);
 }
 
-bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
+bool cmCTestSVN::RunSVNCommand(std::vector<std::string> const& parameters,
                                OutputParser* out, OutputParser* err)
 {
   if (parameters.empty()) {
     return false;
   }
 
-  std::vector<char const*> args;
-  args.push_back(this->CommandLineTool.c_str());
+  std::vector<std::string> args;
+  args.push_back(this->CommandLineTool);
   cm::append(args, parameters);
   args.push_back("--non-interactive");
 
@@ -278,16 +276,12 @@ bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
 
   std::vector<std::string> parsedUserOptions =
     cmSystemTools::ParseArguments(userOptions);
-  for (std::string const& opt : parsedUserOptions) {
-    args.push_back(opt.c_str());
-  }
-
-  args.push_back(nullptr);
+  cm::append(args, parsedUserOptions);
 
-  if (strcmp(parameters[0], "update") == 0) {
-    return this->RunUpdateCommand(args.data(), out, err);
+  if (parameters[0] == "update") {
+    return this->RunUpdateCommand(args, out, err);
   }
-  return this->RunChild(args.data(), out, err);
+  return this->RunChild(args, out, err);
 }
 
 class cmCTestSVN::LogParser
@@ -393,7 +387,7 @@ bool cmCTestSVN::LoadRevisions(SVNInfo& svninfo)
   }
 
   // Run "svn log" to get all global revisions of interest.
-  std::vector<const char*> svn_log;
+  std::vector<std::string> svn_log;
   svn_log.push_back("log");
   svn_log.push_back("--xml");
   svn_log.push_back("-v");
@@ -472,7 +466,7 @@ private:
 bool cmCTestSVN::LoadModifications()
 {
   // Run "svn status" which reports local modifications.
-  std::vector<const char*> svn_status;
+  std::vector<std::string> svn_status;
   svn_status.push_back("status");
   StatusParser out(this, "status-out> ");
   OutputLogger err(this->Log, "status-err> ");
@@ -534,7 +528,7 @@ bool cmCTestSVN::LoadRepositories()
   this->RootInfo = &(this->Repositories.back());
 
   // Run "svn status" to get the list of external repositories
-  std::vector<const char*> svn_status;
+  std::vector<std::string> svn_status;
   svn_status.push_back("status");
   ExternalParser out(this, "external-out> ");
   OutputLogger err(this->Log, "external-err> ");
diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h
index 370d176..1485dc0 100644
--- a/Source/CTest/cmCTestSVN.h
+++ b/Source/CTest/cmCTestSVN.h
@@ -33,7 +33,7 @@ private:
   bool NoteNewRevision() override;
   bool UpdateImpl() override;
 
-  bool RunSVNCommand(std::vector<char const*> const& parameters,
+  bool RunSVNCommand(std::vector<std::string> const& parameters,
                      OutputParser* out, OutputParser* err);
 
   // Information about an SVN repository (root repository or external)
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
index 609ccba..cbbb5a5 100644
--- a/Source/CTest/cmCTestVC.cxx
+++ b/Source/CTest/cmCTestVC.cxx
@@ -7,10 +7,9 @@
 #include <sstream>
 #include <vector>
 
-#include "cmsys/Process.h"
-
 #include "cmCTest.h"
 #include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
 #include "cmValue.h"
 #include "cmXMLWriter.h"
 
@@ -55,18 +54,12 @@ bool cmCTestVC::InitialCheckout(const std::string& command)
 
   // Construct the initial checkout command line.
   std::vector<std::string> args = cmSystemTools::ParseArguments(command);
-  std::vector<char const*> vc_co;
-  vc_co.reserve(args.size() + 1);
-  for (std::string const& arg : args) {
-    vc_co.push_back(arg.c_str());
-  }
-  vc_co.push_back(nullptr);
 
   // Run the initial checkout command and log its output.
   this->Log << "--- Begin Initial Checkout ---\n";
   OutputLogger out(this->Log, "co-out> ");
   OutputLogger err(this->Log, "co-err> ");
-  bool result = this->RunChild(vc_co.data(), &out, &err, parent.c_str());
+  bool result = this->RunChild(args, &out, &err, parent);
   this->Log << "--- End Initial Checkout ---\n";
   if (!result) {
     cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -75,35 +68,35 @@ bool cmCTestVC::InitialCheckout(const std::string& command)
   return result;
 }
 
-bool cmCTestVC::RunChild(char const* const* cmd, OutputParser* out,
-                         OutputParser* err, const char* workDir,
-                         Encoding encoding)
+bool cmCTestVC::RunChild(const std::vector<std::string>& cmd,
+                         OutputParser* out, OutputParser* err,
+                         std::string workDir, Encoding encoding)
 {
   this->Log << cmCTestVC::ComputeCommandLine(cmd) << "\n";
 
-  cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, cmd);
-  workDir = workDir ? workDir : this->SourceDirectory.c_str();
-  cmsysProcess_SetWorkingDirectory(cp, workDir);
-  cmCTestVC::RunProcess(cp, out, err, encoding);
-  int result = cmsysProcess_GetExitValue(cp);
-  cmsysProcess_Delete(cp);
-  return result == 0;
+  cmUVProcessChainBuilder builder;
+  if (workDir.empty()) {
+    workDir = this->SourceDirectory;
+  }
+  builder.AddCommand(cmd).SetWorkingDirectory(workDir);
+  auto status = cmCTestVC::RunProcess(builder, out, err, encoding);
+  return status.front().SpawnResult == 0 && status.front().ExitStatus == 0;
 }
 
-std::string cmCTestVC::ComputeCommandLine(char const* const* cmd)
+std::string cmCTestVC::ComputeCommandLine(const std::vector<std::string>& cmd)
 {
   std::ostringstream line;
   const char* sep = "";
-  for (const char* const* arg = cmd; *arg; ++arg) {
-    line << sep << "\"" << *arg << "\"";
+  for (auto const& arg : cmd) {
+    line << sep << "\"" << arg << "\"";
     sep = " ";
   }
   return line.str();
 }
 
-bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
-                                 OutputParser* err, Encoding encoding)
+bool cmCTestVC::RunUpdateCommand(const std::vector<std::string>& cmd,
+                                 OutputParser* out, OutputParser* err,
+                                 Encoding encoding)
 {
   // Report the command line.
   this->UpdateCommandLine = this->ComputeCommandLine(cmd);
@@ -113,7 +106,7 @@ bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
   }
 
   // Run the command.
-  return this->RunChild(cmd, out, err, nullptr, encoding);
+  return this->RunChild(cmd, out, err, "", encoding);
 }
 
 std::string cmCTestVC::GetNightlyTime()
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
index 7b03d10..dd5456d 100644
--- a/Source/CTest/cmCTestVC.h
+++ b/Source/CTest/cmCTestVC.h
@@ -6,6 +6,7 @@
 
 #include <iosfwd>
 #include <string>
+#include <vector>
 
 #include "cmProcessOutput.h"
 #include "cmProcessTools.h"
@@ -108,15 +109,15 @@ protected:
   };
 
   /** Convert a list of arguments to a human-readable command line.  */
-  static std::string ComputeCommandLine(char const* const* cmd);
+  static std::string ComputeCommandLine(const std::vector<std::string>& cmd);
 
   /** Run a command line and send output to given parsers.  */
-  bool RunChild(char const* const* cmd, OutputParser* out, OutputParser* err,
-                const char* workDir = nullptr,
+  bool RunChild(const std::vector<std::string>& cmd, OutputParser* out,
+                OutputParser* err, std::string workDir = {},
                 Encoding encoding = cmProcessOutput::Auto);
 
   /** Run VC update command line and send output to given parsers.  */
-  bool RunUpdateCommand(char const* const* cmd, OutputParser* out,
+  bool RunUpdateCommand(const std::vector<std::string>& cmd, OutputParser* out,
                         OutputParser* err = nullptr,
                         Encoding encoding = cmProcessOutput::Auto);
 
diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx
index 9e7854b..1dd1dce 100644
--- a/Source/cmProcessTools.cxx
+++ b/Source/cmProcessTools.cxx
@@ -2,48 +2,68 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmProcessTools.h"
 
+#include <algorithm>
+#include <iterator>
 #include <ostream>
 
-#include "cmsys/Process.h"
+#include <cm3p/uv.h>
 
 #include "cmProcessOutput.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVStream.h"
 
-void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
-                                OutputParser* err, Encoding encoding)
+std::vector<cmUVProcessChain::Status> cmProcessTools::RunProcess(
+  cmUVProcessChainBuilder& builder, OutputParser* out, OutputParser* err,
+  Encoding encoding)
 {
-  cmsysProcess_Execute(cp);
-  char* data = nullptr;
-  int length = 0;
-  int p;
   cmProcessOutput processOutput(encoding);
+
+  builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
+
+  auto chain = builder.Start();
+
   std::string strdata;
-  while ((out || err) &&
-         (p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
-    if (out && p == cmsysProcess_Pipe_STDOUT) {
-      processOutput.DecodeText(data, length, strdata, 1);
-      if (!out->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
-        out = nullptr;
+  cm::uv_pipe_ptr outputPipe;
+  outputPipe.init(chain.GetLoop(), 0);
+  uv_pipe_open(outputPipe, chain.OutputStream());
+  auto outputHandle = cmUVStreamRead(
+    outputPipe,
+    [&out, &processOutput, &strdata](std::vector<char> data) {
+      if (out) {
+        processOutput.DecodeText(data.data(), data.size(), strdata, 1);
+        if (!out->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
+          out = nullptr;
+        }
       }
-    } else if (err && p == cmsysProcess_Pipe_STDERR) {
-      processOutput.DecodeText(data, length, strdata, 2);
-      if (!err->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
-        err = nullptr;
+    },
+    [&out]() { out = nullptr; });
+  cm::uv_pipe_ptr errorPipe;
+  errorPipe.init(chain.GetLoop(), 0);
+  uv_pipe_open(errorPipe, chain.ErrorStream());
+  auto errorHandle = cmUVStreamRead(
+    errorPipe,
+    [&err, &processOutput, &strdata](std::vector<char> data) {
+      if (err) {
+        processOutput.DecodeText(data.data(), data.size(), strdata, 2);
+        if (!err->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
+          err = nullptr;
+        }
       }
-    }
+    },
+    [&err]() { err = nullptr; });
+  while (out || err || !chain.Finished()) {
+    uv_run(&chain.GetLoop(), UV_RUN_ONCE);
   }
-  if (out) {
-    processOutput.DecodeText(std::string(), strdata, 1);
-    if (!strdata.empty()) {
-      out->Process(strdata.c_str(), static_cast<int>(strdata.size()));
-    }
-  }
-  if (err) {
-    processOutput.DecodeText(std::string(), strdata, 2);
-    if (!strdata.empty()) {
-      err->Process(strdata.c_str(), static_cast<int>(strdata.size()));
-    }
-  }
-  cmsysProcess_WaitForExit(cp, nullptr);
+
+  std::vector<cmUVProcessChain::Status> result;
+  auto status = chain.GetStatus();
+  std::transform(
+    status.begin(), status.end(), std::back_inserter(result),
+    [](const cmUVProcessChain::Status* s) -> cmUVProcessChain::Status {
+      return *s;
+    });
+  return result;
 }
 
 cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR)
diff --git a/Source/cmProcessTools.h b/Source/cmProcessTools.h
index 74ec5e0..2bdabea 100644
--- a/Source/cmProcessTools.h
+++ b/Source/cmProcessTools.h
@@ -7,8 +7,10 @@
 #include <cstring>
 #include <iosfwd>
 #include <string>
+#include <vector>
 
 #include "cmProcessOutput.h"
+#include "cmUVProcessChain.h"
 
 /** \class cmProcessTools
  * \brief Helper classes for process output parsing
@@ -81,7 +83,7 @@ public:
   };
 
   /** Run a process and send output to given parsers.  */
-  static void RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
-                         OutputParser* err = nullptr,
-                         Encoding encoding = cmProcessOutput::Auto);
+  static std::vector<cmUVProcessChain::Status> RunProcess(
+    cmUVProcessChainBuilder& builder, OutputParser* out,
+    OutputParser* err = nullptr, Encoding encoding = cmProcessOutput::Auto);
 };
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 2ac9d8e..1263bb2 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -28,6 +28,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTransformDepfile.h"
+#include "cmUVHandlePtr.h"
 #include "cmUVProcessChain.h"
 #include "cmUVStream.h"
 #include "cmUtils.hxx"
@@ -295,14 +296,8 @@ int CLCompileAndDependencies(const std::vector<std::string>& args)
     }
   }
 
-  std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp(
-    cmsysProcess_New(), cmsysProcess_Delete);
-  std::vector<const char*> argv(command.size() + 1);
-  std::transform(command.begin(), command.end(), argv.begin(),
-                 [](std::string const& s) { return s.c_str(); });
-  argv.back() = nullptr;
-  cmsysProcess_SetCommand(cp.get(), argv.data());
-  cmsysProcess_SetWorkingDirectory(cp.get(), currentBinaryDir.c_str());
+  cmUVProcessChainBuilder builder;
+  builder.AddCommand(command).SetWorkingDirectory(currentBinaryDir);
 
   cmsys::ofstream fout(depFile.c_str());
   if (!fout) {
@@ -313,22 +308,18 @@ int CLCompileAndDependencies(const std::vector<std::string>& args)
   CLOutputLogger errLogger(std::cerr);
 
   // Start the process.
-  cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger);
+  auto result =
+    cmProcessTools::RunProcess(builder, &includeParser, &errLogger);
+  auto const& subStatus = result.front();
 
   int status = 0;
   // handle status of process
-  switch (cmsysProcess_GetState(cp.get())) {
-    case cmsysProcess_State_Exited:
-      status = cmsysProcess_GetExitValue(cp.get());
-      break;
-    case cmsysProcess_State_Exception:
-      status = 1;
-      break;
-    case cmsysProcess_State_Error:
-      status = 2;
-      break;
-    default:
-      break;
+  if (subStatus.SpawnResult != 0) {
+    status = 2;
+  } else if (subStatus.TermSignal != 0) {
+    status = 1;
+  } else {
+    status = subStatus.ExitStatus;
   }
 
   if (status != 0) {
-- 
cgit v0.12