summaryrefslogtreecommitdiff
path: root/Poof
diff options
context:
space:
mode:
authorVasco <[email protected]>2026-08-23 02:25:33 +0100
committerVasco <[email protected]>2026-08-23 02:25:33 +0100
commitdc96fcd771bea09d726a760266739906e95c09a6 (patch)
tree5af4d4d7660a90a04016fae4defec3c2a422477d /Poof
Peak 0.1.1
Diffstat (limited to 'Poof')
-rw-r--r--Poof/poof.h875
1 files changed, 875 insertions, 0 deletions
diff --git a/Poof/poof.h b/Poof/poof.h
new file mode 100644
index 0000000..55e18ef
--- /dev/null
+++ b/Poof/poof.h
@@ -0,0 +1,875 @@
+/* ===========================================================================
+ * POOF - The Universal Build System - Copyright (c) 2026 Vasco Alves
+ *
+ * PREFIX: Poof_ (types) or poof_ (functions & variables)
+ *
+ * DESCRIPTION:
+ * Platform independent-ish build system!
+ * Performant, multi-threaded and mesmerizing.
+ *
+ * See LICENSE at the end of the file.
+ * =========================================================================== */
+
+#ifndef _POOF_H_
+#define _POOF_H_
+
+#define POOF_MAJOR 0
+#define POOF_MINOR 1
+#define POOF_PATCH 0
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#if defined(_WIN32)
+ #include <windows.h>
+ #include <direct.h>
+ #include <io.h>
+#else
+ #include <unistd.h>
+ #include <sys/wait.h>
+ #include <sys/types.h>
+ #include <dirent.h>
+ #include <errno.h>
+#endif
+
+enum PoofTargetPlatform {
+ POOF_TARGET_HOST = 0,
+ POOF_TARGET_WIN32 = 1,
+ POOF_TARGET_LINUX = 1 << 1,
+ POOF_TARGET_MACOS = 1 << 2,
+};
+
+enum PoofCCFlags {
+ POOF_CC_GCC = 1,
+ POOF_CC_CLANG = 1 << 1,
+ POOF_CC_MSVC = 1 << 2,
+ POOF_CC_MINGW = 1 << 3,
+};
+
+enum PoofOptimizationFlags {
+ POOF_O0 = 0,
+ POOF_O1 = 1,
+ POOF_O2 = 2,
+ POOF_O3 = 3,
+ POOF_MSSE = 1 << 3,
+ POOF_MSSE2 = 1 << 4,
+ POOF_AVX = 1 << 5,
+ POOF_AVX2 = 1 << 6,
+ POOF_AVX512F = 1 << 7,
+};
+
+#define POOF_IS_SET(var, flag) (((var) & (flag)) != 0)
+
+typedef struct Poof_Cmd {
+ const char **items;
+ size_t capacity;
+ size_t count;
+} Poof_Cmd;
+
+typedef struct Poof_CC {
+ uint8_t compiler; // enum PoofCCFlags
+ uint8_t target_platform; // enum PoofTargetPlatform
+ uint32_t optimization; // bitwise PoofOptimizationFlags
+ bool debug_mode;
+ Poof_Cmd inputs;
+ const char *output;
+ Poof_Cmd includes;
+ Poof_Cmd lib_paths;
+ Poof_Cmd libs;
+ Poof_Cmd defines;
+ Poof_Cmd extra_flags;
+
+ /* Platform specific flags */
+ Poof_Cmd win32_flags;
+ Poof_Cmd linux_flags;
+ Poof_Cmd macos_flags;
+} Poof_CC;
+
+typedef struct Poof_Batch {
+ Poof_Cmd *cmds;
+ size_t capacity;
+ size_t count;
+} Poof_Batch;
+
+/* Command operations */
+extern void poof_cmd_append_internal(Poof_Cmd *cmd, ...);
+#define poof_cmd_append(cmd, ...) poof_cmd_append_internal((cmd), __VA_ARGS__, NULL)
+ #define poof_cc_append(cc, ...) poof_cmd_append_internal((cc), __VA_ARGS__, NULL)
+
+#define poof_cc_append_win32(cc, ...) poof_cmd_append_internal(&((cc)->win32_flags), __VA_ARGS__, NULL)
+#define poof_cc_append_linux(cc, ...) poof_cmd_append_internal(&((cc)->linux_flags), __VA_ARGS__, NULL)
+#define poof_cc_append_macos(cc, ...) poof_cmd_append_internal(&((cc)->macos_flags), __VA_ARGS__, NULL)
+
+extern void poof_cmd_free(Poof_Cmd *cmd);
+extern void poof_cmd_clear(Poof_Cmd *cmd);
+extern bool poof_cmd_run(Poof_Cmd *cmd);
+
+/* Batch operations */
+extern void poof_batch_append_cmd(Poof_Batch *batch, Poof_Cmd cmd);
+extern void poof_batch_append_cc(Poof_Batch *batch, Poof_CC *cc);
+#define poof_batch_append(batch, cmd) poof_batch_append_cmd((batch), (cmd))
+extern void poof_batch_free(Poof_Batch *batch);
+extern bool poof_batch_run(Poof_Batch *batch, const char *label);
+extern bool poof_batch_run_parallel(Poof_Batch *batch, const char *label, size_t max_jobs);
+
+/* Compiler abstraction */
+extern uint8_t poof_cc_available(void);
+extern void poof_cc_init(Poof_CC *cc, uint8_t compiler, uint8_t target_platform);
+extern void poof_cc_free(Poof_CC *cc);
+extern bool poof_cc_run(Poof_CC *cc);
+
+/* File and directory utilities */
+extern bool poof_mkdir(const char *path);
+extern bool poof_touch(const char *path);
+extern bool poof_rm(const char *path);
+extern bool poof_rm_recursive(const char *path);
+extern bool poof_copy_file(const char *src, const char *dst);
+extern bool poof_needs_rebuild(const char *target, const char **sources, size_t source_count);
+
+/* Output and pretty printing */
+extern int poof_print(uint32_t col, const char *text, ...);
+extern int poof_progress_bar(const char *label, float value, float min, float max, float width);
+
+/* Rebuild self macro */
+extern void poof_go_rebuild_urself_impl(int argc, char **argv, const char *source_file);
+
+#define POOF_GO_REBUILD_URSELF(argc, argv) poof_go_rebuild_urself_impl(argc, argv, __FILE__)
+
+#endif // _POOF_H_
+
+#ifdef POOF_IMPLEMENTATION
+#undef POOF_IMPLEMENTATION
+
+#if defined(_WIN32)
+#define POOF_DEV_NULL "nul 2>&1"
+#else
+#define POOF_DEV_NULL "/dev/null 2>&1"
+#endif
+
+static bool
+poof__probe_cmd(const char *cmd)
+{
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "%s > " POOF_DEV_NULL, cmd);
+ return (system(buffer) == 0);
+}
+
+extern uint8_t
+poof_cc_available(void)
+{
+ uint8_t available = 0;
+
+ poof_print(0x00FF88, "[POOF] Probing available compilers:\n");
+ if (poof__probe_cmd("gcc --version")) {
+ available |= POOF_CC_GCC;
+ poof_print(0x00FF88, " - GCC: available\n");
+ }
+
+ if (poof__probe_cmd("clang --version")) {
+ available |= POOF_CC_CLANG;
+ poof_print(0x00FF88, " - CLANG: available\n");
+ }
+
+ if (poof__probe_cmd("x86_64-w64-mingw32-gcc --version") || poof__probe_cmd("mingw32-gcc --version")) {
+ available |= POOF_CC_MINGW;
+ poof_print(0x00FF88, " - MinGW: available\n");
+ }
+
+ if (poof__probe_cmd("cl")) {
+ available |= POOF_CC_MSVC;
+ poof_print(0x00FF88, " - MSVC: available\n");
+ }
+
+ return available;
+}
+
+extern void
+poof_cmd_append_internal(Poof_Cmd *cmd, ...)
+{
+ va_list args;
+ va_start(args, cmd);
+ const char *arg = NULL;
+ while ((arg = va_arg(args, const char *)) != NULL) {
+
+ if (cmd->count >= cmd->capacity) {
+ size_t new_cap = cmd->capacity == 0 ? 16 : cmd->capacity * 2;
+ const char **new_items = (const char **)realloc(cmd->items, new_cap * sizeof(const char *));
+ if (!new_items) return;
+ cmd->items = new_items;
+ cmd->capacity = new_cap;
+ }
+ cmd->items[cmd->count++] = arg;
+ }
+ va_end(args);
+}
+
+
+extern void
+poof_cmd_clear(Poof_Cmd *cmd)
+{
+ /* clear count while keeping capacity */
+ cmd->count = 0;
+}
+
+extern void
+poof_cmd_free(Poof_Cmd *cmd)
+{
+ if (cmd->items) {
+ free(cmd->items);
+ cmd->items = NULL;
+ }
+ cmd->capacity = 0;
+ cmd->count = 0;
+}
+
+static char *
+poof__cmd_to_string(const Poof_Cmd *cmd)
+{
+ if (!cmd || cmd->count == 0) return NULL;
+
+ size_t total_len = 0;
+ for (size_t i = 0; i < cmd->count; ++i) {
+ total_len += strlen(cmd->items[i]) + 3; // quotes and space
+ }
+
+ char *cmdline = (char *)malloc(total_len + 1);
+ if (!cmdline) return NULL;
+ cmdline[0] = '\0';
+
+ for (size_t i = 0; i < cmd->count; ++i) {
+ if (i > 0) strcat(cmdline, " ");
+ bool need_quote = (strchr(cmd->items[i], ' ') != NULL);
+ if (need_quote) strcat(cmdline, "\"");
+ strcat(cmdline, cmd->items[i]);
+ if (need_quote) strcat(cmdline, "\"");
+ }
+
+ return cmdline;
+}
+
+extern bool
+poof_cmd_run(Poof_Cmd *cmd)
+{
+ char *cmdline = poof__cmd_to_string(cmd);
+ if (!cmdline) return false;
+
+ printf("[POOF] Executing: ");
+ poof_print(0xA9B665, "%s\n", cmdline);
+
+ int status = system(cmdline);
+ free(cmdline);
+ poof_cmd_clear(cmd);
+ return (status == 0);
+}
+
+extern void
+poof_cc_init(Poof_CC *cc, uint8_t compiler, uint8_t target_platform)
+{
+ memset(cc, 0, sizeof(Poof_CC));
+ cc->compiler = compiler;
+ cc->target_platform = target_platform;
+ cc->optimization = POOF_O0;
+ cc->debug_mode = true;
+}
+
+extern void
+poof_cc_free(Poof_CC *cc)
+{
+ poof_cmd_free(&cc->inputs);
+ poof_cmd_free(&cc->includes);
+ poof_cmd_free(&cc->lib_paths);
+ poof_cmd_free(&cc->libs);
+ poof_cmd_free(&cc->defines);
+ poof_cmd_free(&cc->extra_flags);
+ poof_cmd_free(&cc->win32_flags);
+ poof_cmd_free(&cc->linux_flags);
+ poof_cmd_free(&cc->macos_flags);
+}
+
+extern void
+poof_batch_append_cmd(Poof_Batch *batch, Poof_Cmd cmd)
+{
+ if (batch->count >= batch->capacity) {
+ size_t new_cap = batch->capacity == 0 ? 16 : batch->capacity * 2;
+ Poof_Cmd *new_cmds = (Poof_Cmd *)realloc(batch->cmds, new_cap * sizeof(Poof_Cmd));
+ if (!new_cmds) return;
+ batch->cmds = new_cmds;
+ batch->capacity = new_cap;
+ }
+ batch->cmds[batch->count++] = cmd;
+}
+
+static Poof_Cmd
+poof__cc_build_cmd(const Poof_CC *cc, uint8_t target_platform, bool multi_target)
+{
+ Poof_Cmd cmd = {0};
+
+ // Pick compiler binary
+ if (cc->compiler & POOF_CC_GCC) {
+ if (target_platform == POOF_TARGET_WIN32) {
+ poof_cmd_append(&cmd, "x86_64-w64-mingw32-gcc");
+ } else {
+ poof_cmd_append(&cmd, "gcc");
+ }
+ } else if (cc->compiler & POOF_CC_CLANG) {
+ poof_cmd_append(&cmd, "clang");
+ if (target_platform == POOF_TARGET_WIN32) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-pc-windows-gnu");
+ } else if (target_platform == POOF_TARGET_LINUX) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-unknown-linux-gnu");
+ } else if (target_platform == POOF_TARGET_MACOS) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-apple-darwin");
+ }
+ } else if (cc->compiler & POOF_CC_MINGW) {
+ poof_cmd_append(&cmd, "x86_64-w64-mingw32-gcc");
+ } else if (cc->compiler & POOF_CC_MSVC) {
+ poof_cmd_append(&cmd, "cl");
+ } else {
+ poof_cmd_append(&cmd, "gcc");
+ }
+
+ bool is_msvc = (cc->compiler & POOF_CC_MSVC) != 0;
+
+ // Debug flags
+ if (cc->debug_mode) {
+ poof_cmd_append(&cmd, is_msvc ? "/Zi" : "-g");
+ }
+
+ // Optimization flags
+ uint32_t opt_level = cc->optimization & 3;
+ if (opt_level == POOF_O1) poof_cmd_append(&cmd, is_msvc ? "/O1" : "-O1");
+ else if (opt_level == POOF_O2) poof_cmd_append(&cmd, is_msvc ? "/O2" : "-O2");
+ else if (opt_level == POOF_O3) poof_cmd_append(&cmd, is_msvc ? "/O2" : "-O3");
+ else poof_cmd_append(&cmd, is_msvc ? "/Od" : "-O0");
+
+ // SIMD / Arch extensions
+ if (POOF_IS_SET(cc->optimization, POOF_MSSE)) poof_cmd_append(&cmd, is_msvc ? "/arch:SSE" : "-msse");
+ if (POOF_IS_SET(cc->optimization, POOF_MSSE2)) poof_cmd_append(&cmd, is_msvc ? "/arch:SSE2" : "-msse2");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX" : "-mavx");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX2)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX2" : "-mavx2");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX512F)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX512" : "-mavx512f");
+
+ // Defines
+ for (size_t i = 0; i < cc->defines.count; ++i) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/D" : "-D", cc->defines.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ // Include dirs
+ for (size_t i = 0; i < cc->includes.count; ++i) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/I" : "-I", cc->includes.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ // Input files
+ for (size_t i = 0; i < cc->inputs.count; ++i) {
+ poof_cmd_append(&cmd, cc->inputs.items[i]);
+ }
+
+ // Output target
+ if (cc->output) {
+ char out_path[512];
+ if (target_platform == POOF_TARGET_WIN32) {
+ if (strstr(cc->output, ".exe")) {
+ snprintf(out_path, sizeof(out_path), "%s", cc->output);
+ } else {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_win32.exe" : "%s.exe", cc->output);
+ }
+ } else if (target_platform == POOF_TARGET_MACOS) {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_macos" : "%s", cc->output);
+ } else if (target_platform == POOF_TARGET_LINUX) {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_linux" : "%s", cc->output);
+ } else {
+ snprintf(out_path, sizeof(out_path), "%s", cc->output);
+ }
+
+ if (is_msvc) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "/Fe:%s", out_path);
+ poof_cmd_append(&cmd, strdup(buf));
+ } else {
+ poof_cmd_append(&cmd, "-o");
+ poof_cmd_append(&cmd, strdup(out_path));
+ }
+ }
+
+ // Lib paths & libs
+ for (size_t i = 0; i < cc->lib_paths.count; ++i) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/LIBPATH:" : "-L", cc->lib_paths.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ for (size_t i = 0; i < cc->libs.count; ++i) {
+ if (is_msvc) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s.lib", cc->libs.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ } else {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "-l%s", cc->libs.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+ }
+
+ // Extra flags
+ for (size_t i = 0; i < cc->extra_flags.count; ++i) {
+ poof_cmd_append(&cmd, cc->extra_flags.items[i]);
+ }
+
+ // Platform specific flags
+ const Poof_Cmd *plat_cmd = NULL;
+ if (target_platform == POOF_TARGET_WIN32) plat_cmd = &cc->win32_flags;
+ else if (target_platform == POOF_TARGET_LINUX) plat_cmd = &cc->linux_flags;
+ else if (target_platform == POOF_TARGET_MACOS) plat_cmd = &cc->macos_flags;
+
+ if (plat_cmd) {
+ for (size_t i = 0; i < plat_cmd->count; ++i) {
+ poof_cmd_append(&cmd, plat_cmd->items[i]);
+ }
+ }
+
+ return cmd;
+}
+
+extern void
+poof_batch_append_cc(Poof_Batch *batch, Poof_CC *cc)
+{
+ uint8_t mask = cc->target_platform;
+ if (mask == 0) {
+#if defined(_WIN32)
+ mask = POOF_TARGET_WIN32;
+#elif defined(__APPLE__)
+ mask = POOF_TARGET_MACOS;
+#else
+ mask = POOF_TARGET_LINUX;
+#endif
+ }
+
+ uint8_t targets[3] = { POOF_TARGET_WIN32, POOF_TARGET_LINUX, POOF_TARGET_MACOS };
+ int target_count = 0;
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) target_count++;
+ }
+
+ bool multi_target = target_count > 1;
+
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) {
+ Poof_Cmd cmd = poof__cc_build_cmd(cc, targets[i], multi_target);
+ poof_batch_append_cmd(batch, cmd);
+ }
+ }
+
+ poof_cc_free(cc);
+}
+
+extern void
+poof_batch_free(Poof_Batch *batch)
+{
+ if (batch->cmds) {
+ for (size_t i = 0; i < batch->count; ++i) {
+ poof_cmd_free(&batch->cmds[i]);
+ }
+ free(batch->cmds);
+ batch->cmds = NULL;
+ }
+ batch->capacity = 0;
+ batch->count = 0;
+}
+
+extern bool
+poof_batch_run_parallel(Poof_Batch *batch, const char *label, size_t max_jobs)
+{
+ if (!batch || batch->count == 0) return true;
+ if (!label) label = "BATCH";
+
+#if defined(_WIN32)
+ if (max_jobs == 0) {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ max_jobs = sysinfo.dwNumberOfProcessors > 0 ? sysinfo.dwNumberOfProcessors : 4;
+ }
+ if (max_jobs > MAXIMUM_WAIT_OBJECTS) max_jobs = MAXIMUM_WAIT_OBJECTS;
+
+ size_t total = batch->count;
+ size_t next_job = 0;
+ size_t completed = 0;
+ bool success = true;
+
+ HANDLE *handles = (HANDLE *)calloc(max_jobs, sizeof(HANDLE));
+ if (!handles) return false;
+ size_t active_jobs = 0;
+
+ poof_progress_bar(label, 0.0f, 0.0f, (float)total, 30.0f);
+
+ while (completed < total) {
+ while (active_jobs < max_jobs && next_job < total) {
+ char *cmdline = poof__cmd_to_string(&batch->cmds[next_job]);
+ if (cmdline) {
+ char win_cmd[1024];
+ snprintf(win_cmd, sizeof(win_cmd), "cmd.exe /c \"%s\"", cmdline);
+
+ STARTUPINFOA si = { sizeof(si) };
+ PROCESS_INFORMATION pi = {0};
+
+ if (CreateProcessA(NULL, win_cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ CloseHandle(pi.hThread);
+ handles[active_jobs++] = pi.hProcess;
+ } else {
+ success = false;
+ }
+ free(cmdline);
+ }
+ next_job++;
+ }
+
+ if (active_jobs == 0) break;
+
+ DWORD dwWait = WaitForMultipleObjects((DWORD)active_jobs, handles, FALSE, INFINITE);
+ if (dwWait >= WAIT_OBJECT_0 && dwWait < WAIT_OBJECT_0 + active_jobs) {
+ DWORD idx = dwWait - WAIT_OBJECT_0;
+ DWORD exit_code = 0;
+ GetExitCodeProcess(handles[idx], &exit_code);
+ if (exit_code != 0) success = false;
+ CloseHandle(handles[idx]);
+
+ for (size_t i = idx; i < active_jobs - 1; ++i) {
+ handles[i] = handles[i + 1];
+ }
+ active_jobs--;
+ completed++;
+ poof_progress_bar(label, (float)completed, 0.0f, (float)total, 30.0f);
+ } else {
+ break;
+ }
+ }
+
+ free(handles);
+ poof_batch_free(batch);
+ return success;
+#else
+ if (max_jobs == 0) {
+ long nprocs = sysconf(_SC_NPROCESSORS_ONLN);
+ max_jobs = (nprocs > 0) ? (size_t)nprocs : 4;
+ }
+
+ size_t total = batch->count;
+ size_t next_job = 0;
+ size_t active_jobs = 0;
+ size_t completed = 0;
+ bool success = true;
+
+ poof_progress_bar(label, 0.0f, 0.0f, (float)total, 30.0f);
+
+ while (completed < total) {
+ while (active_jobs < max_jobs && next_job < total) {
+ char *cmdline = poof__cmd_to_string(&batch->cmds[next_job]);
+ if (cmdline) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ execl("/bin/sh", "sh", "-c", cmdline, (char *)NULL);
+ _exit(127);
+ } else if (pid > 0) {
+ active_jobs++;
+ } else {
+ success = false;
+ }
+ free(cmdline);
+ }
+ next_job++;
+ }
+
+ if (active_jobs == 0) break;
+
+ int status = 0;
+ pid_t done_pid = wait(&status);
+ if (done_pid > 0) {
+ active_jobs--;
+ completed++;
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ success = false;
+ }
+ poof_progress_bar(label, (float)completed, 0.0f, (float)total, 30.0f);
+ } else if (done_pid < 0 && errno == ECHILD) {
+ break;
+ }
+ }
+
+ poof_batch_free(batch);
+ return success;
+#endif
+}
+
+extern bool
+poof_batch_run(Poof_Batch *batch, const char *label)
+{
+ return poof_batch_run_parallel(batch, label, 0);
+}
+
+static bool
+poof__cc_run_single(const Poof_CC *cc, uint8_t target_platform, bool multi_target)
+{
+ Poof_Cmd cmd = poof__cc_build_cmd(cc, target_platform, multi_target);
+ bool result = poof_cmd_run(&cmd);
+ poof_cmd_free(&cmd);
+ return result;
+}
+
+extern bool
+poof_cc_run(Poof_CC *cc)
+{
+ uint8_t mask = cc->target_platform;
+ if (mask == 0) {
+#if defined(_WIN32)
+ mask = POOF_TARGET_WIN32;
+#elif defined(__APPLE__)
+ mask = POOF_TARGET_MACOS;
+#else
+ mask = POOF_TARGET_LINUX;
+#endif
+ }
+
+ uint8_t targets[3] = { POOF_TARGET_WIN32, POOF_TARGET_LINUX, POOF_TARGET_MACOS };
+ int target_count = 0;
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) target_count++;
+ }
+
+ bool multi_target = target_count > 1;
+ bool success = true;
+
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) {
+ if (!poof__cc_run_single(cc, targets[i], multi_target)) {
+ success = false;
+ }
+ }
+ }
+
+ poof_cc_free(cc);
+ return success;
+}
+
+
+extern bool
+poof_mkdir(const char *path)
+{
+#if defined(_WIN32)
+ return _mkdir(path) == 0 || errno == EEXIST;
+#else
+ return mkdir(path, 0755) == 0 || errno == EEXIST;
+#endif
+}
+
+extern bool
+poof_touch(const char *path)
+{
+ FILE *f = fopen(path, "a");
+ if (!f) return false;
+ fclose(f);
+ return true;
+}
+
+extern bool
+poof_rm(const char *path)
+{
+ return remove(path) == 0;
+}
+
+extern bool
+poof_rm_recursive(const char *path)
+{
+#if defined(_WIN32)
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "rmdir /s /q \"%s\"", path);
+ return system(cmd) == 0;
+#else
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "rm -rf \"%s\"", path);
+ return system(cmd) == 0;
+#endif
+}
+
+extern bool
+poof_copy_file(const char *src, const char *dst)
+{
+ FILE *in = fopen(src, "rb");
+ if (!in) return false;
+ FILE *out = fopen(dst, "wb");
+ if (!out) {
+ fclose(in);
+ return false;
+ }
+
+ char buffer[8192];
+ size_t bytes;
+ while ((bytes = fread(buffer, 1, sizeof(buffer), in)) > 0) {
+ fwrite(buffer, 1, bytes, out);
+ }
+
+ fclose(in);
+ fclose(out);
+ return true;
+}
+
+static time_t
+poof__get_mtime(const char *path)
+{
+ struct stat attr;
+ if (stat(path, &attr) != 0) return 0;
+ return attr.st_mtime;
+}
+
+extern bool
+poof_needs_rebuild(const char *target, const char **sources, size_t source_count)
+{
+ time_t target_mtime = poof__get_mtime(target);
+ if (target_mtime == 0) return true; // Target does not exist
+
+ for (size_t i = 0; i < source_count; ++i) {
+ time_t src_mtime = poof__get_mtime(sources[i]);
+ if (src_mtime > target_mtime) return true;
+ }
+ return false;
+}
+
+extern int
+poof_print(uint32_t col, const char *text, ...)
+{
+ uint8_t r = (col >> 16) & 0xFF;
+ uint8_t g = (col >> 8) & 0xFF;
+ uint8_t b = col & 0xFF;
+
+ printf("\033[38;2;%d;%d;%dm", r, g, b);
+
+ va_list args;
+ va_start(args, text);
+ int res = vprintf(text, args);
+ va_end(args);
+
+ printf("\033[0m");
+ fflush(stdout);
+ return res;
+}
+
+extern int
+poof_progress_bar(const char *label, float value, float min, float max, float width)
+{
+ float norm = (value - min) / (max - min);
+ if (norm < 0.0f) norm = 0.0f;
+ if (norm > 1.0f) norm = 1.0f;
+
+ int filled = (int)(norm * width);
+ int total = (int)width;
+
+ char bar[256];
+ int pos = 0;
+ for (int i = 0; i < total && pos < (int)sizeof(bar) - 1; ++i) {
+ if (i < filled) bar[pos++] = '|';
+ else bar[pos++] = ' ';
+ }
+ bar[pos] = '\0';
+
+ printf("\r[%s] [", label ? label : "PROGRESS");
+ poof_print(0xFE9900, "%s", bar);
+ printf("] %d/%d jobs", (int)value, (int)max);
+ if (norm >= 1.0f) printf("\n");
+ fflush(stdout);
+ return 0;
+}
+
+extern void
+poof_go_rebuild_urself_impl(int argc, char **argv, const char *source_file)
+{
+ const char *binary_file = argv[0];
+ const char *sources[] = { source_file, "Poof/poof.h" };
+
+ if (!poof_needs_rebuild(binary_file, sources, 2)) {
+ return;
+ }
+
+ char binary_old[4096];
+ snprintf(binary_old, sizeof(binary_old), "%s.old", binary_file);
+
+ poof_print(0xFF8800, "[POOF] Source changed. Rebuilding %s...\n", binary_file);
+
+ poof_rm(binary_old);
+ rename(binary_file, binary_old);
+
+ Poof_Cmd cmd = {0};
+ poof_cmd_append(&cmd, "gcc", "-o", binary_file, source_file, "-IPodium", "-IPoof");
+
+ if (!poof_cmd_run(&cmd)) {
+ poof_print(0xFF0000, "[POOF] Rebuild failed!\n");
+ rename(binary_old, binary_file);
+ exit(1);
+ }
+ poof_cmd_free(&cmd);
+
+ poof_print(0x00FF00, "[POOF] Rebuild successful! Re-launching binary...\n");
+
+ #if defined(_WIN32)
+ // Windows restart
+ int status = system(binary_file);
+ exit(status);
+ #else
+ execv(binary_file, argv);
+ perror("execv");
+ exit(1);
+ #endif
+}
+#endif
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2026 Vasco Alves
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/