kit

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

runtime.c (37065B)


      1 #include "runtime.h"
      2 
      3 #include <kit/archive.h>
      4 #include <kit/compile.h>
      5 #include <kit/core.h>
      6 #include <kit/preprocess.h>
      7 #include <stdint.h>
      8 #include <string.h>
      9 
     10 typedef struct RuntimeVariant {
     11   const char* key;
     12   KitArchKind arch;
     13   KitOSKind os;
     14   KitObjFmt obj;
     15   uint8_t ptr_size;
     16   uint8_t ptr_align;
     17   const char* abi_include;
     18   uint8_t has_int128;
     19   uint8_t ldbl128;
     20   const char* const* sources;
     21   uint32_t nsources;
     22   /* Float-ABI axis (orthogonal to XLEN). A single arch+ptr_size can have
     23    * several float ABIs (rv32 ilp32 soft vs ilp32f single), each needing its
     24    * own runtime build, so the ABI is part of the variant identity. DEFAULT (0)
     25    * means "wildcard" — it matches any target.float_abi (every non-RISC-V
     26    * target and rv64, whose runtime is float-ABI-agnostic, leave it 0). */
     27   uint8_t float_abi; /* KitFloatAbi */
     28   /* -march / -mabi the runtime is compiled with. NULL falls back to the arch
     29    * defaults (correct for every existing variant). rv32 sets them explicitly
     30    * because the default profile (rv32imafc/ilp32f) is wrong for the soft
     31    * ilp32 build. */
     32   const char* isa;
     33   const char* abi;
     34 } RuntimeVariant;
     35 
     36 static const char* const kRtSrcX64[] = {
     37     "assert/assert.c",     "int/int.c",
     38     "int/si_div.c",        "fp/fp.c",
     39     "mem/mem.c",           "string/string.c",
     40     "ctype/ctype.c",       "stdlib/stdlib.c",
     41     "stdlib/qsort.c",      "stdio/printf.c",
     42     "atomic/atomic_freestanding.c",
     43     "cache/clear_cache.c", "kit/ifunc_init.c",
     44     "int64/int64.c",       "coro/x86_64.c",
     45     "coro/coro.c",         "stack/backtrace.c",
     46     "stack/print_backtrace.c",
     47 };
     48 
     49 static const char* const kRtSrcX64Windows[] = {
     50     "int/int.c",
     51     "int/si_div.c",
     52     "fp/fp.c",
     53     "atomic/atomic_freestanding.c",
     54     "cache/clear_cache.c",
     55     "kit/ifunc_init.c",
     56     "int64/int64.c",
     57     "stack/chkstk_x86_64_win.c",
     58     "coro/x86_64_win.c",
     59     "coro/coro.c",
     60 };
     61 
     62 static const char* const kRtSrcAarch64Elf[] = {
     63     "assert/assert.c",     "int/int.c",
     64     "int/si_div.c",        "fp/fp.c",
     65     "mem/mem.c",           "string/string.c",
     66     "ctype/ctype.c",       "stdlib/stdlib.c",
     67     "stdlib/qsort.c",      "stdio/printf.c",
     68     "atomic/atomic_freestanding.c",
     69     "cache/clear_cache.c", "kit/ifunc_init.c",
     70     "int64/int64.c",       "coro/aarch64.c",
     71     "coro/coro.c",         "fp_tf/fp_tf.c",
     72     "fp_ti/fp_ti.c",       "coro/aarch64_elf.s",
     73     "stack/backtrace.c",   "stack/print_backtrace.c",
     74 };
     75 
     76 static const char* const kRtSrcAarch64Darwin[] = {
     77     "assert/assert.c",     "int/int.c",
     78     "int/si_div.c",        "fp/fp.c",
     79     "mem/mem.c",           "string/string.c",
     80     "ctype/ctype.c",       "stdlib/stdlib.c",
     81     "stdlib/qsort.c",      "stdio/printf.c",
     82     "atomic/atomic_freestanding.c",
     83     "cache/clear_cache.c", "kit/ifunc_init.c",
     84     "int64/int64.c",       "coro/aarch64.c",
     85     "coro/coro.c",         "coro/aarch64_macho.s",
     86     "stack/backtrace.c",   "stack/print_backtrace.c",
     87 };
     88 
     89 static const char* const kRtSrcAarch64Windows[] = {
     90     "int/int.c",
     91     "int/si_div.c",
     92     "fp/fp.c",
     93     "atomic/atomic_freestanding.c",
     94     "cache/clear_cache.c",
     95     "kit/ifunc_init.c",
     96     "int64/int64.c",
     97     "coro/aarch64.c",
     98     "coro/coro.c",
     99 };
    100 
    101 static const char* const kRtSrcRv64Elf[] = {
    102     "assert/assert.c",     "int/int.c",
    103     "int/si_div.c",        "fp/fp.c",
    104     "mem/mem.c",           "string/string.c",
    105     "ctype/ctype.c",       "stdlib/stdlib.c",
    106     "stdlib/qsort.c",      "stdio/printf.c",
    107     "atomic/atomic_freestanding.c",
    108     "cache/clear_cache.c", "kit/ifunc_init.c",
    109     "int64/int64.c",       "coro/riscv64.c",
    110     "coro/coro.c",         "fp_tf/fp_tf.c",
    111     "fp_ti/fp_ti.c",       "stack/backtrace.c",
    112     "stack/print_backtrace.c",
    113 };
    114 
    115 /* rv32 freestanding runtime: ilp32 integer layout (int32/int32.c for the
    116  * 64-bit-on-32-bit helpers — __muldi3/__ashldi3/...; int/int.c for the i64
    117  * div/mod) and soft double (fp/fp.c). Shared by the ilp32 (soft) and ilp32f
    118  * (hardware single-float) variants; only the -march/-mabi the sources are
    119  * compiled with differ, captured per-variant in the table below. */
    120 static const char* const kRtSrcRv32Elf[] = {
    121     "assert/assert.c",     "int/int.c",
    122     "int/si_div.c",        "fp/fp.c",
    123     "mem/mem.c",           "string/string.c",
    124     "ctype/ctype.c",       "stdlib/stdlib.c",
    125     "stdlib/qsort.c",      "stdio/printf.c",
    126     "atomic/atomic_freestanding.c",
    127     "cache/clear_cache.c", "kit/ifunc_init.c",
    128     "int32/int32.c",       "coro/riscv32.c",
    129     "coro/coro.c",         "stack/backtrace.c",
    130     "stack/print_backtrace.c",
    131 };
    132 
    133 static const RuntimeVariant kRtVariants[] = {
    134     {"x86_64-linux", KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF, 8, 8,
    135      "lib/include/lp64_le", 1, 0, kRtSrcX64,
    136      (uint32_t)(sizeof(kRtSrcX64) / sizeof(kRtSrcX64[0])),
    137      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    138     /* FreeBSD ELF runtime mirrors the Linux ELF runtime per-arch: the
    139      * compiler-rt helpers and coroutine asm are ABI/ELF-based, not kernel
    140      * based, so the same source set and data model apply. */
    141     {"x86_64-freebsd", KIT_ARCH_X86_64, KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, 8,
    142      "lib/include/lp64_le", 1, 0, kRtSrcX64,
    143      (uint32_t)(sizeof(kRtSrcX64) / sizeof(kRtSrcX64[0])),
    144      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    145     {"x86_64-apple-darwin", KIT_ARCH_X86_64, KIT_OS_MACOS, KIT_OBJ_MACHO, 8, 8,
    146      "lib/include/lp64_le", 1, 0, kRtSrcX64,
    147      (uint32_t)(sizeof(kRtSrcX64) / sizeof(kRtSrcX64[0])),
    148      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    149     {"x86_64-elf", KIT_ARCH_X86_64, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, 8,
    150      "lib/include/lp64_le", 1, 0, kRtSrcX64,
    151      (uint32_t)(sizeof(kRtSrcX64) / sizeof(kRtSrcX64[0])),
    152      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    153     {"x86_64-pc-windows", KIT_ARCH_X86_64, KIT_OS_WINDOWS, KIT_OBJ_COFF, 8, 8,
    154      "lib/include/llp64_le", 1, 0, kRtSrcX64Windows,
    155      (uint32_t)(sizeof(kRtSrcX64Windows) / sizeof(kRtSrcX64Windows[0])),
    156      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    157     {"aarch64-linux", KIT_ARCH_ARM_64, KIT_OS_LINUX, KIT_OBJ_ELF, 8, 8,
    158      "lib/include/lp64_le", 1, 1, kRtSrcAarch64Elf,
    159      (uint32_t)(sizeof(kRtSrcAarch64Elf) / sizeof(kRtSrcAarch64Elf[0])),
    160      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    161     {"aarch64-freebsd", KIT_ARCH_ARM_64, KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, 8,
    162      "lib/include/lp64_le", 1, 1, kRtSrcAarch64Elf,
    163      (uint32_t)(sizeof(kRtSrcAarch64Elf) / sizeof(kRtSrcAarch64Elf[0])),
    164      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    165     {"aarch64-elf", KIT_ARCH_ARM_64, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, 8,
    166      "lib/include/lp64_le", 1, 1, kRtSrcAarch64Elf,
    167      (uint32_t)(sizeof(kRtSrcAarch64Elf) / sizeof(kRtSrcAarch64Elf[0])),
    168      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    169     {"aarch64-apple-darwin", KIT_ARCH_ARM_64, KIT_OS_MACOS, KIT_OBJ_MACHO, 8, 8,
    170      "lib/include/lp64_le", 1, 0, kRtSrcAarch64Darwin,
    171      (uint32_t)(sizeof(kRtSrcAarch64Darwin) / sizeof(kRtSrcAarch64Darwin[0])),
    172      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    173     {"aarch64-windows", KIT_ARCH_ARM_64, KIT_OS_WINDOWS, KIT_OBJ_COFF, 8, 8,
    174      "lib/include/llp64_le", 1, 0, kRtSrcAarch64Windows,
    175      (uint32_t)(sizeof(kRtSrcAarch64Windows) / sizeof(kRtSrcAarch64Windows[0])),
    176      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    177     {"riscv64-linux", KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF, 8, 8,
    178      "lib/include/lp64_le", 1, 1, kRtSrcRv64Elf,
    179      (uint32_t)(sizeof(kRtSrcRv64Elf) / sizeof(kRtSrcRv64Elf[0])),
    180      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    181     {"riscv64-freebsd", KIT_ARCH_RV64, KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, 8,
    182      "lib/include/lp64_le", 1, 1, kRtSrcRv64Elf,
    183      (uint32_t)(sizeof(kRtSrcRv64Elf) / sizeof(kRtSrcRv64Elf[0])),
    184      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    185     {"riscv64-elf", KIT_ARCH_RV64, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, 8,
    186      "lib/include/lp64_le", 1, 1, kRtSrcRv64Elf,
    187      (uint32_t)(sizeof(kRtSrcRv64Elf) / sizeof(kRtSrcRv64Elf[0])),
    188      KIT_FLOAT_ABI_DEFAULT, NULL, NULL},
    189     /* rv32 freestanding. ilp32 (pure soft float) and ilp32f (hardware single
    190      * float, soft double) share one arch+ptr_size, so float_abi is part of the
    191      * variant identity and each is built with its own -march/-mabi. Keys match
    192      * the `make rt` variant dirs (riscv32-elf / riscv32-elf-hardfloat) so a
    193      * checkout shares build/rt with the Makefile. */
    194     {"riscv32-elf", KIT_ARCH_RV32, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 4, 4,
    195      "lib/include/ilp32_le", 0, 0, kRtSrcRv32Elf,
    196      (uint32_t)(sizeof(kRtSrcRv32Elf) / sizeof(kRtSrcRv32Elf[0])),
    197      KIT_FLOAT_ABI_SOFT, "rv32imac", "ilp32"},
    198     {"riscv32-elf-hardfloat", KIT_ARCH_RV32, KIT_OS_FREESTANDING, KIT_OBJ_ELF,
    199      4, 4, "lib/include/ilp32_le", 0, 0, kRtSrcRv32Elf,
    200      (uint32_t)(sizeof(kRtSrcRv32Elf) / sizeof(kRtSrcRv32Elf[0])),
    201      KIT_FLOAT_ABI_SINGLE, "rv32imafc", "ilp32f"},
    202 };
    203 
    204 static char* rt_dup(DriverEnv* env, const char* s, size_t* out_size) {
    205   size_t len = driver_strlen(s);
    206   char* p = (char*)driver_alloc(env, len + 1u);
    207   if (!p) return NULL;
    208   driver_memcpy(p, s, len + 1u);
    209   if (out_size) *out_size = len + 1u;
    210   return p;
    211 }
    212 
    213 static char* rt_join(DriverEnv* env, const char* a, const char* b,
    214                      size_t* out_size) {
    215   size_t la = driver_strlen(a);
    216   size_t lb = driver_strlen(b);
    217   int slash = la > 0 && a[la - 1u] != '/';
    218   size_t n = la + (slash ? 1u : 0u) + lb + 1u;
    219   char* p = (char*)driver_alloc(env, n);
    220   if (!p) return NULL;
    221   driver_memcpy(p, a, la);
    222   if (slash) p[la++] = '/';
    223   driver_memcpy(p + la, b, lb);
    224   p[la + lb] = '\0';
    225   if (out_size) *out_size = n;
    226   return p;
    227 }
    228 
    229 static char* rt_join_slot(DriverEnv* env, char** slot, size_t* size_slot,
    230                           const char* a, const char* b) {
    231   char* p = rt_join(env, a, b, size_slot);
    232   *slot = p;
    233   return p;
    234 }
    235 
    236 static void rt_store_const_ptr(const char** slot, const char* value) {
    237   *slot = value;
    238 }
    239 
    240 static void rt_free_str(DriverEnv* env, char** p, size_t* n) {
    241   if (*p) driver_free(env, *p, *n);
    242   *p = NULL;
    243   *n = 0;
    244 }
    245 
    246 static int rt_has_layout(const char* rt_root) {
    247   char inc[4096];
    248   char lib[4096];
    249   size_t n = driver_strlen(rt_root);
    250   if (n + 13u >= sizeof(inc)) return 0;
    251   driver_memcpy(inc, rt_root, n);
    252   inc[n] = '/';
    253   driver_memcpy(inc + n + 1u, "include", 8u);
    254   driver_memcpy(lib, rt_root, n);
    255   lib[n] = '/';
    256   driver_memcpy(lib + n + 1u, "lib", 4u);
    257   return driver_path_exists(inc) && driver_path_exists(lib);
    258 }
    259 
    260 static int rt_set_layout(DriverEnv* env, DriverRuntimeSupport* out,
    261                          const char* support_root, const char* rt_root) {
    262   out->support_root = rt_dup(env, support_root, &out->support_root_size);
    263   out->rt_root = rt_dup(env, rt_root, &out->rt_root_size);
    264   out->include_dir = rt_join(env, rt_root, "include", &out->include_dir_size);
    265   if (!out->support_root || !out->rt_root || !out->include_dir) {
    266     driver_runtime_support_fini(env, out);
    267     return 1;
    268   }
    269   return 0;
    270 }
    271 
    272 static int rt_try_support_root(DriverEnv* env, const char* root,
    273                                DriverRuntimeSupport* out) {
    274   char* rt_root;
    275   size_t rt_root_size = 0;
    276   int ok;
    277 
    278   rt_root = rt_join(env, root, "rt", &rt_root_size);
    279   if (!rt_root) return 1;
    280   ok = rt_has_layout(rt_root) && rt_set_layout(env, out, root, rt_root) == 0;
    281   driver_free(env, rt_root, rt_root_size);
    282   return ok ? 0 : 1;
    283 }
    284 
    285 /* Directory-separator test for splitting a program path. On Windows the image
    286  * path (argv[0] / GetModuleFileNameW) uses '\\', so binary-relative rt
    287  * discovery must accept it as well as '/'; otherwise kit.exe never finds its
    288  * <bindir>/support/rt or <bindir>/../rt and falls back to the cwd-only ./rt. */
    289 static int rt_is_path_sep(char c) {
    290 #if defined(_WIN32)
    291   return c == '/' || c == '\\';
    292 #else
    293   return c == '/';
    294 #endif
    295 }
    296 
    297 static int rt_try_argv0_support(DriverEnv* env, const char* argv0,
    298                                 DriverRuntimeSupport* out) {
    299   const char* slash;
    300   size_t dir_len;
    301   char* dir;
    302   char* support;
    303   size_t dir_size;
    304   size_t support_size;
    305   int rc;
    306 
    307   if (!argv0) return 1;
    308   slash = argv0 + driver_strlen(argv0);
    309   while (slash > argv0 && !rt_is_path_sep(slash[-1])) --slash;
    310   if (slash == argv0) return 1;
    311   dir_len = (size_t)(slash - argv0);
    312   if (dir_len == 0) return 1;
    313 
    314   dir_size = dir_len + 1u;
    315   dir = (char*)driver_alloc(env, dir_size);
    316   if (!dir) return 1;
    317   driver_memcpy(dir, argv0, dir_len);
    318   dir[dir_len] = '\0';
    319 
    320   support = rt_join(env, dir, "support", &support_size);
    321   driver_free(env, dir, dir_size);
    322   if (!support) return 1;
    323   rc = rt_try_support_root(env, support, out);
    324   driver_free(env, support, support_size);
    325   return rc;
    326 }
    327 
    328 static int rt_try_argv0_checkout_root(DriverEnv* env, const char* argv0,
    329                                       DriverRuntimeSupport* out) {
    330   const char* slash;
    331   size_t dir_len;
    332   char* dir;
    333   char* parent;
    334   size_t dir_size;
    335   size_t parent_size;
    336   int rc;
    337 
    338   if (!argv0) return 1;
    339   slash = argv0 + driver_strlen(argv0);
    340   while (slash > argv0 && !rt_is_path_sep(slash[-1])) --slash;
    341   if (slash == argv0) return 1;
    342   dir_len = (size_t)(slash - argv0);
    343   if (dir_len == 0) return 1;
    344 
    345   dir_size = dir_len + 1u;
    346   dir = (char*)driver_alloc(env, dir_size);
    347   if (!dir) return 1;
    348   driver_memcpy(dir, argv0, dir_len);
    349   dir[dir_len] = '\0';
    350 
    351   parent = rt_join(env, dir, "..", &parent_size);
    352   driver_free(env, dir, dir_size);
    353   if (!parent) return 1;
    354   rc = rt_try_support_root(env, parent, out);
    355   driver_free(env, parent, parent_size);
    356   return rc;
    357 }
    358 
    359 int driver_runtime_resolve(DriverEnv* env, const char* explicit_support_dir,
    360                            const char* argv0, DriverRuntimeSupport* out) {
    361   int rc;
    362   DriverRuntimeSupport zero = {0};
    363   *out = zero;
    364 
    365   char* self = NULL;
    366   size_t self_size = 0;
    367   const char* tool = argv0;
    368 
    369   if (explicit_support_dir) {
    370     rc = rt_try_support_root(env, explicit_support_dir, out);
    371   } else if (rt_try_support_root(env, ".", out) == 0) {
    372     rc = 0;
    373   } else if (rt_try_argv0_checkout_root(env, argv0, out) == 0) {
    374     rc = 0;
    375   } else if (rt_try_argv0_support(env, argv0, out) == 0) {
    376     /* rt found as a <bindir>/support/rt sibling: this is a distribution
    377      * install, not a build tree.  Mark it so the on-demand rt archive lands
    378      * in the user cache dir rather than polluting the install. */
    379     rc = 0;
    380     out->install_layout = 1;
    381   } else if (driver_self_exe_path(env, &self, &self_size) == 0 && self) {
    382     /* argv[0] wasn't a usable path for binary-relative discovery — a bare
    383      * program name when kit is on PATH, a relative invocation, or a tool
    384      * symlink whose directory holds no rt. Retry against the real image path
    385      * (GetModuleFileNameW on Windows, /proc/self/exe on Linux, ...). */
    386     tool = self;
    387     if (rt_try_argv0_checkout_root(env, self, out) == 0) {
    388       rc = 0;
    389     } else if (rt_try_argv0_support(env, self, out) == 0) {
    390       rc = 0;
    391       out->install_layout = 1;
    392     } else {
    393       rc = 1;
    394     }
    395   } else {
    396     rc = 1;
    397   }
    398   /* Own the located image path: it outlives `self`'s free below and the
    399    * caller's argv, and is stat'd later for rt-archive cache invalidation. */
    400   if (rc == 0) out->tool_path = rt_dup(env, tool, &out->tool_path_size);
    401   if (self) driver_free(env, self, self_size);
    402   return rc;
    403 }
    404 
    405 void driver_runtime_support_fini(DriverEnv* env, DriverRuntimeSupport* s) {
    406   rt_free_str(env, &s->include_dir, &s->include_dir_size);
    407   rt_free_str(env, &s->rt_root, &s->rt_root_size);
    408   rt_free_str(env, &s->support_root, &s->support_root_size);
    409   if (s->tool_path && s->tool_path_size) {
    410     driver_free(env, (void*)s->tool_path, s->tool_path_size);
    411     s->tool_path = NULL;
    412     s->tool_path_size = 0;
    413   }
    414 }
    415 
    416 int driver_runtime_add_freestanding_headers(const DriverRuntimeSupport* s,
    417                                             DriverCflags* cf) {
    418   uint32_t i;
    419   if (!s || !s->include_dir || !cf) return 1;
    420   for (i = cf->nsystem_include_dirs; i > 0; --i)
    421     cf->system_include_dirs[i] = cf->system_include_dirs[i - 1u];
    422   cf->system_include_dirs[0] = s->include_dir;
    423   cf->nsystem_include_dirs++;
    424   return 0;
    425 }
    426 
    427 int driver_runtime_append_freestanding_headers(const DriverRuntimeSupport* s,
    428                                                DriverCflags* cf) {
    429   uint32_t i;
    430   if (!s || !s->include_dir || !cf) return 1;
    431   i = cf->nsystem_include_dirs;
    432   cf->system_include_dirs[i] = s->include_dir;
    433   cf->nsystem_include_dirs = i + 1u;
    434   return 0;
    435 }
    436 
    437 static const RuntimeVariant* rt_variant_for_target(KitTargetSpec target) {
    438   uint32_t i;
    439   for (i = 0; i < (uint32_t)(sizeof(kRtVariants) / sizeof(kRtVariants[0]));
    440        ++i) {
    441     const RuntimeVariant* v = &kRtVariants[i];
    442     /* A variant with float_abi DEFAULT is float-ABI-agnostic and matches any
    443      * target (every non-RISC-V variant and rv64). A variant that pins a float
    444      * ABI (the two rv32 entries) matches only that ABI, so ilp32 vs ilp32f
    445      * targets select distinct runtimes. */
    446     if (target.arch == v->arch && target.os == v->os && target.obj == v->obj &&
    447         target.ptr_size == v->ptr_size && target.ptr_align == v->ptr_align &&
    448         (v->float_abi == KIT_FLOAT_ABI_DEFAULT ||
    449          v->float_abi == target.float_abi))
    450       return v;
    451   }
    452   return NULL;
    453 }
    454 
    455 int driver_runtime_has_variant(KitTargetSpec target) {
    456   return rt_variant_for_target(target) != NULL;
    457 }
    458 
    459 static int rt_prepare_pp(DriverEnv* env, const DriverRuntimeSupport* support,
    460                          const RuntimeVariant* variant, int assembler,
    461                          KitPreprocessOptions* pp, char*** owned_dirs,
    462                          size_t** owned_sizes, uint32_t* owned_count) {
    463   static const KitSlice def_int128_1 = KIT_SLICE_LIT("1");
    464   static const KitSlice def_int128_0 = KIT_SLICE_LIT("0");
    465   char** dirs = NULL;
    466   size_t* sizes = NULL;
    467   const char** include_dirs;
    468   const char** system_dirs;
    469   KitDefine* defs;
    470   uint32_t ninc = variant->ldbl128 ? 4u : 3u;
    471   uint32_t nsys = 2u;
    472   uint32_t ndefs = 1u + (variant->ldbl128 ? 1u : 0u) + (assembler ? 1u : 0u);
    473   uint32_t d = 0;
    474   KitPreprocessOptions z = {0};
    475 
    476   *pp = z;
    477   *owned_dirs = NULL;
    478   *owned_sizes = NULL;
    479   *owned_count = 0;
    480 
    481   include_dirs = (const char**)driver_alloc_zeroed(
    482       env, (size_t)ninc * sizeof(*include_dirs));
    483   system_dirs = (const char**)driver_alloc_zeroed(
    484       env, (size_t)nsys * sizeof(*system_dirs));
    485   defs = (KitDefine*)driver_alloc_zeroed(env, (size_t)ndefs * sizeof(*defs));
    486   dirs =
    487       (char**)driver_alloc_zeroed(env, (size_t)(ninc + nsys) * sizeof(*dirs));
    488   sizes =
    489       (size_t*)driver_alloc_zeroed(env, (size_t)(ninc + nsys) * sizeof(*sizes));
    490   if (!include_dirs || !system_dirs || !defs || !dirs || !sizes) {
    491     if (include_dirs)
    492       driver_free(env, (void*)include_dirs,
    493                   (size_t)ninc * sizeof(*include_dirs));
    494     if (system_dirs)
    495       driver_free(env, (void*)system_dirs, (size_t)nsys * sizeof(*system_dirs));
    496     if (defs) driver_free(env, defs, (size_t)ndefs * sizeof(*defs));
    497     if (dirs) driver_free(env, dirs, (size_t)(ninc + nsys) * sizeof(*dirs));
    498     if (sizes) driver_free(env, sizes, (size_t)(ninc + nsys) * sizeof(*sizes));
    499     return 1;
    500   }
    501 
    502   rt_join_slot(env, &dirs[0], &sizes[0], support->rt_root,
    503                "lib/include/common");
    504   rt_store_const_ptr(&include_dirs[0], dirs[0]);
    505   rt_join_slot(env, &dirs[1], &sizes[1], support->rt_root, "lib/impl");
    506   rt_store_const_ptr(&include_dirs[1], dirs[1]);
    507   rt_join_slot(env, &dirs[2], &sizes[2], support->rt_root,
    508                variant->abi_include);
    509   rt_store_const_ptr(&include_dirs[2], dirs[2]);
    510   if (variant->ldbl128) {
    511     rt_join_slot(env, &dirs[3], &sizes[3], support->rt_root,
    512                  "lib/include/lp64_le_ldbl128");
    513     rt_store_const_ptr(&include_dirs[3], dirs[3]);
    514     rt_join_slot(env, &dirs[4], &sizes[4], support->rt_root, "include");
    515     rt_store_const_ptr(&system_dirs[0], dirs[4]);
    516     rt_join_slot(env, &dirs[5], &sizes[5], support->rt_root, "include/libc");
    517     rt_store_const_ptr(&system_dirs[1], dirs[5]);
    518     d = 6;
    519   } else {
    520     rt_join_slot(env, &dirs[3], &sizes[3], support->rt_root, "include");
    521     rt_store_const_ptr(&system_dirs[0], dirs[3]);
    522     rt_join_slot(env, &dirs[4], &sizes[4], support->rt_root, "include/libc");
    523     rt_store_const_ptr(&system_dirs[1], dirs[4]);
    524     d = 5;
    525   }
    526   for (uint32_t i = 0; i < d; ++i) {
    527     if (!dirs[i]) {
    528       uint32_t j;
    529       for (j = 0; j < d; ++j)
    530         if (dirs[j]) driver_free(env, dirs[j], sizes[j]);
    531       driver_free(env, (void*)include_dirs,
    532                   (size_t)ninc * sizeof(*include_dirs));
    533       driver_free(env, (void*)system_dirs, (size_t)nsys * sizeof(*system_dirs));
    534       driver_free(env, defs, (size_t)ndefs * sizeof(*defs));
    535       driver_free(env, dirs, (size_t)(ninc + nsys) * sizeof(*dirs));
    536       driver_free(env, sizes, (size_t)(ninc + nsys) * sizeof(*sizes));
    537       return 1;
    538     }
    539   }
    540 
    541   defs[0].name = KIT_SLICE_LIT("HAS_INT128");
    542   defs[0].body = variant->has_int128 ? def_int128_1 : def_int128_0;
    543   uint32_t i = 1;
    544   if (variant->ldbl128) {
    545     defs[i].name = KIT_SLICE_LIT("KITRT_LDBL128");
    546     defs[i].body = KIT_SLICE_LIT("1");
    547     ++i;
    548   }
    549   if (assembler) {
    550     defs[i].name = KIT_SLICE_LIT("__ASSEMBLER__");
    551     defs[i].body = KIT_SLICE_LIT("1");
    552   }
    553 
    554   pp->include_dirs = include_dirs;
    555   pp->ninclude_dirs = ninc;
    556   pp->system_include_dirs = system_dirs;
    557   pp->nsystem_include_dirs = nsys;
    558   pp->defines = defs;
    559   pp->ndefines = ndefs;
    560   *owned_dirs = dirs;
    561   *owned_sizes = sizes;
    562   *owned_count = d;
    563   return 0;
    564 }
    565 
    566 static void rt_free_pp(DriverEnv* env, KitPreprocessOptions* pp,
    567                        char** owned_dirs, size_t* owned_sizes,
    568                        uint32_t owned_count) {
    569   uint32_t i;
    570   for (i = 0; i < owned_count; ++i)
    571     if (owned_dirs[i]) driver_free(env, owned_dirs[i], owned_sizes[i]);
    572   if (owned_dirs)
    573     driver_free(env, owned_dirs, (size_t)owned_count * sizeof(*owned_dirs));
    574   if (owned_sizes)
    575     driver_free(env, owned_sizes, (size_t)owned_count * sizeof(*owned_sizes));
    576   if (pp->include_dirs)
    577     driver_free(env, (void*)pp->include_dirs,
    578                 (size_t)pp->ninclude_dirs * sizeof(*pp->include_dirs));
    579   if (pp->system_include_dirs)
    580     driver_free(
    581         env, (void*)pp->system_include_dirs,
    582         (size_t)pp->nsystem_include_dirs * sizeof(*pp->system_include_dirs));
    583   if (pp->defines)
    584     driver_free(env, (void*)pp->defines,
    585                 (size_t)pp->ndefines * sizeof(*pp->defines));
    586 }
    587 
    588 static int rt_compile_source(DriverEnv* env,
    589                              const DriverRuntimeSupport* support,
    590                              const RuntimeVariant* variant, const char* tool,
    591                              KitCompiler* compiler, const char* rel,
    592                              KitArInput* member, KitWriter** obj_writer) {
    593   KitContext ctx = driver_env_to_context(env);
    594   char* lib_path = NULL;
    595   char* src_path = NULL;
    596   size_t lib_path_size = 0;
    597   size_t src_path_size = 0;
    598   DriverLoad src_load = {0};
    599   KitSlice input = {0};
    600   KitWriter* writer = NULL;
    601   KitWriter* pp_writer = NULL;
    602   const uint8_t* obj_data;
    603   size_t obj_len = 0;
    604   KitStatus st;
    605   int is_asm;
    606   int preprocess_asm;
    607   int rc = 1;
    608 
    609   *obj_writer = NULL;
    610   lib_path = rt_join(env, support->rt_root, "lib", &lib_path_size);
    611   if (!lib_path) goto out;
    612   src_path = rt_join(env, lib_path, rel, &src_path_size);
    613   if (!src_path) goto out;
    614   if (driver_load_bytes(ctx.file_io, tool, src_path, &src_load, &input) != 0)
    615     goto out;
    616   if (kit_writer_mem(ctx.heap, &writer) != KIT_OK) goto out;
    617 
    618   is_asm = driver_has_suffix(rel, ".s") || driver_has_suffix(rel, ".S");
    619   preprocess_asm = driver_has_suffix(rel, ".S");
    620   if (is_asm) {
    621     KitAsmCompileOptions aopts = {0};
    622     KitSlice asm_input = input;
    623     if (preprocess_asm) {
    624       KitPreprocessOptions pp;
    625       char** owned_dirs = NULL;
    626       size_t* owned_sizes = NULL;
    627       uint32_t owned_count = 0;
    628       if (rt_prepare_pp(env, support, variant, 1, &pp, &owned_dirs,
    629                         &owned_sizes, &owned_count) != 0)
    630         goto out;
    631       if (kit_writer_mem(ctx.heap, &pp_writer) != KIT_OK) {
    632         rt_free_pp(env, &pp, owned_dirs, owned_sizes, owned_count);
    633         goto out;
    634       }
    635       st = kit_cpp_preprocess(compiler, &pp, kit_slice_cstr(src_path), &input,
    636                               pp_writer);
    637       rt_free_pp(env, &pp, owned_dirs, owned_sizes, owned_count);
    638       if (st != KIT_OK || kit_writer_status(pp_writer) != KIT_OK) goto out;
    639       asm_input.data = kit_writer_mem_bytes(pp_writer, &asm_input.len);
    640     }
    641     {
    642       KitCompileSessionOptions sopts;
    643       KitCompileSession* session = NULL;
    644       KitSourceInput sin;
    645       KitObjBuilder* ob = NULL;
    646       memset(&sopts, 0, sizeof(sopts));
    647       sopts.lang = KIT_LANG_ASM;
    648       sopts.compile.code = aopts.code;
    649       sopts.compile.diagnostics = aopts.diagnostics;
    650       sopts.compile.language_options = &aopts;
    651       memset(&sin, 0, sizeof(sin));
    652       sin.name = kit_slice_cstr(src_path);
    653       sin.bytes = asm_input;
    654       sin.lang = KIT_LANG_ASM;
    655       st = kit_compile_session_new(compiler, &sopts, &session);
    656       if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &ob);
    657       if (st == KIT_OK) st = kit_obj_builder_emit(ob, writer);
    658       kit_obj_builder_free(ob);
    659       kit_compile_session_free(session);
    660     }
    661   } else {
    662     KitCCompileOptions copts = {0};
    663     KitPreprocessOptions pp = {0};
    664     KitCompileSessionOptions sopts;
    665     KitCompileSession* session = NULL;
    666     KitSourceInput sin;
    667     KitObjBuilder* ob = NULL;
    668     char** owned_dirs = NULL;
    669     size_t* owned_sizes = NULL;
    670     uint32_t owned_count = 0;
    671     if (rt_prepare_pp(env, support, variant, 0, &pp, &owned_dirs, &owned_sizes,
    672                       &owned_count) != 0)
    673       goto out;
    674     memset(&sopts, 0, sizeof(sopts));
    675     sopts.lang = KIT_LANG_C;
    676     sopts.compile.code = copts.code;
    677     sopts.compile.diagnostics = copts.diagnostics;
    678     sopts.compile.preprocess = pp;
    679     memset(&sin, 0, sizeof(sin));
    680     sin.name = kit_slice_cstr(src_path);
    681     sin.bytes = input;
    682     sin.lang = KIT_LANG_C;
    683     st = kit_compile_session_new(compiler, &sopts, &session);
    684     if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &ob);
    685     if (st == KIT_OK) st = kit_obj_builder_emit(ob, writer);
    686     kit_obj_builder_free(ob);
    687     kit_compile_session_free(session);
    688     rt_free_pp(env, &pp, owned_dirs, owned_sizes, owned_count);
    689   }
    690   if (st != KIT_OK || kit_writer_status(writer) != KIT_OK) {
    691     driver_errf(tool, "failed to build runtime source: %.*s",
    692                 KIT_SLICE_ARG(kit_slice_cstr(src_path)));
    693     goto out;
    694   }
    695 
    696   obj_data = kit_writer_mem_bytes(writer, &obj_len);
    697   member->name = kit_slice_cstr(driver_basename(rel));
    698   member->bytes.data = obj_data;
    699   member->bytes.len = obj_len;
    700   *obj_writer = writer;
    701   writer = NULL;
    702   rc = 0;
    703 
    704 out:
    705   if (pp_writer) kit_writer_close(pp_writer);
    706   if (writer) kit_writer_close(writer);
    707   driver_release_bytes(ctx.file_io, &src_load);
    708   if (src_path) driver_free(env, src_path, src_path_size);
    709   if (lib_path) driver_free(env, lib_path, lib_path_size);
    710   return rc;
    711 }
    712 
    713 static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support,
    714                             const RuntimeVariant* variant, const char* tool,
    715                             uint64_t epoch, const char* archive_path) {
    716   KitContext ctx = driver_env_to_context(env);
    717   KitTarget* resolved_target = NULL;
    718   KitCompiler* compiler = NULL;
    719   KitWriter* archive_writer = NULL;
    720   KitArInput* members = NULL;
    721   KitWriter** obj_writers = NULL;
    722   KitArWriteOptions ar_opts = {0};
    723   KitTargetSpec target;
    724   uint32_t i;
    725   int rc = 1;
    726 
    727   members = (KitArInput*)driver_alloc_zeroed(
    728       env, (size_t)variant->nsources * sizeof(*members));
    729   obj_writers = (KitWriter**)driver_alloc_zeroed(
    730       env, (size_t)variant->nsources * sizeof(*obj_writers));
    731   if (!members || !obj_writers) {
    732     driver_errf(tool, "out of memory");
    733     goto out;
    734   }
    735 
    736   target.arch = variant->arch;
    737   target.os = variant->os;
    738   target.obj = variant->obj;
    739   target.ptr_size = variant->ptr_size;
    740   target.ptr_align = variant->ptr_align;
    741   target.big_endian = 0;
    742   target.pic = KIT_PIC_NONE;
    743   target.code_model = KIT_CM_DEFAULT;
    744   target.float_abi = KIT_FLOAT_ABI_DEFAULT; /* resolved from abi below */
    745 
    746   {
    747     KitTargetOptions topts;
    748     memset(&topts, 0, sizeof topts);
    749     topts.spec = target;
    750     /* Build the runtime with the variant's -march/-mabi. NULL leaves the arch
    751      * defaults (every non-rv32 variant); rv32 pins them so the soft ilp32 and
    752      * hard ilp32f archives are each compiled correctly, and kit_target_new
    753      * resolves spec.float_abi from the ABI string to match the call sites. */
    754     if (variant->isa) topts.isa = kit_slice_cstr(variant->isa);
    755     if (variant->abi) topts.abi = kit_slice_cstr(variant->abi);
    756     if (kit_target_new(&ctx, &topts, &resolved_target) != KIT_OK ||
    757         driver_compiler_new(resolved_target, &ctx, &compiler) != KIT_OK) {
    758       driver_errf(tool, "failed to initialize compiler for runtime");
    759       goto out;
    760     }
    761   }
    762 
    763   for (i = 0; i < variant->nsources; ++i) {
    764     if (rt_compile_source(env, support, variant, tool, compiler,
    765                           variant->sources[i], &members[i],
    766                           &obj_writers[i]) != 0)
    767       goto out;
    768   }
    769 
    770   if (ctx.file_io->open_writer(ctx.file_io->user, archive_path,
    771                                &archive_writer) != KIT_OK) {
    772     driver_errf(tool, "failed to open runtime archive: %.*s",
    773                 KIT_SLICE_ARG(kit_slice_cstr(archive_path)));
    774     goto out;
    775   }
    776 
    777   ar_opts.epoch = epoch;
    778   ar_opts.long_names = 1;
    779   if (kit_ar_write(archive_writer, members, variant->nsources, &ar_opts) !=
    780       KIT_OK) {
    781     driver_errf(tool, "failed to write runtime archive: %.*s",
    782                 KIT_SLICE_ARG(kit_slice_cstr(archive_path)));
    783     goto out;
    784   }
    785   rc = 0;
    786 
    787 out:
    788   if (archive_writer) kit_writer_close(archive_writer);
    789   if (compiler) driver_compiler_free(compiler);
    790   kit_target_free(resolved_target);
    791   if (obj_writers) {
    792     for (i = 0; i < variant->nsources; ++i)
    793       if (obj_writers[i]) kit_writer_close(obj_writers[i]);
    794     driver_free(env, obj_writers,
    795                 (size_t)variant->nsources * sizeof(*obj_writers));
    796   }
    797   if (members)
    798     driver_free(env, members, (size_t)variant->nsources * sizeof(*members));
    799   return rc;
    800 }
    801 
    802 static int rt_is_archive_stale(DriverEnv* env,
    803                                const DriverRuntimeSupport* support,
    804                                const RuntimeVariant* variant,
    805                                const char* archive_path) {
    806   int64_t archive_mtime;
    807   int64_t tool_mtime;
    808   uint32_t i;
    809   if (driver_path_mtime_ns(archive_path, &archive_mtime) != 0) return 1;
    810   if (support->tool_path &&
    811       driver_path_mtime_ns(support->tool_path, &tool_mtime) == 0 &&
    812       tool_mtime > archive_mtime)
    813     return 1;
    814   for (i = 0; i < variant->nsources; ++i) {
    815     char* lib_path;
    816     char* src_path;
    817     size_t lib_path_size = 0;
    818     size_t src_path_size = 0;
    819     int64_t src_mtime;
    820     int stale = 0;
    821     lib_path = rt_join(env, support->rt_root, "lib", &lib_path_size);
    822     if (!lib_path) return 1;
    823     src_path = rt_join(env, lib_path, variant->sources[i], &src_path_size);
    824     driver_free(env, lib_path, lib_path_size);
    825     if (!src_path) return 1;
    826     if (driver_path_mtime_ns(src_path, &src_mtime) != 0 ||
    827         src_mtime > archive_mtime)
    828       stale = 1;
    829     driver_free(env, src_path, src_path_size);
    830     if (stale) return 1;
    831   }
    832   return 0;
    833 }
    834 
    835 static char* rt_archive_dir_for_root(DriverEnv* env, const char* root,
    836                                      const RuntimeVariant* variant,
    837                                      size_t* out_size) {
    838   char* build_rt;
    839   char* dir = NULL;
    840   size_t build_rt_size = 0;
    841   size_t dir_size = 0;
    842   build_rt = rt_join(env, root, "build/rt", &build_rt_size);
    843   if (!build_rt) return NULL;
    844   dir = rt_join(env, build_rt, variant->key, &dir_size);
    845   driver_free(env, build_rt, build_rt_size);
    846   if (out_size) *out_size = dir ? dir_size : 0;
    847   return dir;
    848 }
    849 
    850 static int rt_archive_try_dir(DriverEnv* env, const char* tool,
    851                               const DriverRuntimeSupport* support,
    852                               const RuntimeVariant* variant, uint64_t epoch,
    853                               const char* cache_dir, char** out_path,
    854                               size_t* out_path_size) {
    855   char* archive_path;
    856   size_t archive_path_size = 0;
    857 
    858   archive_path = rt_join(env, cache_dir, "libkit_rt.a", &archive_path_size);
    859   if (!archive_path) {
    860     driver_errf(tool, "out of memory");
    861     return 1;
    862   }
    863 
    864   if (!driver_path_exists(archive_path) ||
    865       rt_is_archive_stale(env, support, variant, archive_path)) {
    866     if (driver_mkdir_p(env, cache_dir) != 0) {
    867       driver_free(env, archive_path, archive_path_size);
    868       return 2;
    869     }
    870     if (rt_build_archive(env, support, variant, tool, epoch, archive_path) !=
    871         0) {
    872       driver_errf(tool, "compiler runtime for %.*s could not be built",
    873                   KIT_SLICE_ARG(kit_slice_cstr(variant->key)));
    874       driver_errf(tool, "support dir: %.*s",
    875                   KIT_SLICE_ARG(kit_slice_cstr(support->support_root)));
    876       driver_free(env, archive_path, archive_path_size);
    877       return 1;
    878     }
    879   }
    880 
    881   *out_path = archive_path;
    882   *out_path_size = archive_path_size;
    883   return 0;
    884 }
    885 
    886 int driver_runtime_ensure_archive(DriverEnv* env, const char* tool,
    887                                   const DriverRuntimeSupport* support,
    888                                   KitTargetSpec target, uint64_t epoch,
    889                                   char** out_path, size_t* out_path_size) {
    890   const RuntimeVariant* variant = rt_variant_for_target(target);
    891   const char* diag_tool = tool ? tool : "rt";
    892   char* in_tree_dir = NULL; /* <support_root>/build/rt/<variant> */
    893   char* cache_dir = NULL;   /* <env->cache_dir>/<variant>        */
    894   size_t in_tree_dir_size = 0;
    895   size_t cache_dir_size = 0;
    896   char* primary_dir;
    897   char* fallback_dir;
    898   int primary_rc;
    899   int fallback_rc = 1;
    900 
    901   *out_path = NULL;
    902   *out_path_size = 0;
    903 
    904   if (!variant) {
    905     driver_errf(diag_tool, "compiler runtime is not available for this target");
    906     return 1;
    907   }
    908 
    909   /* In-tree location, shared with `make rt` when support_root is a checkout. */
    910   in_tree_dir = rt_archive_dir_for_root(env, support->support_root, variant,
    911                                         &in_tree_dir_size);
    912   if (!in_tree_dir) {
    913     driver_errf(diag_tool, "out of memory");
    914     return 1;
    915   }
    916   /* User cache location, outside any support/install tree. */
    917   if (env->cache_dir) {
    918     cache_dir = rt_join(env, env->cache_dir, variant->key, &cache_dir_size);
    919     if (!cache_dir) {
    920       driver_free(env, in_tree_dir, in_tree_dir_size);
    921       driver_errf(diag_tool, "out of memory");
    922       return 1;
    923     }
    924   }
    925 
    926   /* A distribution install is not a build tree: prefer the user cache dir and
    927    * keep the in-tree dir only as a fallback so the build never writes into the
    928    * install.  A checkout (or explicit --support-dir) keeps the historical
    929    * in-tree-first order, sharing `make rt`'s build/rt cache per checkout. */
    930   if (support->install_layout && cache_dir) {
    931     primary_dir = cache_dir;
    932     fallback_dir = in_tree_dir;
    933   } else {
    934     primary_dir = in_tree_dir;
    935     fallback_dir = cache_dir;
    936   }
    937 
    938   primary_rc = rt_archive_try_dir(env, diag_tool, support, variant, epoch,
    939                                   primary_dir, out_path, out_path_size);
    940   if (primary_rc == 0) {
    941     if (cache_dir) driver_free(env, cache_dir, cache_dir_size);
    942     driver_free(env, in_tree_dir, in_tree_dir_size);
    943     return 0;
    944   }
    945 
    946   if (primary_rc != 2) {
    947     if (cache_dir) driver_free(env, cache_dir, cache_dir_size);
    948     driver_free(env, in_tree_dir, in_tree_dir_size);
    949     return 1;
    950   }
    951 
    952   if (fallback_dir) {
    953     fallback_rc = rt_archive_try_dir(env, diag_tool, support, variant, epoch,
    954                                      fallback_dir, out_path, out_path_size);
    955   }
    956 
    957   if (fallback_rc == 2 || !fallback_dir) {
    958     driver_errf(diag_tool, "failed to create runtime cache: %.*s",
    959                 KIT_SLICE_ARG(kit_slice_cstr(primary_dir)));
    960     if (fallback_dir) {
    961       driver_errf(diag_tool, "failed to create runtime cache: %.*s",
    962                   KIT_SLICE_ARG(kit_slice_cstr(fallback_dir)));
    963     }
    964   }
    965   if (cache_dir) driver_free(env, cache_dir, cache_dir_size);
    966   driver_free(env, in_tree_dir, in_tree_dir_size);
    967   return fallback_rc == 0 ? 0 : 1;
    968 }
    969 
    970 int driver_runtime_prepare_archive(DriverEnv* env, const char* tool,
    971                                    const DriverRuntimeSupport* support,
    972                                    KitTargetSpec target, uint64_t epoch,
    973                                    DriverRuntimeArchive* out) {
    974   DriverRuntimeArchive z = {0};
    975   if (!out) return 1;
    976   *out = z;
    977   if (driver_runtime_ensure_archive(env, tool, support, target, epoch,
    978                                     &out->path, &out->path_size) != 0)
    979     return 1;
    980   out->whole_archive = 0;
    981   out->link_mode = KIT_LM_STATIC;
    982   out->group_id = 0;
    983   return 0;
    984 }
    985 
    986 void driver_runtime_archive_fini(DriverEnv* env, DriverRuntimeArchive* a) {
    987   if (!a) return;
    988   if (a->path) driver_free(env, a->path, a->path_size);
    989   a->path = NULL;
    990   a->path_size = 0;
    991   a->whole_archive = 0;
    992   a->link_mode = 0;
    993   a->group_id = 0;
    994 }