cmExecProgramCommand.cxx 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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 "cmExecProgramCommand.h"
  4. #include "cmSystemTools.h"
  5. #include <cmsys/Process.h>
  6. // cmExecProgramCommand
  7. bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
  8. cmExecutionStatus&)
  9. {
  10. if (args.empty()) {
  11. this->SetError("called with incorrect number of arguments");
  12. return false;
  13. }
  14. std::string arguments;
  15. bool doingargs = false;
  16. int count = 0;
  17. std::string output_variable;
  18. bool haveoutput_variable = false;
  19. std::string return_variable;
  20. bool havereturn_variable = false;
  21. for (size_t i = 0; i < args.size(); ++i) {
  22. if (args[i] == "OUTPUT_VARIABLE") {
  23. count++;
  24. doingargs = false;
  25. havereturn_variable = false;
  26. haveoutput_variable = true;
  27. } else if (haveoutput_variable) {
  28. if (!output_variable.empty()) {
  29. this->SetError("called with incorrect number of arguments");
  30. return false;
  31. }
  32. output_variable = args[i];
  33. haveoutput_variable = false;
  34. count++;
  35. } else if (args[i] == "RETURN_VALUE") {
  36. count++;
  37. doingargs = false;
  38. haveoutput_variable = false;
  39. havereturn_variable = true;
  40. } else if (havereturn_variable) {
  41. if (!return_variable.empty()) {
  42. this->SetError("called with incorrect number of arguments");
  43. return false;
  44. }
  45. return_variable = args[i];
  46. havereturn_variable = false;
  47. count++;
  48. } else if (args[i] == "ARGS") {
  49. count++;
  50. havereturn_variable = false;
  51. haveoutput_variable = false;
  52. doingargs = true;
  53. } else if (doingargs) {
  54. arguments += args[i];
  55. arguments += " ";
  56. count++;
  57. }
  58. }
  59. std::string command;
  60. if (!arguments.empty()) {
  61. command = cmSystemTools::ConvertToRunCommandPath(args[0].c_str());
  62. command += " ";
  63. command += arguments;
  64. } else {
  65. command = args[0];
  66. }
  67. bool verbose = true;
  68. if (!output_variable.empty()) {
  69. verbose = false;
  70. }
  71. int retVal = 0;
  72. std::string output;
  73. bool result = true;
  74. if (args.size() - count == 2) {
  75. cmSystemTools::MakeDirectory(args[1].c_str());
  76. result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
  77. args[1].c_str(), verbose);
  78. } else {
  79. result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
  80. CM_NULLPTR, verbose);
  81. }
  82. if (!result) {
  83. retVal = -1;
  84. }
  85. if (!output_variable.empty()) {
  86. std::string::size_type first = output.find_first_not_of(" \n\t\r");
  87. std::string::size_type last = output.find_last_not_of(" \n\t\r");
  88. if (first == std::string::npos) {
  89. first = 0;
  90. }
  91. if (last == std::string::npos) {
  92. last = output.size() - 1;
  93. }
  94. std::string coutput = std::string(output, first, last - first + 1);
  95. this->Makefile->AddDefinition(output_variable, coutput.c_str());
  96. }
  97. if (!return_variable.empty()) {
  98. char buffer[100];
  99. sprintf(buffer, "%d", retVal);
  100. this->Makefile->AddDefinition(return_variable, buffer);
  101. }
  102. return true;
  103. }
  104. bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
  105. int& retVal, const char* dir,
  106. bool verbose)
  107. {
  108. if (cmSystemTools::GetRunCommandOutput()) {
  109. verbose = false;
  110. }
  111. #if defined(_WIN32) && !defined(__CYGWIN__)
  112. // if the command does not start with a quote, then
  113. // try to find the program, and if the program can not be
  114. // found use system to run the command as it must be a built in
  115. // shell command like echo or dir
  116. int count = 0;
  117. std::string shortCmd;
  118. if (command[0] == '\"') {
  119. // count the number of quotes
  120. for (const char* s = command; *s != 0; ++s) {
  121. if (*s == '\"') {
  122. count++;
  123. if (count > 2) {
  124. break;
  125. }
  126. }
  127. }
  128. // if there are more than two double quotes use
  129. // GetShortPathName, the cmd.exe program in windows which
  130. // is used by system fails to execute if there are more than
  131. // one set of quotes in the arguments
  132. if (count > 2) {
  133. cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)");
  134. if (quoted.find(command)) {
  135. std::string cmd = quoted.match(1);
  136. std::string args = quoted.match(2);
  137. if (!cmSystemTools::FileExists(cmd.c_str())) {
  138. shortCmd = cmd;
  139. } else if (!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) {
  140. cmSystemTools::Error("GetShortPath failed for ", cmd.c_str());
  141. return false;
  142. }
  143. shortCmd += " ";
  144. shortCmd += args;
  145. command = shortCmd.c_str();
  146. } else {
  147. cmSystemTools::Error("Could not parse command line with quotes ",
  148. command);
  149. }
  150. }
  151. }
  152. #endif
  153. // Allocate a process instance.
  154. cmsysProcess* cp = cmsysProcess_New();
  155. if (!cp) {
  156. cmSystemTools::Error("Error allocating process instance.");
  157. return false;
  158. }
  159. #if defined(_WIN32) && !defined(__CYGWIN__)
  160. if (dir) {
  161. cmsysProcess_SetWorkingDirectory(cp, dir);
  162. }
  163. if (cmSystemTools::GetRunCommandHideConsole()) {
  164. cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
  165. }
  166. cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
  167. const char* cmd[] = { command, 0 };
  168. cmsysProcess_SetCommand(cp, cmd);
  169. #else
  170. std::string commandInDir;
  171. if (dir) {
  172. commandInDir = "cd \"";
  173. commandInDir += dir;
  174. commandInDir += "\" && ";
  175. commandInDir += command;
  176. } else {
  177. commandInDir = command;
  178. }
  179. #ifndef __VMS
  180. commandInDir += " 2>&1";
  181. #endif
  182. command = commandInDir.c_str();
  183. if (verbose) {
  184. cmSystemTools::Stdout("running ");
  185. cmSystemTools::Stdout(command);
  186. cmSystemTools::Stdout("\n");
  187. }
  188. fflush(stdout);
  189. fflush(stderr);
  190. const char* cmd[] = { "/bin/sh", "-c", command, CM_NULLPTR };
  191. cmsysProcess_SetCommand(cp, cmd);
  192. #endif
  193. cmsysProcess_Execute(cp);
  194. // Read the process output.
  195. int length;
  196. char* data;
  197. int p;
  198. while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
  199. if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) {
  200. if (verbose) {
  201. cmSystemTools::Stdout(data, length);
  202. }
  203. output.append(data, length);
  204. }
  205. }
  206. // All output has been read. Wait for the process to exit.
  207. cmsysProcess_WaitForExit(cp, CM_NULLPTR);
  208. // Check the result of running the process.
  209. std::string msg;
  210. switch (cmsysProcess_GetState(cp)) {
  211. case cmsysProcess_State_Exited:
  212. retVal = cmsysProcess_GetExitValue(cp);
  213. break;
  214. case cmsysProcess_State_Exception:
  215. retVal = -1;
  216. msg += "\nProcess terminated due to: ";
  217. msg += cmsysProcess_GetExceptionString(cp);
  218. break;
  219. case cmsysProcess_State_Error:
  220. retVal = -1;
  221. msg += "\nProcess failed because: ";
  222. msg += cmsysProcess_GetErrorString(cp);
  223. break;
  224. case cmsysProcess_State_Expired:
  225. retVal = -1;
  226. msg += "\nProcess terminated due to timeout.";
  227. break;
  228. }
  229. if (!msg.empty()) {
  230. #if defined(_WIN32) && !defined(__CYGWIN__)
  231. // Old Windows process execution printed this info.
  232. msg += "\n\nfor command: ";
  233. msg += command;
  234. if (dir) {
  235. msg += "\nin dir: ";
  236. msg += dir;
  237. }
  238. msg += "\n";
  239. if (verbose) {
  240. cmSystemTools::Stdout(msg.c_str());
  241. }
  242. output += msg;
  243. #else
  244. // Old UNIX process execution only put message in output.
  245. output += msg;
  246. #endif
  247. }
  248. // Delete the process instance.
  249. cmsysProcess_Delete(cp);
  250. return true;
  251. }