cmExecProgramCommand.cxx 7.9 KB

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