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 }