int main(void) {
build("./");
+ cflags = NONE;
compile("main");
+ lflags = NONE;
load('x', "main", LIST("main"));
return EXIT_SUCCESS;
```
## Detailed usage
-cbs tries to be as simple as possible, while still remaining powerful. Its simplicity is rooted in its intentionally limited scope to just build C projects. Thus, cbs just needs to worry about compiling and linking C code, and calling other build executables.
+cbs tries to be as simple as possible, while still remaining powerful. Its simplicity is rooted in its intentionally limited scope of only building C projects. Thus, cbs only needs to compile and link C code, as well as call other build executables.
### Compiling source files
The `compile()` function is given a single source file to compile and will generate an object file with the same name. In general, file extensions are unnecessary in your build files as they can usually be inferred based on the function being called. This has the added benefit of being able to reuse lists of file names in both compiling and linking.
-To define flags for the compiler to use, you can set the global `cflags` variable to a list of strings of flags. This list is expected to be NULL-terminated, an easy thing to forget, so a simple C macro has been defined to avoid the issue altogether.
+Before you run `compile()`, the global `cflags` variable has to be initialized with a list of flags to pass to the compiler. If no flags are needed, than the `NONE` macro should be used; otherwise the `LIST()` macro can be used.
```c
cflags = LIST("-Wall", "-O3");
The third and final argument is a list of object files and libraries that will be linked to create the target file. Here, file extensions *are* required for libraries since they're mixed in with object files. The `LIST()` macro can also be used for this list since it too is expected to be NULL-terminated.
-Similar to the global `cflags` variable, there is a global `lflags` variable used by the linker.
+Similar to `cflags`, there is a global `lflags` variable used by the linker.
```c
lflags = LIST("-lm");
load('s', "main", LIST("first" DYEXT, "second", "third.a"));
```
-`DYEXT` is another macro defined as the platform-specific file extension for dynamic libraries, this time to aid the portability of build files.
+`DYEXT` is macro defined to be the platform-specific file extension for dynamic libraries, to aid the portability of build files.
### Recursive builds
#define DYEXT ".so"
#endif
+#define NONE (char *[]){NULL}
#define LIST(...) (char *[]){__VA_ARGS__, NULL}
extern char **environ;
char *dp, *bp, *e, *r;
size_t d, b, l;
- if (!(dp = path)) return NULL;
-
- bp = (bp = strrchr(dp, '/')) ? bp + 1 : dp;
+ bp = (bp = strrchr(dp = path, '/')) ? bp + 1 : dp;
d = bp - dp;
b = (e = strrchr(bp, '.')) ? e - bp : (e = ext, strlen(bp));
if (*ext == '!') e = ++ext;
void run(char *file, char **args, char *what, char *who) {
size_t i;
- if (*args) for (i = 0; args[i]; ++i) {
+ if (*file == '!') ++file;
+ else for (i = 0; args[i]; ++i) {
fputs(args[i], stdout);
putchar(args[i + 1] ? ' ' : '\n');
- } else ++args;
+ }
if (execve(file, args, environ) == -1)
err(EXIT_FAILURE, "Unable to %s `%s'", what, who);
void compile(char *src) {
size_t f;
- char **args, **p;
+ char **args, **p, *obj;
pid_t cpid;
- f = 0;
- if (cflags) while (cflags[f]) ++f;
+ for (f = 0; cflags[f]; ++f);
p = args = allocate((2 + f + 3 + 1) * sizeof*args);
*p++ = "cc";
*p++ = "-c";
- if (cflags) for (f = 0; cflags[f]; *p++ = cflags[f++]);
+ for (f = 0; cflags[f]; *p++ = cflags[f++]);
*p++ = "-o";
- *p++ = extend(src, "!.o");
+ *p++ = obj = extend(src, "!.o");
*p++ = src = extend(src, ".c");
if ((cpid = fork()) == -1) err(EXIT_FAILURE, "Unable to fork");
else if (!cpid) run("/usr/bin/cc", args, "compile", src);
await(cpid, "compile", src);
+ free(obj);
free(src);
free(args);
}
char **args, **p, **a, **fp, *path;
pid_t cpid;
- f = o = 0;
- while (objs[o]) ++o;
- if (lflags) while (lflags[f]) ++f;
+ for (o = 0; objs[o]; ++o);
+ for (f = 0; lflags[f]; ++f);
args = allocate((3 + o + 1 + f + 1) * sizeof*args);
fp = (a = (p = args) + 3) + o;
errx(EXIT_FAILURE, "Unknown target type `%c'", type);
}
*p++ = target;
- f = o = 0;
- while (objs[o]) *p++ = extend(objs[o++], ".o");
- if (lflags) while (lflags[f]) *fp++ = lflags[f++];
+ for (o = 0; objs[o]; *p++ = extend(objs[o++], ".o"));
+ for (f = 0; lflags[f]; *fp++ = lflags[f++]);
if ((cpid = fork()) == -1) err(EXIT_FAILURE, "Unable to fork");
else if (!cpid) run(path, args, "link", target);
if (self || !exists) {
c = cflags;
l = lflags;
- lflags = cflags = NULL;
+ cflags = NONE;
compile("build");
+
+ lflags = NONE;
load('x', "build", LIST("build"));
cflags = c;
lflags = l;
}
- run("build", LIST(NULL, "build"), "run", "build");
+ run("!build", LIST("build"), "run", "build");
}