kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

lib_resolve.c (6117B)


      1 #include "lib_resolve.h"
      2 
      3 #include <kit/link.h>
      4 #include <stdbool.h>
      5 #include <stddef.h>
      6 #include <stdint.h>
      7 
      8 /* Compose `<dir>/<prefix><name><suffix>` into a fresh heap buffer.
      9  * Empty `dir` is treated as the current directory: the path becomes
     10  * `<prefix><name><suffix>`. `prefix` is "lib" or "" (Windows MSVC-
     11  * style libs ship without the prefix); `suffix` is e.g. ".a" or ".so"
     12  * — both caller-owned, NUL-terminated. The leaf (`prefix+name+suffix`) is
     13  * built first, then joined onto `dir` via the shared driver_path_join so the
     14  * separator decision (including Windows '\\') lives in one place. */
     15 static char* compose_path(DriverEnv* env, const char* dir, const char* prefix,
     16                           const char* name, const char* suffix,
     17                           size_t* out_size) {
     18   size_t plen = driver_strlen(prefix);
     19   size_t nlen = driver_strlen(name);
     20   size_t slen = driver_strlen(suffix);
     21   size_t leaf_bytes = plen + nlen + slen + 1;
     22   char* leaf = driver_alloc(env, leaf_bytes);
     23   char* buf;
     24   size_t off = 0;
     25   if (!leaf) return NULL;
     26   if (plen) {
     27     driver_memcpy(leaf + off, prefix, plen);
     28     off += plen;
     29   }
     30   if (nlen) {
     31     driver_memcpy(leaf + off, name, nlen);
     32     off += nlen;
     33   }
     34   if (slen) {
     35     driver_memcpy(leaf + off, suffix, slen);
     36     off += slen;
     37   }
     38   leaf[off] = '\0';
     39   buf = driver_path_join(env, dir, leaf, out_size);
     40   driver_free(env, leaf, leaf_bytes);
     41   return buf;
     42 }
     43 
     44 /* Probe one candidate `<dir>/<prefix><name><suffix>` for kit_lib_resolve:
     45  * compose the path, test existence, and on a hit hand the heap path + size +
     46  * kind back to the resolver and stop the search. Allocation failure also stops
     47  * (flagged via `oom`); a miss frees the candidate and continues. */
     48 typedef struct LibProbeCtx {
     49   DriverEnv* env;
     50   char** out_path;
     51   size_t* out_size;
     52   LibResolveKind* out_kind;
     53   int oom;
     54 } LibProbeCtx;
     55 
     56 static bool lib_probe(void* user, const char* dir, const char* prefix,
     57                       const char* name, const char* suffix, uint8_t kind) {
     58   LibProbeCtx* c = (LibProbeCtx*)user;
     59   size_t bytes;
     60   char* cand = compose_path(c->env, dir, prefix, name, suffix, &bytes);
     61   if (!cand) {
     62     c->oom = 1;
     63     return true;
     64   }
     65   if (driver_path_exists(cand)) {
     66     *c->out_path = cand;
     67     *c->out_size = bytes;
     68     if (c->out_kind) *c->out_kind = (LibResolveKind)kind;
     69     return true;
     70   }
     71   driver_free(c->env, cand, bytes);
     72   return false;
     73 }
     74 
     75 int driver_lib_resolve_for_os(DriverEnv* env, const char* name,
     76                               LibResolveMode mode, LibResolveOS os,
     77                               const char* const* search_dirs,
     78                               uint32_t nsearch_dirs, char** out_path,
     79                               size_t* out_size, LibResolveKind* out_kind) {
     80   LibProbeCtx ctx;
     81   if (!env || !name) return 1;
     82   ctx.env = env;
     83   ctx.out_path = out_path;
     84   ctx.out_size = out_size;
     85   ctx.out_kind = out_kind;
     86   ctx.oom = 0;
     87   /* libkit owns the GNU-ld suffix order; lib_probe does the composition and
     88    * filesystem I/O. The LibResolve* enum values match KitLibResolve* exactly,
     89    * so the OS/mode/kind casts are value-preserving. */
     90   if (kit_lib_resolve((uint8_t)os, (uint8_t)mode, name, search_dirs,
     91                       nsearch_dirs, lib_probe, &ctx)) {
     92     return ctx.oom ? 1 : 0; /* stopped on a recorded hit, or on OOM */
     93   }
     94   return 1; /* no candidate matched in any search dir */
     95 }
     96 
     97 int driver_lib_resolve(DriverEnv* env, const char* name, LibResolveMode mode,
     98                        const char* const* search_dirs, uint32_t nsearch_dirs,
     99                        char** out_path, size_t* out_size,
    100                        LibResolveKind* out_kind) {
    101   return driver_lib_resolve_for_os(env, name, mode, LIB_RESOLVE_OS_POSIX,
    102                                    search_dirs, nsearch_dirs, out_path,
    103                                    out_size, out_kind);
    104 }
    105 
    106 static char* compose_framework_path(DriverEnv* env, const char* dir,
    107                                     const char* name, const char* leaf_suffix,
    108                                     size_t* out_size) {
    109   size_t nlen = driver_strlen(name);
    110   size_t slen = driver_strlen(leaf_suffix);
    111   size_t fw_leaf_size = nlen + 10u + 1u; /* ".framework" + NUL */
    112   size_t bin_leaf_size = nlen + slen + 1u;
    113   char* fw_leaf = driver_alloc(env, fw_leaf_size);
    114   char* bin_leaf = driver_alloc(env, bin_leaf_size);
    115   char* fw_dir = NULL;
    116   size_t fw_dir_size = 0;
    117   char* out = NULL;
    118   if (!fw_leaf || !bin_leaf) goto out;
    119 
    120   driver_memcpy(fw_leaf, name, nlen);
    121   driver_memcpy(fw_leaf + nlen, ".framework", 10u);
    122   fw_leaf[nlen + 10u] = '\0';
    123 
    124   driver_memcpy(bin_leaf, name, nlen);
    125   if (slen) driver_memcpy(bin_leaf + nlen, leaf_suffix, slen);
    126   bin_leaf[nlen + slen] = '\0';
    127 
    128   fw_dir = driver_path_join(env, dir, fw_leaf, &fw_dir_size);
    129   if (!fw_dir) goto out;
    130   out = driver_path_join(env, fw_dir, bin_leaf, out_size);
    131 
    132 out:
    133   if (fw_dir) driver_free(env, fw_dir, fw_dir_size);
    134   if (fw_leaf) driver_free(env, fw_leaf, fw_leaf_size);
    135   if (bin_leaf) driver_free(env, bin_leaf, bin_leaf_size);
    136   return out;
    137 }
    138 
    139 int driver_framework_resolve(DriverEnv* env, const char* name,
    140                              const char* const* search_dirs,
    141                              uint32_t nsearch_dirs, char** out_path,
    142                              size_t* out_size, LibResolveKind* out_kind) {
    143   uint32_t i;
    144   if (!env || !name || !out_path || !out_size) return 1;
    145   for (i = 0; i < nsearch_dirs; ++i) {
    146     size_t size = 0;
    147     char* cand = compose_framework_path(env, search_dirs[i], name, ".tbd",
    148                                         &size);
    149     if (!cand) return 1;
    150     if (driver_path_exists(cand)) {
    151       *out_path = cand;
    152       *out_size = size;
    153       if (out_kind) *out_kind = LIB_RESOLVE_KIND_TBD;
    154       return 0;
    155     }
    156     driver_free(env, cand, size);
    157 
    158     cand = compose_framework_path(env, search_dirs[i], name, "", &size);
    159     if (!cand) return 1;
    160     if (driver_path_exists(cand)) {
    161       *out_path = cand;
    162       *out_size = size;
    163       if (out_kind) *out_kind = LIB_RESOLVE_KIND_SHARED;
    164       return 0;
    165     }
    166     driver_free(env, cand, size);
    167   }
    168   return 1;
    169 }