// #include #define DQN_IMPLEMENTATION #include "External/tely/External/dqn/dqn.h" struct Dqn_OSRunCommandAsyncResult { void *process; }; struct Dqn_OSRunCommandResult { uint32_t os_error_code; uint32_t exit_code; }; Dqn_OSRunCommandResult Dqn_OS_RunCommandWait(Dqn_OSRunCommandAsyncResult run_cmd) { Dqn_OSRunCommandResult result = {}; DWORD exec_result = WaitForSingleObject(run_cmd.process, INFINITE); if (exec_result == WAIT_FAILED) { result.os_error_code = GetLastError(); return result; } DWORD exit_status; if (!GetExitCodeProcess(run_cmd.process, &exit_status)) { result.os_error_code = GetLastError(); return result; } result.exit_code = exit_status; CloseHandle(run_cmd.process); return result; } Dqn_OSRunCommandAsyncResult Dqn_OS_RunCommandAsync(Dqn_String8 cmd) { Dqn_OSRunCommandAsyncResult result = {}; #if defined(DQN_OS_WIN32) Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_String16 cmd16 = Dqn_Win_String8ToString16(scratch.arena, cmd); PROCESS_INFORMATION proc_info = {}; STARTUPINFOW startup_info = {}; startup_info.cb = sizeof(STARTUPINFOW); startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); startup_info.dwFlags |= STARTF_USESTDHANDLES; BOOL create_result = CreateProcessW(nullptr, cmd16.data, nullptr, nullptr, true, 0, nullptr, nullptr, &startup_info, &proc_info); if (!create_result) return result; CloseHandle(proc_info.hThread); result.process = proc_info.hProcess; #else pid_t cpid = fork(); if (cpid < 0) { nob_log(NOB_ERROR, "Could not fork child process: %s", strerror(errno)); return NOB_INVALID_PROC; } if (cpid == 0) { // NOTE: This leaks a bit of memory in the child process. // But do we actually care? It's a one off leak anyway... Nob_Cmd cmd_null = {0}; nob_da_append_many(&cmd_null, cmd.items, cmd.count); nob_cmd_append(&cmd_null, NULL); if (execvp(cmd.items[0], (char * const*) cmd_null.items) < 0) { nob_log(NOB_ERROR, "Could not exec child process: %s", strerror(errno)); exit(1); } NOB_ASSERT(0 && "unreachable"); } return cpid; #endif return result; } int main() { Dqn_Library_Init(); Dqn_String8 build_dir = DQN_STRING8("./Build"); if (!Dqn_Fs_MakeDir(build_dir)) { Dqn_Log_ErrorF("Failed to make build dir '%.*s'", DQN_STRING_FMT(build_dir)); return -1; } Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_String8 exe_dir = Dqn_OS_EXEDir(scratch.arena); Dqn_String8Builder raylib_cmd_builder = {}; raylib_cmd_builder.allocator = scratch.allocator; Dqn_String8 raylib_files[] = { DQN_STRING8("rcore.c"), DQN_STRING8("utils.c"), DQN_STRING8("raudio.c"), DQN_STRING8("rmodels.c"), DQN_STRING8("rtext.c"), DQN_STRING8("rtextures.c"), DQN_STRING8("rshapes.c"), DQN_STRING8("rglfw.c"), }; Dqn_String8 raylib_dir = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/External/tely/external/raylib", DQN_STRING_FMT(exe_dir)); Dqn_String8 raylib_include_dirs[] = { Dqn_FsPath_ConvertF(scratch.arena, "%.*s", DQN_STRING_FMT(raylib_dir)), Dqn_FsPath_ConvertF(scratch.arena, "%.*s/external/glfw/include", DQN_STRING_FMT(raylib_dir)), Dqn_FsPath_ConvertF(scratch.arena, "%.*s/glfw/deps/mingw", DQN_STRING_FMT(raylib_dir)), }; Dqn_String8 compile_flags = DQN_STRING8("/W4 /Z7 /MT /EHsc /nologo"); Dqn_String8 link_flags = DQN_STRING8("/link /incremental:no"); Dqn_String8Builder_AppendF(&raylib_cmd_builder, "cl %.*s /w /c /D _DEFAULT_SOURCE /D PLATFORM_DESKTOP", DQN_STRING_FMT(compile_flags)); for (Dqn_String8 include_dir : raylib_include_dirs) Dqn_String8Builder_AppendF(&raylib_cmd_builder, " /I %.*s", DQN_STRING_FMT(include_dir)); for (Dqn_String8 file_name : raylib_files) Dqn_String8Builder_AppendRef(&raylib_cmd_builder, Dqn_FsPath_ConvertF(scratch.arena, " %.*s/%.*s", DQN_STRING_FMT(raylib_dir), DQN_STRING_FMT(file_name))); Dqn_String8 cmd = Dqn_String8Builder_Build(&raylib_cmd_builder, scratch.allocator); Dqn_OSRunCommandAsyncResult run_result = Dqn_OS_RunCommandAsync(cmd); Dqn_OS_RunCommandWait(run_result); return 0; }