diff --git a/cbt.c b/cbt.c index 5663102..e2d6a4b 100644 --- a/cbt.c +++ b/cbt.c @@ -1,13 +1,18 @@ -// x-run: ~/scripts/runc.sh % -Wall -Wextra +// x-run: python3 ./add-impl.py && ~/scripts/runc.sh % -Wall -Wextra #define CBT_IMPLEMENTATION #include "cbt.h" int main(int argc, char **argv) { CBT_INIT(argc, argv); - struct cbt_proc proc = - cbt_proc_new(CBT_PROC_NORMAL, "sh", "-c", "echo 'owo'"); - cbt_proc_wait(proc); + cbt_shell(CBT_PROC_AUTO, "sh", "-c", "echo 'owo'"); + + struct cbt_lib raylib = cbt_lib("raylib", "./raylib"); + cbt_lib_src(&raylib, "rcore.c"); + cbt_lib_ldflags(&raylib, "-lm"); + cbt_lib_cflags(&raylib, "-Wall", "-Wextra"); + cbt_lib_build(raylib, NULL); + cbt_lib_free(raylib); cbt_cleanup(); return 0; diff --git a/cbt.h b/cbt.h index 1604d49..9d9090e 100644 --- a/cbt.h +++ b/cbt.h @@ -15,9 +15,14 @@ enum cbt_loglevel { CBT_LOG_ALL }; +struct cbt_chararray { + char **items; + size_t size, cap; +}; + extern long cbt_start_time; extern enum cbt_loglevel cbt_verbosity; -extern char *cbt_cc; +extern char *cbt_cc, *cbt_cache_dir; void cbt__init(int argc, char **argv, const char *source_file); void cbt_cleanup(void); @@ -27,11 +32,15 @@ extern const char *cbt_log__colors[CBT_LOG_ALL + 1]; extern const char *cbt_log__typecolors[8]; void cbt_log(enum cbt_loglevel lvl, const char *fmt, ...); + long cbt_get_time(void); + unsigned long cbt_get_modtime(const char *filename); bool cbt_needs_recompilation(const char *input, const char *output); + const char *cbt_escape_shell(char *arg); const char *cbt_escape_args(char **args); +const char *cbt_escape_argsd(struct cbt_chararray arr); #ifndef CBT_FMT_NBUFS #define CBT_FMT_NBUFS 64 @@ -43,11 +52,6 @@ const char *cbt_escape_args(char **args); const char *cbt_fmt(const char *fmt, ...); -struct cbt_proc_args { - char **items; - size_t size, cap; -}; - struct cbt_proc { FILE *fp_stdin, *fp_stdout, *fp_stderr; int pid; @@ -56,20 +60,53 @@ struct cbt_proc { struct cbt_procgroup { struct cbt_proc *items; size_t size, cap; + bool fixed_size; }; enum cbt_proc_mode { - CBT_PROC_NORMAL = 0, + CBT_PROC_AUTO = 0, CBT_PROC_R = 1, CBT_PROC_W = 2, CBT_PROC_RW = 3, }; #define cbt_proc_new(...) _cbt_proc_new(__VA_ARGS__, NULL) +#define cbt_shell(...) cbt_proc_wait(_cbt_proc_new(__VA_ARGS__, NULL)) struct cbt_proc _cbt_proc_new(enum cbt_proc_mode mode, ...); struct cbt_proc cbt_proc_newv(enum cbt_proc_mode mode, va_list args); int cbt_proc_wait(struct cbt_proc proc); +enum cbt_libtype { CBT_LIB_STATIC, CBT_LIB_SHARED }; + +struct cbt_lib { + enum cbt_libtype type; + const char *basepath; + const char *libname; + struct cbt_chararray sources, cflags, ldflags; +}; + +#define cbt_lib_src(LIB, ...) _cbt_lib_src(LIB, __VA_ARGS__, NULL) +#define cbt_lib_cflags(LIB, ...) _cbt_lib_cflags(LIB, __VA_ARGS__, NULL) +#define cbt_lib_ldflags(LIB, ...) _cbt_lib_ldflags(LIB, __VA_ARGS__, NULL) +struct cbt_lib cbt_lib(const char *libname, const char *basepath); +void _cbt_lib_src(struct cbt_lib *lib, ...); +void _cbt_lib_cflags(struct cbt_lib *lib, ...); +void _cbt_lib_ldflags(struct cbt_lib *lib, ...); +bool cbt_lib_build(struct cbt_lib lib, const char *cc); +void cbt_lib_free(struct cbt_lib lib); + +struct cbt_binary { + const char *out_path; + struct cbt_chararray sources, cflags, ldflags; +}; + +#define cbt_binary_add_src(B, ...) _cbt_binary_add_src(B, __VA_ARGS__, NULL) +#define cbt_binary_build(B, CC, ...) _cbt_binary_build(B, CC, __VA_ARGS__, NULL) +struct cbt_binary cbt_binary(const char *out_path); +void _cbt_binary_add_src(struct cbt_binary bin, ...); +bool _cbt_binary_build(struct cbt_binary bin, const char *compiler, ...); +void cbt_binary_free(struct cbt_binary bin); + #define CBT_ARRLEN(ARR) (sizeof(ARR) / sizeof(ARR[0])) #ifndef CBT_REALLOC @@ -95,11 +132,30 @@ int cbt_proc_wait(struct cbt_proc proc); ARR.size--; \ } +#define cbt_da_merge(OUT, IN) \ + { \ + OUT.cap = OUT.size + IN.size; \ + OUT.items = realloc(OUT.items, sizeof(OUT.items[0]) * OUT.cap); \ + size_t offset = OUT.size; \ + OUT.size = OUT.size + IN.size; \ + memmove(&OUT.items[offset], IN.items, sizeof(OUT.items[0]) * IN.size); \ + } + +#define cbt_da_copy(OUT, IN, T) { \ + OUT.size = IN.size; \ + OUT.cap = IN.size; \ + OUT.items = malloc(sizeof(IN.items[0]) * IN.size); \ + memcpy(OUT.items, IN.items, sizeof(IN.items[0]) * IN.size); \ +} + #ifdef CBT_IMPLEMENTATION //-*- begin cbt_impl.c 5 #define __USE_GNU #include #include +#include +#include +#include #include #include #include @@ -119,8 +175,17 @@ int cbt_proc_wait(struct cbt_proc proc); abort(); \ }; +#define CBT_TODO(NAME) \ + { \ + cbt_log(CBT_LOG_FATAL, "%s: Not implemented! %s:%d", NAME, __FILE__, \ + __LINE__); \ + abort(); \ + } + enum cbt_loglevel cbt_verbosity = CBT_LOG_INFO; char *cbt_cc = NULL; +char cbt_location[PATH_MAX] = {0}; +char *cbt_cache_dir = NULL; long cbt_start_time = 0; bool cbt_running = false; @@ -137,9 +202,9 @@ struct _cbt__autoproc_set { size_t size, cap; } cbt__autoproc_set = {0}; -struct cbt_procgroup cbt__default_procgroup = {.items = 0, .size = 0, .cap = 4}; +struct cbt_procgroup cbt__proc_pool = {0, .cap = 4, .fixed_size = 1}; -pthread_t _cbt__autoproc_thread; +pthread_t cbt__autoproc_thread; pthread_mutex_t _cbt__autoproc_mut = PTHREAD_MUTEX_INITIALIZER; const char *cbt_log__colors[CBT_LOG_ALL + 1] = { @@ -154,7 +219,7 @@ void cbt__init(int argc, char **argv, const char *source_file) { cbt_running = true; (void)argc; - cbt_log(CBT_LOG_INFO, "Running CBT build %s %s from %s", __DATE__, __TIME__, __FILE__); + cbt_log(CBT_LOG_INFO, "Running CBT build %s %s", __DATE__, __TIME__); if (!cbt_cc) cbt_cc = getenv("CC"); @@ -162,24 +227,35 @@ void cbt__init(int argc, char **argv, const char *source_file) { cbt_cc = "cc"; cbt_log(CBT_LOG_INFO, "Found C Compiler: %s", cbt_cc); + + CBT_FAIL(readlink("/proc/self/exe", cbt_location, PATH_MAX) == -1); + cbt_log(CBT_LOG_INFO, "Location: %s", cbt_location); + + char *cbt_cache_dir = strdup(cbt_location); + cbt_cache_dir = strdup(cbt_fmt("%s/%s", dirname(cbt_cache_dir), "cache")); + cbt_log(CBT_LOG_DEBUG, "Args: %s", cbt_escape_args(argv)); cbt_log(CBT_LOG_DEBUG, "%s", cbt_fmt("format test: %s", "ok")); - cbt__default_procgroup.items = - calloc(cbt__default_procgroup.cap, sizeof(struct cbt_proc)); + cbt_log(CBT_LOG_INFO, "Cache dir: %s", cbt_cache_dir); - cbt_log(CBT_LOG_DEBUG, "Starting line processor thread"); + cbt__proc_pool.items = calloc(cbt__proc_pool.cap, sizeof(struct cbt_proc)); - int err; - if ((err = pthread_create(&_cbt__autoproc_thread, NULL, cbt__line_processor, NULL)) != 0) { - cbt_log(CBT_LOG_ERROR, "pthread_create() failed for line processor: %d", err); - exit(1); + { + cbt_log(CBT_LOG_DEBUG, "Starting line processor thread"); + int err; + if ((err = pthread_create(&cbt__autoproc_thread, NULL, cbt__line_processor, + NULL)) != 0) { + cbt_log(CBT_LOG_ERROR, "pthread_create() failed for line processor: %d", + err); + exit(1); + } } if (cbt_needs_recompilation(source_file, argv[0])) { cbt_log(CBT_LOG_INFO, "Recompiling..."); - struct cbt_proc cc = cbt_proc_new(CBT_PROC_NORMAL, cbt_cc, source_file, - "-o", argv[0], "-Wall", "-Wextra", NULL); + struct cbt_proc cc = cbt_proc_new(CBT_PROC_AUTO, cbt_cc, source_file, "-o", + argv[0], "-Wall", "-Wextra", NULL); int status = cbt_proc_wait(cc); cbt_log(CBT_LOG_INFO, "CC returned %d", status); if (status == 0) { @@ -196,7 +272,7 @@ void cbt_cleanup(void) { pthread_mutex_lock(&_cbt__autoproc_mut); cbt_running = false; cbt_log(CBT_LOG_INFO, "cbt shutting down"); - pthread_join(_cbt__autoproc_thread, NULL); + pthread_join(cbt__autoproc_thread, NULL); pthread_mutex_unlock(&_cbt__autoproc_mut); cbt_log(CBT_LOG_INFO, "shutdown complete"); } @@ -279,6 +355,18 @@ const char *cbt_escape_args(char **args) { return out; } +const char *cbt_escape_argsd(struct cbt_chararray arr) { + if (arr.size == 0 || arr.items[0] == NULL) + return cbt_fmt(""); + char *out = (char *)cbt_escape_shell(arr.items[0]); + for (size_t i = 1; i < arr.size; i++) { + if (arr.items[i]) { + out = (char *)cbt_fmt("%s %s", out, cbt_escape_shell(arr.items[i])); + } + } + return out; +} + unsigned long cbt_get_modtime(const char *filename) { struct stat st; int ret = lstat(filename, &st); @@ -328,7 +416,7 @@ struct cbt_proc _cbt_proc_new(enum cbt_proc_mode mode, ...) { struct cbt_proc cbt_proc_newv(enum cbt_proc_mode mode, va_list args) { struct cbt_proc procinfo = {0}; - struct cbt_proc_args args_da = {0}; + struct cbt_chararray args_da = {0}; while (true) { const char *arg = va_arg(args, const char *); if (arg == NULL) @@ -469,6 +557,91 @@ void *cbt__line_processor(void *arg) { return NULL; } +struct cbt_lib cbt_lib(const char *libname, const char *basepath) { + return (struct cbt_lib){.type = CBT_LIB_STATIC, + .basepath = basepath, + .libname = libname, + .cflags = {0}, + .ldflags = {0}, + .sources = {0}}; +} + +int _cbt_globerr(const char *epath, int eerrno) { + cbt_log(CBT_LOG_WARNING, "glob() failed at %s: %s", epath, strerror(eerrno)); + return 0; +} + +void _cbt_lib_src(struct cbt_lib *lib, ...) { + va_list args; + va_start(args, lib); + + glob_t globbuf; + + for (char *arg = va_arg(args, char *); arg; arg = va_arg(args, char *)) { + glob(cbt_fmt("%s/%s", lib->basepath, arg), + GLOB_APPEND | GLOB_BRACE | GLOB_NOCHECK, _cbt_globerr, &globbuf); + } + + for (size_t i = 0; i < globbuf.gl_pathc; i++) { + char *path = strdup(globbuf.gl_pathv[i]); + cbt_da_add(lib->sources, path); + } + + globfree(&globbuf); + va_end(args); +} + +void _cbt_lib_cflags(struct cbt_lib *lib, ...) { + va_list args; + va_start(args, lib); + for (char *arg = va_arg(args, char *); arg; arg = va_arg(args, char *)) { + cbt_da_add(lib->cflags, arg); + } + va_end(args); +} + +void _cbt_lib_ldflags(struct cbt_lib *lib, ...) { + va_list args; + va_start(args, lib); + for (char *arg = va_arg(args, char *); arg; arg = va_arg(args, char *)) { + cbt_da_add(lib->ldflags, arg); + } + va_end(args); +} + +bool cbt_lib_build(struct cbt_lib lib, const char *compiler) { + cbt_log(CBT_LOG_INFO, "library: %s in %s", lib.libname, lib.basepath); + cbt_log(CBT_LOG_INFO, " cflags: %s", cbt_escape_argsd(lib.cflags)); + cbt_log(CBT_LOG_INFO, " ldflags: %s", cbt_escape_argsd(lib.ldflags)); + cbt_log(CBT_LOG_INFO, " sources: %s", cbt_escape_argsd(lib.sources)); + cbt_log(CBT_LOG_INFO, " cc: %s", compiler ? compiler : cbt_cc); + + struct cbt_chararray args = {0}; + cbt_da_add(args, (char *)(compiler ? compiler : cbt_cc)); + + cbt_da_merge(args, lib.cflags); + + cbt_log(CBT_LOG_INFO, "args.size: %d", args.size); + cbt_log(CBT_LOG_INFO, "CMD: %s", cbt_escape_argsd(args)); + + CBT_TODO("cbt_lib_build()"); +} + +void cbt_lib_free(struct cbt_lib lib) { + free(lib.cflags.items); + free(lib.ldflags.items); + for (size_t i = 0; i < lib.sources.size; i++) { + free(lib.sources.items[i]); + } + free(lib.sources.items); +} + +struct cbt_binary cbt_binary(const char *out_path); +void _cbt_binary_add_src(struct cbt_binary bin, ...); +bool _cbt_binary_build(struct cbt_binary bin, const char *compiler, ...); +void cbt_binary_free(struct cbt_binary bin); + +#undef CBT_TODO #undef CBT_FAIL //-*- end #endif