|
|
@@ -22,7 +22,6 @@
|
|
|
|
|
|
#include <cmsys/RegularExpression.hxx>
|
|
|
#include <cmsys/Directory.hxx>
|
|
|
-#include <cmsys/Process.h>
|
|
|
|
|
|
// support for realpath call
|
|
|
#ifndef _WIN32
|
|
|
@@ -302,116 +301,283 @@ bool cmSystemTools::RunCommand(const char* command,
|
|
|
dir, verbose, timeout);
|
|
|
}
|
|
|
|
|
|
-bool cmSystemTools::RunCommand(const char* command,
|
|
|
- std::string& output,
|
|
|
- int &retVal,
|
|
|
- const char* dir,
|
|
|
- bool verbose,
|
|
|
- int)
|
|
|
+#if defined(WIN32) && !defined(__CYGWIN__)
|
|
|
+#include "cmWin32ProcessExecution.h"
|
|
|
+// use this for shell commands like echo and dir
|
|
|
+bool RunCommandViaWin32(const char* command,
|
|
|
+ const char* dir,
|
|
|
+ std::string& output,
|
|
|
+ int& retVal,
|
|
|
+ bool verbose,
|
|
|
+ int timeout)
|
|
|
{
|
|
|
- if(s_DisableRunCommandOutput)
|
|
|
+#if defined(__BORLANDC__)
|
|
|
+ return cmWin32ProcessExecution::BorlandRunCommand(command, dir, output,
|
|
|
+ retVal,
|
|
|
+ verbose, timeout,
|
|
|
+ cmSystemTools::GetRunCommandHideConsole());
|
|
|
+#else // Visual studio
|
|
|
+ ::SetLastError(ERROR_SUCCESS);
|
|
|
+ if ( ! command )
|
|
|
+ {
|
|
|
+ cmSystemTools::Error("No command specified");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ cmWin32ProcessExecution resProc;
|
|
|
+ if(cmSystemTools::GetRunCommandHideConsole())
|
|
|
{
|
|
|
- verbose = false;
|
|
|
+ resProc.SetHideWindows(true);
|
|
|
}
|
|
|
|
|
|
- std::vector<std::string> args;
|
|
|
- std::string arg;
|
|
|
-
|
|
|
- // Split the command into an argv array.
|
|
|
- for(const char* c = command; *c;)
|
|
|
+ if ( cmSystemTools::GetWindows9xComspecSubstitute() )
|
|
|
{
|
|
|
- // Skip over whitespace.
|
|
|
- while(*c == ' ' || *c == '\t')
|
|
|
- {
|
|
|
- ++c;
|
|
|
- }
|
|
|
- arg = "";
|
|
|
- if(*c == '"')
|
|
|
+ resProc.SetConsoleSpawn(cmSystemTools::GetWindows9xComspecSubstitute() );
|
|
|
+ }
|
|
|
+ if ( !resProc.StartProcess(command, dir, verbose) )
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ resProc.Wait(timeout);
|
|
|
+ output = resProc.GetOutput();
|
|
|
+ retVal = resProc.GetExitValue();
|
|
|
+ return true;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+// use this for shell commands like echo and dir
|
|
|
+bool RunCommandViaSystem(const char* command,
|
|
|
+ const char* dir,
|
|
|
+ std::string& output,
|
|
|
+ int& retVal,
|
|
|
+ bool verbose)
|
|
|
+{
|
|
|
+ std::cout << "@@ " << command << std::endl;
|
|
|
+
|
|
|
+ std::string commandInDir;
|
|
|
+ if(dir)
|
|
|
+ {
|
|
|
+ commandInDir = "cd ";
|
|
|
+ commandInDir += cmSystemTools::ConvertToOutputPath(dir);
|
|
|
+ commandInDir += " && ";
|
|
|
+ commandInDir += command;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ commandInDir = command;
|
|
|
+ }
|
|
|
+ command = commandInDir.c_str();
|
|
|
+ std::string commandToFile = command;
|
|
|
+ commandToFile += " > ";
|
|
|
+ std::string tempFile;
|
|
|
+ tempFile += _tempnam(0, "cmake");
|
|
|
+
|
|
|
+ commandToFile += tempFile;
|
|
|
+ retVal = system(commandToFile.c_str());
|
|
|
+ std::ifstream fin(tempFile.c_str());
|
|
|
+ if(!fin)
|
|
|
+ {
|
|
|
+ if(verbose)
|
|
|
{
|
|
|
- // Parse a quoted argument.
|
|
|
- ++c;
|
|
|
- while(*c && *c != '"')
|
|
|
- {
|
|
|
- if(*c == '\\')
|
|
|
- {
|
|
|
- ++c;
|
|
|
- if(*c)
|
|
|
- {
|
|
|
- arg.append(1, *c);
|
|
|
- ++c;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- arg.append(1, *c);
|
|
|
- ++c;
|
|
|
- }
|
|
|
- }
|
|
|
- if(*c)
|
|
|
- {
|
|
|
- ++c;
|
|
|
- }
|
|
|
- args.push_back(arg);
|
|
|
+ std::string errormsg = "RunCommand produced no output: command: \"";
|
|
|
+ errormsg += command;
|
|
|
+ errormsg += "\"";
|
|
|
+ errormsg += "\nOutput file: ";
|
|
|
+ errormsg += tempFile;
|
|
|
+ cmSystemTools::Error(errormsg.c_str());
|
|
|
}
|
|
|
- else if(*c)
|
|
|
+ fin.close();
|
|
|
+ cmSystemTools::RemoveFile(tempFile.c_str());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ bool multiLine = false;
|
|
|
+ std::string line;
|
|
|
+ while(cmSystemTools::GetLineFromStream(fin, line))
|
|
|
+ {
|
|
|
+ output += line;
|
|
|
+ if(multiLine)
|
|
|
{
|
|
|
- // Parse an unquoted argument.
|
|
|
- while(*c && *c != ' ' && *c != '\t')
|
|
|
- {
|
|
|
- arg.append(1, *c);
|
|
|
- ++c;
|
|
|
- }
|
|
|
- args.push_back(arg);
|
|
|
+ output += "\n";
|
|
|
}
|
|
|
+ multiLine = true;
|
|
|
}
|
|
|
-
|
|
|
- std::vector<const char*> argv;
|
|
|
- for(std::vector<std::string>::const_iterator a = args.begin();
|
|
|
- a != args.end(); ++a)
|
|
|
+ fin.close();
|
|
|
+ cmSystemTools::RemoveFile(tempFile.c_str());
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+#else // We have popen
|
|
|
+
|
|
|
+bool RunCommandViaPopen(const char* command,
|
|
|
+ const char* dir,
|
|
|
+ std::string& output,
|
|
|
+ int& retVal,
|
|
|
+ bool verbose,
|
|
|
+ int /*timeout*/)
|
|
|
+{
|
|
|
+ // if only popen worked on windows.....
|
|
|
+ std::string commandInDir;
|
|
|
+ if(dir)
|
|
|
{
|
|
|
- argv.push_back(a->c_str());
|
|
|
+ commandInDir = "cd \"";
|
|
|
+ commandInDir += dir;
|
|
|
+ commandInDir += "\" && ";
|
|
|
+ commandInDir += command;
|
|
|
}
|
|
|
- argv.push_back(0);
|
|
|
-
|
|
|
- if(argv.size() < 2)
|
|
|
+ else
|
|
|
+ {
|
|
|
+ commandInDir = command;
|
|
|
+ }
|
|
|
+ commandInDir += " 2>&1";
|
|
|
+ command = commandInDir.c_str();
|
|
|
+ const int BUFFER_SIZE = 4096;
|
|
|
+ char buffer[BUFFER_SIZE];
|
|
|
+ if(verbose)
|
|
|
+ {
|
|
|
+ std::cout << "running " << command << std::endl;
|
|
|
+ }
|
|
|
+ fflush(stdout);
|
|
|
+ fflush(stderr);
|
|
|
+ FILE* cpipe = popen(command, "r");
|
|
|
+ if(!cpipe)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
- output = "";
|
|
|
- cmsysProcess* cp = cmsysProcess_New();
|
|
|
- cmsysProcess_SetCommand(cp, &*argv.begin());
|
|
|
- cmsysProcess_SetWorkingDirectory(cp, dir);
|
|
|
- cmsysProcess_Execute(cp);
|
|
|
-
|
|
|
- char* data;
|
|
|
- int length;
|
|
|
- while(cmsysProcess_WaitForData(cp, (cmsysProcess_Pipe_STDOUT |
|
|
|
- cmsysProcess_Pipe_STDERR),
|
|
|
- &data, &length, 0))
|
|
|
+ fgets(buffer, BUFFER_SIZE, cpipe);
|
|
|
+ while(!feof(cpipe))
|
|
|
{
|
|
|
- output.append(data, length);
|
|
|
if(verbose)
|
|
|
{
|
|
|
- std::cout.write(data, length);
|
|
|
+ std::cout << buffer << std::flush;
|
|
|
}
|
|
|
+ output += buffer;
|
|
|
+ fgets(buffer, BUFFER_SIZE, cpipe);
|
|
|
}
|
|
|
-
|
|
|
- cmsysProcess_WaitForExit(cp, 0);
|
|
|
-
|
|
|
- bool result = true;
|
|
|
- if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
|
|
|
+
|
|
|
+ retVal = pclose(cpipe);
|
|
|
+ if (WIFEXITED(retVal))
|
|
|
{
|
|
|
- retVal = cmsysProcess_GetExitValue(cp);
|
|
|
+ retVal = WEXITSTATUS(retVal);
|
|
|
+ return true;
|
|
|
}
|
|
|
- else
|
|
|
+ if (WIFSIGNALED(retVal))
|
|
|
{
|
|
|
- result = false;
|
|
|
+ retVal = WTERMSIG(retVal);
|
|
|
+ cmOStringStream error;
|
|
|
+ error << "\nProcess terminated due to ";
|
|
|
+ switch (retVal)
|
|
|
+ {
|
|
|
+#ifdef SIGKILL
|
|
|
+ case SIGKILL:
|
|
|
+ error << "SIGKILL";
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+#ifdef SIGFPE
|
|
|
+ case SIGFPE:
|
|
|
+ error << "SIGFPE";
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+#ifdef SIGBUS
|
|
|
+ case SIGBUS:
|
|
|
+ error << "SIGBUS";
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+#ifdef SIGSEGV
|
|
|
+ case SIGSEGV:
|
|
|
+ error << "SIGSEGV";
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+ default:
|
|
|
+ error << "signal " << retVal;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ output += error.str();
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+#endif // endif WIN32 not CYGWIN
|
|
|
+
|
|
|
+
|
|
|
+// run a command unix uses popen (easy)
|
|
|
+// windows uses system and ShortPath
|
|
|
+bool cmSystemTools::RunCommand(const char* command,
|
|
|
+ std::string& output,
|
|
|
+ int &retVal,
|
|
|
+ const char* dir,
|
|
|
+ bool verbose,
|
|
|
+ int timeout)
|
|
|
+{
|
|
|
+ if(s_DisableRunCommandOutput)
|
|
|
+ {
|
|
|
+ verbose = false;
|
|
|
}
|
|
|
|
|
|
- cmsysProcess_Delete(cp);
|
|
|
-
|
|
|
- return result;
|
|
|
+#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;
|
|
|
+ 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 shortCmd;
|
|
|
+ std::string cmd = quoted.match(1);
|
|
|
+ std::string args = quoted.match(2);
|
|
|
+ if(! cmSystemTools::FileExists(cmd.c_str()) )
|
|
|
+ {
|
|
|
+ shortCmd = cmd;
|
|
|
+ }
|
|
|
+ else if(!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd))
|
|
|
+ {
|
|
|
+ cmSystemTools::Error("GetShortPath failed for " , cmd.c_str());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ shortCmd += " ";
|
|
|
+ shortCmd += args;
|
|
|
+
|
|
|
+ //return RunCommandViaSystem(shortCmd.c_str(), dir,
|
|
|
+ // output, retVal, verbose);
|
|
|
+ //return WindowsRunCommand(shortCmd.c_str(), dir,
|
|
|
+ //output, retVal, verbose);
|
|
|
+ return RunCommandViaWin32(shortCmd.c_str(), dir,
|
|
|
+ output, retVal, verbose, timeout);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ cmSystemTools::Error("Could not parse command line with quotes ",
|
|
|
+ command);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // if there is only one set of quotes or no quotes then just run the command
|
|
|
+ //return RunCommandViaSystem(command, dir, output, retVal, verbose);
|
|
|
+ //return WindowsRunCommand(command, dir, output, retVal, verbose);
|
|
|
+ return ::RunCommandViaWin32(command, dir, output, retVal, verbose, timeout);
|
|
|
+#else
|
|
|
+ return ::RunCommandViaPopen(command, dir, output, retVal, verbose, timeout);
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
bool cmSystemTools::DoesFileExistWithExtensions(
|