cmProcess.cxx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmProcess.h"
  4. #include "cmProcessOutput.h"
  5. #include "cmSystemTools.h"
  6. #include <iostream>
  7. cmProcess::cmProcess()
  8. {
  9. this->Process = nullptr;
  10. this->Timeout = 0;
  11. this->TotalTime = 0;
  12. this->ExitValue = 0;
  13. this->Id = 0;
  14. this->StartTime = 0;
  15. }
  16. cmProcess::~cmProcess()
  17. {
  18. cmsysProcess_Delete(this->Process);
  19. }
  20. void cmProcess::SetCommand(const char* command)
  21. {
  22. this->Command = command;
  23. }
  24. void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
  25. {
  26. this->Arguments = args;
  27. }
  28. bool cmProcess::StartProcess()
  29. {
  30. if (this->Command.empty()) {
  31. return false;
  32. }
  33. this->StartTime = cmSystemTools::GetTime();
  34. this->ProcessArgs.clear();
  35. // put the command as arg0
  36. this->ProcessArgs.push_back(this->Command.c_str());
  37. // now put the command arguments in
  38. for (std::string const& arg : this->Arguments) {
  39. this->ProcessArgs.push_back(arg.c_str());
  40. }
  41. this->ProcessArgs.push_back(nullptr); // null terminate the list
  42. this->Process = cmsysProcess_New();
  43. cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin());
  44. if (!this->WorkingDirectory.empty()) {
  45. cmsysProcess_SetWorkingDirectory(this->Process,
  46. this->WorkingDirectory.c_str());
  47. }
  48. cmsysProcess_SetTimeout(this->Process, this->Timeout);
  49. cmsysProcess_SetOption(this->Process, cmsysProcess_Option_MergeOutput, 1);
  50. cmsysProcess_Execute(this->Process);
  51. return (cmsysProcess_GetState(this->Process) ==
  52. cmsysProcess_State_Executing);
  53. }
  54. bool cmProcess::Buffer::GetLine(std::string& line)
  55. {
  56. // Scan for the next newline.
  57. for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
  58. if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
  59. // Extract the range first..last as a line.
  60. const char* text = &*this->begin() + this->First;
  61. size_type length = this->Last - this->First;
  62. while (length && text[length - 1] == '\r') {
  63. length--;
  64. }
  65. line.assign(text, length);
  66. // Start a new range for the next line.
  67. ++this->Last;
  68. this->First = Last;
  69. // Return the line extracted.
  70. return true;
  71. }
  72. }
  73. // Available data have been exhausted without a newline.
  74. if (this->First != 0) {
  75. // Move the partial line to the beginning of the buffer.
  76. this->erase(this->begin(), this->begin() + this->First);
  77. this->First = 0;
  78. this->Last = this->size();
  79. }
  80. return false;
  81. }
  82. bool cmProcess::Buffer::GetLast(std::string& line)
  83. {
  84. // Return the partial last line, if any.
  85. if (!this->empty()) {
  86. line.assign(&*this->begin(), this->size());
  87. this->First = this->Last = 0;
  88. this->clear();
  89. return true;
  90. }
  91. return false;
  92. }
  93. int cmProcess::GetNextOutputLine(std::string& line, double timeout)
  94. {
  95. cmProcessOutput processOutput(cmProcessOutput::UTF8);
  96. std::string strdata;
  97. for (;;) {
  98. // Look for lines already buffered.
  99. if (this->Output.GetLine(line)) {
  100. return cmsysProcess_Pipe_STDOUT;
  101. }
  102. // Check for more data from the process.
  103. char* data;
  104. int length;
  105. int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout);
  106. if (p == cmsysProcess_Pipe_Timeout) {
  107. return cmsysProcess_Pipe_Timeout;
  108. }
  109. if (p == cmsysProcess_Pipe_STDOUT) {
  110. processOutput.DecodeText(data, length, strdata);
  111. this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
  112. } else { // p == cmsysProcess_Pipe_None
  113. // The process will provide no more data.
  114. break;
  115. }
  116. }
  117. processOutput.DecodeText(std::string(), strdata);
  118. if (!strdata.empty()) {
  119. this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
  120. }
  121. // Look for partial last lines.
  122. if (this->Output.GetLast(line)) {
  123. return cmsysProcess_Pipe_STDOUT;
  124. }
  125. // No more data. Wait for process exit.
  126. if (!cmsysProcess_WaitForExit(this->Process, &timeout)) {
  127. return cmsysProcess_Pipe_Timeout;
  128. }
  129. // Record exit information.
  130. this->ExitValue = cmsysProcess_GetExitValue(this->Process);
  131. this->TotalTime = cmSystemTools::GetTime() - this->StartTime;
  132. // Because of a processor clock scew the runtime may become slightly
  133. // negative. If someone changed the system clock while the process was
  134. // running this may be even more. Make sure not to report a negative
  135. // duration here.
  136. if (this->TotalTime <= 0.0) {
  137. this->TotalTime = 0.0;
  138. }
  139. // std::cerr << "Time to run: " << this->TotalTime << "\n";
  140. return cmsysProcess_Pipe_None;
  141. }
  142. // return the process status
  143. int cmProcess::GetProcessStatus()
  144. {
  145. if (!this->Process) {
  146. return cmsysProcess_State_Exited;
  147. }
  148. return cmsysProcess_GetState(this->Process);
  149. }
  150. int cmProcess::ReportStatus()
  151. {
  152. int result = 1;
  153. switch (cmsysProcess_GetState(this->Process)) {
  154. case cmsysProcess_State_Starting: {
  155. std::cerr << "cmProcess: Never started " << this->Command
  156. << " process.\n";
  157. } break;
  158. case cmsysProcess_State_Error: {
  159. std::cerr << "cmProcess: Error executing " << this->Command
  160. << " process: " << cmsysProcess_GetErrorString(this->Process)
  161. << "\n";
  162. } break;
  163. case cmsysProcess_State_Exception: {
  164. std::cerr << "cmProcess: " << this->Command
  165. << " process exited with an exception: ";
  166. switch (cmsysProcess_GetExitException(this->Process)) {
  167. case cmsysProcess_Exception_None: {
  168. std::cerr << "None";
  169. } break;
  170. case cmsysProcess_Exception_Fault: {
  171. std::cerr << "Segmentation fault";
  172. } break;
  173. case cmsysProcess_Exception_Illegal: {
  174. std::cerr << "Illegal instruction";
  175. } break;
  176. case cmsysProcess_Exception_Interrupt: {
  177. std::cerr << "Interrupted by user";
  178. } break;
  179. case cmsysProcess_Exception_Numerical: {
  180. std::cerr << "Numerical exception";
  181. } break;
  182. case cmsysProcess_Exception_Other: {
  183. std::cerr << "Unknown";
  184. } break;
  185. }
  186. std::cerr << "\n";
  187. } break;
  188. case cmsysProcess_State_Executing: {
  189. std::cerr << "cmProcess: Never terminated " << this->Command
  190. << " process.\n";
  191. } break;
  192. case cmsysProcess_State_Exited: {
  193. result = cmsysProcess_GetExitValue(this->Process);
  194. std::cerr << "cmProcess: " << this->Command
  195. << " process exited with code " << result << "\n";
  196. } break;
  197. case cmsysProcess_State_Expired: {
  198. std::cerr << "cmProcess: killed " << this->Command
  199. << " process due to timeout.\n";
  200. } break;
  201. case cmsysProcess_State_Killed: {
  202. std::cerr << "cmProcess: killed " << this->Command << " process.\n";
  203. } break;
  204. }
  205. return result;
  206. }
  207. void cmProcess::ChangeTimeout(double t)
  208. {
  209. this->Timeout = t;
  210. cmsysProcess_SetTimeout(this->Process, this->Timeout);
  211. }
  212. void cmProcess::ResetStartTime()
  213. {
  214. cmsysProcess_ResetStartTime(this->Process);
  215. this->StartTime = cmSystemTools::GetTime();
  216. }
  217. int cmProcess::GetExitException()
  218. {
  219. return cmsysProcess_GetExitException(this->Process);
  220. }
  221. std::string cmProcess::GetExitExceptionString()
  222. {
  223. return cmsysProcess_GetExceptionString(this->Process);
  224. }