From: Michael D. Lowis Date: Sun, 6 Dec 2020 01:16:15 +0000 (-0500) Subject: rework build system and adjust style of functions X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=8beec0b6101b7f24bd9c3c47315e70084e72ea5f;p=proto%2Faos.git rework build system and adjust style of functions --- diff --git a/.gitignore b/.gitignore index 567609b..26fa21f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ build/ +build.bin diff --git a/build.c b/build.c new file mode 100644 index 0000000..75fa30a --- /dev/null +++ b/build.c @@ -0,0 +1,388 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +enum { F_FILES, F_DIRS }; + +typedef struct Target { + struct Target* next; + char** outputs; + char** inputs; + void (*build)(struct Target*); +} Target; + +int MaxJobs = 4; + +char* CCCMD[] = { + "cc", + "-Wall", "-Wextra", "-Werror", + "-Iinc/", + "-I/usr/X11/include/", + "-I/usr/X11/include/freetype2", + "-c", "-o", + /* output */ + /* inputs */ + NULL +}; + +char* ARCMD[] = { + "ar", "rcs", + NULL +}; + +char* LDCMD[] = { + "cc", + "-L./build/lib", + "-L/usr/X11/lib/", + "-o", + /* output */ + /* inputs */ + /* LIBS */ + NULL +}; + +char* LIBS[] = { + "-lX11", + "-lfontconfig", + NULL +}; + +Target* Srcs = NULL; +Target* Libs = NULL; +Target* Bins = NULL; + +/* + Helper Routines +*/ + +static char* strmcat(char* first, ...) +{ + va_list args; + /* calculate the length of the final string */ + size_t len = strlen(first); + va_start(args, first); + for (char* s = NULL; (s = va_arg(args, char*));) + { + len += strlen(s); + } + va_end(args); + /* allocate the final string and copy the args into it */ + char *str = malloc(len+1), *curr = str; + while (first && *first) + { + *(curr++) = *(first++); + } + va_start(args, first); + for (char* s = NULL; (s = va_arg(args, char*));) + { + while (s && *s) + { + *(curr++) = *(s++); + } + } + va_end(args); + /* null terminate and return */ + *curr = '\0'; + return str; +} + +static char** dir_entries(char* path, int flags) +{ + size_t nentries = 0; + char** entries = calloc(1, sizeof(char*)); + struct dirent* entry = NULL; + struct stat attrs = {0}; + + DIR* dir = opendir(path); + while ( (entry = readdir(dir)) ) + { + if (entry->d_name[0] == '.') continue; + char* epath = strmcat(path, "/", entry->d_name, 0); + memset(&attrs, 0, sizeof(attrs)); + stat(epath, &attrs); + if ( ((flags == F_FILES) && !S_ISDIR(attrs.st_mode)) || + ((flags == F_DIRS) && S_ISDIR(attrs.st_mode)) ) + { + entries = realloc(entries, (nentries+2)*sizeof(char*)); + entries[nentries++] = epath; + entries[nentries] = NULL; + } + } + + return entries; +} + +char** make_cmd(char*** cmd_parts) +{ + size_t count = 0; + char** cmd = NULL; + for (; *cmd_parts; cmd_parts++) + { + char** subpart = *cmd_parts; + for (; *subpart; subpart++) + { + cmd = realloc(cmd, ++count * sizeof(char*)); + cmd[count-1] = *subpart; + } + } + cmd = realloc(cmd, ++count * sizeof(char*)); + cmd[count-1] = NULL; + return cmd; +} + +void print_cmd(char** cmd) +{ + for (; *cmd; cmd++) + { + printf("%s ", *cmd); + } + puts(""); +} + +int wait_for_jobs(int count) +{ + int ret_status = 0; + do + { + int status = 0; + waitpid(-1, &status, 0); + if (WIFEXITED(status)) + { + count--; + } + int exitcode = WEXITSTATUS(status); + ret_status = (!ret_status ? exitcode : ret_status); + } + while (count > 0); + return ret_status; +} + +void make_dirs(char** outputs) +{ + for (; *outputs; outputs++) + { + char* out = strdup(*outputs); + char* slash = strrchr(out, '/'); + if (slash) + { + *slash = '\0'; + mkdir(out, 0755); + } + } +} + +time_t timestamp(char* path) +{ + struct stat s; + time_t mtime = 0; + if (!stat(path, &s)) + { + mtime = s.st_mtime; + } + return mtime; +} + +int should_rebuild(char** outputs, char** inputs) +{ + time_t mtime = 0; + for (; *outputs; outputs++) + { + time_t mt = timestamp(*outputs); + mtime = (mt > mtime ? mt : mtime); + } + for (; *inputs; inputs++) + { + time_t mt = timestamp(*inputs); + if (mt > mtime) + { + return 1; /* rebuild! */ + } + } + return 0; /* no need to rebuild */ +} + +/* + Build Routines +*/ + +void object(Target* tgt) +{ + printf("Object %s\n", tgt->outputs[0]); + char** cmd = make_cmd((char**[]){ CCCMD, tgt->outputs, tgt->inputs, NULL }); + make_dirs(tgt->outputs); + exit(execvp(cmd[0], cmd)); +} + +void library(Target* tgt) +{ + printf("Library %s\n", tgt->outputs[0]); + char** cmd = make_cmd((char**[]){ ARCMD, tgt->outputs, tgt->inputs, NULL }); + exit(execvp(cmd[0], cmd)); +} + +void binary(Target* tgt) +{ + printf("Binary %s\n", tgt->outputs[0]); + char** cmd = make_cmd((char**[]){ + LDCMD, tgt->outputs, tgt->inputs, LIBS, NULL }); + exit(execvp(cmd[0], cmd)); +} + +/* + Target List Routines +*/ + +void add_target(Target** list, char** outputs, char** inputs, void (*build)(Target*)) +{ + Target* tgt = calloc(1, sizeof(Target)); + tgt->next = *list; + tgt->outputs = outputs; + tgt->inputs = inputs; + tgt->build = build; + *list = tgt; +} + +/* + Target Routines +*/ + +char* add_src(char* src) +{ + char* obj = strmcat("build/obj/", src, 0); + obj[strlen(obj)-1] = 'o'; + char** outputs = calloc(2, sizeof(char*)); + outputs[0] = obj; + char** inputs = calloc(2, sizeof(char*)); + inputs[0] = src; + add_target(&Srcs, outputs, inputs, object); + return obj; +} + +char* add_lib(char* path, char** srcs) +{ + char* libname = strrchr(path, '/') + 1; + char* lib = strmcat("build/lib/lib", libname, ".a", 0); + char** outputs = calloc(2, sizeof(char*)); + outputs[0] = lib; + add_target(&Libs, outputs, srcs, library); + return lib; +} + +char* add_bin(char* path, char** srcs) +{ + char* binname = strdup(strrchr(path, '/') + 1); + char* ext = strrchr(binname, '.'); + + if (ext) + { + *ext = '\0'; + } + char* bin = strmcat("build/bin/", binname, 0); + char** outputs = calloc(2, sizeof(char*)); + outputs[0] = bin; + add_target(&Bins, outputs, srcs, binary); + + return bin; +} + +char** add_srcs(char* path) +{ + char** srcs = dir_entries(path, F_FILES); + for (char** s = srcs; *s; s++) + { + char* obj = add_src(*s); + *s = obj; + } + + return srcs; +} + +/* + Build Routines +*/ + +void build_targets(Target* targets) +{ + int exitcode = 0; + int count = 0; + + for (; !exitcode && targets; targets = targets->next) + { + count++; + int pid = fork(); + if (pid == 0) + { + if (should_rebuild(targets->outputs, targets->inputs)) + { + targets->build(targets); + } + exit(0); + } + else if (count >= MaxJobs) + { + int code = wait_for_jobs(1); + exitcode = (!exitcode ? code : exitcode); + count--; + } + } + int code = wait_for_jobs(count); + exitcode = (!exitcode ? code : exitcode); + + if (exitcode) + { + printf("Job Failed!\n"); + exit(exitcode); + } +} + +/* + Main Routine +*/ + +int main(int argc, char** argv) +{ + (void)argc, (void)argv; + + /* register all of the libraries */ + char** libs = dir_entries("lib", F_DIRS); + for (; *libs; libs++) + { + char** srcs = add_srcs(*libs); + add_lib(*libs, srcs); + } + + /* register all the complex binaries */ + char** cbins = dir_entries("bin", F_DIRS); + for (; *cbins; cbins++) + { + char** srcs = add_srcs(*cbins); + add_bin(*cbins, srcs); + } + + /* register all the simple binaries */ + char** sbins = dir_entries("bin", F_FILES); + for (; *sbins; sbins++) + { + add_bin(*sbins, (char*[]){ *sbins, NULL }); + } + + /* create output directories */ + mkdir("build/", 0755); + mkdir("build/obj/", 0755); + mkdir("build/obj/bin/", 0755); + mkdir("build/obj/lib/", 0755); + mkdir("build/bin/", 0755); + mkdir("build/lib/", 0755); + + /* now build all of the things */ + build_targets(Srcs); + build_targets(Libs); + build_targets(Bins); + + return 0; +} \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..064ecc5 --- /dev/null +++ b/build.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +if [ "build.c" -nt "build.bin" ]; then + cc -Wall -Wextra -Werror -o build.bin build.c +fi +./build.bin \ No newline at end of file diff --git a/lib/ui/libui_impl.h b/inc/libui_impl.h similarity index 100% rename from lib/ui/libui_impl.h rename to inc/libui_impl.h diff --git a/lib/a/ecalloc.c b/lib/a/ecalloc.c index af75b3a..c4b2a31 100644 --- a/lib/a/ecalloc.c +++ b/lib/a/ecalloc.c @@ -5,6 +5,8 @@ void* ecalloc(size_t num, size_t size) { void* ret; if (NULL == (ret = calloc(num,size))) + { fatal("calloc(%zu, %zu) failed:", num, size); + } return ret; } diff --git a/lib/a/efopen.c b/lib/a/efopen.c index 1d6e01e..7b900f3 100644 --- a/lib/a/efopen.c +++ b/lib/a/efopen.c @@ -6,6 +6,8 @@ FILE* efopen(const char* filename, const char* mode) FILE* file; errno = 0; if (NULL == (file = fopen(filename, mode)) || errno != 0) + { fatal("fopen(%s, %s) failed:", filename, mode); + } return file; } diff --git a/lib/a/efreadline.c b/lib/a/efreadline.c index 0fc3a9f..b2069f0 100644 --- a/lib/a/efreadline.c +++ b/lib/a/efreadline.c @@ -5,22 +5,31 @@ char* efreadline(FILE* input) { size_t size = 8; size_t index = 0; - char* str = (char*)emalloc(size); + char* str = (char*)emalloc(size); memset(str, 0, 8); - if (feof(input)) { + if (feof(input)) + { free(str); return NULL; } - while (true) { + while (true) + { char ch = fgetc(input); - if (ch == EOF) break; + if (ch == EOF) + { + break; + } str[index++] = ch; str[index] = '\0'; - if (index+1 >= size) { + if (index+1 >= size) + { size = size << 1; str = erealloc(str, size); } - if (ch == '\n') break; + if (ch == '\n') + { + break; + } } return str; } diff --git a/lib/a/emalloc.c b/lib/a/emalloc.c index c4e61e2..ea9f6c1 100644 --- a/lib/a/emalloc.c +++ b/lib/a/emalloc.c @@ -5,6 +5,8 @@ void* emalloc(size_t size) { void* ret; if (NULL == (ret = malloc(size))) + { fatal("malloc(%zu) failed:", size); + } return ret; } diff --git a/lib/a/eraise.c b/lib/a/eraise.c index 25c53da..7c45dd4 100644 --- a/lib/a/eraise.c +++ b/lib/a/eraise.c @@ -5,6 +5,8 @@ int eraise(int sig) { int ret; if ((ret = raise(sig)) != 0) + { fatal("raise(%d) failed:", sig); + } return ret; } diff --git a/lib/a/erealloc.c b/lib/a/erealloc.c index 929ac01..cf9af01 100644 --- a/lib/a/erealloc.c +++ b/lib/a/erealloc.c @@ -5,6 +5,8 @@ void* erealloc(void* ptr, size_t size) { void* ret; if (NULL == (ret = realloc(ptr,size))) + { fatal("realloc(%p, %zu) failed:", ptr, size); + } return ret; } diff --git a/lib/a/esignal.c b/lib/a/esignal.c index 23f6a20..7231f51 100644 --- a/lib/a/esignal.c +++ b/lib/a/esignal.c @@ -6,5 +6,7 @@ void esignal(int sig, void (*func)(int)) errno = 0; func = signal(sig, func); if (func == SIG_ERR || errno > 0) + { fatal("signal(%d, %p) failed:", sig, func); + } } diff --git a/lib/a/fatal.c b/lib/a/fatal.c index 539a90d..3e5d08e 100644 --- a/lib/a/fatal.c +++ b/lib/a/fatal.c @@ -4,14 +4,18 @@ void fatal(const char* fmt, ...) { fflush(stdout); - if (ARGV0) fprintf(stderr, "%s: ", ARGV0); + if (ARGV0) + { + fprintf(stderr, "%s: ", ARGV0); + } va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); if (*fmt && fmt[strlen(fmt)-1] == ':') + { fprintf(stderr, " %s", strerror(errno)); + } fprintf(stderr, "\n"); exit(EXIT_FAILURE); } -