]> Trent Huber's Code - cbs.git/commitdiff
Improve dynamic library behavior
authorTrent Huber <trentmhuber@gmail.com>
Wed, 16 Apr 2025 22:32:30 +0000 (18:32 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Wed, 16 Apr 2025 22:32:30 +0000 (18:32 -0400)
README.md
cbs.c

index 20ed3ed42d150e4dbcf36ffbd6d37e7fa8570e96..e027b35c9dc550dd5225b4438be33ed3ab992514 100644 (file)
--- a/README.md
+++ b/README.md
@@ -86,17 +86,19 @@ The first argument to `load()`[^2] is the type of the target file. The options a
 'd' - dynamically linked library
 ```
 
-The second argument is the name of the target. There is no assumed typical file extension for the target as executables commonly lack them. It is also common to prepend `lib` to files that are static or dynamic libraries; this is done automatically and in a nature similar to typical file extensions. This allows you to use the same name to refer to a statically linked library in the same way you would when refering to a dynamically linked library in the linker flags.
+The second argument is the name of the target. There is no assumed typical file extension for the target as executables commonly lack them. It is also common to prepend `lib` to files that are static or dynamic libraries; this is done automatically and in a nature similar to typical file extensions. The idea is similar to the manner in which you would typically pass system libraries to the linker flag `-l`.
 
-The rest of the arguments are the names of the files you want to link together. The typical file extension for these files is `.o`. Generally the only other files that would use a different file extension would be statically linked libraries (note that dynamically linked libraries aren't really linked in the same way as object files nor statically linked libraries and should thus be passed as linker flags instead). As is the case with compiling, **the arguments passed to `load()` must be terminated with a null pointer**.
+The rest of the arguments are the names of the files you want to link together. The typical file extension for these files is `.o`. Generally the only other files that would use a different file extension would be statically linked libraries or dynamically linked libraries (the linker flag `-l` should be used to link system libraries as opposed to project libraries). As is the case with compiling, **the arguments passed to `load()` must be terminated with a null pointer**.
 
 In a similar way as compiling, the predefined `lflags` variable can be used to define flags for the linker.
 
-An example of linking `liba.dylib`, `b.o`, and `libc.a` as a statically linked library `libmain.a`.
+The `DYEXT` macro has been defined which represents the platform-dependent file extension for dyanmic libraries, `".dylib"` for macOS and `".so"` for anything else. This can be used to allow portability of build files.
+
+An example of linking `liba.dylib` (or `liba.so`), `b.o`, `libc.a`, and the system math library as a statically linked library `libmain.a`.
 
 ```c
-lflags = (char *[]){"-la", NULL};
-load('s', "main", "b", "c.a", NULL);
+lflags = (char *[]){"-lm", NULL};
+load('s', "main", "a" DYEXT, "b", "c.a", NULL);
 ```
 
 ### Recursive builds
diff --git a/cbs.c b/cbs.c
index e392ca64f6a4c4fc3f4e5578aaf15b29574ace88..18a0b39f63ce9707dd4e71a7aa44a9522e3dda23 100644 (file)
--- a/cbs.c
+++ b/cbs.c
@@ -30,39 +30,52 @@ void error(char *fmt, ...) {
    exit(EXIT_FAILURE);
 }
 
-void *alloc(size_t s) {
+void *allocate(size_t s) {
    void *r;
 
    if (!(r = malloc(s))) error("Memory allocation");
 
-   return r;
+   return memset(r, 0, s);
 }
 
 char *extend(char *path, char *ext) {
-   char *bp, *ep, *r, *p;
-   size_t d, b, l, e;
-
-   if (!path) return NULL;
+   char *dp, *bp, *e, *r;
+   size_t d, b, l;
+
+   if (!(dp = path)) return NULL;
+
+   bp = (bp = strrchr(dp, '/')) ? bp + 1 : dp;
+   d = bp - dp;
+   b = (e = strrchr(bp, '.')) ? e - bp : (e = ext, strlen(bp));
+   if (*ext == '!') e = ++ext;
+   l = strcmp(e, ".a") == 0 || strcmp(e, DYEXT) == 0 ? 3 : 0;
+
+   if (strcmp(e, DYEXT) == 0) {
+       path = d ? strndup(dp, d) : strdup(".");
+       if (!(dp = realpath(path, NULL)))
+           error("Unable to get absolute path of `%s'", path);
+       free(path);
+       dp[(d = strlen(dp))] = '/';
+       ++d;
+   }
 
-   bp = (bp = strrchr(path, '/')) ? bp + 1 : path;
-   d = bp - path;
-   b = (ep = strrchr(bp, '.')) ? ep - bp : (ep = ext, strlen(bp));
-   if (*ext == '!') ep = ext + 1;
-   l = strcmp(ep, ".a") == 0 || strcmp(ep, DYEXT) == 0 ? 3 : 0;
-   e = strlen(ep);
+   r = allocate(d + l + b + strlen(e) + 1);
+   strncat(r, dp, d);
+   strncat(r, "lib", l);
+   strncat(r, bp, b);
+   strcat(r, e);
 
-   p = r = alloc(d + l + b + e + 1);
-   p = stpncpy(p, path, d);
-   p = stpncpy(p, "lib", l);
-   p = stpncpy(p, bp, b);
-   strcpy(p, ep);
+   if (dp != path) free(dp);
 
    return r;
 }
 
 int modified(char *target, char *dep) {
+   char *e;
    struct stat tstat, dstat;
 
+   if ((e = strrchr(dep, '.')) && strcmp(e, DYEXT) == 0) return 0;
+
    if (stat(target, &tstat) == -1) {
        if (errno == ENOENT) return !(errno = 0);
        error("Unable to stat `%s'", target);
@@ -99,15 +112,14 @@ void compile(char *src, ...) {
    pid_t cpid;
 
    if (f = 0, cflags) while (cflags[f]) ++f;
-   p = args = alloc((5 + f + 1) * sizeof*args);
+   p = args = allocate((5 + f + 1) * sizeof*args);
 
    *p++ = "cc";
-   if (cflags) for (f = 0; cflags[f]; *p++ = cflags[f++]);
    *p++ = "-c";
+   if (cflags) for (f = 0; cflags[f]; *p++ = cflags[f++]);
    *p++ = "-o";
    *p++ = obj = extend(src, "!.o");
    *p++ = hdr = src = extend(src, ".c");
-   *p = NULL;
 
    va_start(hdrs, src);
    do if (modified(obj, hdr = extend(hdr, ".h"))) {
@@ -133,7 +145,7 @@ void load(char type, char *target, char *obj, ...) {
    for (o = 1; va_arg(count, char *); ++o);
    va_end(count);
    if (f = 0, lflags) while (lflags[f]) ++f;
-   args = alloc((3 + o + 1 + f + 1) * sizeof*args);
+   args = allocate((3 + o + 1 + f + 1) * sizeof*args);
    fp = (a = (p = args) + 3) + o;
 
    switch (type) {
@@ -161,7 +173,6 @@ void load(char type, char *target, char *obj, ...) {
    do *p++ = extend(obj, ".o"); while ((obj = va_arg(objs, char *)));
    va_end(objs);
    if (lflags) for (f = 0; lflags[f]; *fp++ = lflags[f++]);
-   if (fp > p) *fp = NULL;
    fp = p;
 
    p -= o;