From 5499560c6a497c72aa1bd5c5dd770795d789d4d5 Mon Sep 17 00:00:00 2001 From: Trent Huber Date: Wed, 6 Aug 2025 14:17:48 -0400 Subject: [PATCH] Simplify bootstrapping --- README.md | 6 ------ cbs.c | 41 +++++++++++++++-------------------------- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index c1ec22c..7189a3d 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,6 @@ Next, compile the build file and run the resulting executable, called `build`. ```console > cc -o build build.c > build -cc -c -o build.o build.c -cc -o build build.o cc -c -o main.o main.c cc -o main main.o > main @@ -102,12 +100,8 @@ The `build()` function allows one build executable to run another build executab If the current directory is passed to `build()`, then it will *recompile its own build file* before rerunning *itself*. Thus, including a statement like `build("./");` at the beginning of your build file means you don't have to manually recompile that build file whenever you modify it. -`build()` uses the `cflags` and `lflags` variables whenever it recompiles build files. The value of each variable is maintained between calls to `build()`. - ```c build("./"); build("../../src/"); - -cflags = LIST("-Iinclude/"); build("/usr/local/project/src/"); ``` diff --git a/cbs.c b/cbs.c index d5fa83a..fcbe83b 100644 --- a/cbs.c +++ b/cbs.c @@ -10,10 +10,12 @@ #ifdef __APPLE__ #define DYEXT ".dylib" -#define TIME st_mtimespec +#define SEC st_mtimespec.tv_sec +#define NSEC st_mtimespec.tv_nsec #else #define DYEXT ".so" -#define TIME st_mtim +#define SEC st_mtim.tv_sec +#define NSEC st_mtim.tv_nsec #endif #define NONE (char *[]){NULL} @@ -77,8 +79,7 @@ void await(pid_t cpid, char *what, char *who) { if (cpid == -1 || waitpid(cpid, &status, 0) == -1) err(EXIT_FAILURE, "Unable to %s `%s'", what, who); - if (WIFSIGNALED(status)) - errx(EXIT_FAILURE, "%s", strsignal(WTERMSIG(status))); + if (WIFSIGNALED(status)) errx(EXIT_FAILURE, "%s", strsignal(WTERMSIG(status))); if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) exit(EXIT_FAILURE); } @@ -149,20 +150,11 @@ void load(char type, char *target, char **objs) { free(args); } -int after(struct stat astat, struct stat bstat) { - struct timespec a, b; - - a = astat.TIME; - b = bstat.TIME; - - return a.tv_sec == b.tv_sec ? a.tv_nsec > b.tv_nsec : a.tv_sec > b.tv_sec; -} - void build(char *path) { char *absolute, *current; pid_t cpid; - int self, exists, restart; - struct stat src, obj, exe; + int self, exists, rebuild; + struct stat src, exe; if (!(absolute = realpath(path, NULL))) err(EXIT_FAILURE, "Unable to resolve `%s'", path); @@ -185,18 +177,15 @@ void build(char *path) { if (cpid) return; - if (stat(current = "build.c", &src) == -1) - err(EXIT_FAILURE, "Unable to stat `build.c'"); - if (stat("build.o", &obj) == -1) obj.TIME = (struct timespec){0}; - if (!(exists = stat("build", &exe) != -1)) exe.TIME = (struct timespec){0}; - - if ((restart = after(src, obj) || after(exe, obj)) - && after(src, exe) && (self || !exists)) { + if (stat("build.c", &src) == -1) err(EXIT_FAILURE, "Unable to stat `build.c'"); + if (!(exists = stat("build", &exe) != -1)) exe.SEC = 0; + rebuild = src.SEC == exe.SEC ? src.NSEC > exe.NSEC : src.SEC > exe.SEC; + + if (!self && !exists || self && rebuild) { compile("build"); load('x', "build", LIST("build")); - if (self) current = "build.o"; } - if (utimensat(AT_FDCWD, current, NULL, 0) == -1) - err(EXIT_FAILURE, "Unable to update `%s' modification time", current); - if (restart) run("!build", LIST("build"), "run", "build"); + if (!self || rebuild) run("!build", LIST("build"), "run", "build"); + if (utimensat(AT_FDCWD, "build.c", NULL, 0) == -1) + err(EXIT_FAILURE, "Unable to update `build.c' modification time"); } -- 2.51.0