mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-28 10:11:33 +00:00
This CL updates the clang format files to have a single shared format between Dawn and Tint. The major changes are tabs are 4 spaces, lines are 100 columns and namespaces are not indented. Bug: dawn:1339 Change-Id: I4208742c95643998d9fd14e77a9cc558071ded39 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/87603 Commit-Queue: Dan Sinclair <dsinclair@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
242 lines
7.4 KiB
C++
242 lines
7.4 KiB
C++
// Copyright 2021 The Tint Authors.
|
|
//
|
|
// 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 "src/tint/utils/io/command.h"
|
|
|
|
#define WIN32_LEAN_AND_MEAN 1
|
|
#include <Windows.h>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace tint::utils {
|
|
|
|
namespace {
|
|
|
|
/// Handle is a simple wrapper around the Win32 HANDLE
|
|
class Handle {
|
|
public:
|
|
/// Constructor
|
|
Handle() : handle_(nullptr) {}
|
|
|
|
/// Constructor
|
|
explicit Handle(HANDLE handle) : handle_(handle) {}
|
|
|
|
/// Destructor
|
|
~Handle() { Close(); }
|
|
|
|
/// Move assignment operator
|
|
Handle& operator=(Handle&& rhs) {
|
|
Close();
|
|
handle_ = rhs.handle_;
|
|
rhs.handle_ = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
/// Closes the handle (if it wasn't already closed)
|
|
void Close() {
|
|
if (handle_) {
|
|
CloseHandle(handle_);
|
|
}
|
|
handle_ = nullptr;
|
|
}
|
|
|
|
/// @returns the handle
|
|
operator HANDLE() { return handle_; }
|
|
|
|
/// @returns true if the handle is not invalid
|
|
operator bool() { return handle_ != nullptr; }
|
|
|
|
private:
|
|
Handle(const Handle&) = delete;
|
|
Handle& operator=(const Handle&) = delete;
|
|
|
|
HANDLE handle_ = nullptr;
|
|
};
|
|
|
|
/// Pipe is a simple wrapper around a Win32 CreatePipe() function
|
|
class Pipe {
|
|
public:
|
|
/// Constructs the pipe
|
|
explicit Pipe(bool for_read) {
|
|
SECURITY_ATTRIBUTES sa;
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.bInheritHandle = TRUE;
|
|
sa.lpSecurityDescriptor = nullptr;
|
|
|
|
HANDLE hread;
|
|
HANDLE hwrite;
|
|
if (CreatePipe(&hread, &hwrite, &sa, 0)) {
|
|
read = Handle(hread);
|
|
write = Handle(hwrite);
|
|
// Ensure the read handle to the pipe is not inherited
|
|
if (!SetHandleInformation(for_read ? read : write, HANDLE_FLAG_INHERIT, 0)) {
|
|
read.Close();
|
|
write.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// @returns true if the pipe has an open read or write file
|
|
operator bool() { return read || write; }
|
|
|
|
/// The reader end of the pipe
|
|
Handle read;
|
|
|
|
/// The writer end of the pipe
|
|
Handle write;
|
|
};
|
|
|
|
bool ExecutableExists(const std::string& path) {
|
|
DWORD type = 0;
|
|
return GetBinaryTypeA(path.c_str(), &type);
|
|
}
|
|
|
|
std::string FindExecutable(const std::string& name) {
|
|
if (ExecutableExists(name)) {
|
|
return name;
|
|
}
|
|
if (ExecutableExists(name + ".exe")) {
|
|
return name + ".exe";
|
|
}
|
|
if (name.find("/") == std::string::npos && name.find("\\") == std::string::npos) {
|
|
char* path_env = nullptr;
|
|
size_t path_env_len = 0;
|
|
if (_dupenv_s(&path_env, &path_env_len, "PATH")) {
|
|
return "";
|
|
}
|
|
std::istringstream path{path_env};
|
|
free(path_env);
|
|
std::string dir;
|
|
while (getline(path, dir, ';')) {
|
|
auto test = dir + "\\" + name;
|
|
if (ExecutableExists(test)) {
|
|
return test;
|
|
}
|
|
if (ExecutableExists(test + ".exe")) {
|
|
return test + ".exe";
|
|
}
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Command::Command(const std::string& path) : path_(path) {}
|
|
|
|
Command Command::LookPath(const std::string& executable) {
|
|
return Command(FindExecutable(executable));
|
|
}
|
|
|
|
bool Command::Found() const {
|
|
return ExecutableExists(path_);
|
|
}
|
|
|
|
Command::Output Command::Exec(std::initializer_list<std::string> arguments) const {
|
|
Pipe stdout_pipe(true);
|
|
Pipe stderr_pipe(true);
|
|
Pipe stdin_pipe(false);
|
|
if (!stdin_pipe || !stdout_pipe || !stderr_pipe) {
|
|
Output output;
|
|
output.err = "Command::Exec(): Failed to create pipes";
|
|
return output;
|
|
}
|
|
|
|
if (!input_.empty()) {
|
|
if (!WriteFile(stdin_pipe.write, input_.data(), input_.size(), nullptr, nullptr)) {
|
|
Output output;
|
|
output.err = "Command::Exec() Failed to write stdin";
|
|
return output;
|
|
}
|
|
}
|
|
stdin_pipe.write.Close();
|
|
|
|
STARTUPINFOA si{};
|
|
si.cb = sizeof(si);
|
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
|
si.hStdOutput = stdout_pipe.write;
|
|
si.hStdError = stderr_pipe.write;
|
|
si.hStdInput = stdin_pipe.read;
|
|
|
|
std::stringstream args;
|
|
args << path_;
|
|
for (auto& arg : arguments) {
|
|
args << " " << arg;
|
|
}
|
|
|
|
PROCESS_INFORMATION pi{};
|
|
if (!CreateProcessA(nullptr, // No module name (use command line)
|
|
const_cast<LPSTR>(args.str().c_str()), // Command line
|
|
nullptr, // Process handle not inheritable
|
|
nullptr, // Thread handle not inheritable
|
|
TRUE, // Handles are inherited
|
|
0, // No creation flags
|
|
nullptr, // Use parent's environment block
|
|
nullptr, // Use parent's starting directory
|
|
&si, // Pointer to STARTUPINFO structure
|
|
&pi)) { // Pointer to PROCESS_INFORMATION structure
|
|
Output out;
|
|
out.err = "Command::Exec() CreateProcess() failed";
|
|
return out;
|
|
}
|
|
|
|
stdin_pipe.read.Close();
|
|
stdout_pipe.write.Close();
|
|
stderr_pipe.write.Close();
|
|
|
|
struct StreamReadThreadArgs {
|
|
HANDLE stream;
|
|
std::string output;
|
|
};
|
|
|
|
auto stream_read_thread = [](LPVOID user) -> DWORD {
|
|
auto* thread_args = reinterpret_cast<StreamReadThreadArgs*>(user);
|
|
DWORD n = 0;
|
|
char buf[256];
|
|
while (ReadFile(thread_args->stream, buf, sizeof(buf), &n, NULL)) {
|
|
auto s = std::string(buf, buf + n);
|
|
thread_args->output += std::string(buf, buf + n);
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
StreamReadThreadArgs stdout_read_args{stdout_pipe.read, {}};
|
|
auto* stdout_read_thread =
|
|
::CreateThread(nullptr, 0, stream_read_thread, &stdout_read_args, 0, nullptr);
|
|
|
|
StreamReadThreadArgs stderr_read_args{stderr_pipe.read, {}};
|
|
auto* stderr_read_thread =
|
|
::CreateThread(nullptr, 0, stream_read_thread, &stderr_read_args, 0, nullptr);
|
|
|
|
HANDLE handles[] = {pi.hProcess, stdout_read_thread, stderr_read_thread};
|
|
constexpr DWORD num_handles = sizeof(handles) / sizeof(handles[0]);
|
|
|
|
Output output;
|
|
|
|
auto res = WaitForMultipleObjects(num_handles, handles, /* wait_all = */ TRUE, INFINITE);
|
|
if (res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_0 + num_handles) {
|
|
output.out = stdout_read_args.output;
|
|
output.err = stderr_read_args.output;
|
|
DWORD exit_code = 0;
|
|
GetExitCodeProcess(pi.hProcess, &exit_code);
|
|
output.error_code = static_cast<int>(exit_code);
|
|
} else {
|
|
output.err = "Command::Exec() WaitForMultipleObjects() returned " + std::to_string(res);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
} // namespace tint::utils
|