From a7b6fa5bee58f40aafa64665b73ff3efc68f7930 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 17 Feb 2016 15:56:06 -0700 Subject: [PATCH] os: implement windows os layer --- src/link.cpp | 6 +- src/main.cpp | 2 + src/os.cpp | 223 +++++++++++++++++++++++++++++++++++++++++++++++---- src/os.hpp | 3 +- 4 files changed, 218 insertions(+), 16 deletions(-) diff --git a/src/link.cpp b/src/link.cpp index 673d6de6b6..0f8a576d97 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -802,7 +802,11 @@ void codegen_link(CodeGen *g, const char *out_file) { int return_code; Buf ld_stderr = BUF_INIT; Buf ld_stdout = BUF_INIT; - os_exec_process(buf_ptr(g->linker_path), lj.args, &return_code, &ld_stderr, &ld_stdout); + int err = os_exec_process(buf_ptr(g->linker_path), lj.args, &return_code, &ld_stderr, &ld_stdout); + if (err) { + fprintf(stderr, "linker not found: '%s'\n", buf_ptr(g->linker_path)); + exit(1); + } if (return_code != 0) { fprintf(stderr, "linker failed with return code %d\n", return_code); diff --git a/src/main.cpp b/src/main.cpp index 83606da59f..c58f3a0942 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -98,6 +98,8 @@ enum Cmd { }; int main(int argc, char **argv) { + os_init(); + char *arg0 = argv[0]; Cmd cmd = CmdInvalid; const char *in_file = nullptr; diff --git a/src/os.cpp b/src/os.cpp index 4442f42475..69779c2f0f 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -24,10 +24,6 @@ #define WIN32_LEAN_AND_MEAN #endif -#if !defined(UNICODE) -#define UNICODE -#endif - #include #include #else @@ -44,6 +40,11 @@ #include #include +#include + +// these implementations are lazy. But who cares, we'll make a robust +// implementation in the zig standard library and then this code all gets +// deleted when we self-host. it works for now. #if defined(ZIG_OS_POSIX) @@ -70,7 +71,13 @@ static void os_spawn_process_posix(const char *exe, ZigList &args, #if defined(ZIG_OS_WINDOWS) static void os_spawn_process_windows(const char *exe, ZigList &args, int *return_code) { - zig_panic("TODO os_spawn_process_windows"); + Buf stderr_buf = BUF_INIT; + Buf stdout_buf = BUF_INIT; + + // TODO this is supposed to inherit stdout/stderr instead of capturing it + os_exec_process(exe, args, return_code, &stderr_buf, &stdout_buf); + fwrite(buf_ptr(&stderr_buf), 1, buf_len(&stderr_buf), stderr); + fwrite(buf_ptr(&stdout_buf), 1, buf_len(&stdout_buf), stdout); } #endif @@ -111,7 +118,12 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { int os_path_real(Buf *rel_path, Buf *out_abs_path) { #if defined(ZIG_OS_WINDOWS) - zig_panic("TODO os_path_real for windows"); + buf_resize(out_abs_path, 4096); + if (_fullpath(buf_ptr(out_abs_path), buf_ptr(rel_path), buf_len(out_abs_path)) == nullptr) { + zig_panic("_fullpath failed"); + } + buf_resize(out_abs_path, strlen(buf_ptr(out_abs_path))); + return ErrorNone; #elif defined(ZIG_OS_POSIX) buf_resize(out_abs_path, PATH_MAX + 1); char *result = realpath(buf_ptr(rel_path), buf_ptr(out_abs_path)); @@ -157,7 +169,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) { #if defined(ZIG_OS_POSIX) -static void os_exec_process_posix(const char *exe, ZigList &args, +static int os_exec_process_posix(const char *exe, ZigList &args, int *return_code, Buf *out_stderr, Buf *out_stdout) { int stdin_pipe[2]; @@ -193,7 +205,11 @@ static void os_exec_process_posix(const char *exe, ZigList &args, argv[i + 1] = args.at(i); } execvp(exe, const_cast(argv)); - zig_panic("execvp failed: %s", strerror(errno)); + if (errno == ENOENT) { + return ErrorFileNotFound; + } else { + zig_panic("execvp failed: %s", strerror(errno)); + } } else { // parent close(stdin_pipe[0]); @@ -205,19 +221,158 @@ static void os_exec_process_posix(const char *exe, ZigList &args, os_fetch_file(fdopen(stdout_pipe[0], "rb"), out_stdout); os_fetch_file(fdopen(stderr_pipe[0], "rb"), out_stderr); + return 0; } } #endif #if defined(ZIG_OS_WINDOWS) -static void os_exec_process_windows(const char *exe, ZigList &args, + +/* +static void win32_panic(const char *str) { + DWORD err = GetLastError(); + LPSTR messageBuffer = nullptr; + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + zig_panic(str, messageBuffer); + LocalFree(messageBuffer); +} +*/ + +static int os_exec_process_windows(const char *exe, ZigList &args, int *return_code, Buf *out_stderr, Buf *out_stdout) { - zig_panic("TODO implement os_exec_process_windows"); + Buf command_line = BUF_INIT; + buf_resize(&command_line, 0); + + buf_append_char(&command_line, '\"'); + buf_append_str(&command_line, exe); + buf_append_char(&command_line, '\"'); + + for (int arg_i = 0; arg_i < args.length; arg_i += 1) { + buf_append_str(&command_line, " \""); + const char *arg = args.at(arg_i); + int arg_len = strlen(arg); + for (int c_i = 0; c_i < arg_len; c_i += 1) { + if (arg[c_i] == '\"') { + zig_panic("TODO"); + } + buf_append_char(&command_line, arg[c_i]); + } + buf_append_char(&command_line, '\"'); + } + + + HANDLE g_hChildStd_IN_Rd = NULL; + HANDLE g_hChildStd_IN_Wr = NULL; + HANDLE g_hChildStd_OUT_Rd = NULL; + HANDLE g_hChildStd_OUT_Wr = NULL; + HANDLE g_hChildStd_ERR_Rd = NULL; + HANDLE g_hChildStd_ERR_Wr = NULL; + + SECURITY_ATTRIBUTES saAttr; + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) { + zig_panic("StdoutRd CreatePipe"); + } + + if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { + zig_panic("Stdout SetHandleInformation"); + } + + if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) { + zig_panic("stderr CreatePipe"); + } + + if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) { + zig_panic("stderr SetHandleInformation"); + } + + if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) { + zig_panic("Stdin CreatePipe"); + } + + if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) { + zig_panic("Stdin SetHandleInformation"); + } + + + PROCESS_INFORMATION piProcInfo = {0}; + STARTUPINFO siStartInfo = {0}; + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = g_hChildStd_ERR_Wr; + siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; + siStartInfo.hStdInput = g_hChildStd_IN_Rd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + BOOL success = CreateProcess(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr, + &siStartInfo, &piProcInfo); + + if (!success) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) { + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + return ErrorFileNotFound; + } + zig_panic("CreateProcess failed. exe: %s command_line: %s", exe, buf_ptr(&command_line)); + } + + if (!CloseHandle(g_hChildStd_IN_Wr)) { + zig_panic("stdinwr closehandle"); + } + + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_ERR_Wr); + CloseHandle(g_hChildStd_OUT_Wr); + + static const int BUF_SIZE = 4 * 1024; + { + DWORD dwRead; + char chBuf[BUF_SIZE]; + + buf_resize(out_stdout, 0); + for (;;) { + success = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUF_SIZE, &dwRead, NULL); + if (!success || dwRead == 0) break; + + buf_append_mem(out_stdout, chBuf, dwRead); + } + CloseHandle(g_hChildStd_OUT_Rd); + } + { + DWORD dwRead; + char chBuf[BUF_SIZE]; + + buf_resize(out_stderr, 0); + for (;;) { + success = ReadFile( g_hChildStd_ERR_Rd, chBuf, BUF_SIZE, &dwRead, NULL); + if (!success || dwRead == 0) break; + + buf_append_mem(out_stderr, chBuf, dwRead); + } + CloseHandle(g_hChildStd_ERR_Rd); + } + + WaitForSingleObject(piProcInfo.hProcess, INFINITE); + + DWORD exit_code; + if (!GetExitCodeProcess(piProcInfo.hProcess, &exit_code)) { + zig_panic("GetExitCodeProcess failed"); + } + *return_code = exit_code; + + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + + return 0; } #endif -void os_exec_process(const char *exe, ZigList &args, +int os_exec_process(const char *exe, ZigList &args, int *return_code, Buf *out_stderr, Buf *out_stdout) { #if defined(ZIG_OS_WINDOWS) @@ -267,7 +422,11 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) { int os_get_cwd(Buf *out_cwd) { #if defined(ZIG_OS_WINDOWS) - zig_panic("TODO os_get_cwd for windows"); + buf_resize(out_cwd, 4096); + if (GetCurrentDirectory(buf_len(out_cwd), buf_ptr(out_cwd)) == 0) { + zig_panic("GetCurrentDirectory failed"); + } + return 0; #elif defined(ZIG_OS_POSIX) int err = ERANGE; buf_resize(out_cwd, 512); @@ -296,8 +455,12 @@ bool os_stderr_tty(void) { #if defined(ZIG_OS_POSIX) static int os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_path) { + const char *tmp_dir = getenv("TMPDIR"); + if (!tmp_dir) { + tmp_dir = P_tmpdir; + } buf_resize(out_tmp_path, 0); - buf_appendf(out_tmp_path, "/tmp/XXXXXX%s", buf_ptr(suffix)); + buf_appendf(out_tmp_path, "%s/XXXXXX%s", tmp_dir, buf_ptr(suffix)); int fd = mkstemps(buf_ptr(out_tmp_path), buf_len(suffix)); if (fd < 0) { @@ -321,7 +484,35 @@ static int os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_pat #if defined(ZIG_OS_WINDOWS) static int os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) { - zig_panic("TODO implement os_buf_to_tmp_file_windows"); + char tmp_dir[MAX_PATH + 1]; + if (GetTempPath(MAX_PATH, tmp_dir) == 0) { + zig_panic("GetTempPath failed"); + } + buf_init_from_str(out_tmp_path, tmp_dir); + + const char base64[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; + assert(array_length(base64) == 64 + 1); + for (int i = 0; i < 8; i += 1) { + buf_append_char(out_tmp_path, base64[rand() % 64]); + } + + buf_append_buf(out_tmp_path, suffix); + + FILE *f = fopen(buf_ptr(out_tmp_path), "wb"); + + if (!f) { + zig_panic("unable to open %s: %s", buf_ptr(out_tmp_path), strerror(errno)); + } + + size_t amt_written = fwrite(buf_ptr(contents), 1, buf_len(contents), f); + if (amt_written != (size_t)buf_len(contents)) { + zig_panic("write failed: %s", strerror(errno)); + } + + if (fclose(f)) { + zig_panic("fclose failed"); + } + return 0; } #endif @@ -342,3 +533,7 @@ int os_delete_file(Buf *path) { return 0; } } + +void os_init(void) { + srand(time(NULL)); +} diff --git a/src/os.hpp b/src/os.hpp index b96ba9b0ef..ae43f8fe91 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -13,8 +13,9 @@ #include +void os_init(void); void os_spawn_process(const char *exe, ZigList &args, int *return_code); -void os_exec_process(const char *exe, ZigList &args, +int os_exec_process(const char *exe, ZigList &args, int *return_code, Buf *out_stderr, Buf *out_stdout); void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);