From cefe891507c4d24c1f94b94732dc76fcad14ef7b Mon Sep 17 00:00:00 2001 From: LeonardoBizzoni Date: Fri, 15 Aug 2025 15:46:37 +0200 Subject: [PATCH] [LNX] Autorecompile + command execution --- cbuild.h | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 cbuild.h diff --git a/cbuild.h b/cbuild.h new file mode 100644 index 0000000..8370ce5 --- /dev/null +++ b/cbuild.h @@ -0,0 +1,227 @@ +#ifndef CBUILD_H +#define CBUILD_H + +#include +#include +#include +#include + +#include +#include + +#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) +# define COMPILER_GCC 1 +#elif defined(__clang__) && !defined(_MSC_VER) +# define COMPILER_CLANG 1 +#elif defined(_MSC_VER) +# define COMPILER_CL 1 +#else +# error Unsupported compiler +#endif + +#if defined(__gnu_linux__) +# define OS_LINUX 1 +#elif defined(__unix__) +# define OS_BSD 1 +#elif defined(_WIN32) +# define OS_WINDOWS 1 +#elif defined(__APPLE__) +# define OS_MAC 1 +#else +# error Unknown operating system +#endif + +#if defined(__cplusplus) +# define CPP 1 +#else +# define CPP 0 +#endif + +#if !defined(COMPILER_GCC) +# define COMPILER_GCC 0 +#endif +#if !defined(COMPILER_CLANG) +# define COMPILER_CLANG 0 +#endif +#if !defined(COMPILER_CL) +# define COMPILER_CL 0 +#endif + +#if !defined(OS_LINUX) +# define OS_LINUX 0 +#endif +#if !defined(OS_BSD) +# define OS_BSD 0 +#endif +#if !defined(OS_MAC) +# define OS_MAC 0 +#endif +#if !defined(OS_WINDOWS) +# define OS_WINDOWS 0 +#endif +#if !defined(OS_NONE) +# define OS_NONE 0 +#endif + +#if !CPP +# if __STDC_VERSION__ >= 199901L +# include +# else +typedef enum {false, true} bool; +# endif +#endif + +#ifndef _assert_break +# if OS_WINDOWS +# define _assert_break() __debugbreak() +# else +# define _assert_break() __builtin_trap() +# endif +#endif +#define Assert(COND) do { if (!(COND)) { _assert_break(); } } while (0) +#define StackPush(Head, Nodeptr) \ + LLPushFrontCustom((Head), (Head), (Nodeptr), next) +#define StackPop(Head) (Head ? (Head = Head->next) : 0) +#define LLPushFrontCustom(Head, Last, Nodeptr, Next) \ + (!(Head) ? (Head) = (Nodeptr), (Last) = (Nodeptr) \ + : ((Nodeptr)->Next = (Head), (Head) = (Nodeptr))) +#define QueuePush(Head, Last, Nodeptr) \ + LLPushBackCustom((Head), (Last), (Nodeptr), next) +#define QueuePop(Head) (Head ? (Head = Head->next) : 0) +#define LLPushBackCustom(Head, Last, Nodeptr, Next) \ + (!(Head) ? (Head) = (Last) = (Nodeptr) \ + : ((Last) ? ((Last)->Next = (Nodeptr), (Last) = (Nodeptr)) \ + : ((Head)->Next = (Last) = (Nodeptr)))) + +struct cb_path_list { + char **values; + size_t count; + size_t capacity; +}; + +typedef struct cb_path_list cb_cmd; + +struct cb_run_args { + bool async; + bool reset; +}; + +#ifndef CB_DYN_DEFAULT_CAPACITY +# define CB_DYN_DEFAULT_CAPACITY 8 +#endif + +#if OS_WINDOWS +# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) "cl.exe", "/Fe:" (Exe_name), (Builder_src) +#else +# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) "cc", "-o", (Exe_name), (Builder_src) +#endif + +#define cb_dyn_reserve(Dynarr, HowMany) cb_dyn_reserve_custom((Dynarr), (HowMany), values, count, capacity) +#define cb_dyn_free(Dynarr) cb_dyn_free_custom((Dynarr), values) +#define cb_dyn_push(Dynarr, Node) cb_dyn_push_custom((Dynarr), (Node), values, count, capacity) +#define cb_dyn_append(Dynarr, Array, Size) cb_dyn_append_custom((Dynarr), (Array), (Size), values, count, capacity) +#define cb_cmd_push(Dynarr, Value) cb_dyn_push(Dynarr, Value) +#define cb_cmd_append_dyn(Dynarr, Values, Count) cb_dyn_append((Dynarr), (Values), (Count)); +#define cb_cmd_append(Dynarr, ...) cb_dyn_append((Dynarr), \ + ((char*[]){__VA_ARGS__}), \ + sizeof((char*[]){__VA_ARGS__})/sizeof(char*)) +#define cb_rebuild(argc, argv) _cb_rebuild(argc, argv, __FILE__, 0) +#define cb_rebuild_with(argc, argv, ...) _cb_rebuild(argc, argv, __FILE__, __VA_ARGS__, 0) +#define cb_run(Cmd, ...) _cb_run((Cmd), (struct cb_run_args) { \ + .async = false, \ + .reset = true, \ + __VA_ARGS__ \ + }) + +#define cb_dyn_free_custom(Dynarr, Values) free((Dynarr)->Values) +#define cb_dyn_reserve_custom(Dynarr, HowMany, Values, Count, Capacity) \ + do { \ + if (!(Dynarr)->Capacity) { \ + (Dynarr)->Capacity = CB_DYN_DEFAULT_CAPACITY; \ + } \ + while ((HowMany) > (Dynarr)->Capacity) { \ + (Dynarr)->Capacity *= 2; \ + } \ + (Dynarr)->Values = realloc((Dynarr)->Values, (Dynarr)->Capacity * \ + sizeof((Dynarr)->Values[0])); \ + Assert((Dynarr)->Values); \ + } while(0) +#define cb_dyn_push_custom(Dynarr, Node, Values, Count, Capacity) \ + do { \ + cb_dyn_reserve_custom((Dynarr), (Dynarr)->Count + 1, \ + Values, Count, Capacity); \ + (Dynarr)->Values[(Dynarr)->Count++] = (Node); \ + } while(0) +#define cb_dyn_append_custom(Dynarr, Array, Size, Values, Count, Capacity) \ + do { \ + cb_dyn_reserve((Dynarr), (Size)); \ + memcpy((Dynarr)->Values + (Dynarr)->Count, (Array), \ + (Size) * sizeof((Dynarr)->Values[0])); \ + (Dynarr)->Count += (Size); \ + } while(0) + +static bool _cb_need_rebuild(char *output_path, struct cb_path_list sources); +static void _cb_rebuild(int argc, char **argv, char *cb_src, ...); +static void _cb_run(cb_cmd *cmd, struct cb_run_args args); + +static void _cb_rebuild(int argc, char **argv, char *builder_src, ...) { + Assert(argc >= 1); + char *exe_name = argv[0]; + + struct cb_path_list sources = {}; + cb_dyn_push(&sources, builder_src); + + va_list args; + va_start(args, builder_src); + for (;;) { + char *path = va_arg(args, char*); + if (!path) { break; } + cb_dyn_push(&sources, path); + } + va_end(args); + + if (!_cb_need_rebuild(exe_name, sources)) { + cb_dyn_free(&sources); + return; + } + + cb_cmd cmd = {}; + cb_cmd_append(&cmd, CB_CMD_REBUILD_SELF(exe_name, builder_src)); + cb_run(&cmd); + + cb_cmd_push(&cmd, exe_name); + cb_cmd_append_dyn(&cmd, argv, argc); + cb_run(&cmd); + exit(0); +} + +static bool _cb_need_rebuild(char *output_path, struct cb_path_list sources) { + // NOTE(lb): on `fstat` failure assume needed rebuild + struct stat output_stat = {}; + if (stat(output_path, &output_stat) < 0) { return true; } + for (size_t i = 0; i < sources.count; ++i) { + struct stat source_stat = {}; + if (stat(sources.values[i], &source_stat) < 0 || + output_stat.st_mtime < source_stat.st_mtime) { return true; } + } + return false; +} + +static void _cb_run(cb_cmd *cmd, struct cb_run_args args) { + pid_t child_pid = fork(); + if (child_pid) { + if (args.reset) { + cmd->count = 0; + } + if (!args.async) { + Assert(waitpid(child_pid, 0, 0) == child_pid); + } + } else { + cb_cmd _cmd = {}; + cb_cmd_append_dyn(&_cmd, cmd->values, cmd->count); + cb_cmd_push(&_cmd, 0); + exit(execvp(cmd->values[0], cmd->values)); + } +} + +#endif -- 2.52.0