summaryrefslogtreecommitdiffstats
path: root/Source/cmcldeps.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmcldeps.cxx')
-rw-r--r--Source/cmcldeps.cxx516
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;