diff options
author | Bill Hoffman <bill.hoffman@kitware.com> | 2012-06-27 16:28:12 (GMT) |
---|---|---|
committer | Bill Hoffman <bill.hoffman@kitware.com> | 2012-06-27 16:28:12 (GMT) |
commit | 5f12424ebc9f810ef279d09f1e660e20558dd535 (patch) | |
tree | e42617c6c100febe9c6bd92652b691426976bf78 /Source/cmcldeps.cxx | |
parent | bd67f75e41e4525abdf3db5184c34d7d5895615d (diff) | |
download | CMake-5f12424ebc9f810ef279d09f1e660e20558dd535.zip CMake-5f12424ebc9f810ef279d09f1e660e20558dd535.tar.gz CMake-5f12424ebc9f810ef279d09f1e660e20558dd535.tar.bz2 |
Remove process execution code from cmcldeps and have it use cmake code.
This simplifies the code in cmcldeps and avoids having yet another
set of process execution code.
Diffstat (limited to 'Source/cmcldeps.cxx')
-rw-r--r-- | Source/cmcldeps.cxx | 516 |
1 files changed, 34 insertions, 482 deletions
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx index 7d3c4bd..39f696f 100644 --- a/Source/cmcldeps.cxx +++ b/Source/cmcldeps.cxx @@ -1,8 +1,4 @@ -/* - ninja's subprocess.h -*/ - -// Copyright 2012 Google Inc. All Rights Reserved. +// Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,114 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef NINJA_SUBPROCESS_H_ -#define NINJA_SUBPROCESS_H_ -#include <string> -#include <vector> -#include <queue> -#include <cstdio> -#include <algorithm> +// Wrapper around cl that adds /showIncludes to command line, and uses that to +// generate .d files that match the style from gcc -MD. +// +// /showIncludes is equivalent to -MD, not -MMD, that is, system headers are +// included. -#ifdef _WIN32 #include <windows.h> -#else -#include <signal.h> -#endif - - -#if defined(_WIN64) -typedef unsigned __int64 cmULONG_PTR; -#else -typedef unsigned long cmULONG_PTR; -#endif - -//#include "exit_status.h" -enum ExitStatus { - ExitSuccess, - ExitFailure, - ExitInterrupted -}; - -/// Subprocess wraps a single async subprocess. It is entirely -/// passive: it expects the caller to notify it when its fds are ready -/// for reading, as well as call Finish() to reap the child once done() -/// is true. -struct Subprocess { - ~Subprocess(); - - /// Returns ExitSuccess on successful process exit, ExitInterrupted if - /// the process was interrupted, ExitFailure if it otherwise failed. - ExitStatus Finish(); - - bool Done() const; - - const std::string& GetOutput() const; - - int ExitCode() const { return exit_code_; } - - private: - Subprocess(); - bool Start(struct SubprocessSet* set, const std::string& command, - const std::string& dir); - void OnPipeReady(); - - std::string buf_; - -#ifdef _WIN32 - /// Set up pipe_ as the parent-side pipe of the subprocess; return the - /// other end of the pipe, usable in the child process. - HANDLE SetupPipe(HANDLE ioport); - - PROCESS_INFORMATION child_; - HANDLE pipe_; - OVERLAPPED overlapped_; - char overlapped_buf_[4 << 10]; - bool is_reading_; - int exit_code_; -#else - int fd_; - pid_t pid_; -#endif - - friend struct SubprocessSet; -}; - -/// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses. -/// DoWork() waits for any state change in subprocesses; finished_ -/// is a queue of subprocesses as they finish. -struct SubprocessSet { - SubprocessSet(); - ~SubprocessSet(); - - Subprocess* Add(const std::string& command, const std::string& dir); - bool DoWork(); - Subprocess* NextFinished(); - void Clear(); - - std::vector<Subprocess*> running_; - std::queue<Subprocess*> finished_; - -#ifdef _WIN32 - static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType); - static HANDLE ioport_; -#else - static void SetInterruptedFlag(int signum); - static bool interrupted_; - - struct sigaction old_act_; - sigset_t old_mask_; -#endif -}; - -#endif // NINJA_SUBPROCESS_H_ - - -/* - ninja's util functions -*/ +#include <sstream> +#include <cmSystemTools.h> +// We don't want any wildcard expansion. +// See http://msdn.microsoft.com/en-us/library/zay8tzh6(v=vs.85).aspx +void _setargv() {} static void Fatal(const char* msg, ...) { va_list ap; @@ -132,370 +35,13 @@ static void Fatal(const char* msg, ...) { vfprintf(stderr, msg, ap); va_end(ap); fprintf(stderr, "\n"); -#ifdef _WIN32 // On Windows, some tools may inject extra threads. // exit() may block on locks held by those threads, so forcibly exit. fflush(stderr); fflush(stdout); ExitProcess(1); -#else - exit(1); -#endif -} - - -#ifdef _WIN32 -std::string GetLastErrorString() { - DWORD err = GetLastError(); - - char* msg_buf; - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (char*)&msg_buf, - 0, - NULL); - std::string msg = msg_buf; - LocalFree(msg_buf); - return msg; -} -#endif - -#define snprintf _snprintf - - -/* - ninja's subprocess-win32.cc -*/ - -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//#include "subprocess.h" - -#include <stdio.h> - -#include <algorithm> - -//#include "util.h" - -namespace { - -void Win32Fatal(const char* function) { - Fatal("%s: %s", function, GetLastErrorString().c_str()); -} - -} // anonymous namespace - -Subprocess::Subprocess() : overlapped_(), is_reading_(false), - exit_code_(1) { - child_.hProcess = NULL; -} - -Subprocess::~Subprocess() { - if (pipe_) { - if (!CloseHandle(pipe_)) - Win32Fatal("CloseHandle"); - } - // Reap child if forgotten. - if (child_.hProcess) - Finish(); -} - -HANDLE Subprocess::SetupPipe(HANDLE ioport) { - char pipe_name[100]; - snprintf(pipe_name, sizeof(pipe_name), - "\\\\.\\pipe\\ninja_pid%u_sp%p", GetCurrentProcessId(), this); - - pipe_ = ::CreateNamedPipeA(pipe_name, - PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE, - PIPE_UNLIMITED_INSTANCES, - 0, 0, INFINITE, NULL); - if (pipe_ == INVALID_HANDLE_VALUE) - Win32Fatal("CreateNamedPipe"); - - if (!CreateIoCompletionPort(pipe_, ioport, (cmULONG_PTR)this, 0)) - Win32Fatal("CreateIoCompletionPort"); - - memset(&overlapped_, 0, sizeof(overlapped_)); - if (!ConnectNamedPipe(pipe_, &overlapped_) && - GetLastError() != ERROR_IO_PENDING) { - Win32Fatal("ConnectNamedPipe"); - } - - // Get the write end of the pipe as a handle inheritable across processes. - HANDLE output_write_handle = CreateFile(pipe_name, GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, 0, NULL); - HANDLE output_write_child; - if (!DuplicateHandle(GetCurrentProcess(), output_write_handle, - GetCurrentProcess(), &output_write_child, - 0, TRUE, DUPLICATE_SAME_ACCESS)) { - Win32Fatal("DuplicateHandle"); - } - CloseHandle(output_write_handle); - - return output_write_child; -} - -bool Subprocess::Start(SubprocessSet* set, const std::string& command, - const std::string& dir) { - HANDLE child_pipe = SetupPipe(set->ioport_); - - SECURITY_ATTRIBUTES security_attributes; - memset(&security_attributes, 0, sizeof(SECURITY_ATTRIBUTES)); - security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); - security_attributes.bInheritHandle = TRUE; - // Must be inheritable so subprocesses can dup to children. - HANDLE nul = CreateFile("NUL", GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - &security_attributes, OPEN_EXISTING, 0, NULL); - if (nul == INVALID_HANDLE_VALUE) - Fatal("couldn't open nul"); - - STARTUPINFOA startup_info; - memset(&startup_info, 0, sizeof(startup_info)); - startup_info.cb = sizeof(STARTUPINFO); - startup_info.dwFlags = STARTF_USESTDHANDLES; - startup_info.hStdInput = nul; - startup_info.hStdOutput = child_pipe; - startup_info.hStdError = child_pipe; - - PROCESS_INFORMATION process_info; - memset(&process_info, 0, sizeof(process_info)); - - // Do not prepend 'cmd /c' on Windows, this breaks command - // lines greater than 8,191 chars. - if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL, - /* inherit handles */ TRUE, CREATE_NEW_PROCESS_GROUP, - NULL, (dir.empty() ? NULL : dir.c_str()), - &startup_info, &process_info)) { - DWORD error = GetLastError(); - if (error == ERROR_FILE_NOT_FOUND) { - // file (program) not found error is treated - // as a normal build action failure - if (child_pipe) - CloseHandle(child_pipe); - CloseHandle(pipe_); - CloseHandle(nul); - pipe_ = NULL; - // child_ is already NULL; - buf_ = - "CreateProcess failed: The system cannot find the file specified.\n"; - return true; - } else { - Win32Fatal("CreateProcess"); // pass all other errors to Win32Fatal - } - } - - // Close pipe channel only used by the child. - if (child_pipe) - CloseHandle(child_pipe); - CloseHandle(nul); - - CloseHandle(process_info.hThread); - child_ = process_info; - - return true; -} - -void Subprocess::OnPipeReady() { - DWORD bytes; - if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) { - if (GetLastError() == ERROR_BROKEN_PIPE) { - CloseHandle(pipe_); - pipe_ = NULL; - return; - } - Win32Fatal("GetOverlappedResult"); - } - - if (is_reading_ && bytes) - buf_.append(overlapped_buf_, bytes); - - memset(&overlapped_, 0, sizeof(overlapped_)); - is_reading_ = true; - if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_), - &bytes, &overlapped_)) { - if (GetLastError() == ERROR_BROKEN_PIPE) { - CloseHandle(pipe_); - pipe_ = NULL; - return; - } - if (GetLastError() != ERROR_IO_PENDING) - Win32Fatal("ReadFile"); - } - - // Even if we read any bytes in the readfile call, we'll enter this - // function again later and get them at that point. -} - -ExitStatus Subprocess::Finish() { - if (!child_.hProcess) - return ExitFailure; - - // TODO: add error handling for all of these. - WaitForSingleObject(child_.hProcess, INFINITE); - - DWORD exit_code = 0; - GetExitCodeProcess(child_.hProcess, &exit_code); - - CloseHandle(child_.hProcess); - child_.hProcess = NULL; - exit_code_ = exit_code; - return exit_code == 0 ? ExitSuccess : - exit_code == CONTROL_C_EXIT ? ExitInterrupted : - ExitFailure; -} - -bool Subprocess::Done() const { - return pipe_ == NULL; -} - -const std::string& Subprocess::GetOutput() const { - return buf_; -} - -HANDLE SubprocessSet::ioport_; - -SubprocessSet::SubprocessSet() { - ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); - if (!ioport_) - Win32Fatal("CreateIoCompletionPort"); - if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE)) - Win32Fatal("SetConsoleCtrlHandler"); -} - -SubprocessSet::~SubprocessSet() { - Clear(); - - SetConsoleCtrlHandler(NotifyInterrupted, FALSE); - CloseHandle(ioport_); -} - -BOOL WINAPI SubprocessSet::NotifyInterrupted(DWORD dwCtrlType) { - if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { - if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL)) - Win32Fatal("PostQueuedCompletionStatus"); - return TRUE; - } - - return FALSE; -} - -Subprocess *SubprocessSet::Add(const std::string& command, - const std::string& dir) { - Subprocess *subprocess = new Subprocess; - if (!subprocess->Start(this, command, dir)) { - delete subprocess; - return 0; - } - if (subprocess->child_.hProcess) - running_.push_back(subprocess); - else - finished_.push(subprocess); - return subprocess; -} - -bool SubprocessSet::DoWork() { - DWORD bytes_read; - Subprocess* subproc; - OVERLAPPED* overlapped; - - if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (cmULONG_PTR*)&subproc, - &overlapped, INFINITE)) { - if (GetLastError() != ERROR_BROKEN_PIPE) - Win32Fatal("GetQueuedCompletionStatus"); - } - - if (!subproc) // A NULL subproc indicates that we were interrupted and is - // delivered by NotifyInterrupted above. - return true; - - subproc->OnPipeReady(); - - if (subproc->Done()) { - std::vector<Subprocess*>::iterator end = - std::remove(running_.begin(), running_.end(), subproc); - if (running_.end() != end) { - finished_.push(subproc); - running_.resize(end - running_.begin()); - } - } - - return false; -} - -Subprocess* SubprocessSet::NextFinished() { - if (finished_.empty()) - return NULL; - Subprocess* subproc = finished_.front(); - finished_.pop(); - return subproc; -} - -void SubprocessSet::Clear() { - std::vector<Subprocess*>::iterator it = running_.begin(); - for (; it != running_.end(); ++it) { - if ((*it)->child_.hProcess) { - if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, - (*it)->child_.dwProcessId)) - Win32Fatal("GenerateConsoleCtrlEvent"); - } - } - it = running_.begin(); - for (; it != running_.end(); ++it) - delete *it; - running_.clear(); } - -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -// Wrapper around cl that adds /showIncludes to command line, and uses that to -// generate .d files that match the style from gcc -MD. -// -// /showIncludes is equivalent to -MD, not -MMD, that is, system headers are -// included. - - -#include <windows.h> -#include <sstream> -//#include "subprocess.h" -//#include "util.h" - -// We don't want any wildcard expansion. -// See http://msdn.microsoft.com/en-us/library/zay8tzh6(v=vs.85).aspx -void _setargv() {} - static void usage(const char* msg) { Fatal("%s\n\nusage:\n " "cmcldeps " @@ -629,24 +175,30 @@ static int process( const std::string& srcfilename, const std::string& prefix, const std::string& cmd, const std::string& dir = "", - bool quiet = false) { - - SubprocessSet subprocs; - Subprocess* subproc = subprocs.Add(cmd, dir); - - if(!subproc) + bool quiet = false) +{ + std::string output; + int ret = 0; + // break up command line into a vector + std::vector<std::string> args; + cmSystemTools::ParseWindowsCommandLine(cmd.c_str(), + args); + // convert to correct vector type for RunSingleCommand + std::vector<cmStdString> command; + for(std::vector<std::string>::iterator i = args.begin(); + i != args.end(); ++i) + { + command.push_back(i->c_str()); + } + // run the command + bool success = + cmSystemTools::RunSingleCommand(command, &output, &ret, dir.c_str(), + cmSystemTools::OUTPUT_NONE); + if(ret!= 0) + { return 2; - - while ((subproc = subprocs.NextFinished()) == NULL) { - subprocs.DoWork(); - } - - bool success = subproc->Finish() == ExitSuccess; - int exit_code = subproc->ExitCode(); - - std::string output = subproc->GetOutput(); - delete subproc; - + } + int exit_code = ret; // process the include directives and output everything else std::stringstream ss(output); std::string line; |