123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmExecProgramCommand.h"
- #include "cmsys/Process.h"
- #include <stdio.h>
- #include "cmMakefile.h"
- #include "cmProcessOutput.h"
- #include "cmSystemTools.h"
- class cmExecutionStatus;
- // cmExecProgramCommand
- bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus&)
- {
- if (args.empty()) {
- this->SetError("called with incorrect number of arguments");
- return false;
- }
- std::string arguments;
- bool doingargs = false;
- int count = 0;
- std::string output_variable;
- bool haveoutput_variable = false;
- std::string return_variable;
- bool havereturn_variable = false;
- for (std::string const& arg : args) {
- if (arg == "OUTPUT_VARIABLE") {
- count++;
- doingargs = false;
- havereturn_variable = false;
- haveoutput_variable = true;
- } else if (haveoutput_variable) {
- if (!output_variable.empty()) {
- this->SetError("called with incorrect number of arguments");
- return false;
- }
- output_variable = arg;
- haveoutput_variable = false;
- count++;
- } else if (arg == "RETURN_VALUE") {
- count++;
- doingargs = false;
- haveoutput_variable = false;
- havereturn_variable = true;
- } else if (havereturn_variable) {
- if (!return_variable.empty()) {
- this->SetError("called with incorrect number of arguments");
- return false;
- }
- return_variable = arg;
- havereturn_variable = false;
- count++;
- } else if (arg == "ARGS") {
- count++;
- havereturn_variable = false;
- haveoutput_variable = false;
- doingargs = true;
- } else if (doingargs) {
- arguments += arg;
- arguments += " ";
- count++;
- }
- }
- std::string command;
- if (!arguments.empty()) {
- command = cmSystemTools::ConvertToRunCommandPath(args[0].c_str());
- command += " ";
- command += arguments;
- } else {
- command = args[0];
- }
- bool verbose = true;
- if (!output_variable.empty()) {
- verbose = false;
- }
- int retVal = 0;
- std::string output;
- bool result = true;
- if (args.size() - count == 2) {
- cmSystemTools::MakeDirectory(args[1]);
- result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
- args[1].c_str(), verbose);
- } else {
- result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
- nullptr, verbose);
- }
- if (!result) {
- retVal = -1;
- }
- if (!output_variable.empty()) {
- std::string::size_type first = output.find_first_not_of(" \n\t\r");
- std::string::size_type last = output.find_last_not_of(" \n\t\r");
- if (first == std::string::npos) {
- first = 0;
- }
- if (last == std::string::npos) {
- last = output.size() - 1;
- }
- std::string coutput = std::string(output, first, last - first + 1);
- this->Makefile->AddDefinition(output_variable, coutput.c_str());
- }
- if (!return_variable.empty()) {
- char buffer[100];
- sprintf(buffer, "%d", retVal);
- this->Makefile->AddDefinition(return_variable, buffer);
- }
- return true;
- }
- bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
- int& retVal, const char* dir,
- bool verbose, Encoding encoding)
- {
- if (cmSystemTools::GetRunCommandOutput()) {
- verbose = false;
- }
- #if defined(_WIN32) && !defined(__CYGWIN__)
- // if the command does not start with a quote, then
- // try to find the program, and if the program can not be
- // found use system to run the command as it must be a built in
- // shell command like echo or dir
- int count = 0;
- std::string shortCmd;
- if (command[0] == '\"') {
- // count the number of quotes
- for (const char* s = command; *s != 0; ++s) {
- if (*s == '\"') {
- count++;
- if (count > 2) {
- break;
- }
- }
- }
- // if there are more than two double quotes use
- // GetShortPathName, the cmd.exe program in windows which
- // is used by system fails to execute if there are more than
- // one set of quotes in the arguments
- if (count > 2) {
- cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)");
- if (quoted.find(command)) {
- std::string cmd = quoted.match(1);
- std::string args = quoted.match(2);
- if (!cmSystemTools::FileExists(cmd)) {
- shortCmd = cmd;
- } else if (!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) {
- cmSystemTools::Error("GetShortPath failed for ", cmd.c_str());
- return false;
- }
- shortCmd += " ";
- shortCmd += args;
- command = shortCmd.c_str();
- } else {
- cmSystemTools::Error("Could not parse command line with quotes ",
- command);
- }
- }
- }
- #endif
- // Allocate a process instance.
- cmsysProcess* cp = cmsysProcess_New();
- if (!cp) {
- cmSystemTools::Error("Error allocating process instance.");
- return false;
- }
- #if defined(_WIN32) && !defined(__CYGWIN__)
- if (dir) {
- cmsysProcess_SetWorkingDirectory(cp, dir);
- }
- if (cmSystemTools::GetRunCommandHideConsole()) {
- cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
- }
- cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
- const char* cmd[] = { command, 0 };
- cmsysProcess_SetCommand(cp, cmd);
- #else
- std::string commandInDir;
- if (dir) {
- commandInDir = "cd \"";
- commandInDir += dir;
- commandInDir += "\" && ";
- commandInDir += command;
- } else {
- commandInDir = command;
- }
- #ifndef __VMS
- commandInDir += " 2>&1";
- #endif
- command = commandInDir.c_str();
- if (verbose) {
- cmSystemTools::Stdout("running ");
- cmSystemTools::Stdout(command);
- cmSystemTools::Stdout("\n");
- }
- fflush(stdout);
- fflush(stderr);
- const char* cmd[] = { "/bin/sh", "-c", command, nullptr };
- cmsysProcess_SetCommand(cp, cmd);
- #endif
- cmsysProcess_Execute(cp);
- // Read the process output.
- int length;
- char* data;
- int p;
- cmProcessOutput processOutput(encoding);
- std::string strdata;
- while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr), p)) {
- if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) {
- if (verbose) {
- processOutput.DecodeText(data, length, strdata);
- cmSystemTools::Stdout(strdata.c_str(), strdata.size());
- }
- output.append(data, length);
- }
- }
- if (verbose) {
- processOutput.DecodeText(std::string(), strdata);
- if (!strdata.empty()) {
- cmSystemTools::Stdout(strdata.c_str(), strdata.size());
- }
- }
- // All output has been read. Wait for the process to exit.
- cmsysProcess_WaitForExit(cp, nullptr);
- processOutput.DecodeText(output, output);
- // Check the result of running the process.
- std::string msg;
- switch (cmsysProcess_GetState(cp)) {
- case cmsysProcess_State_Exited:
- retVal = cmsysProcess_GetExitValue(cp);
- break;
- case cmsysProcess_State_Exception:
- retVal = -1;
- msg += "\nProcess terminated due to: ";
- msg += cmsysProcess_GetExceptionString(cp);
- break;
- case cmsysProcess_State_Error:
- retVal = -1;
- msg += "\nProcess failed because: ";
- msg += cmsysProcess_GetErrorString(cp);
- break;
- case cmsysProcess_State_Expired:
- retVal = -1;
- msg += "\nProcess terminated due to timeout.";
- break;
- }
- if (!msg.empty()) {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- // Old Windows process execution printed this info.
- msg += "\n\nfor command: ";
- msg += command;
- if (dir) {
- msg += "\nin dir: ";
- msg += dir;
- }
- msg += "\n";
- if (verbose) {
- cmSystemTools::Stdout(msg.c_str());
- }
- output += msg;
- #else
- // Old UNIX process execution only put message in output.
- output += msg;
- #endif
- }
- // Delete the process instance.
- cmsysProcess_Delete(cp);
- return true;
- }
|