From eafa6d066b5d21b950cf8a9c7bfbda32bc848768 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Sat, 8 Jun 2024 18:52:34 +0200 Subject: Update README --- README.md | 178 +++++++++++++++++++++++++------------------------------------- 1 file changed, 72 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index e6a9c0e..4ebb334 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,12 @@ CBS is very much inspired by Tsoding’s ‘Nob’. ## Features -— Simple and easy to understand API -— Easy command building and execution +— C99 and POSIX compliant — Capturing of command output +— Easy command building and execution — PkgConfig support +— Simple and easy to understand API — Thread pool support -— Preprocessor-friendly variadic macros* - -*See the examples below ## Important @@ -62,74 +60,40 @@ itself. ```c #include +#define CBS_NO_THREADS #include "cbs.h" -#define CC "cc" -#define CFLAGS "-Wall", "-Wextra", "-Werror", "-O3" -#define TARGET "my-file" +static char *cflags[] = {"-Wall", "-Wextra", "-Werror", "-O3"}; int main(int argc, char **argv) { - int ec; - cmd_t cmd = {0}; - struct strv v = {0}; - - cbsinit(argc, argv); - rebuild(); - - if (!foutdated(TARGET, TARGET ".c")) - return EXIT_SUCCESS; - - cmdadd(&cmd, CC); - if (pcquery(&v, "liblux", PKGC_LIBS | PKGC_CFLAGS)) - cmdaddv(&cmd, v.buf, v.len); - else - cmdadd(&cmd, "-llux"); - cmdadd(&cmd, CFLAGS, "-o", TARGET, TARGET ".c"); - - cmdput(cmd); - if ((ec = cmdexec(cmd)) != EXIT_SUCCESS) - diex("%s failed with exit-code %d", *cmd._argv, ec); - - return EXIT_SUCCESS; -} -``` - - -## Example With Environment Variables - -In many cases a user may want to use environment variables to alter the -build process. They may want to specify their own compiler via `CC`, -their own compiler flags via `CFLAGS`, or the installation directory via -`DESTDIR` and `PREFIX`. These are made easy to configure via -`env_or_default()`. - -```c -#include "cbs.h" - -#define CC "cc" -#define CFLAGS "-Wall", "-Wextra", "-O3" - -int -main(int argc, char **argv) -{ - cmd_t c = {0}; - struct strv sv = {0}; - + /* Initialize the library, and rebuild this script if needed */ cbsinit(argc, argv); rebuild(); - /* Append the expanded values of ‘CC’ and ‘CFLAGS’ to ‘sv’ if they’re set, - using the defaults specified by the macros otherwise. */ - env_or_default(&sv, "CC", CC); - env_or_default(&sv, "CFLAGS", CFLAGS); + /* If the compiled binary isn’t outdated, do nothing */ + if (!foutdatedl("my-file", "my-file.c")) + return EXIT_SUCCESS; + + /* Append ‘cc’ and our cflags to the command, but allow the user to use the + $CC and $CFLAGS environment variables to override them */ + struct strs cmd = {0}; + strspushenvl(&cmd, "CC", "cc"); + strspushenv(&cmd, "CFLAGS", cflags, lengthof(cflags)); + + /* Call pkg-config with the --libs and --cflags options for the library + ‘liblux’, appending the result to our command. If it fails then we + fallback to using -llux */ + if (!pcquery(&cmd, "liblux", PC_LIBS | PC_CFLAGS)) + strspushl(&cmd, "-llux"); - cmdaddv(&c, sv.buf, sv.len); - cmdput(c); - (void)cmdexec(c); + /* Push the final arguments to our command */ + strspushl(&cmd, "-o", "my-file", "-c", "my-file.c"); - strvfree(&sv); + /* Print our command to stdout, and execute it */ + cmdput(cmd); + return cmdexec(cmd); } ``` @@ -137,79 +101,81 @@ main(int argc, char **argv) ## Example With Threads This is like the previous example, but you should compile with -lpthread. -This is not the most efficient way to build a multi-file project, but -this is simply for demonstration purposes. ```c -#include -#include +#include -#define CBS_PTHREAD #include "cbs.h" -#define CC "cc" -#define CFLAGS "-Wall", "-Wextra", "-Werror", "-O3" -#define TARGET "my-file" - -static const char *sources[] = {"foo.c", "bar.c", "baz.c"}; -static const char *objects[] = {"foo.o", "bar.o", "baz.o"}; +static char *cflags[] = {"-Wall", "-Wextra", "-Werror", "-O3"}; +static char *sources[] = {"foo.c", "bar.c", "baz.c"}; static void build(void *); int main(int argc, char **argv) { - int ec, cpus; - cmd_t cmd = {0}; - tpool_t tp; - cbsinit(argc, argv); rebuild(); - if (!foutdatedv(TARGET, sources, lengthof(sources))) + if (!foutdated("my-file", sources, lengthof(sources))) return EXIT_SUCCESS; - if ((cpus = nproc()) == -1) { - if (errno) - die("nproc"); - /* System not properly supported; default to 8 threads */ + /* Get the number of CPUs available. If this fails we fallback to 8. */ + int cpus = nproc(); + if (cpus == -1) cpus = 8; - } + + /* Create a thread pool, with one thread per CPU */ + tpool tp; tpinit(&tp, cpus); + /* For each of our source files, add a task to the thread pool to build + the file ‘sources[i]’ with the function ‘build’ */ for (size_t i = 0; i < lengthof(sources); i++) tpenq(&tp, build, sources[i], NULL); + + /* Wait for all the tasks to complete and free the thread pool */ tpwait(&tp); tpfree(&tp); - cmdadd(&cmd, CC, "-o", TARGET); - cmdaddv(&cmd, objects, lengthof(objects)); - cmdput(cmd); - if ((ec = cmdexec(cmd)) != EXIT_SUCCESS) - diex("%s failed with exit-code %d", *cmd._argv, ec); + struct strs cmd = {0}; + strspushenvl(&cmd, "CC", "cc"); + strspushl(&cmd, "-o", "my-file"); - return EXIT_SUCCESS; + for (size_t i = 0; i < lengthof(sources); i++) + strspushl(&cmd, swpext(sources[i], "o")); + + cmdput(cmd); + return cmdexec(cmd); } void build(void *arg) { - int ec; - char *dst, *src = arg; - cmd_t cmd = {0}; - - for (size_t i = 0; i < lengthof(sources); i++) { - /* All the sources and objects have 3 letter names + an extension */ - if (strncmp(src, objects[i], 3) == 0) { - dst = objects[i]; - break; - } - } - - cmdadd(&cmd, CC, CFLAGS, "-o", dst, "-c", src); - cmdput(cmd); - if ((ec = cmdexec(cmd)) != EXIT_SUCCESS) - diex("%s failed with exit-code %d", *cmd._argv, ec); - free(cmd._argv); + /* This function will be called by the thread pool with ‘arg’ set to a + filename such as ‘foo.c’ */ + + struct strs cmd = {0}; + + strspushenvl(&cmd, "CC", "cc"); + strspushenv(&cmd, "CFLAGS", cflags, lengthof(cflags)); + + /* Allocate a copy of the string ‘arg’, with the file extension replaced. + This will for example return ‘foo.o’ when given ‘foo.c’ */ + char *object = swpext(arg, "o"); + + strspushl(&cmd, "-o", object, "-c", arg); + + cmdput(cmd); + if (cmdexec(cmd) != EXIT_SUCCESS) + exit(EXIT_FAILURE); + free(object); + strsfree(&cmd); } ``` + + +## Documentation + +Coming soon! -- cgit v1.2.3