Add two cmake commands -E echo for echoing strings and -E comspec for workaround of bug of windows 9x; add another implementation of run command on windows which should work...
This commit is contained in:
parent
c310600df5
commit
780a9bbda7
|
@ -74,6 +74,19 @@ bool cmSystemTools::s_DisableRunCommandOutput = false;
|
||||||
bool cmSystemTools::s_ErrorOccured = false;
|
bool cmSystemTools::s_ErrorOccured = false;
|
||||||
bool cmSystemTools::s_DisableMessages = false;
|
bool cmSystemTools::s_DisableMessages = false;
|
||||||
|
|
||||||
|
std::string cmSystemTools::s_Windows9xComspecSubstitute = "command.com";
|
||||||
|
void cmSystemTools::SetWindows9xComspecSubstitute(const char* str)
|
||||||
|
{
|
||||||
|
if ( str )
|
||||||
|
{
|
||||||
|
cmSystemTools::s_Windows9xComspecSubstitute = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char* cmSystemTools::GetWindows9xComspecSubstitute()
|
||||||
|
{
|
||||||
|
return cmSystemTools::s_Windows9xComspecSubstitute.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
void (*cmSystemTools::s_ErrorCallback)(const char*, const char*, bool&, void*);
|
void (*cmSystemTools::s_ErrorCallback)(const char*, const char*, bool&, void*);
|
||||||
void* cmSystemTools::s_ErrorCallbackClientData = 0;
|
void* cmSystemTools::s_ErrorCallbackClientData = 0;
|
||||||
|
|
||||||
|
@ -1004,7 +1017,7 @@ void cmSystemTools::Message(const char* m1, const char *title)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << m1 << std::endl;
|
std::cerr << m1 << std::endl << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1249,6 +1262,250 @@ bool cmSystemTools::RunCommand(const char* command,
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||||
|
// Code from a Borland web site with the following explaination :
|
||||||
|
/* In this article, I will explain how to spawn a console application
|
||||||
|
* and redirect its standard input/output using anonymous pipes. An
|
||||||
|
* anonymous pipe is a pipe that goes only in one direction (read
|
||||||
|
* pipe, write pipe, etc.). Maybe you are asking, "why would I ever
|
||||||
|
* need to do this sort of thing?" One example would be a Windows
|
||||||
|
* telnet server, where you spawn a shell and listen on a port and
|
||||||
|
* send and receive data between the shell and the socket
|
||||||
|
* client. (Windows does not really have a built-in remote
|
||||||
|
* shell). First, we should talk about pipes. A pipe in Windows is
|
||||||
|
* simply a method of communication, often between process. The SDK
|
||||||
|
* defines a pipe as "a communication conduit with two ends;
|
||||||
|
a process
|
||||||
|
* with a handle to one end can communicate with a process having a
|
||||||
|
* handle to the other end." In our case, we are using "anonymous"
|
||||||
|
* pipes, one-way pipes that "transfer data between a parent process
|
||||||
|
* and a child process or between two child processes of the same
|
||||||
|
* parent process." It's easiest to imagine a pipe as its namesake. An
|
||||||
|
* actual pipe running between processes that can carry data. We are
|
||||||
|
* using anonymous pipes because the console app we are spawning is a
|
||||||
|
* child process. We use the CreatePipe function which will create an
|
||||||
|
* anonymous pipe and return a read handle and a write handle. We will
|
||||||
|
* create two pipes, on for stdin and one for stdout. We will then
|
||||||
|
* monitor the read end of the stdout pipe to check for display on our
|
||||||
|
* child process. Every time there is something availabe for reading,
|
||||||
|
* we will display it in our app. Consequently, we check for input in
|
||||||
|
* our app and send it off to the write end of the stdin pipe. */
|
||||||
|
|
||||||
|
inline bool IsWinNT()
|
||||||
|
//check if we're running NT
|
||||||
|
{
|
||||||
|
OSVERSIONINFO osv;
|
||||||
|
osv.dwOSVersionInfoSize = sizeof(osv);
|
||||||
|
GetVersionEx(&osv);
|
||||||
|
return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayErrorMessage()
|
||||||
|
{
|
||||||
|
LPVOID lpMsgBuf;
|
||||||
|
FormatMessage(
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL,
|
||||||
|
GetLastError(),
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||||
|
(LPTSTR) &lpMsgBuf,
|
||||||
|
0,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
// Process any inserts in lpMsgBuf.
|
||||||
|
// ...
|
||||||
|
// Display the string.
|
||||||
|
MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
|
||||||
|
// Free the buffer.
|
||||||
|
LocalFree( lpMsgBuf );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool WindowsRunCommand(const char* command, const char* dir,
|
||||||
|
std::string& output, int& retVal, bool verbose)
|
||||||
|
{
|
||||||
|
//verbose = true;
|
||||||
|
std::cerr << std::endl
|
||||||
|
<< "WindowsRunCommand(" << command << ")" << std::endl
|
||||||
|
<< std::flush;
|
||||||
|
const int BUFFER_SIZE = 4096;
|
||||||
|
char buf[BUFFER_SIZE];
|
||||||
|
|
||||||
|
//i/o buffer
|
||||||
|
STARTUPINFO si;
|
||||||
|
SECURITY_ATTRIBUTES sa;
|
||||||
|
SECURITY_DESCRIPTOR sd;
|
||||||
|
|
||||||
|
//security information for pipes
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
HANDLE newstdin,newstdout,read_stdout,write_stdin;
|
||||||
|
|
||||||
|
//pipe handles
|
||||||
|
if (IsWinNT())
|
||||||
|
//initialize security descriptor (Windows NT)
|
||||||
|
{
|
||||||
|
InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
|
||||||
|
SetSecurityDescriptorDacl(&sd, true, NULL, false);
|
||||||
|
sa.lpSecurityDescriptor = &sd;
|
||||||
|
|
||||||
|
}
|
||||||
|
else sa.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
|
sa.bInheritHandle = true;
|
||||||
|
|
||||||
|
//allow inheritable handles
|
||||||
|
if (!CreatePipe(&newstdin,&write_stdin,&sa,0))
|
||||||
|
//create stdin pipe
|
||||||
|
{
|
||||||
|
std::cerr << "CreatePipe" << std::endl;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!CreatePipe(&read_stdout,&newstdout,&sa,0))
|
||||||
|
//create stdout pipe
|
||||||
|
{
|
||||||
|
std::cerr << "CreatePipe" << std::endl;
|
||||||
|
CloseHandle(newstdin);
|
||||||
|
CloseHandle(write_stdin);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
GetStartupInfo(&si);
|
||||||
|
|
||||||
|
//set startupinfo for the spawned process
|
||||||
|
/* The dwFlags member tells CreateProcess how to make the
|
||||||
|
* process. STARTF_USESTDHANDLES validates the hStd*
|
||||||
|
* members. STARTF_USESHOWWINDOW validates the wShowWindow
|
||||||
|
* member. */
|
||||||
|
|
||||||
|
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
||||||
|
si.wShowWindow = SW_HIDE;
|
||||||
|
si.hStdOutput = newstdout;
|
||||||
|
si.hStdError = newstdout;
|
||||||
|
|
||||||
|
//set the new handles for the child process si.hStdInput = newstdin;
|
||||||
|
char* commandAndArgs = strcpy(new char[strlen(command)+1], command);
|
||||||
|
if (!CreateProcess(NULL,commandAndArgs,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,
|
||||||
|
NULL,dir,&si,&pi))
|
||||||
|
{
|
||||||
|
std::cerr << "CreateProcess failed " << commandAndArgs << std::endl;
|
||||||
|
CloseHandle(newstdin);
|
||||||
|
CloseHandle(newstdout);
|
||||||
|
CloseHandle(read_stdout);
|
||||||
|
CloseHandle(write_stdin);
|
||||||
|
delete [] commandAndArgs;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
delete [] commandAndArgs;
|
||||||
|
unsigned long exit=0;
|
||||||
|
|
||||||
|
//process exit code unsigned
|
||||||
|
unsigned long bread;
|
||||||
|
|
||||||
|
//bytes read unsigned
|
||||||
|
unsigned long avail;
|
||||||
|
|
||||||
|
//bytes available
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
for(;;)
|
||||||
|
//main program loop
|
||||||
|
{
|
||||||
|
Sleep(10);
|
||||||
|
//std::cout << "Check for process..." << std::endl;
|
||||||
|
GetExitCodeProcess(pi.hProcess,&exit);
|
||||||
|
|
||||||
|
//while the process is running
|
||||||
|
if (exit != STILL_ACTIVE) break;
|
||||||
|
|
||||||
|
//check to see if there is any data to read from stdout
|
||||||
|
//std::cout << "Peek for data..." << std::endl;
|
||||||
|
PeekNamedPipe(read_stdout,buf,1023,&bread,&avail,NULL);
|
||||||
|
if (bread != 0)
|
||||||
|
{
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
if (avail > 1023)
|
||||||
|
{
|
||||||
|
while (bread >= 1023)
|
||||||
|
{
|
||||||
|
//std::cout << "Read data..." << std::endl;
|
||||||
|
ReadFile(read_stdout,buf,1023,&bread,NULL);
|
||||||
|
|
||||||
|
//read the stdout pipe
|
||||||
|
printf("%s",buf);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReadFile(read_stdout,buf,1023,&bread,NULL);
|
||||||
|
output += buf;
|
||||||
|
output += "\n";
|
||||||
|
if(verbose)
|
||||||
|
{
|
||||||
|
std::cerr << verbose << " [{" << buf << "}]"
|
||||||
|
<< std::endl << std::flush;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(newstdin);
|
||||||
|
|
||||||
|
//clean stuff up
|
||||||
|
CloseHandle(newstdout);
|
||||||
|
CloseHandle(read_stdout);
|
||||||
|
CloseHandle(write_stdin);
|
||||||
|
retVal = exit;
|
||||||
|
std::cerr << std::endl << "End of WindowsRunCommand(" << command << ")" << std::endl << std::flush;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
if ( ! command )
|
||||||
|
{
|
||||||
|
cmSystemTools::Error("No command specified");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//std::cout << "Command: " << command << std::endl;
|
||||||
|
if ( dir )
|
||||||
|
{
|
||||||
|
//std::cout << "Dir: " << dir << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmWin32ProcessExecution resProc;
|
||||||
|
if ( cmSystemTools::GetWindows9xComspecSubstitute() )
|
||||||
|
{
|
||||||
|
resProc.SetConsoleSpawn(cmSystemTools::GetWindows9xComspecSubstitute() );
|
||||||
|
}
|
||||||
|
if ( !resProc.StartProcess(command, dir, verbose) )
|
||||||
|
{
|
||||||
|
std::cout << "Problem starting command" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
resProc.Wait(INFINITE);
|
||||||
|
output = resProc.GetOutput();
|
||||||
|
retVal = resProc.GetExitValue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// use this for shell commands like echo and dir
|
// use this for shell commands like echo and dir
|
||||||
bool RunCommandViaSystem(const char* command,
|
bool RunCommandViaSystem(const char* command,
|
||||||
const char* dir,
|
const char* dir,
|
||||||
|
@ -1256,6 +1513,8 @@ bool RunCommandViaSystem(const char* command,
|
||||||
int& retVal,
|
int& retVal,
|
||||||
bool verbose)
|
bool verbose)
|
||||||
{
|
{
|
||||||
|
std::cout << "@@ " << command << std::endl;
|
||||||
|
|
||||||
const int BUFFER_SIZE = 4096;
|
const int BUFFER_SIZE = 4096;
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
std::string commandInDir;
|
std::string commandInDir;
|
||||||
|
@ -1366,8 +1625,13 @@ bool cmSystemTools::RunCommand(const char* command,
|
||||||
}
|
}
|
||||||
shortCmd += " ";
|
shortCmd += " ";
|
||||||
shortCmd += args;
|
shortCmd += args;
|
||||||
return RunCommandViaSystem(shortCmd.c_str(), dir,
|
|
||||||
output, retVal, verbose);
|
//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);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1377,7 +1641,9 @@ bool cmSystemTools::RunCommand(const char* command,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if there is only one set of quotes or no quotes then just run the 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 RunCommandViaSystem(command, dir, output, retVal, verbose);
|
||||||
|
//return WindowsRunCommand(command, dir, output, retVal, verbose);
|
||||||
|
return RunCommandViaWin32(command, dir, output, retVal, verbose);
|
||||||
#else
|
#else
|
||||||
// if only popen worked on windows.....
|
// if only popen worked on windows.....
|
||||||
std::string commandInDir;
|
std::string commandInDir;
|
||||||
|
|
|
@ -311,6 +311,14 @@ public:
|
||||||
*/
|
*/
|
||||||
static e_FileFormat GetFileFormat(const char* ext);
|
static e_FileFormat GetFileFormat(const char* ext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Windows 9x we need a comspec (command.com) substitute to run
|
||||||
|
* programs correctly. This string has to be constant available
|
||||||
|
* through the running of program. This method does not create a copy.
|
||||||
|
*/
|
||||||
|
static void SetWindows9xComspecSubstitute(const char*);
|
||||||
|
static const char* GetWindows9xComspecSubstitute();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// these two functions can be called from ConvertToOutputPath
|
// these two functions can be called from ConvertToOutputPath
|
||||||
/**
|
/**
|
||||||
|
@ -333,6 +341,8 @@ private:
|
||||||
static bool s_DisableRunCommandOutput;
|
static bool s_DisableRunCommandOutput;
|
||||||
static ErrorCallback s_ErrorCallback;
|
static ErrorCallback s_ErrorCallback;
|
||||||
static void* s_ErrorCallbackClientData;
|
static void* s_ErrorCallbackClientData;
|
||||||
|
|
||||||
|
static std::string s_Windows9xComspecSubstitute;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "cmGlobalVisualStudio7Generator.h"
|
#include "cmGlobalVisualStudio7Generator.h"
|
||||||
#include "cmGlobalBorlandMakefileGenerator.h"
|
#include "cmGlobalBorlandMakefileGenerator.h"
|
||||||
#include "cmGlobalNMakeMakefileGenerator.h"
|
#include "cmGlobalNMakeMakefileGenerator.h"
|
||||||
|
#include "cmWin32ProcessExecution.h"
|
||||||
#else
|
#else
|
||||||
#include "cmGlobalUnixMakefileGenerator.h"
|
#include "cmGlobalUnixMakefileGenerator.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -430,6 +431,11 @@ int cmake::AddCMakePaths(const char *arg0)
|
||||||
this->m_CacheManager->AddCacheEntry
|
this->m_CacheManager->AddCacheEntry
|
||||||
("CMAKE_ROOT", cMakeRoot.c_str(),
|
("CMAKE_ROOT", cMakeRoot.c_str(),
|
||||||
"Path to CMake installation.", cmCacheManager::INTERNAL);
|
"Path to CMake installation.", cmCacheManager::INTERNAL);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
cmSystemTools::SetWindows9xComspecSubstitute(
|
||||||
|
(cMakeSelf + " -E comspec").c_str());
|
||||||
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,12 +454,14 @@ void CMakeCommandUsage(const char* program)
|
||||||
<< "Available commands: \n"
|
<< "Available commands: \n"
|
||||||
<< " chdir dir cmd [args]... - run command in a given directory\n"
|
<< " chdir dir cmd [args]... - run command in a given directory\n"
|
||||||
<< " copy file destination - copy file to destination (either file or directory)\n"
|
<< " copy file destination - copy file to destination (either file or directory)\n"
|
||||||
|
<< " echo [string]... - displays arguments as text\n"
|
||||||
<< " remove file1 file2 ... - remove the file(s)\n"
|
<< " remove file1 file2 ... - remove the file(s)\n"
|
||||||
<< " time command [args] ... - run command and return elapsed time\n";
|
<< " time command [args] ... - run command and return elapsed time\n";
|
||||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
errorStream
|
errorStream
|
||||||
<< " write_regv key value - write registry value\n"
|
<< " write_regv key value - write registry value\n"
|
||||||
<< " delete_regv key - delete registry value\n";
|
<< " delete_regv key - delete registry value\n"
|
||||||
|
<< " comspec - on windows 9x use this for RunCommand\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cmSystemTools::Error(errorStream.str().c_str());
|
cmSystemTools::Error(errorStream.str().c_str());
|
||||||
|
@ -470,6 +478,18 @@ int cmake::CMakeCommand(std::vector<std::string>& args)
|
||||||
return cmSystemTools::GetErrorOccuredFlag();
|
return cmSystemTools::GetErrorOccuredFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Echo string
|
||||||
|
else if (args[1] == "echo" )
|
||||||
|
{
|
||||||
|
int cc;
|
||||||
|
for ( cc = 2; cc < args.size(); cc ++ )
|
||||||
|
{
|
||||||
|
std::cout << args[cc] << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove file
|
// Remove file
|
||||||
else if (args[1] == "remove" && args.size() > 2)
|
else if (args[1] == "remove" && args.size() > 2)
|
||||||
{
|
{
|
||||||
|
@ -522,7 +542,7 @@ int cmake::CMakeCommand(std::vector<std::string>& args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clock command
|
// Clock command
|
||||||
else if (args[1] == "chdir" && args.size() > 2)
|
else if (args[1] == "chdir" && args.size() == 4)
|
||||||
{
|
{
|
||||||
std::string directory = args[2];
|
std::string directory = args[2];
|
||||||
std::string command = args[3];
|
std::string command = args[3];
|
||||||
|
@ -557,6 +577,17 @@ int cmake::CMakeCommand(std::vector<std::string>& args)
|
||||||
{
|
{
|
||||||
return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
|
return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
// Remove file
|
||||||
|
else if (args[1] == "comspec" && args.size() > 2)
|
||||||
|
{
|
||||||
|
int cc;
|
||||||
|
std::string command = args[2];
|
||||||
|
for ( cc = 3; cc < args.size(); cc ++ )
|
||||||
|
{
|
||||||
|
command += " " + args[cc];
|
||||||
|
}
|
||||||
|
return cmWin32ProcessExecution::Windows9xHack(command.c_str());
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue