diff options
author | Evan Martin <martine@danga.com> | 2012-08-12 21:52:18 (GMT) |
---|---|---|
committer | Evan Martin <martine@danga.com> | 2012-08-12 21:52:18 (GMT) |
commit | 1843f550d9b8b6d271cefdfb5fffd150bb8ef069 (patch) | |
tree | 6d4e9aa59249d5397f954ba541333126c5d52f38 /src/msvc_helper-win32.cc | |
parent | 031237133e33ee4eb5e9641396d6b0f566b575c8 (diff) | |
download | Ninja-1843f550d9b8b6d271cefdfb5fffd150bb8ef069.zip Ninja-1843f550d9b8b6d271cefdfb5fffd150bb8ef069.tar.gz Ninja-1843f550d9b8b6d271cefdfb5fffd150bb8ef069.tar.bz2 |
add subprocess-spawning to msvc_helper
Rather than using subprocess.h, reimplement the subprocess code.
This allows:
1) using anonymous (instead of named) pipes
2) not using all the completion port craziness
3) printing the output as it happens
4) further variation, like adjusting the environment (in a forthcoming
change) without affecting the main subprocess code
Diffstat (limited to 'src/msvc_helper-win32.cc')
-rw-r--r-- | src/msvc_helper-win32.cc | 98 |
1 files changed, 97 insertions, 1 deletions
diff --git a/src/msvc_helper-win32.cc b/src/msvc_helper-win32.cc index ff18e80..ac957e4 100644 --- a/src/msvc_helper-win32.cc +++ b/src/msvc_helper-win32.cc @@ -15,8 +15,9 @@ #include "msvc_helper.h" #include <string.h> +#include <windows.h> -#include "string_piece.h" +#include "util.h" // static string CLWrapper::FilterShowIncludes(const string& line) { @@ -33,3 +34,98 @@ string CLWrapper::FilterShowIncludes(const string& line) { } return ""; } + +int CLWrapper::Run(const string& command, string* extra_output) { + SECURITY_ATTRIBUTES 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"); + + HANDLE stdout_read, stdout_write; + if (!CreatePipe(&stdout_read, &stdout_write, &security_attributes, 0)) + Win32Fatal("CreatePipe"); + + if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) + Win32Fatal("SetHandleInformation"); + + PROCESS_INFORMATION process_info = {}; + STARTUPINFO startup_info = {}; + startup_info.cb = sizeof(STARTUPINFO); + startup_info.hStdInput = nul; + startup_info.hStdError = stdout_write; + startup_info.hStdOutput = stdout_write; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + + if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL, + /* inherit handles */ TRUE, 0, + NULL, NULL, + &startup_info, &process_info)) { + Win32Fatal("CreateProcess"); + } + + if (!CloseHandle(nul) || + !CloseHandle(stdout_write)) { + Win32Fatal("CloseHandle"); + } + + // Read output of the subprocess and parse it. + string output; + DWORD read_len = 1; + while (read_len) { + char buf[64 << 10]; + read_len = 0; + if (!::ReadFile(stdout_read, buf, sizeof(buf), &read_len, NULL) && + GetLastError() != ERROR_BROKEN_PIPE) { + Win32Fatal("ReadFile"); + } + output.append(buf, read_len); + + // Loop over all lines in the output and process them. + for (;;) { + size_t ofs = output.find_first_of("\r\n"); + if (ofs == string::npos) + break; + string line = output.substr(0, ofs); + + string include = FilterShowIncludes(line); + if (!include.empty()) { + includes_.push_back(include); + } else { + if (extra_output) { + extra_output->append(line); + extra_output->append("\n"); + } else { + printf("%s\n", line.c_str()); + } + } + + if (ofs < output.size() && output[ofs] == '\r') + ++ofs; + if (ofs < output.size() && output[ofs] == '\n') + ++ofs; + output = output.substr(ofs); + } + } + + if (WaitForSingleObject(process_info.hProcess, INFINITE) == WAIT_FAILED) + Win32Fatal("WaitForSingleObject"); + + DWORD exit_code = 0; + if (!GetExitCodeProcess(process_info.hProcess, &exit_code)) + Win32Fatal("GetExitCodeProcess"); + + if (!CloseHandle(stdout_read) || + !CloseHandle(process_info.hProcess) || + !CloseHandle(process_info.hThread)) { + Win32Fatal("CloseHandle"); + } + + return exit_code; +} |