kit

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

build.c (84376B)


      1 #include <kit/compile.h>
      2 #include <kit/core.h>
      3 #include <kit/link.h>
      4 #include <kit/preprocess.h>
      5 #include <stdint.h>
      6 #include <string.h>
      7 
      8 #include "archive_engine.h"
      9 #include "cflags.h"
     10 #include "compile_engine.h"
     11 #include "driver.h"
     12 #include "hosted.h"
     13 #include "lib_resolve.h"
     14 #include "link_engine.h"
     15 #include "link_flags.h"
     16 #include "runtime.h"
     17 
     18 /* `kit build-exe` / `build-lib` / `build-obj` — the kit-native build verbs.
     19  *
     20  * Each command is polyglot (C / asm / toy / wasm resolved per file), compiles
     21  * entirely in memory, and writes no intermediate files. They share one
     22  * parse+run parameterized by output kind:
     23  *
     24  *   build-exe   link an executable           (link session, OUTPUT_EXE)
     25  *   build-lib   static .a                    (archive of compiled objects;
     26  *                                             dynamic/shared not yet supported)
     27  *   build-obj   one object; or a relocatable  (compile each source / link
     28  *               combine of N sources; or       session, OUTPUT_RELOCATABLE)
     29  *               --emit=asm|c|ir; -fsyntax-only
     30  *
     31  * build-obj fully replaces the retired `compile` tool. Two flag tiers:
     32  *   - global / per-output flags apply to the whole build (target, -O/-g, link
     33  *     flags, output flags); they may appear anywhere outside a --group.
     34  *   - scopable flags (-I/-isystem/-D/-U, -x, -X<lang>) form a global baseline
     35  *     and may be overridden inside a `--group [flags] -- sources...` block.
     36  *
     37  * Per-language frontend flags route through `-X<lang> FLAG` (e.g.
     38  * `-Xwasm -mfeature=simd128`). */
     39 
     40 /* Stand-in for "no -x; resolve language from the path suffix at compile time."
     41  */
     42 #define BUILD_LANG_AUTO ((KitLanguage)KIT_LANG_COUNT)
     43 
     44 typedef enum BuildOutputKind {
     45   BUILD_OUT_EXE,
     46   BUILD_OUT_LIB,
     47   BUILD_OUT_OBJ,
     48 } BuildOutputKind;
     49 
     50 typedef enum BuildEmit {
     51   BUILD_EMIT_OBJ = 0,
     52   BUILD_EMIT_ASM,
     53   BUILD_EMIT_C,
     54   BUILD_EMIT_IR,
     55 } BuildEmit;
     56 
     57 typedef enum BuildLinkKind {
     58   BUILD_LINK_SOURCE,
     59   BUILD_LINK_OBJECT,
     60   BUILD_LINK_ARCHIVE,
     61   BUILD_LINK_DSO,
     62   BUILD_LINK_LIB,
     63 } BuildLinkKind;
     64 
     65 typedef struct BuildLinkItem {
     66   uint8_t kind; /* BuildLinkKind */
     67   uint8_t pad[3];
     68   uint32_t index;
     69 } BuildLinkItem;
     70 
     71 typedef struct BuildSource {
     72   const char* path; /* argv-borrowed */
     73   uint32_t group;   /* index into o->groups[]; 0 = global/bare baseline */
     74 } BuildSource;
     75 
     76 typedef struct BuildArchiveInput {
     77   const char* path;
     78   int owned;
     79   size_t owned_size;
     80   uint8_t whole_archive;
     81   uint8_t link_mode;
     82   uint8_t group_id;
     83   uint8_t pad;
     84 } BuildArchiveInput;
     85 
     86 typedef struct BuildDsoInput {
     87   const char* path;
     88   int owned;
     89   size_t owned_size;
     90 } BuildDsoInput;
     91 
     92 typedef struct BuildPendingLib {
     93   const char* name;
     94   uint8_t whole_archive;
     95   uint8_t link_mode;
     96   uint8_t group_id;
     97   uint8_t resolved_kind; /* BuildLinkKind: ARCHIVE or DSO */
     98   uint32_t resolved_index;
     99 } BuildPendingLib;
    100 
    101 /* One -X<lang> frontend flag token, scoped to a language. */
    102 typedef struct BuildFeFlag {
    103   uint8_t lang; /* KitLanguage */
    104   uint8_t pad[3];
    105   char* tok; /* argv-borrowed */
    106 } BuildFeFlag;
    107 
    108 /* A compile-flag scope: the global baseline (groups[0]) plus one entry per
    109  * `--group`. Each carries its own preprocessor delta, language override, and
    110  * per-language frontend flags. */
    111 typedef struct BuildGroup {
    112   DriverCflags cf;
    113   int cf_inited;
    114   KitLanguage forced_lang; /* BUILD_LANG_AUTO if -x not set */
    115   BuildFeFlag* fe;
    116   uint32_t nfe;
    117   /* Merged preprocessor view (group delta over the global baseline), filled
    118    * after parsing. For groups[0] this borrows cf directly; for real groups it
    119    * points at the m_* arrays below. */
    120   KitPreprocessOptions pp;
    121   const char** m_inc;
    122   uint32_t m_ninc;
    123   const char** m_sys;
    124   uint32_t m_nsys;
    125   KitDefine* m_def;
    126   uint32_t m_ndef;
    127   uint32_t
    128       m_def_cap; /* allocation size; m_ndef <= cap once globals are shadowed */
    129   KitSlice* m_und;
    130   uint32_t m_nund;
    131 } BuildGroup;
    132 
    133 typedef struct BuildOptions {
    134   DriverEnv* env;
    135   const char* tool;        /* "build-exe" | "build-lib" | "build-obj" */
    136   int kind;                /* BuildOutputKind */
    137   const char* driver_path; /* argv[0] */
    138   size_t argv_bound;
    139 
    140   /* Output / per-output state. */
    141   int emit; /* BuildEmit (build-obj) */
    142   int syntax_only;
    143   int opt_level;
    144   int debug_info;
    145   int dynamic;                /* -dynamic / -shared */
    146   int shared_requested;       /* -shared spelling, for build-exe diagnostics */
    147   int shared;                 /* computed: kind==lib && dynamic */
    148   int static_link;            /* -static */
    149   int pie;                    /* -pie */
    150   int function_sections;      /* -ffunction-sections */
    151   int data_sections;          /* -fdata-sections */
    152   int lto;                    /* -flto/-fno-lto */
    153   uint8_t default_visibility; /* KitSymVis */
    154   int warnings_are_errors;
    155   uint32_t max_errors;
    156   const char* output_path;
    157 
    158   KitTargetSpec target;
    159   DriverTargetFeatures target_features;
    160 
    161   /* Link-session options and owned -Wl state. */
    162   DriverLinkFlags link;
    163   uint64_t epoch;
    164 
    165   /* Hosted libc / sysroot state. */
    166   const char* sysroot;
    167   const char* support_dir;
    168   int freestanding;
    169   int nostdinc;
    170   int no_stdlib;
    171   int no_defaultlibs;
    172   int no_startfiles;
    173   int wants_hosted_libc;
    174   DriverHostedPlan hosted;
    175   char* owned_sysroot_lib_dir;
    176   size_t owned_sysroot_lib_dir_size;
    177 
    178   /* Sources + compile-flag scopes. */
    179   BuildSource* sources;
    180   uint32_t nsources;
    181   BuildGroup* groups;
    182   uint32_t ngroups;
    183   uint32_t cur_group; /* scope for newly seen sources */
    184 
    185   /* Link inputs (build-exe). */
    186   const char** object_files;
    187   uint32_t nobject_files;
    188   BuildArchiveInput* archives;
    189   uint32_t narchives;
    190   BuildDsoInput* dsos;
    191   uint32_t ndsos;
    192   const char** lib_search_paths;
    193   uint32_t nlib_search_paths;
    194   BuildPendingLib* pending_libs;
    195   uint32_t npending_libs;
    196   BuildLinkItem* link_items;
    197   uint32_t nlink_items;
    198   uint8_t cur_whole_archive;
    199   uint8_t cur_link_mode;
    200   uint8_t cur_group_id;
    201 } BuildOptions;
    202 
    203 /* ===================================================================== */
    204 /* small parse helpers                                                    */
    205 /* ===================================================================== */
    206 
    207 static int build_parse_u64(const char* s, uint64_t* out) {
    208   uint64_t v = 0;
    209   int any = 0;
    210   if (!s) return 1;
    211   while (*s) {
    212     unsigned d;
    213     if (*s < '0' || *s > '9') return 1;
    214     d = (unsigned)(*s - '0');
    215     if (v > (UINT64_MAX - d) / 10u) return 1;
    216     v = v * 10u + d;
    217     any = 1;
    218     s++;
    219   }
    220   if (!any) return 1;
    221   *out = v;
    222   return 0;
    223 }
    224 
    225 static int build_record_mcmodel(BuildOptions* o, const char* val) {
    226   if (driver_streq(val, "small") || driver_streq(val, "medlow")) {
    227     o->target.code_model = KIT_CM_SMALL;
    228     return 0;
    229   }
    230   if (driver_streq(val, "medium") || driver_streq(val, "medany")) {
    231     o->target.code_model = KIT_CM_MEDIUM;
    232     return 0;
    233   }
    234   if (driver_streq(val, "large")) {
    235     o->target.code_model = KIT_CM_LARGE;
    236     return 0;
    237   }
    238   driver_errf(o->tool, "unknown -mcmodel value: %.*s",
    239               KIT_SLICE_ARG(kit_slice_cstr(val)));
    240   return 1;
    241 }
    242 
    243 static int build_lang_from_name(const char* name, KitLanguage* out) {
    244   /* Resolve off the compile-time default frontend set (no compiler exists at
    245    * arg-parse time). Value-equivalent to the former explicit map:
    246    * c->C, asm/s->ASM, toy->TOY, wasm/wat->WASM. */
    247   KitLanguage lang = kit_language_for_name(NULL, name);
    248   if (lang == KIT_LANG_UNKNOWN) return 1;
    249   *out = lang;
    250   return 0;
    251 }
    252 
    253 /* ===================================================================== */
    254 /* allocation / lifetime                                                  */
    255 /* ===================================================================== */
    256 
    257 static int build_group_cf_init(BuildOptions* o, BuildGroup* g) {
    258   if (g->cf_inited) return 0;
    259   if (driver_cflags_init(&g->cf, o->env,
    260                          (int)(o->argv_bound + DRIVER_HOSTED_MAX_DEFINES +
    261                                DRIVER_HOSTED_MAX_INCLUDES)) != 0)
    262     return 1;
    263   g->cf_inited = 1;
    264   g->forced_lang = BUILD_LANG_AUTO;
    265   g->fe = driver_alloc_zeroed(o->env, o->argv_bound * sizeof(*g->fe));
    266   return g->fe ? 0 : 1;
    267 }
    268 
    269 static int build_alloc(BuildOptions* o, int argc) {
    270   size_t bound = (size_t)argc + 16u;
    271   o->argv_bound = bound;
    272   o->sources = driver_alloc_zeroed(o->env, bound * sizeof(*o->sources));
    273   o->groups = driver_alloc_zeroed(o->env, bound * sizeof(*o->groups));
    274   o->object_files =
    275       driver_alloc_zeroed(o->env, bound * sizeof(*o->object_files));
    276   o->archives = driver_alloc_zeroed(o->env, bound * sizeof(*o->archives));
    277   o->dsos = driver_alloc_zeroed(o->env, bound * sizeof(*o->dsos));
    278   o->lib_search_paths =
    279       driver_alloc_zeroed(o->env, bound * sizeof(*o->lib_search_paths));
    280   o->pending_libs =
    281       driver_alloc_zeroed(o->env, bound * sizeof(*o->pending_libs));
    282   o->link_items = driver_alloc_zeroed(o->env, bound * sizeof(*o->link_items));
    283   if (!o->sources || !o->groups || !o->object_files || !o->archives ||
    284       !o->dsos || !o->lib_search_paths || !o->pending_libs || !o->link_items) {
    285     driver_errf(o->tool, "out of memory");
    286     return 1;
    287   }
    288   o->cur_link_mode = KIT_LM_DEFAULT;
    289   /* groups[0] is the global / bare baseline. */
    290   o->ngroups = 1;
    291   if (driver_link_flags_init(&o->link, o->env, o->tool, (uint32_t)bound) != 0 ||
    292       build_group_cf_init(o, &o->groups[0]) != 0 ||
    293       driver_target_features_init(&o->target_features, o->env, argc) != 0) {
    294     driver_errf(o->tool, "out of memory");
    295     return 1;
    296   }
    297   return 0;
    298 }
    299 
    300 static void build_release(BuildOptions* o) {
    301   uint32_t i;
    302   size_t bound = o->argv_bound;
    303   for (i = 0; i < o->narchives; ++i)
    304     if (o->archives[i].owned)
    305       driver_free(o->env, (void*)o->archives[i].path,
    306                   o->archives[i].owned_size);
    307   for (i = 0; i < o->ndsos; ++i)
    308     if (o->dsos[i].owned)
    309       driver_free(o->env, (void*)o->dsos[i].path, o->dsos[i].owned_size);
    310   for (i = 0; i < o->ngroups; ++i) {
    311     BuildGroup* g = &o->groups[i];
    312     if (g->cf_inited) driver_cflags_fini(&g->cf, o->env);
    313     if (g->fe) driver_free(o->env, g->fe, bound * sizeof(*g->fe));
    314     if (g->m_inc) driver_free(o->env, g->m_inc, g->m_ninc * sizeof(*g->m_inc));
    315     if (g->m_sys) driver_free(o->env, g->m_sys, g->m_nsys * sizeof(*g->m_sys));
    316     if (g->m_def)
    317       driver_free(o->env, g->m_def, g->m_def_cap * sizeof(*g->m_def));
    318     if (g->m_und) driver_free(o->env, g->m_und, g->m_nund * sizeof(*g->m_und));
    319   }
    320   if (o->owned_sysroot_lib_dir)
    321     driver_free(o->env, o->owned_sysroot_lib_dir,
    322                 o->owned_sysroot_lib_dir_size);
    323   driver_hosted_plan_fini(o->env, &o->hosted);
    324   driver_link_flags_fini(&o->link);
    325   driver_target_features_fini(&o->target_features, o->env);
    326   if (o->sources) driver_free(o->env, o->sources, bound * sizeof(*o->sources));
    327   if (o->groups) driver_free(o->env, o->groups, bound * sizeof(*o->groups));
    328   if (o->object_files)
    329     driver_free(o->env, o->object_files, bound * sizeof(*o->object_files));
    330   if (o->archives)
    331     driver_free(o->env, o->archives, bound * sizeof(*o->archives));
    332   if (o->dsos) driver_free(o->env, o->dsos, bound * sizeof(*o->dsos));
    333   if (o->lib_search_paths)
    334     driver_free(o->env, o->lib_search_paths,
    335                 bound * sizeof(*o->lib_search_paths));
    336   if (o->pending_libs)
    337     driver_free(o->env, o->pending_libs, bound * sizeof(*o->pending_libs));
    338   if (o->link_items)
    339     driver_free(o->env, o->link_items, bound * sizeof(*o->link_items));
    340 }
    341 
    342 /* ===================================================================== */
    343 /* link-item bookkeeping (build-exe)                                      */
    344 /* ===================================================================== */
    345 
    346 static void build_push_link_item(BuildOptions* o, uint8_t kind,
    347                                  uint32_t index) {
    348   BuildLinkItem* it = &o->link_items[o->nlink_items++];
    349   it->kind = kind;
    350   it->index = index;
    351 }
    352 
    353 static void build_insert_link_item(BuildOptions* o, uint32_t pos, uint8_t kind,
    354                                    uint32_t index) {
    355   uint32_t i;
    356   if (pos > o->nlink_items) pos = o->nlink_items;
    357   for (i = o->nlink_items; i > pos; --i)
    358     o->link_items[i] = o->link_items[i - 1u];
    359   o->link_items[pos].kind = kind;
    360   o->link_items[pos].index = index;
    361   o->nlink_items++;
    362 }
    363 
    364 static int build_append_hosted_input(BuildOptions* o,
    365                                      const DriverHostedInput* in,
    366                                      uint32_t insert_pos, int insert) {
    367   uint32_t index;
    368   uint8_t kind;
    369   switch ((DriverHostedInputKind)in->kind) {
    370     case DRIVER_HOSTED_INPUT_OBJECT:
    371       index = o->nobject_files++;
    372       o->object_files[index] = in->path;
    373       kind = BUILD_LINK_OBJECT;
    374       break;
    375     case DRIVER_HOSTED_INPUT_ARCHIVE: {
    376       BuildArchiveInput* ar = &o->archives[o->narchives++];
    377       ar->path = in->path;
    378       ar->link_mode = KIT_LM_DEFAULT;
    379       index = o->narchives - 1u;
    380       kind = BUILD_LINK_ARCHIVE;
    381       break;
    382     }
    383     case DRIVER_HOSTED_INPUT_DSO: {
    384       BuildDsoInput* d = &o->dsos[o->ndsos++];
    385       d->path = in->path;
    386       index = o->ndsos - 1u;
    387       kind = BUILD_LINK_DSO;
    388       break;
    389     }
    390     default:
    391       driver_errf(o->tool, "internal error: unknown hosted input kind");
    392       return 1;
    393   }
    394   if (insert)
    395     build_insert_link_item(o, insert_pos, kind, index);
    396   else
    397     build_push_link_item(o, kind, index);
    398   return 0;
    399 }
    400 
    401 static void build_insert_runtime_archive(BuildOptions* o,
    402                                          DriverRuntimeArchive* rt,
    403                                          uint32_t insert_pos) {
    404   BuildArchiveInput* ar = &o->archives[o->narchives++];
    405   ar->path = rt->path;
    406   ar->owned = 1;
    407   ar->owned_size = rt->path_size;
    408   ar->whole_archive = rt->whole_archive;
    409   ar->link_mode = rt->link_mode;
    410   ar->group_id = rt->group_id;
    411   rt->path = NULL;
    412   rt->path_size = 0;
    413   build_insert_link_item(o, insert_pos, BUILD_LINK_ARCHIVE, o->narchives - 1u);
    414 }
    415 
    416 /* ===================================================================== */
    417 /* positional classification                                              */
    418 /* ===================================================================== */
    419 
    420 /* Routed through the shared driver_path_is_source authority (canonical
    421  * extension registry, headers excluded), so adding a frontend extension reaches
    422  * cc/build/run/dbg at once. build still treats .h as a header, not a source —
    423  * the helper excludes it. */
    424 static int build_is_source(const char* s) { return driver_path_is_source(s); }
    425 
    426 static int build_is_dso(const char* s) {
    427   return driver_has_suffix(s, ".so") || driver_has_suffix(s, ".dylib") ||
    428          driver_has_suffix(s, ".tbd");
    429 }
    430 
    431 /* The language forced (via -x) for sources in group `gi`: the group's own -x,
    432  * else the global baseline's, else -1 (resolve by suffix). */
    433 static int build_scope_forced_lang(const BuildOptions* o, uint32_t gi) {
    434   if (gi != 0 && o->groups[gi].forced_lang != BUILD_LANG_AUTO)
    435     return (int)o->groups[gi].forced_lang;
    436   if (o->groups[0].forced_lang != BUILD_LANG_AUTO)
    437     return (int)o->groups[0].forced_lang;
    438   return -1;
    439 }
    440 
    441 static int build_classify_positional(BuildOptions* o, const char* a) {
    442   if (driver_streq(a, "-")) {
    443     driver_errf(o->tool, "stdin ('-') is not supported; pass a source file");
    444     return 1;
    445   }
    446   /* Explicit link-input suffixes are always link inputs — never reinterpreted
    447    * as sources, even when -x forces a language. */
    448   if (driver_has_suffix(a, ".o") || driver_has_suffix(a, ".obj")) {
    449     o->object_files[o->nobject_files++] = a;
    450     build_push_link_item(o, BUILD_LINK_OBJECT, o->nobject_files - 1u);
    451     return 0;
    452   }
    453   if (driver_has_suffix(a, ".a")) {
    454     BuildArchiveInput* ar = &o->archives[o->narchives++];
    455     ar->path = a;
    456     ar->whole_archive = o->cur_whole_archive;
    457     ar->link_mode = o->cur_link_mode;
    458     ar->group_id = o->cur_group_id;
    459     build_push_link_item(o, BUILD_LINK_ARCHIVE, o->narchives - 1u);
    460     return 0;
    461   }
    462   if (build_is_dso(a)) {
    463     BuildDsoInput* d = &o->dsos[o->ndsos++];
    464     d->path = a;
    465     build_push_link_item(o, BUILD_LINK_DSO, o->ndsos - 1u);
    466     return 0;
    467   }
    468   /* Otherwise a source: a recognized source suffix, or any file at all when a
    469    * language is forced in scope (so `-x toy mykernel` compiles an extensionless
    470    * or odd-suffix file). */
    471   if (build_is_source(a) || build_scope_forced_lang(o, o->cur_group) >= 0) {
    472     BuildSource* s = &o->sources[o->nsources];
    473     s->path = a;
    474     s->group = o->cur_group;
    475     build_push_link_item(o, BUILD_LINK_SOURCE, o->nsources);
    476     o->nsources++;
    477     return 0;
    478   }
    479   driver_errf(o->tool,
    480               "input does not have a recognized suffix: %.*s (use -x LANG)",
    481               KIT_SLICE_ARG(kit_slice_cstr(a)));
    482   return 1;
    483 }
    484 
    485 /* ===================================================================== */
    486 /* scopable-flag parsing (shared by global context and --group blocks)    */
    487 /* ===================================================================== */
    488 
    489 /* Try to consume a scopable flag (-I/-isystem/-D/-U, -x, -X<lang>) at argv[*i]
    490  * into group `g`. Returns 1 consumed, 0 not a scopable flag, -1 on error. */
    491 static int build_try_scopable(BuildOptions* o, BuildGroup* g, int argc,
    492                               char** argv, int* i) {
    493   const char* a = argv[*i];
    494   int r = driver_cflags_try_consume(&g->cf, o->env, o->tool, argc, argv, i);
    495   if (r != 0) return r;
    496 
    497   if (driver_streq(a, "-x")) {
    498     KitLanguage lang;
    499     if (++(*i) >= argc) {
    500       driver_errf(o->tool, "-x requires an argument");
    501       return -1;
    502     }
    503     if (driver_streq(argv[*i], "--")) {
    504       driver_errf(o->tool, "-x requires an argument before `--`");
    505       return -1;
    506     }
    507     if (build_lang_from_name(argv[*i], &lang) != 0) {
    508       driver_errf(o->tool, "unsupported -x language: %.*s",
    509                   KIT_SLICE_ARG(kit_slice_cstr(argv[*i])));
    510       return -1;
    511     }
    512     g->forced_lang = lang;
    513     return 1;
    514   }
    515   if (driver_strneq(a, "-X", 2) && a[2] != '\0') {
    516     KitLanguage lang;
    517     BuildFeFlag* f;
    518     if (build_lang_from_name(a + 2, &lang) != 0) {
    519       driver_errf(o->tool, "unsupported -X language: %.*s (use c|asm|toy|wasm)",
    520                   KIT_SLICE_ARG(kit_slice_cstr(a + 2)));
    521       return -1;
    522     }
    523     if (++(*i) >= argc) {
    524       driver_errf(o->tool, "%.*s requires a following flag",
    525                   KIT_SLICE_ARG(kit_slice_cstr(a)));
    526       return -1;
    527     }
    528     if (driver_streq(argv[*i], "--")) {
    529       driver_errf(o->tool, "%.*s requires a following flag before `--`",
    530                   KIT_SLICE_ARG(kit_slice_cstr(a)));
    531       return -1;
    532     }
    533     f = &g->fe[g->nfe++];
    534     f->lang = (uint8_t)lang;
    535     f->tok = argv[*i];
    536     return 1;
    537   }
    538   return 0;
    539 }
    540 
    541 /* Recognize the global / per-output flags, so a --group block can flag them as
    542  * misplaced with a pointed diagnostic. */
    543 static int build_is_global_flag(const char* a) {
    544   return driver_streq(a, "-o") || driver_strneq(a, "--output", 8) ||
    545          driver_strneq(a, "-O", 2) || driver_streq(a, "-g") ||
    546          driver_streq(a, "-S") || driver_strneq(a, "--emit=", 7) ||
    547          driver_streq(a, "-fsyntax-only") || driver_strneq(a, "-fPIC", 5) ||
    548          driver_strneq(a, "-fpic", 5) || driver_strneq(a, "-fPIE", 5) ||
    549          driver_strneq(a, "-fpie", 5) ||
    550          driver_strneq(a, "-fvisibility=", 13) ||
    551          driver_streq(a, "-ffunction-sections") ||
    552          driver_streq(a, "-fdata-sections") || driver_streq(a, "-flto") ||
    553          driver_streq(a, "-fno-lto") || driver_streq(a, "-static") ||
    554          driver_streq(a, "-dynamic") || driver_streq(a, "-shared") ||
    555          driver_streq(a, "-pie") || driver_streq(a, "-no-pie") ||
    556          driver_streq(a, "-target") || driver_strneq(a, "--target", 8) ||
    557          driver_strneq(a, "-l", 2) || driver_strneq(a, "-L", 2) ||
    558          driver_streq(a, "-e") || driver_streq(a, "-T") ||
    559          driver_strneq(a, "-Wl,", 4) || driver_strneq(a, "--build-id", 10) ||
    560          driver_streq(a, "-Werror") || driver_strneq(a, "-fmax-errors=", 13) ||
    561          driver_strneq(a, "-m", 2);
    562 }
    563 
    564 /* ===================================================================== */
    565 /* main parser                                                            */
    566 /* ===================================================================== */
    567 
    568 static int build_parse_group(BuildOptions* o, int argc, char** argv, int* i) {
    569   BuildGroup* g;
    570   uint32_t gid = o->ngroups++;
    571   g = &o->groups[gid];
    572   if (build_group_cf_init(o, g) != 0) {
    573     driver_errf(o->tool, "out of memory");
    574     return 1;
    575   }
    576   ++(*i); /* past --group */
    577   /* scopable flag section, terminated by `--` */
    578   for (; *i < argc && !driver_streq(argv[*i], "--"); ++(*i)) {
    579     int r = build_try_scopable(o, g, argc, argv, i);
    580     if (r < 0) return 1;
    581     if (r > 0) continue;
    582     if (build_is_global_flag(argv[*i])) {
    583       driver_errf(o->tool,
    584                   "%.*s is a per-output flag; place it before any --group",
    585                   KIT_SLICE_ARG(kit_slice_cstr(argv[*i])));
    586       return 1;
    587     }
    588     driver_errf(o->tool, "unsupported flag in --group: %.*s",
    589                 KIT_SLICE_ARG(kit_slice_cstr(argv[*i])));
    590     return 1;
    591   }
    592   if (*i >= argc) {
    593     driver_errf(o->tool, "--group requires `--` before its sources");
    594     return 1;
    595   }
    596   ++(*i);             /* past `--` */
    597   o->cur_group = gid; /* subsequent sources belong to this group */
    598   return 0;
    599 }
    600 
    601 static int build_parse(int argc, char** argv, BuildOptions* o) {
    602   int i;
    603   o->target = driver_host_target();
    604 
    605   for (i = 1; i < argc; ++i) {
    606     const char* a = argv[i];
    607 
    608     if (driver_streq(a, "--group")) {
    609       if (build_parse_group(o, argc, argv, &i) != 0) return 1;
    610       --i; /* parse_group leaves i at the next token; loop's ++i re-reads it */
    611       continue;
    612     }
    613 
    614     /* Scopable flags in the global context feed the baseline (groups[0]). */
    615     {
    616       int r = build_try_scopable(o, &o->groups[0], argc, argv, &i);
    617       if (r < 0) return 1;
    618       if (r > 0) continue;
    619     }
    620 
    621     /* Output form. */
    622     if (driver_streq(a, "-c")) {
    623       o->emit = BUILD_EMIT_OBJ;
    624       continue;
    625     }
    626     if (driver_streq(a, "-S") || driver_streq(a, "--emit=asm")) {
    627       o->emit = BUILD_EMIT_ASM;
    628       continue;
    629     }
    630     if (driver_streq(a, "--emit=obj")) {
    631       o->emit = BUILD_EMIT_OBJ;
    632       continue;
    633     }
    634     if (driver_streq(a, "--emit=c")) {
    635       o->emit = BUILD_EMIT_C;
    636       continue;
    637     }
    638     if (driver_streq(a, "--emit=ir")) {
    639       o->emit = BUILD_EMIT_IR;
    640       continue;
    641     }
    642     if (driver_streq(a, "-fsyntax-only")) {
    643       o->syntax_only = 1;
    644       continue;
    645     }
    646     if (driver_streq(a, "-o")) {
    647       if (++i >= argc) {
    648         driver_errf(o->tool, "-o requires an argument");
    649         return 1;
    650       }
    651       o->output_path = argv[i];
    652       continue;
    653     }
    654     if (driver_strneq(a, "-o", 2)) {
    655       o->output_path = a + 2;
    656       continue;
    657     }
    658     if (driver_strneq(a, "--output=", 9)) {
    659       o->output_path = a + 9;
    660       continue;
    661     }
    662     if (driver_streq(a, "--output")) {
    663       if (++i >= argc) {
    664         driver_errf(o->tool, "--output requires an argument");
    665         return 1;
    666       }
    667       o->output_path = argv[i];
    668       continue;
    669     }
    670 
    671     /* Optimization / debug / codegen knobs. */
    672     if (driver_streq(a, "-g")) {
    673       o->debug_info = 1;
    674       continue;
    675     }
    676     if (driver_streq(a, "-O0")) {
    677       o->opt_level = 0;
    678       continue;
    679     }
    680     if (driver_streq(a, "-O1")) {
    681       o->opt_level = 1;
    682       continue;
    683     }
    684     if (driver_streq(a, "-O2") || driver_streq(a, "-O") ||
    685         driver_streq(a, "-O3") || driver_streq(a, "-Os") ||
    686         driver_streq(a, "-Oz") || driver_streq(a, "-Ofast")) {
    687       o->opt_level = 2;
    688       continue;
    689     }
    690     if (driver_streq(a, "-Werror") || driver_strneq(a, "-Werror=", 8)) {
    691       o->warnings_are_errors = 1;
    692       continue;
    693     }
    694     if (driver_strneq(a, "-fmax-errors=", 13)) {
    695       uint64_t v;
    696       if (build_parse_u64(a + 13, &v) != 0 || v > 0xFFFFFFFFu) {
    697         driver_errf(o->tool, "-fmax-errors= requires a non-negative integer");
    698         return 1;
    699       }
    700       o->max_errors = (uint32_t)v;
    701       continue;
    702     }
    703     if (driver_streq(a, "-fPIC") || driver_streq(a, "-fpic")) {
    704       o->target.pic = KIT_PIC_PIC;
    705       continue;
    706     }
    707     if (driver_streq(a, "-fPIE") || driver_streq(a, "-fpie")) {
    708       o->target.pic = KIT_PIC_PIE;
    709       continue;
    710     }
    711     if (driver_streq(a, "-fno-PIC") || driver_streq(a, "-fno-pic") ||
    712         driver_streq(a, "-fno-PIE") || driver_streq(a, "-fno-pie")) {
    713       o->target.pic = KIT_PIC_NONE;
    714       continue;
    715     }
    716     if (driver_streq(a, "-fvisibility=hidden")) {
    717       o->default_visibility = KIT_SV_HIDDEN;
    718       continue;
    719     }
    720     if (driver_streq(a, "-fvisibility=default")) {
    721       o->default_visibility = KIT_SV_DEFAULT;
    722       continue;
    723     }
    724     if (driver_strneq(a, "-fvisibility=", 13)) {
    725       driver_errf(o->tool, "unsupported visibility: %.*s",
    726                   KIT_SLICE_ARG(kit_slice_cstr(a + 13)));
    727       return 1;
    728     }
    729     if (driver_streq(a, "-ffunction-sections")) {
    730       o->function_sections = 1;
    731       continue;
    732     }
    733     if (driver_streq(a, "-fno-function-sections")) {
    734       o->function_sections = 0;
    735       continue;
    736     }
    737     if (driver_streq(a, "-fdata-sections")) {
    738       o->data_sections = 1;
    739       continue;
    740     }
    741     if (driver_streq(a, "-fno-data-sections")) {
    742       o->data_sections = 0;
    743       continue;
    744     }
    745     if (driver_streq(a, "-flto")) {
    746       o->lto = 1;
    747       continue;
    748     }
    749     if (driver_streq(a, "-fno-lto")) {
    750       o->lto = 0;
    751       continue;
    752     }
    753     if (driver_streq(a, "-ffreestanding")) {
    754       o->freestanding = 1;
    755       continue;
    756     }
    757     if (driver_streq(a, "-fhosted")) {
    758       o->freestanding = 0;
    759       continue;
    760     }
    761     if (driver_streq(a, "-nostdinc")) {
    762       o->nostdinc = 1;
    763       continue;
    764     }
    765     if (driver_streq(a, "-nostdlib")) {
    766       o->no_stdlib = 1;
    767       continue;
    768     }
    769     if (driver_streq(a, "-nodefaultlibs")) {
    770       o->no_defaultlibs = 1;
    771       continue;
    772     }
    773     if (driver_streq(a, "-nostartfiles")) {
    774       o->no_startfiles = 1;
    775       continue;
    776     }
    777 
    778     /* Link kind. */
    779     if (driver_streq(a, "-static")) {
    780       o->static_link = 1;
    781       o->target.pic = KIT_PIC_NONE;
    782       o->cur_link_mode = KIT_LM_STATIC;
    783       continue;
    784     }
    785     if (driver_streq(a, "-dynamic")) {
    786       o->dynamic = 1;
    787       continue;
    788     }
    789     if (driver_streq(a, "-shared")) {
    790       o->dynamic = 1;
    791       o->shared_requested = 1;
    792       continue;
    793     }
    794     if (driver_streq(a, "-pie")) {
    795       o->target.pic = KIT_PIC_PIE;
    796       o->pie = 1;
    797       continue;
    798     }
    799     if (driver_streq(a, "-no-pie")) {
    800       o->target.pic = KIT_PIC_NONE;
    801       o->pie = 0;
    802       continue;
    803     }
    804 
    805     /* Link inputs / flags. */
    806     if (driver_strneq(a, "-L", 2)) {
    807       const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL);
    808       if (!dir) {
    809         driver_errf(o->tool, "-L requires an argument");
    810         return 1;
    811       }
    812       o->lib_search_paths[o->nlib_search_paths++] = dir;
    813       continue;
    814     }
    815     if (driver_strneq(a, "-l", 2)) {
    816       const char* name = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL);
    817       if (!name) {
    818         driver_errf(o->tool, "-l requires an argument");
    819         return 1;
    820       }
    821       if (driver_streq(name, "c") && !o->no_stdlib && !o->no_defaultlibs) {
    822         o->wants_hosted_libc = 1;
    823         continue;
    824       }
    825       {
    826         BuildPendingLib* pl = &o->pending_libs[o->npending_libs++];
    827         pl->name = name;
    828         pl->whole_archive = o->cur_whole_archive;
    829         pl->link_mode = o->cur_link_mode;
    830         pl->group_id = o->cur_group_id;
    831         build_push_link_item(o, BUILD_LINK_LIB, o->npending_libs - 1u);
    832       }
    833       continue;
    834     }
    835     if (driver_streq(a, "-e")) {
    836       if (++i >= argc) {
    837         driver_errf(o->tool, "-e requires an argument");
    838         return 1;
    839       }
    840       o->link.entry = argv[i];
    841       continue;
    842     }
    843     if (driver_streq(a, "-T")) {
    844       if (++i >= argc) {
    845         driver_errf(o->tool, "-T requires an argument");
    846         return 1;
    847       }
    848       o->link.linker_script = argv[i];
    849       continue;
    850     }
    851     if (driver_strneq(a, "-Wl,", 4)) {
    852       if (driver_link_flags_record_wl(&o->link, a + 4) != 0) return 1;
    853       continue;
    854     }
    855     if (driver_streq(a, "-Xlinker")) {
    856       if (++i >= argc) {
    857         driver_errf(o->tool, "-Xlinker requires an argument");
    858         return 1;
    859       }
    860       if (driver_link_flags_record_wl(&o->link, argv[i]) != 0) return 1;
    861       continue;
    862     }
    863     if (driver_strneq(a, "--build-id=", 11)) {
    864       if (driver_link_flags_record_build_id(&o->link, a + 11) != 0) return 1;
    865       continue;
    866     }
    867     if (driver_streq(a, "-mwindows")) {
    868       o->link.pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_GUI;
    869       continue;
    870     }
    871     if (driver_streq(a, "-mconsole")) {
    872       o->link.pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_CUI;
    873       continue;
    874     }
    875     if (driver_strneq(a, "-mcmodel=", 9)) {
    876       if (build_record_mcmodel(o, a + 9) != 0) return 1;
    877       continue;
    878     }
    879 
    880     /* Target. */
    881     if (driver_streq(a, "-target") || driver_streq(a, "--target")) {
    882       if (++i >= argc) {
    883         driver_errf(o->tool, "%.*s requires an argument",
    884                     KIT_SLICE_ARG(kit_slice_cstr(a)));
    885         return 1;
    886       }
    887       if (driver_target_from_triple(argv[i], &o->target) != 0) {
    888         driver_errf(o->tool, "unrecognized target triple: %.*s",
    889                     KIT_SLICE_ARG(kit_slice_cstr(argv[i])));
    890         return 1;
    891       }
    892       continue;
    893     }
    894     if (driver_strneq(a, "--target=", 9)) {
    895       if (driver_target_from_triple(a + 9, &o->target) != 0) {
    896         driver_errf(o->tool, "unrecognized target triple: %.*s",
    897                     KIT_SLICE_ARG(kit_slice_cstr(a + 9)));
    898         return 1;
    899       }
    900       continue;
    901     }
    902     {
    903       int tr = driver_target_features_try_consume(&o->target_features, o->env,
    904                                                   o->tool, argc, argv, &i);
    905       if (tr < 0) return 1;
    906       if (tr > 0) continue;
    907     }
    908 
    909     /* Support dir / sysroot. */
    910     if (driver_streq(a, "-isysroot") || driver_streq(a, "--sysroot")) {
    911       if (++i >= argc) {
    912         driver_errf(o->tool, "%.*s requires an argument",
    913                     KIT_SLICE_ARG(kit_slice_cstr(a)));
    914         return 1;
    915       }
    916       o->sysroot = argv[i];
    917       continue;
    918     }
    919     if (driver_strneq(a, "--sysroot=", 10)) {
    920       o->sysroot = a + 10;
    921       continue;
    922     }
    923     if (driver_streq(a, "--support-dir")) {
    924       if (++i >= argc) {
    925         driver_errf(o->tool, "--support-dir requires an argument");
    926         return 1;
    927       }
    928       o->support_dir = argv[i];
    929       continue;
    930     }
    931     if (driver_strneq(a, "--support-dir=", 14)) {
    932       o->support_dir = a + 14;
    933       continue;
    934     }
    935 
    936     if (driver_streq(a, "--")) {
    937       for (++i; i < argc; ++i)
    938         if (build_classify_positional(o, argv[i]) != 0) return 1;
    939       break;
    940     }
    941     if (a[0] == '-' && a[1] != '\0') {
    942       driver_errf(o->tool, "unknown flag: %.*s",
    943                   KIT_SLICE_ARG(kit_slice_cstr(a)));
    944       return 1;
    945     }
    946     if (build_classify_positional(o, a) != 0) return 1;
    947   }
    948   return 0;
    949 }
    950 
    951 /* ===================================================================== */
    952 /* hosted libc / runtime orchestration (build-exe; shared build-lib)      */
    953 /* ===================================================================== */
    954 
    955 static int build_is_link_output(const BuildOptions* o) {
    956   if (o->kind == BUILD_OUT_EXE && o->target.obj == KIT_OBJ_WASM) return 0;
    957   return o->kind == BUILD_OUT_EXE || (o->kind == BUILD_OUT_LIB && o->dynamic);
    958 }
    959 
    960 static int build_resolve_pending_libs(BuildOptions* o) {
    961   uint32_t i;
    962   for (i = 0; i < o->npending_libs; ++i) {
    963     BuildPendingLib* pl = &o->pending_libs[i];
    964     char* p;
    965     size_t sz;
    966     LibResolveKind kind;
    967     LibResolveMode mode = (o->static_link || pl->link_mode == KIT_LM_STATIC)
    968                               ? LIB_RESOLVE_STATIC_ONLY
    969                               : LIB_RESOLVE_DYNAMIC_PREFER;
    970     LibResolveOS resolve_os = (o->target.os == KIT_OS_WINDOWS)
    971                                   ? LIB_RESOLVE_OS_WINDOWS
    972                                   : LIB_RESOLVE_OS_POSIX;
    973     if (driver_lib_resolve_for_os(o->env, pl->name, mode, resolve_os,
    974                                   o->lib_search_paths, o->nlib_search_paths, &p,
    975                                   &sz, &kind) != 0) {
    976       driver_errf(o->tool, "library not found: -l%.*s",
    977                   KIT_SLICE_ARG(kit_slice_cstr(pl->name)));
    978       return 1;
    979     }
    980     if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) {
    981       BuildDsoInput* d = &o->dsos[o->ndsos++];
    982       d->path = p;
    983       d->owned = 1;
    984       d->owned_size = sz;
    985       pl->resolved_kind = BUILD_LINK_DSO;
    986       pl->resolved_index = o->ndsos - 1u;
    987     } else {
    988       BuildArchiveInput* ar = &o->archives[o->narchives++];
    989       ar->path = p;
    990       ar->owned = 1;
    991       ar->owned_size = sz;
    992       ar->whole_archive = pl->whole_archive;
    993       ar->link_mode = pl->link_mode;
    994       ar->group_id = pl->group_id;
    995       pl->resolved_kind = BUILD_LINK_ARCHIVE;
    996       pl->resolved_index = o->narchives - 1u;
    997     }
    998   }
    999   return 0;
   1000 }
   1001 
   1002 /* A sysroot on its own engages the hosted libc profile (matching clang/gcc).
   1003  * -ffreestanding / -nostdinc / -nostdlib opt back out; -dynamic (shared) keeps
   1004  * its standalone meaning. */
   1005 static void build_enable_hosted_for_sysroot(BuildOptions* o) {
   1006   if (o->wants_hosted_libc || o->shared) return;
   1007   if (!o->sysroot || !o->sysroot[0]) return;
   1008   if (o->freestanding || o->nostdinc) return;
   1009   if (o->no_stdlib || o->no_defaultlibs) return;
   1010   o->wants_hosted_libc = 1;
   1011 }
   1012 
   1013 static void build_apply_default_hosted_profile(BuildOptions* o) {
   1014   if (!driver_target_default_hosted_profile(o->target)) return;
   1015   if (o->no_stdlib || o->no_defaultlibs || o->wants_hosted_libc) return;
   1016   if (!o->sysroot || !o->sysroot[0]) return;
   1017   o->wants_hosted_libc = 1;
   1018 }
   1019 
   1020 static int build_apply_hosted_profile(BuildOptions* o) {
   1021   DriverHostedRequest req;
   1022   uint32_t i;
   1023   uint32_t insert_pos = 0;
   1024   if (!o->wants_hosted_libc || o->shared) return 0;
   1025   if (o->no_stdlib || o->no_defaultlibs) {
   1026     driver_errf(o->tool,
   1027                 "-lc hosted expansion is disabled by -nostdlib/-nodefaultlibs");
   1028     return 1;
   1029   }
   1030   {
   1031     DriverHostedRequest z = {0};
   1032     req = z;
   1033   }
   1034   req.env = o->env;
   1035   req.tool = o->tool;
   1036   req.target = o->target;
   1037   req.sysroot = o->sysroot;
   1038   req.static_link = o->static_link;
   1039   req.link_inputs = 1;
   1040   if (driver_hosted_resolve(&req, &o->hosted) != 0) return 1;
   1041   for (i = 0; i < o->hosted.nsystem_includes; ++i)
   1042     o->groups[0]
   1043         .cf.system_include_dirs[o->groups[0].cf.nsystem_include_dirs++] =
   1044         o->hosted.system_includes[i];
   1045   for (i = 0; i < o->hosted.ndefines; ++i)
   1046     o->groups[0].cf.defines[o->groups[0].cf.ndefines++] = o->hosted.defines[i];
   1047   for (i = 0; i < o->hosted.nbefore; ++i) {
   1048     if (o->no_startfiles) break;
   1049     if (build_append_hosted_input(o, &o->hosted.before[i], insert_pos, 1) != 0)
   1050       return 1;
   1051     insert_pos++;
   1052   }
   1053   for (i = 0; i < o->hosted.nafter; ++i)
   1054     if (build_append_hosted_input(o, &o->hosted.after[i], 0, 0) != 0) return 1;
   1055   for (i = 0; i < o->hosted.nfinal; ++i) {
   1056     if (o->no_startfiles) break;
   1057     if (build_append_hosted_input(o, &o->hosted.final[i], 0, 0) != 0) return 1;
   1058   }
   1059   if (!o->link.interp_path && o->hosted.interp_path)
   1060     o->link.interp_path = o->hosted.interp_path;
   1061   return 0;
   1062 }
   1063 
   1064 /* Append `<sysroot>/lib` to the search path for Windows targets (mirrors cc).
   1065  */
   1066 static int build_append_windows_lib_dirs(BuildOptions* o) {
   1067   const char* sysroot = o->sysroot;
   1068   char* joined;
   1069   size_t srlen, need_slash, bytes, off = 0;
   1070   if (!driver_target_needs_sysroot_libdir(o->target)) return 0;
   1071   if (!sysroot || !sysroot[0]) {
   1072     sysroot = driver_getenv("KIT_SYSROOT");
   1073     if (!sysroot || !sysroot[0]) return 0;
   1074     o->sysroot = sysroot;
   1075   }
   1076   srlen = driver_strlen(sysroot);
   1077   need_slash = (srlen > 0 && sysroot[srlen - 1] != '/') ? 1u : 0u;
   1078   bytes = srlen + need_slash + 3u + 1u;
   1079   joined = driver_alloc(o->env, bytes);
   1080   if (!joined) {
   1081     driver_errf(o->tool, "out of memory");
   1082     return 1;
   1083   }
   1084   driver_memcpy(joined + off, sysroot, srlen);
   1085   off += srlen;
   1086   if (need_slash) joined[off++] = '/';
   1087   driver_memcpy(joined + off, "lib", 3);
   1088   off += 3;
   1089   joined[off] = '\0';
   1090   o->owned_sysroot_lib_dir = joined;
   1091   o->owned_sysroot_lib_dir_size = bytes;
   1092   o->lib_search_paths[o->nlib_search_paths++] = joined;
   1093   return 0;
   1094 }
   1095 
   1096 /* ===================================================================== */
   1097 /* merged preprocessor view per group                                     */
   1098 /* ===================================================================== */
   1099 
   1100 static int build_group_build_pp(BuildOptions* o, uint32_t gi) {
   1101   BuildGroup* g = &o->groups[gi];
   1102   BuildGroup* gl = &o->groups[0];
   1103   uint32_t k;
   1104   if (gi == 0) {
   1105     driver_cflags_fill_pp(&gl->cf, &g->pp);
   1106     return 0;
   1107   }
   1108   /* include = group then global (group searched first). */
   1109   g->m_ninc = g->cf.ninclude_dirs + gl->cf.ninclude_dirs;
   1110   g->m_nsys = g->cf.nsystem_include_dirs + gl->cf.nsystem_include_dirs;
   1111   g->m_def_cap = gl->cf.ndefines + g->cf.ndefines;
   1112   g->m_nund = gl->cf.nundefines + g->cf.nundefines;
   1113   if (g->m_ninc)
   1114     g->m_inc = driver_alloc_zeroed(o->env, g->m_ninc * sizeof(*g->m_inc));
   1115   if (g->m_nsys)
   1116     g->m_sys = driver_alloc_zeroed(o->env, g->m_nsys * sizeof(*g->m_sys));
   1117   if (g->m_def_cap)
   1118     g->m_def = driver_alloc_zeroed(o->env, g->m_def_cap * sizeof(*g->m_def));
   1119   if (g->m_nund)
   1120     g->m_und = driver_alloc_zeroed(o->env, g->m_nund * sizeof(*g->m_und));
   1121   if ((g->m_ninc && !g->m_inc) || (g->m_nsys && !g->m_sys) ||
   1122       (g->m_def_cap && !g->m_def) || (g->m_nund && !g->m_und)) {
   1123     driver_errf(o->tool, "out of memory");
   1124     return 1;
   1125   }
   1126   {
   1127     uint32_t p = 0, j;
   1128     for (k = 0; k < g->cf.ninclude_dirs; ++k)
   1129       g->m_inc[p++] = g->cf.include_dirs[k];
   1130     for (k = 0; k < gl->cf.ninclude_dirs; ++k)
   1131       g->m_inc[p++] = gl->cf.include_dirs[k];
   1132     p = 0;
   1133     for (k = 0; k < g->cf.nsystem_include_dirs; ++k)
   1134       g->m_sys[p++] = g->cf.system_include_dirs[k];
   1135     for (k = 0; k < gl->cf.nsystem_include_dirs; ++k)
   1136       g->m_sys[p++] = gl->cf.system_include_dirs[k];
   1137     /* defines: each global define survives only if the group does not redefine
   1138      * the same name; the group's defines then follow. This realizes "a group
   1139      * -D of an already-defined name overrides it for that group" without
   1140      * emitting a duplicate (which the preprocessor rejects as a conflicting
   1141      * redefinition). */
   1142     p = 0;
   1143     for (k = 0; k < gl->cf.ndefines; ++k) {
   1144       int shadowed = 0;
   1145       for (j = 0; j < g->cf.ndefines; ++j) {
   1146         if (kit_slice_eq(gl->cf.defines[k].name, g->cf.defines[j].name)) {
   1147           shadowed = 1;
   1148           break;
   1149         }
   1150       }
   1151       if (!shadowed) g->m_def[p++] = gl->cf.defines[k];
   1152     }
   1153     for (k = 0; k < g->cf.ndefines; ++k) g->m_def[p++] = g->cf.defines[k];
   1154     g->m_ndef = p;
   1155     p = 0;
   1156     for (k = 0; k < gl->cf.nundefines; ++k) g->m_und[p++] = gl->cf.undefines[k];
   1157     for (k = 0; k < g->cf.nundefines; ++k) g->m_und[p++] = g->cf.undefines[k];
   1158   }
   1159   {
   1160     KitPreprocessOptions z = {0};
   1161     g->pp = z;
   1162     g->pp.include_dirs = g->m_inc;
   1163     g->pp.ninclude_dirs = g->m_ninc;
   1164     g->pp.system_include_dirs = g->m_sys;
   1165     g->pp.nsystem_include_dirs = g->m_nsys;
   1166     g->pp.defines = g->m_def;
   1167     g->pp.ndefines = g->m_ndef;
   1168     g->pp.undefines = g->m_und;
   1169     g->pp.nundefines = g->m_nund;
   1170   }
   1171   return 0;
   1172 }
   1173 
   1174 /* ===================================================================== */
   1175 /* compile one source                                                     */
   1176 /* ===================================================================== */
   1177 
   1178 static KitLanguage build_resolve_lang(BuildOptions* o, KitCompiler* compiler,
   1179                                       uint32_t si) {
   1180   uint32_t gi = o->sources[si].group;
   1181   if (gi != 0 && o->groups[gi].forced_lang != BUILD_LANG_AUTO)
   1182     return o->groups[gi].forced_lang;
   1183   if (o->groups[0].forced_lang != BUILD_LANG_AUTO)
   1184     return o->groups[0].forced_lang;
   1185   return kit_language_for_path(compiler, o->sources[si].path);
   1186 }
   1187 
   1188 /* Collect the -X<lang> frontend tokens for a source into a fresh argv:
   1189  * global (groups[0]) tokens first, then the source's group's. */
   1190 static int build_collect_fe_argv(BuildOptions* o, uint32_t si, KitLanguage lang,
   1191                                  char*** out_argv, uint32_t* out_n) {
   1192   uint32_t gi = o->sources[si].group;
   1193   uint32_t n = 0, k, p = 0;
   1194   char** argv;
   1195   for (k = 0; k < o->groups[0].nfe; ++k)
   1196     if (o->groups[0].fe[k].lang == (uint8_t)lang) n++;
   1197   if (gi != 0)
   1198     for (k = 0; k < o->groups[gi].nfe; ++k)
   1199       if (o->groups[gi].fe[k].lang == (uint8_t)lang) n++;
   1200   *out_argv = NULL;
   1201   *out_n = 0;
   1202   if (n == 0) return 0;
   1203   argv = driver_alloc_zeroed(o->env, n * sizeof(*argv));
   1204   if (!argv) {
   1205     driver_errf(o->tool, "out of memory");
   1206     return 1;
   1207   }
   1208   for (k = 0; k < o->groups[0].nfe; ++k)
   1209     if (o->groups[0].fe[k].lang == (uint8_t)lang)
   1210       argv[p++] = o->groups[0].fe[k].tok;
   1211   if (gi != 0)
   1212     for (k = 0; k < o->groups[gi].nfe; ++k)
   1213       if (o->groups[gi].fe[k].lang == (uint8_t)lang)
   1214         argv[p++] = o->groups[gi].fe[k].tok;
   1215   *out_argv = argv;
   1216   *out_n = n;
   1217   return 0;
   1218 }
   1219 
   1220 /* Compile source[si]; emit to `emit_out` (per-source output) or return a
   1221  * builder via `obj_out` (link/archive). Exactly one of the two is non-NULL. */
   1222 static int build_compile_source(BuildOptions* o, KitCompiler* compiler,
   1223                                 const KitContext* ctx, uint32_t si,
   1224                                 const KitCodeOptions* code,
   1225                                 const KitDiagnosticOptions* diag,
   1226                                 KitWriter* emit_out, KitObjBuilder** obj_out) {
   1227   const char* path = o->sources[si].path;
   1228   uint32_t gi = o->sources[si].group;
   1229   DriverLoad load = {0};
   1230   KitSlice bytes = {0};
   1231   KitLanguage lang;
   1232   char** fe_argv = NULL;
   1233   uint32_t fe_n = 0;
   1234   void* lang_extra = NULL;
   1235   KitStatus st;
   1236   int rc = 1;
   1237 
   1238   if (driver_load_bytes(ctx->file_io, o->tool, path, &load, &bytes) != 0)
   1239     return 1;
   1240 
   1241   lang = build_resolve_lang(o, compiler, si);
   1242   if (lang == KIT_LANG_UNKNOWN) {
   1243     driver_errf(o->tool, "cannot determine language for %.*s (use -x LANG)",
   1244                 KIT_SLICE_ARG(kit_slice_cstr(path)));
   1245     goto out;
   1246   }
   1247   if (build_collect_fe_argv(o, si, lang, &fe_argv, &fe_n) != 0) goto out;
   1248   if (fe_n) {
   1249     if (kit_frontend_parse_options(compiler, lang, (int)fe_n, fe_argv,
   1250                                    &lang_extra) != KIT_OK) {
   1251       driver_errf(o->tool, "unsupported -X%.*s frontend flag: %.*s",
   1252                   KIT_SLICE_ARG(kit_slice_cstr(kit_language_name(compiler, lang))),
   1253                   KIT_SLICE_ARG(kit_slice_cstr(fe_argv[0])));
   1254       goto out;
   1255     }
   1256   }
   1257 
   1258   st = driver_compile_run(compiler, lang, code, diag, &o->groups[gi].pp,
   1259                           lang_extra, kit_slice_cstr(path), &bytes, emit_out,
   1260                           obj_out);
   1261   rc = (st == KIT_OK) ? 0 : 1;
   1262 
   1263 out:
   1264   if (lang_extra) kit_frontend_free_options(compiler, lang, lang_extra);
   1265   if (fe_argv) driver_free(o->env, fe_argv, fe_n * sizeof(*fe_argv));
   1266   driver_release_bytes(ctx->file_io, &load);
   1267   return rc;
   1268 }
   1269 
   1270 static void build_fill_code(const BuildOptions* o, KitCodeOptions* code) {
   1271   KitCodeOptions z = {0};
   1272   *code = z;
   1273   code->opt_level = o->syntax_only ? 0 : o->opt_level;
   1274   code->debug_info = o->debug_info ? true : false;
   1275   code->check_only = o->syntax_only ? true : false;
   1276   code->default_visibility = o->default_visibility;
   1277   code->function_sections = o->function_sections ? true : false;
   1278   code->data_sections = o->data_sections ? true : false;
   1279   code->lto = o->lto ? true : false;
   1280   code->epoch = o->epoch;
   1281 }
   1282 
   1283 /* ===================================================================== */
   1284 /* default output naming                                                  */
   1285 /* ===================================================================== */
   1286 
   1287 static char* build_default_obj_name(DriverEnv* env, const BuildOptions* o,
   1288                                     const char* src, size_t* out_size) {
   1289   const char* ext;
   1290   size_t ext_len, srclen = driver_strlen(src), dot = driver_strlen(src),
   1291                   slash = 0, k;
   1292   switch ((BuildEmit)o->emit) {
   1293     case BUILD_EMIT_ASM:
   1294       ext = ".s";
   1295       ext_len = 2u;
   1296       break;
   1297     case BUILD_EMIT_IR:
   1298       ext = ".ir";
   1299       ext_len = 3u;
   1300       break;
   1301     case BUILD_EMIT_C:
   1302       ext = ".c";
   1303       ext_len = 2u;
   1304       break;
   1305     default:
   1306       driver_default_obj_ext(o->target, &ext, &ext_len);
   1307       break;
   1308   }
   1309   for (k = srclen; k > 0; --k) {
   1310     if (src[k - 1] == '.') {
   1311       dot = k - 1;
   1312       break;
   1313     }
   1314     if (src[k - 1] == '/') break;
   1315   }
   1316   for (k = dot; k > 0; --k) {
   1317     if (src[k - 1] == '/') {
   1318       slash = k;
   1319       break;
   1320     }
   1321   }
   1322   {
   1323     size_t name_len = dot - slash;
   1324     size_t bufsz = name_len + ext_len + 1u;
   1325     char* buf = driver_alloc(env, bufsz);
   1326     if (!buf) return NULL;
   1327     driver_memcpy(buf, src + slash, name_len);
   1328     driver_memcpy(buf + name_len, ext, ext_len);
   1329     buf[name_len + ext_len] = '\0';
   1330     *out_size = bufsz;
   1331     return buf;
   1332   }
   1333 }
   1334 
   1335 /* Open the output: a file, or stdout for "-". */
   1336 static int build_open_output(const KitContext* ctx, DriverEnv* env,
   1337                              const char* tool, const char* path,
   1338                              KitWriter** out) {
   1339   if (driver_streq(path, "-")) {
   1340     *out = driver_stdout_writer(env);
   1341     if (!*out) {
   1342       driver_errf(tool, "out of memory");
   1343       return 1;
   1344     }
   1345     return 0;
   1346   }
   1347   if (ctx->file_io->open_writer(ctx->file_io->user, path, out) != KIT_OK) {
   1348     driver_errf(tool, "failed to open output: %.*s",
   1349                 KIT_SLICE_ARG(kit_slice_cstr(path)));
   1350     return 1;
   1351   }
   1352   return 0;
   1353 }
   1354 
   1355 /* Compile every source to an in-memory builder; objs[] is caller-owned. */
   1356 static int build_compile_all(BuildOptions* o, KitCompiler* compiler,
   1357                              const KitContext* ctx, const KitCodeOptions* code,
   1358                              const KitDiagnosticOptions* diag,
   1359                              KitObjBuilder** objs, uint32_t* source_obj_index,
   1360                              uint8_t* source_order_keep,
   1361                              const DriverCompileBatchOptions* batch,
   1362                              DriverCompilePendingLto* pending_lto,
   1363                              uint32_t* nobjs_out) {
   1364   DriverLoad* loads = NULL;
   1365   DriverCompileSource* sources = NULL;
   1366   void** lang_extras = NULL;
   1367   DriverCompileObjects out;
   1368   uint32_t i;
   1369   KitStatus st;
   1370   int rc = 1;
   1371 
   1372   if (nobjs_out) *nobjs_out = 0;
   1373   if (o->nsources == 0) return 0;
   1374 
   1375   loads = driver_alloc_zeroed(o->env, o->nsources * sizeof(*loads));
   1376   sources = driver_alloc_zeroed(o->env, o->nsources * sizeof(*sources));
   1377   lang_extras = driver_alloc_zeroed(o->env, o->nsources * sizeof(*lang_extras));
   1378   if (!loads || !sources || !lang_extras) {
   1379     driver_errf(o->tool, "out of memory");
   1380     goto out;
   1381   }
   1382 
   1383   for (i = 0; i < o->nsources; ++i) {
   1384     const char* path = o->sources[i].path;
   1385     uint32_t gi = o->sources[i].group;
   1386     KitLanguage lang;
   1387     char** fe_argv = NULL;
   1388     uint32_t fe_n = 0;
   1389 
   1390     if (driver_load_bytes(ctx->file_io, o->tool, path, &loads[i],
   1391                           &sources[i].bytes) != 0)
   1392       goto out;
   1393     lang = build_resolve_lang(o, compiler, i);
   1394     if (lang == KIT_LANG_UNKNOWN) {
   1395       driver_errf(o->tool, "cannot determine language for %.*s (use -x LANG)",
   1396                   KIT_SLICE_ARG(kit_slice_cstr(path)));
   1397       goto out;
   1398     }
   1399     if (build_collect_fe_argv(o, i, lang, &fe_argv, &fe_n) != 0) {
   1400       if (fe_argv) driver_free(o->env, fe_argv, fe_n * sizeof(*fe_argv));
   1401       goto out;
   1402     }
   1403     if (fe_n) {
   1404       if (kit_frontend_parse_options(compiler, lang, (int)fe_n, fe_argv,
   1405                                      &lang_extras[i]) != KIT_OK) {
   1406         driver_errf(
   1407             o->tool, "unsupported -X%.*s frontend flag: %.*s",
   1408             KIT_SLICE_ARG(kit_slice_cstr(kit_language_name(compiler, lang))),
   1409             KIT_SLICE_ARG(kit_slice_cstr(fe_argv[0])));
   1410         if (fe_argv) driver_free(o->env, fe_argv, fe_n * sizeof(*fe_argv));
   1411         goto out;
   1412       }
   1413     }
   1414     if (fe_argv) driver_free(o->env, fe_argv, fe_n * sizeof(*fe_argv));
   1415     sources[i].lang = lang;
   1416     sources[i].name = kit_slice_cstr(path);
   1417     sources[i].pp = &o->groups[gi].pp;
   1418     sources[i].lang_extra = lang_extras[i];
   1419   }
   1420 
   1421   memset(&out, 0, sizeof out);
   1422   out.objs = objs;
   1423   out.source_obj_index = source_obj_index;
   1424   out.source_order_keep = source_order_keep;
   1425   out.pending_lto = pending_lto;
   1426   st = driver_compile_sources_run(compiler, code, diag, sources, o->nsources,
   1427                                   batch, &out);
   1428   if (nobjs_out) *nobjs_out = out.nobjs;
   1429   if (st != KIT_OK) goto out;
   1430   rc = 0;
   1431 
   1432 out:
   1433   if (lang_extras && sources) {
   1434     for (i = 0; i < o->nsources; ++i)
   1435       if (lang_extras[i])
   1436         kit_frontend_free_options(compiler, sources[i].lang, lang_extras[i]);
   1437   }
   1438   if (loads)
   1439     for (i = 0; i < o->nsources; ++i)
   1440       driver_release_bytes(ctx->file_io, &loads[i]);
   1441   if (lang_extras)
   1442     driver_free(o->env, lang_extras, o->nsources * sizeof(*lang_extras));
   1443   if (sources) driver_free(o->env, sources, o->nsources * sizeof(*sources));
   1444   if (loads) driver_free(o->env, loads, o->nsources * sizeof(*loads));
   1445   return rc;
   1446 }
   1447 
   1448 /* build-exe / shared build-lib: compile sources, load link inputs, link. */
   1449 static int build_run_link(BuildOptions* o, KitCompiler* compiler,
   1450                           const KitContext* ctx, const KitCodeOptions* code,
   1451                           const KitDiagnosticOptions* diag,
   1452                           uint8_t output_kind) {
   1453   DriverEnv* env = o->env;
   1454   const KitFileIO* io = ctx->file_io;
   1455   KitWriter* out_w = NULL;
   1456   DriverLoad* obj_lf = NULL;
   1457   DriverLoad* arch_lf = NULL;
   1458   DriverLoad* dso_lf = NULL;
   1459   DriverLoad script_lf = {0};
   1460   KitSlice* obj_in = NULL;
   1461   KitSlice* obj_names = NULL;
   1462   KitLinkArchiveInput* arch_in = NULL;
   1463   KitSlice* dso_in = NULL;
   1464   KitSlice* dso_names = NULL;
   1465   KitLinkInputOrder* order = NULL;
   1466   KitObjBuilder** objs = NULL;
   1467   DriverCompilePendingLto pending_lto = {0};
   1468   uint32_t* source_obj_index = NULL;
   1469   uint8_t* source_order_keep = NULL;
   1470   KitLinkScript* script = NULL;
   1471   KitSlice* rpath_slices = NULL;
   1472   DriverCompileBatchOptions lto_batch;
   1473   uint32_t nobjs = 0;
   1474   uint32_t i;
   1475   uint32_t norder = 0;
   1476   int rc = 1;
   1477 
   1478   if (o->nsources) {
   1479     objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs));
   1480     source_obj_index =
   1481         driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index));
   1482     source_order_keep =
   1483         driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep));
   1484     if (!objs || !source_obj_index || !source_order_keep) goto oom;
   1485   }
   1486   if (o->nobject_files) {
   1487     obj_lf = driver_alloc_zeroed(env, o->nobject_files * sizeof(*obj_lf));
   1488     obj_in = driver_alloc_zeroed(env, o->nobject_files * sizeof(*obj_in));
   1489     obj_names = driver_alloc_zeroed(env, o->nobject_files * sizeof(*obj_names));
   1490     if (!obj_lf || !obj_in || !obj_names) goto oom;
   1491   }
   1492   if (o->narchives) {
   1493     arch_lf = driver_alloc_zeroed(env, o->narchives * sizeof(*arch_lf));
   1494     arch_in = driver_alloc_zeroed(env, o->narchives * sizeof(*arch_in));
   1495     if (!arch_lf || !arch_in) goto oom;
   1496   }
   1497   if (o->ndsos) {
   1498     dso_lf = driver_alloc_zeroed(env, o->ndsos * sizeof(*dso_lf));
   1499     dso_in = driver_alloc_zeroed(env, o->ndsos * sizeof(*dso_in));
   1500     dso_names = driver_alloc_zeroed(env, o->ndsos * sizeof(*dso_names));
   1501     if (!dso_lf || !dso_in || !dso_names) goto oom;
   1502   }
   1503   if (o->nlink_items) {
   1504     order = driver_alloc_zeroed(env, o->nlink_items * sizeof(*order));
   1505     if (!order) goto oom;
   1506   }
   1507 
   1508   for (i = 0; i < o->nobject_files; ++i) {
   1509     if (driver_load_bytes(io, o->tool, o->object_files[i], &obj_lf[i],
   1510                           &obj_in[i]) != 0)
   1511       goto out;
   1512     obj_names[i] = kit_slice_cstr(o->object_files[i]);
   1513   }
   1514   for (i = 0; i < o->narchives; ++i) {
   1515     if (driver_load_bytes(io, o->tool, o->archives[i].path, &arch_lf[i],
   1516                           &arch_in[i].bytes) != 0)
   1517       goto out;
   1518     arch_in[i].name = kit_slice_cstr(o->archives[i].path);
   1519     arch_in[i].link_mode = o->archives[i].link_mode;
   1520     arch_in[i].whole_archive = o->archives[i].whole_archive ? true : false;
   1521     arch_in[i].group_id = o->archives[i].group_id;
   1522   }
   1523   for (i = 0; i < o->ndsos; ++i) {
   1524     if (driver_load_bytes(io, o->tool, o->dsos[i].path, &dso_lf[i],
   1525                           &dso_in[i]) != 0)
   1526       goto out;
   1527     dso_names[i] = kit_slice_cstr(o->dsos[i].path);
   1528   }
   1529   if (o->link.linker_script) {
   1530     KitSlice dummy;
   1531     if (driver_load_bytes(io, o->tool, o->link.linker_script, &script_lf,
   1532                           &dummy) != 0)
   1533       goto out;
   1534   }
   1535 
   1536   if (script_lf.loaded) {
   1537     KitSlice text = {.s = (const char*)script_lf.fd.data,
   1538                      .len = script_lf.fd.size};
   1539     if (kit_link_script_parse(ctx, text, &script) != KIT_OK) goto out;
   1540   }
   1541 
   1542   {
   1543     memset(&lto_batch, 0, sizeof lto_batch);
   1544     lto_batch.output_kind = output_kind == KIT_LINK_OUTPUT_SHARED
   1545                                 ? KIT_CG_OUTPUT_SHARED
   1546                                 : KIT_CG_OUTPUT_EXECUTABLE;
   1547     lto_batch.interposition_policy =
   1548         output_kind == KIT_LINK_OUTPUT_SHARED
   1549             ? KIT_CG_INTERPOSITION_DEFAULT_VISIBILITY
   1550             : KIT_CG_INTERPOSITION_DEFAULT;
   1551     lto_batch.defer_lto_finish = 1;
   1552     if (build_compile_all(o, compiler, ctx, code, diag, objs, source_obj_index,
   1553                           source_order_keep, &lto_batch, &pending_lto,
   1554                           &nobjs) != 0)
   1555       goto out;
   1556   }
   1557 
   1558   if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0)
   1559     goto out;
   1560 
   1561   /* Translate the recorded link order into KitLinkInputOrder. */
   1562   for (i = 0; i < o->nlink_items; ++i) {
   1563     const BuildLinkItem* item = &o->link_items[i];
   1564     KitLinkInputOrder* ord;
   1565     switch ((BuildLinkKind)item->kind) {
   1566       case BUILD_LINK_SOURCE:
   1567         if (!source_order_keep[item->index]) continue;
   1568         ord = &order[norder++];
   1569         ord->kind = KIT_LINK_INPUT_OBJ;
   1570         ord->index = source_obj_index[item->index];
   1571         break;
   1572       case BUILD_LINK_OBJECT:
   1573         ord = &order[norder++];
   1574         ord->kind = KIT_LINK_INPUT_OBJ_BYTES;
   1575         ord->index = item->index;
   1576         break;
   1577       case BUILD_LINK_ARCHIVE:
   1578         ord = &order[norder++];
   1579         ord->kind = KIT_LINK_INPUT_ARCHIVE;
   1580         ord->index = item->index;
   1581         break;
   1582       case BUILD_LINK_DSO:
   1583         ord = &order[norder++];
   1584         ord->kind = KIT_LINK_INPUT_DSO;
   1585         ord->index = item->index;
   1586         break;
   1587       case BUILD_LINK_LIB: {
   1588         const BuildPendingLib* pl = &o->pending_libs[item->index];
   1589         ord = &order[norder++];
   1590         if (pl->resolved_kind == BUILD_LINK_DSO) {
   1591           ord->kind = KIT_LINK_INPUT_DSO;
   1592           ord->index = pl->resolved_index;
   1593         } else {
   1594           ord->kind = KIT_LINK_INPUT_ARCHIVE;
   1595           ord->index = pl->resolved_index;
   1596         }
   1597         break;
   1598       }
   1599     }
   1600   }
   1601 
   1602   {
   1603     KitLinkSessionOptions lopts;
   1604     DriverLinkInputs li;
   1605     KitStatus st;
   1606     if (driver_link_flags_fill_options(
   1607             &o->link, o->target, o->pie, o->shared,
   1608             output_kind == KIT_LINK_OUTPUT_RELOCATABLE, output_kind, script,
   1609             &lopts, &rpath_slices) != 0)
   1610       goto out;
   1611     memset(&li, 0, sizeof(li));
   1612     li.objs = objs;
   1613     li.nobjs = nobjs;
   1614     li.obj_names = obj_names;
   1615     li.obj_bytes = obj_in;
   1616     li.nobj_bytes = o->nobject_files;
   1617     li.archives = arch_in;
   1618     li.narchives = o->narchives;
   1619     li.dso_names = dso_names;
   1620     li.dso_bytes = dso_in;
   1621     li.ndsos = o->ndsos;
   1622     li.order = order;
   1623     li.norder = norder;
   1624     st = driver_link_engine_emit_with_lto(compiler, &lopts, &li, &pending_lto,
   1625                                           &lto_batch, out_w);
   1626     rc = (st == KIT_OK) ? 0 : 1;
   1627   }
   1628 
   1629 out:
   1630   if (out_w) kit_writer_close(out_w);
   1631   if (rc == 0 && output_kind == KIT_LINK_OUTPUT_EXE &&
   1632       !driver_streq(o->output_path, "-")) {
   1633     if (driver_mark_executable_output(o->output_path) != 0) {
   1634       driver_errf(o->tool, "failed to set executable mode: %.*s",
   1635                   KIT_SLICE_ARG(kit_slice_cstr(o->output_path)));
   1636       rc = 1;
   1637     }
   1638   }
   1639   if (script) kit_link_script_free(ctx, script);
   1640   driver_compile_pending_lto_abort(&pending_lto);
   1641   driver_link_flags_free_rpath_slices(&o->link, rpath_slices);
   1642   driver_release_bytes(io, &script_lf);
   1643   if (arch_lf)
   1644     for (i = 0; i < o->narchives; ++i) driver_release_bytes(io, &arch_lf[i]);
   1645   if (dso_lf)
   1646     for (i = 0; i < o->ndsos; ++i) driver_release_bytes(io, &dso_lf[i]);
   1647   if (obj_lf)
   1648     for (i = 0; i < o->nobject_files; ++i) driver_release_bytes(io, &obj_lf[i]);
   1649   if (arch_in) driver_free(env, arch_in, o->narchives * sizeof(*arch_in));
   1650   if (arch_lf) driver_free(env, arch_lf, o->narchives * sizeof(*arch_lf));
   1651   if (dso_in) driver_free(env, dso_in, o->ndsos * sizeof(*dso_in));
   1652   if (dso_names) driver_free(env, dso_names, o->ndsos * sizeof(*dso_names));
   1653   if (dso_lf) driver_free(env, dso_lf, o->ndsos * sizeof(*dso_lf));
   1654   if (order) driver_free(env, order, o->nlink_items * sizeof(*order));
   1655   if (obj_in) driver_free(env, obj_in, o->nobject_files * sizeof(*obj_in));
   1656   if (obj_names)
   1657     driver_free(env, obj_names, o->nobject_files * sizeof(*obj_names));
   1658   if (obj_lf) driver_free(env, obj_lf, o->nobject_files * sizeof(*obj_lf));
   1659   /* The link session borrows the per-source builders (it frees only its own
   1660    * pointer array), so the caller still owns and must release them. */
   1661   if (objs) {
   1662     for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]);
   1663     driver_free(env, objs, o->nsources * sizeof(*objs));
   1664   }
   1665   if (source_order_keep)
   1666     driver_free(env, source_order_keep,
   1667                 o->nsources * sizeof(*source_order_keep));
   1668   if (source_obj_index)
   1669     driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index));
   1670   return rc;
   1671 
   1672 oom:
   1673   driver_errf(o->tool, "out of memory");
   1674   goto out;
   1675 }
   1676 
   1677 /* build-obj multi-source: combine into one relocatable object (ld -r). */
   1678 static int build_run_relocatable(BuildOptions* o, KitCompiler* compiler,
   1679                                  const KitContext* ctx,
   1680                                  const KitCodeOptions* code,
   1681                                  const KitDiagnosticOptions* diag) {
   1682   DriverEnv* env = o->env;
   1683   KitObjBuilder** objs = NULL;
   1684   uint32_t* source_obj_index = NULL;
   1685   uint8_t* source_order_keep = NULL;
   1686   KitLinkInputOrder* order = NULL;
   1687   DriverCompilePendingLto pending_lto = {0};
   1688   KitWriter* out_w = NULL;
   1689   DriverCompileBatchOptions lto_batch;
   1690   uint32_t nobjs = 0;
   1691   uint32_t norder = 0;
   1692   uint32_t i;
   1693   int rc = 1;
   1694 
   1695   objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs));
   1696   source_obj_index =
   1697       driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index));
   1698   source_order_keep =
   1699       driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep));
   1700   order = driver_alloc_zeroed(env, o->nsources * sizeof(*order));
   1701   if (!objs || !source_obj_index || !source_order_keep || !order) {
   1702     driver_errf(o->tool, "out of memory");
   1703     goto out;
   1704   }
   1705   {
   1706     memset(&lto_batch, 0, sizeof lto_batch);
   1707     lto_batch.output_kind = KIT_CG_OUTPUT_RELOCATABLE;
   1708     lto_batch.interposition_policy = KIT_CG_INTERPOSITION_DEFAULT;
   1709     lto_batch.defer_lto_finish = 1;
   1710     if (build_compile_all(o, compiler, ctx, code, diag, objs, source_obj_index,
   1711                           source_order_keep, &lto_batch, &pending_lto,
   1712                           &nobjs) != 0)
   1713       goto out;
   1714   }
   1715   for (i = 0; i < o->nsources; ++i) {
   1716     if (!source_order_keep[i]) continue;
   1717     order[norder].kind = KIT_LINK_INPUT_OBJ;
   1718     order[norder].index = source_obj_index[i];
   1719     ++norder;
   1720   }
   1721   if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0)
   1722     goto out;
   1723   {
   1724     KitLinkSessionOptions lopts;
   1725     DriverLinkInputs li;
   1726     KitStatus st;
   1727     memset(&lopts, 0, sizeof(lopts));
   1728     lopts.output_kind = KIT_LINK_OUTPUT_RELOCATABLE;
   1729     lopts.allow_undefined = 1;
   1730     lopts.strip_debug = o->link.strip_debug ? true : false;
   1731     memset(&li, 0, sizeof(li));
   1732     li.objs = objs;
   1733     li.nobjs = nobjs;
   1734     li.order = order;
   1735     li.norder = norder;
   1736     st = driver_link_engine_emit_with_lto(compiler, &lopts, &li, &pending_lto,
   1737                                           &lto_batch, out_w);
   1738     rc = (st == KIT_OK) ? 0 : 1;
   1739   }
   1740 
   1741 out:
   1742   if (out_w) kit_writer_close(out_w);
   1743   driver_compile_pending_lto_abort(&pending_lto);
   1744   if (order) driver_free(env, order, o->nsources * sizeof(*order));
   1745   /* The link session borrows the builders; release them here (see
   1746    * build_run_link). */
   1747   if (objs) {
   1748     for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]);
   1749     driver_free(env, objs, o->nsources * sizeof(*objs));
   1750   }
   1751   if (source_order_keep)
   1752     driver_free(env, source_order_keep,
   1753                 o->nsources * sizeof(*source_order_keep));
   1754   if (source_obj_index)
   1755     driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index));
   1756   return rc;
   1757 }
   1758 
   1759 /* build-obj wasm multi-source: merge all inputs into one .wasm via CG merge. */
   1760 static int build_run_wasm_module(BuildOptions* o, KitCompiler* compiler,
   1761                                  const KitContext* ctx,
   1762                                  const KitCodeOptions* code,
   1763                                  const KitDiagnosticOptions* diag) {
   1764   DriverEnv* env = o->env;
   1765   KitObjBuilder** objs = NULL;
   1766   uint32_t* source_obj_index = NULL;
   1767   uint8_t* source_order_keep = NULL;
   1768   KitWriter* out_w = NULL;
   1769   KitCodeOptions code2 = *code;
   1770   uint32_t nobjs = 0;
   1771   uint32_t i;
   1772   int rc = 1;
   1773 
   1774   code2.lto = true;
   1775 
   1776   objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs));
   1777   source_obj_index =
   1778       driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index));
   1779   source_order_keep =
   1780       driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep));
   1781   if (!objs || !source_obj_index || !source_order_keep) {
   1782     driver_errf(o->tool, "out of memory");
   1783     goto out;
   1784   }
   1785   {
   1786     DriverCompileBatchOptions batch;
   1787     memset(&batch, 0, sizeof batch);
   1788     batch.output_kind = KIT_CG_OUTPUT_RELOCATABLE;
   1789     batch.interposition_policy = KIT_CG_INTERPOSITION_DEFAULT;
   1790     if (build_compile_all(o, compiler, ctx, &code2, diag, objs, source_obj_index,
   1791                           source_order_keep, &batch, NULL, &nobjs) != 0)
   1792       goto out;
   1793   }
   1794   if (nobjs != 1) {
   1795     driver_errf(o->tool,
   1796                 "build-obj: wasm multi-input expects a single merged module");
   1797     goto out;
   1798   }
   1799   if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0)
   1800     goto out;
   1801   rc = (kit_obj_builder_emit(objs[0], out_w) == KIT_OK) ? 0 : 1;
   1802 
   1803 out:
   1804   if (out_w) kit_writer_close(out_w);
   1805   if (objs) {
   1806     for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]);
   1807     driver_free(env, objs, o->nsources * sizeof(*objs));
   1808   }
   1809   if (source_order_keep)
   1810     driver_free(env, source_order_keep,
   1811                 o->nsources * sizeof(*source_order_keep));
   1812   if (source_obj_index)
   1813     driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index));
   1814   return rc;
   1815 }
   1816 
   1817 /* build-exe wasm: merge all sources into one .wasm with DCE/internalization. */
   1818 static int build_run_wasm_exe(BuildOptions* o, KitCompiler* compiler,
   1819                               const KitContext* ctx,
   1820                               const KitCodeOptions* code,
   1821                               const KitDiagnosticOptions* diag) {
   1822   DriverEnv* env = o->env;
   1823   KitObjBuilder** objs = NULL;
   1824   uint32_t* source_obj_index = NULL;
   1825   uint8_t* source_order_keep = NULL;
   1826   DriverCompilePendingLto pending_lto = {0};
   1827   KitWriter* out_w = NULL;
   1828   KitCodeOptions code2 = *code;
   1829   uint32_t nobjs = 0;
   1830   uint32_t i;
   1831   int rc = 1;
   1832 
   1833   code2.lto = true;
   1834 
   1835   objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs));
   1836   source_obj_index =
   1837       driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index));
   1838   source_order_keep =
   1839       driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep));
   1840   if (!objs || !source_obj_index || !source_order_keep) {
   1841     driver_errf(o->tool, "out of memory");
   1842     goto out;
   1843   }
   1844   {
   1845     DriverCompileBatchOptions batch;
   1846     memset(&batch, 0, sizeof batch);
   1847     batch.output_kind = KIT_CG_OUTPUT_EXECUTABLE;
   1848     batch.interposition_policy = KIT_CG_INTERPOSITION_NONE;
   1849     batch.defer_lto_finish = 1;
   1850     if (build_compile_all(o, compiler, ctx, &code2, diag, objs,
   1851                           source_obj_index, source_order_keep,
   1852                           &batch, &pending_lto, &nobjs) != 0)
   1853       goto out;
   1854   }
   1855   if (nobjs != 1) {
   1856     driver_errf(o->tool, "build-exe: wasm expects a single merged module");
   1857     goto out;
   1858   }
   1859   {
   1860     const char* entry_name = o->link.entry ? o->link.entry : "main";
   1861     KitSym entry_interned =
   1862         kit_sym_intern(compiler, kit_slice_cstr(entry_name));
   1863     KitObjSymbol entry_sym = KIT_OBJ_SYMBOL_NONE;
   1864     DriverCompileBatchOptions batch2;
   1865     KitCgSym csym;
   1866 
   1867     if (!entry_interned ||
   1868         kit_obj_builder_find_symbol(pending_lto.obj, entry_interned,
   1869                                     &entry_sym) != KIT_OK) {
   1870       driver_errf(o->tool,
   1871                   "build-exe: entry symbol '%s' not found in module",
   1872                   entry_name);
   1873       goto out;
   1874     }
   1875     csym = (KitCgSym)entry_sym;
   1876     memset(&batch2, 0, sizeof batch2);
   1877     batch2.output_kind = KIT_CG_OUTPUT_EXECUTABLE;
   1878     batch2.interposition_policy = KIT_CG_INTERPOSITION_NONE;
   1879     if (driver_compile_pending_lto_finish(&pending_lto, &batch2,
   1880                                           &csym, 1) != KIT_OK) {
   1881       driver_errf(o->tool, "build-exe: LTO finish failed");
   1882       goto out;
   1883     }
   1884     kit_obj_builder_wasm_add_custom(objs[0], KIT_SLICE_LIT("kit-entry"),
   1885                                     kit_slice_cstr(entry_name));
   1886   }
   1887   if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0)
   1888     goto out;
   1889   rc = (kit_obj_builder_emit(objs[0], out_w) == KIT_OK) ? 0 : 1;
   1890 
   1891 out:
   1892   if (out_w) kit_writer_close(out_w);
   1893   if (pending_lto.active) driver_compile_pending_lto_abort(&pending_lto);
   1894   if (objs) {
   1895     for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]);
   1896     driver_free(env, objs, o->nsources * sizeof(*objs));
   1897   }
   1898   if (source_order_keep)
   1899     driver_free(env, source_order_keep,
   1900                 o->nsources * sizeof(*source_order_keep));
   1901   if (source_obj_index)
   1902     driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index));
   1903   return rc;
   1904 }
   1905 
   1906 /* build-lib static: archive every compiled source object. */
   1907 static int build_run_archive(BuildOptions* o, KitCompiler* compiler,
   1908                              const KitContext* ctx, const KitCodeOptions* code,
   1909                              const KitDiagnosticOptions* diag) {
   1910   DriverEnv* env = o->env;
   1911   KitObjBuilder** objs = NULL;
   1912   uint32_t* source_obj_index = NULL;
   1913   uint8_t* source_order_keep = NULL;
   1914   KitSlice* names = NULL;
   1915   char** owned_names = NULL;
   1916   size_t* owned_name_sizes = NULL;
   1917   KitWriter* out_w = NULL;
   1918   uint32_t nobjs = 0;
   1919   uint32_t i;
   1920   int rc = 1;
   1921 
   1922   objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs));
   1923   source_obj_index =
   1924       driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index));
   1925   source_order_keep =
   1926       driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep));
   1927   names = driver_alloc_zeroed(env, o->nsources * sizeof(*names));
   1928   owned_names = driver_alloc_zeroed(env, o->nsources * sizeof(*owned_names));
   1929   owned_name_sizes =
   1930       driver_alloc_zeroed(env, o->nsources * sizeof(*owned_name_sizes));
   1931   if (!objs || !source_obj_index || !source_order_keep || !names ||
   1932       !owned_names || !owned_name_sizes) {
   1933     driver_errf(o->tool, "out of memory");
   1934     goto out;
   1935   }
   1936   {
   1937     DriverCompileBatchOptions batch;
   1938     memset(&batch, 0, sizeof batch);
   1939     batch.output_kind = KIT_CG_OUTPUT_ARCHIVE_MEMBER;
   1940     batch.interposition_policy = KIT_CG_INTERPOSITION_DEFAULT;
   1941     if (build_compile_all(o, compiler, ctx, code, diag, objs, source_obj_index,
   1942                           source_order_keep, &batch, NULL, &nobjs) != 0)
   1943       goto out;
   1944   }
   1945   /* build-lib always emits objects (validated), so build_default_obj_name
   1946    * yields the right `.o`/`.obj` member name. */
   1947   for (i = 0; i < o->nsources; ++i) {
   1948     uint32_t oi;
   1949     if (!source_order_keep[i]) continue;
   1950     oi = source_obj_index[i];
   1951     owned_names[oi] = build_default_obj_name(env, o, o->sources[i].path,
   1952                                              &owned_name_sizes[oi]);
   1953     if (!owned_names[oi]) {
   1954       driver_errf(o->tool, "out of memory");
   1955       goto out;
   1956     }
   1957     names[oi] = kit_slice_cstr(owned_names[oi]);
   1958   }
   1959   if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0)
   1960     goto out;
   1961   rc = driver_archive_emit(env, ctx, o->tool, objs, names, nobjs, o->epoch,
   1962                            out_w);
   1963 
   1964 out:
   1965   if (out_w) kit_writer_close(out_w);
   1966   if (objs)
   1967     for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]);
   1968   if (owned_names) {
   1969     for (i = 0; i < o->nsources; ++i)
   1970       if (owned_names[i]) driver_free(env, owned_names[i], owned_name_sizes[i]);
   1971   }
   1972   if (objs) driver_free(env, objs, o->nsources * sizeof(*objs));
   1973   if (source_order_keep)
   1974     driver_free(env, source_order_keep,
   1975                 o->nsources * sizeof(*source_order_keep));
   1976   if (source_obj_index)
   1977     driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index));
   1978   if (names) driver_free(env, names, o->nsources * sizeof(*names));
   1979   if (owned_names)
   1980     driver_free(env, owned_names, o->nsources * sizeof(*owned_names));
   1981   if (owned_name_sizes)
   1982     driver_free(env, owned_name_sizes, o->nsources * sizeof(*owned_name_sizes));
   1983   return rc;
   1984 }
   1985 
   1986 /* build-obj per-source: check-only, or one output per source (obj/asm/c/ir). */
   1987 static int build_run_per_source(BuildOptions* o, KitCompiler* compiler,
   1988                                 const KitContext* ctx,
   1989                                 const KitCodeOptions* code_in,
   1990                                 const KitDiagnosticOptions* diag) {
   1991   DriverEnv* env = o->env;
   1992   KitCodeOptions code = *code_in;
   1993   uint32_t i;
   1994 
   1995   code.emit_asm_source = (o->emit == BUILD_EMIT_ASM) ? true : false;
   1996   code.emit_c_source = (o->emit == BUILD_EMIT_C) ? true : false;
   1997   code.emit_ir = (o->emit == BUILD_EMIT_IR) ? true : false;
   1998 
   1999   for (i = 0; i < o->nsources; ++i) {
   2000     if (o->syntax_only) {
   2001       KitObjBuilder* ob = NULL;
   2002       int rc =
   2003           build_compile_source(o, compiler, ctx, i, &code, diag, NULL, &ob);
   2004       kit_obj_builder_free(ob);
   2005       if (rc != 0) return rc;
   2006       continue;
   2007     }
   2008     {
   2009       const char* out_path = o->output_path;
   2010       char* owned = NULL;
   2011       size_t owned_size = 0;
   2012       KitWriter* w = NULL;
   2013       int rc;
   2014       if (!out_path) {
   2015         owned = build_default_obj_name(env, o, o->sources[i].path, &owned_size);
   2016         if (!owned) {
   2017           driver_errf(o->tool, "out of memory");
   2018           return 1;
   2019         }
   2020         out_path = owned;
   2021       }
   2022       if (build_open_output(ctx, env, o->tool, out_path, &w) != 0) {
   2023         if (owned) driver_free(env, owned, owned_size);
   2024         return 1;
   2025       }
   2026       rc = build_compile_source(o, compiler, ctx, i, &code, diag, w, NULL);
   2027       kit_writer_close(w);
   2028       if (owned) driver_free(env, owned, owned_size);
   2029       if (rc != 0) return rc;
   2030     }
   2031   }
   2032   return 0;
   2033 }
   2034 
   2035 /* ===================================================================== */
   2036 /* validation                                                             */
   2037 /* ===================================================================== */
   2038 
   2039 static int build_validate(BuildOptions* o) {
   2040   uint32_t total_link =
   2041       o->nobject_files + o->narchives + o->ndsos + o->npending_libs;
   2042 
   2043   if (o->nsources == 0 && total_link == 0) {
   2044     driver_errf(o->tool, "no input files");
   2045     return 1;
   2046   }
   2047 
   2048   /* -dynamic selects the default executable link mode for build-exe and the
   2049    * not-yet-supported shared-library mode for build-lib. -shared is the GCC
   2050    * spelling for producing a shared library, so build-exe rejects it. */
   2051 
   2052   if (o->kind == BUILD_OUT_EXE) {
   2053     if (o->shared_requested) {
   2054       driver_errf(o->tool, "-shared is not valid for build-exe");
   2055       return 1;
   2056     }
   2057     if (o->emit != BUILD_EMIT_OBJ || o->syntax_only) {
   2058       driver_errf(o->tool, "--emit/-S/-fsyntax-only are build-obj options");
   2059       return 1;
   2060     }
   2061     if (!o->output_path) {
   2062       o->output_path = (o->target.obj == KIT_OBJ_WASM)
   2063                            ? "a.wasm"
   2064                            : driver_default_exe_name(o->target);
   2065     }
   2066     if (o->target.obj == KIT_OBJ_WASM) {
   2067       uint32_t total_link =
   2068           o->nobject_files + o->narchives + o->ndsos + o->npending_libs;
   2069       if (total_link) {
   2070         driver_errf(o->tool,
   2071                     "build-exe -target wasm32-none accepts only source files "
   2072                     "(no .o / .a / -l inputs)");
   2073         return 1;
   2074       }
   2075     }
   2076     return 0;
   2077   }
   2078 
   2079   if (o->kind == BUILD_OUT_LIB) {
   2080     if (o->dynamic) {
   2081       driver_errf(o->tool,
   2082                   "creating dynamic/shared libraries is not yet supported; "
   2083                   "build-lib produces a static .a");
   2084       return 1;
   2085     }
   2086     if (o->emit != BUILD_EMIT_OBJ || o->syntax_only) {
   2087       driver_errf(o->tool, "--emit/-S/-fsyntax-only are build-obj options");
   2088       return 1;
   2089     }
   2090     if (total_link != 0) {
   2091       driver_errf(o->tool,
   2092                   "build-lib takes only sources; pass .o/.a/-l to build-exe");
   2093       return 1;
   2094     }
   2095     if (o->nsources == 0) {
   2096       driver_errf(o->tool, "no source files");
   2097       return 1;
   2098     }
   2099     if (!o->output_path) {
   2100       driver_errf(o->tool, "-o is required (no default library name)");
   2101       return 1;
   2102     }
   2103     return 0;
   2104   }
   2105 
   2106   /* build-obj */
   2107   if (total_link != 0) {
   2108     driver_errf(o->tool,
   2109                 "build-obj takes only sources; pass .o/.a/-l to build-exe");
   2110     return 1;
   2111   }
   2112   if (o->nsources == 0) {
   2113     driver_errf(o->tool, "no source files");
   2114     return 1;
   2115   }
   2116   if (o->dynamic) {
   2117     driver_errf(o->tool, "-dynamic/-shared is only valid for build-lib");
   2118     return 1;
   2119   }
   2120   if (o->syntax_only) {
   2121     if (o->output_path) {
   2122       driver_errf(o->tool, "-o is incompatible with -fsyntax-only");
   2123       return 1;
   2124     }
   2125     return 0;
   2126   }
   2127   if (o->emit == BUILD_EMIT_IR && o->opt_level < 1) {
   2128     driver_errf(o->tool,
   2129                 "--emit=ir requires -O1 or higher (the IR tape is only "
   2130                 "recorded when the optimizer runs)");
   2131     return 1;
   2132   }
   2133   if (o->emit == BUILD_EMIT_OBJ && o->nsources > 1) {
   2134     /* relocatable combine */
   2135     if (!o->output_path) {
   2136       driver_errf(o->tool,
   2137                   "-o is required to combine multiple sources into one object");
   2138       return 1;
   2139     }
   2140     return 0;
   2141   }
   2142   /* per-source emit (single obj, or asm/c/ir) */
   2143   if (o->output_path && o->nsources > 1) {
   2144     driver_errf(o->tool, "-o cannot be used with multiple sources");
   2145     return 1;
   2146   }
   2147   if (o->emit == BUILD_EMIT_C && !o->output_path) {
   2148     driver_errf(o->tool, "--emit=c requires -o");
   2149     return 1;
   2150   }
   2151   return 0;
   2152 }
   2153 
   2154 /* ===================================================================== */
   2155 /* driver                                                                 */
   2156 /* ===================================================================== */
   2157 
   2158 static int build_apply_env(BuildOptions* o) {
   2159   const char* sde = driver_getenv("SOURCE_DATE_EPOCH");
   2160   if (sde && build_parse_u64(sde, &o->epoch) != 0) {
   2161     driver_errf(o->tool, "invalid SOURCE_DATE_EPOCH: %.*s",
   2162                 KIT_SLICE_ARG(kit_slice_cstr(sde)));
   2163     return 1;
   2164   }
   2165   return 0;
   2166 }
   2167 
   2168 static int build_main(int argc, char** argv, int kind, const char* tool) {
   2169   DriverEnv env;
   2170   BuildOptions o = {0};
   2171   DriverRuntimeSupport runtime = {0};
   2172   int runtime_resolved = 0;
   2173   KitContext ctx;
   2174   KitTarget* target = NULL;
   2175   KitCompiler* compiler = NULL;
   2176   KitCodeOptions code;
   2177   KitDiagnosticOptions diag = {0};
   2178   uint32_t gi;
   2179   int rc = 2;
   2180 
   2181   driver_env_init(&env);
   2182   o.env = &env;
   2183   o.tool = tool;
   2184   o.kind = kind;
   2185   o.driver_path = argv[0];
   2186 
   2187   if (build_alloc(&o, argc) != 0) {
   2188     rc = 2;
   2189     goto done;
   2190   }
   2191   if (build_parse(argc, argv, &o) != 0) goto done;
   2192   if (build_apply_env(&o) != 0) goto done;
   2193 
   2194   o.shared = (o.kind == BUILD_OUT_LIB && o.dynamic);
   2195   if (o.shared && o.target.pic == KIT_PIC_NONE) o.target.pic = KIT_PIC_PIC;
   2196 
   2197   if (build_validate(&o) != 0) goto done;
   2198 
   2199   /* Freestanding runtime headers so C/asm #includes resolve (mirrors compile);
   2200    * for link outputs, also the runtime archive + hosted libc wiring. */
   2201   if (driver_runtime_resolve(&env, o.support_dir, o.driver_path, &runtime) ==
   2202       0) {
   2203     runtime_resolved = 1;
   2204     if (driver_runtime_add_freestanding_headers(&runtime, &o.groups[0].cf) !=
   2205         0) {
   2206       driver_errf(tool, "failed to add freestanding headers");
   2207       rc = 1;
   2208       goto done;
   2209     }
   2210   } else {
   2211     driver_errf(tool, "support dir not found");
   2212     rc = 1;
   2213     goto done;
   2214   }
   2215 
   2216   if (build_is_link_output(&o)) {
   2217     if (build_append_windows_lib_dirs(&o) != 0) {
   2218       rc = 1;
   2219       goto done;
   2220     }
   2221     build_enable_hosted_for_sysroot(&o);
   2222     build_apply_default_hosted_profile(&o);
   2223     if (build_apply_hosted_profile(&o) != 0) {
   2224       rc = 1;
   2225       goto done;
   2226     }
   2227     if (build_resolve_pending_libs(&o) != 0) {
   2228       rc = 1;
   2229       goto done;
   2230     }
   2231     if (!o.no_stdlib && !o.no_defaultlibs) {
   2232       DriverRuntimeArchive rt = {0};
   2233       uint32_t insert_pos;
   2234       if (driver_runtime_prepare_archive(&env, tool, &runtime, o.target,
   2235                                          o.epoch, &rt) != 0) {
   2236         driver_runtime_archive_fini(&env, &rt);
   2237         rc = 1;
   2238         goto done;
   2239       }
   2240       insert_pos = o.nlink_items;
   2241       if (o.hosted.nfinal <= insert_pos) insert_pos -= o.hosted.nfinal;
   2242       build_insert_runtime_archive(&o, &rt, insert_pos);
   2243       driver_runtime_archive_fini(&env, &rt);
   2244     }
   2245   } else if (o.npending_libs) {
   2246     driver_errf(tool, "-l is only valid for build-exe");
   2247     rc = 1;
   2248     goto done;
   2249   }
   2250 
   2251   /* Build per-group merged preprocessor views now that the global baseline
   2252    * (groups[0]) holds the runtime/hosted includes and defines. */
   2253   for (gi = 0; gi < o.ngroups; ++gi) {
   2254     if (build_group_build_pp(&o, gi) != 0) {
   2255       rc = 1;
   2256       goto done;
   2257     }
   2258   }
   2259 
   2260   ctx = driver_env_to_context(&env);
   2261   if (driver_target_new(&ctx, o.target, &o.target_features, tool, &target) !=
   2262           KIT_OK ||
   2263       driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
   2264     driver_errf(tool, "failed to initialize compiler");
   2265     rc = 1;
   2266     goto done;
   2267   }
   2268 
   2269   build_fill_code(&o, &code);
   2270   diag.warnings_are_errors = o.warnings_are_errors ? true : false;
   2271   diag.max_errors = o.max_errors;
   2272 
   2273   if (o.kind == BUILD_OUT_EXE) {
   2274     if (o.target.obj == KIT_OBJ_WASM)
   2275       rc = build_run_wasm_exe(&o, compiler, &ctx, &code, &diag);
   2276     else
   2277       rc = build_run_link(&o, compiler, &ctx, &code, &diag, KIT_LINK_OUTPUT_EXE);
   2278   } else if (o.kind == BUILD_OUT_LIB) {
   2279     rc = o.shared ? build_run_link(&o, compiler, &ctx, &code, &diag,
   2280                                    KIT_LINK_OUTPUT_SHARED)
   2281                   : build_run_archive(&o, compiler, &ctx, &code, &diag);
   2282   } else if (o.syntax_only) {
   2283     rc = build_run_per_source(&o, compiler, &ctx, &code, &diag);
   2284   } else if (o.emit == BUILD_EMIT_OBJ && o.nsources > 1 &&
   2285              o.target.obj == KIT_OBJ_WASM) {
   2286     rc = build_run_wasm_module(&o, compiler, &ctx, &code, &diag);
   2287   } else if (o.emit == BUILD_EMIT_OBJ && o.nsources > 1) {
   2288     rc = build_run_relocatable(&o, compiler, &ctx, &code, &diag);
   2289   } else {
   2290     rc = build_run_per_source(&o, compiler, &ctx, &code, &diag);
   2291   }
   2292 
   2293 done:
   2294   if (compiler) driver_compiler_free(compiler);
   2295   kit_target_free(target);
   2296   if (runtime_resolved) driver_runtime_support_fini(&env, &runtime);
   2297   build_release(&o);
   2298   driver_env_fini(&env);
   2299   return rc;
   2300 }
   2301 
   2302 /* ===================================================================== */
   2303 /* help + entry points                                                    */
   2304 /* ===================================================================== */
   2305 
   2306 void driver_help_build_exe(void) {
   2307   driver_printf(
   2308       "%.*s",
   2309       KIT_SLICE_ARG(KIT_SLICE_LIT(
   2310           "kit build-exe — link a polyglot source set into an executable\n"
   2311           "\n"
   2312           "USAGE\n"
   2313           "  kit build-exe [options] inputs...\n"
   2314           "\n"
   2315           "DESCRIPTION\n"
   2316           "  Compiles C / asm / toy / wasm sources (language per file) in\n"
   2317           "  memory and links them with any .o/.a/.so inputs into one\n"
   2318           "  executable. No intermediate files.\n"
   2319           "\n"
   2320           "OPTIONS (selection)\n"
   2321           "  -o PATH               Output (default a.out / a.exe)\n"
   2322           "  -O0 -O1 -O2  -g       Optimization / debug info\n"
   2323           "  -target TRIPLE        Cross-compile target\n"
   2324           "  -flto                 Link-time optimization for source inputs\n"
   2325           "  -static               Fully static executable\n"
   2326           "  -l NAME  -L DIR       Link a library / add a search dir\n"
   2327           "  -e SYM  -T script.ld  Entry symbol / linker script\n"
   2328           "  -Wl,...               Linker pass-through\n"
   2329           "  --group [flags] -- sources...   Scope compile flags to sources\n"
   2330           "  -X<lang> FLAG         Per-language frontend flag "
   2331           "(c|asm|toy|wasm)\n"
   2332           "  -h, --help            Show this help\n")));
   2333 }
   2334 
   2335 void driver_help_build_lib(void) {
   2336   driver_printf(
   2337       "%.*s",
   2338       KIT_SLICE_ARG(KIT_SLICE_LIT(
   2339           "kit build-lib — build a static library (.a)\n"
   2340           "\n"
   2341           "USAGE\n"
   2342           "  kit build-lib -o LIB.a [options] sources...\n"
   2343           "\n"
   2344           "DESCRIPTION\n"
   2345           "  Compiles a polyglot source set in memory and archives the "
   2346           "objects\n"
   2347           "  into a static library (.a) with a symbol index. Dynamic/shared\n"
   2348           "  libraries are not yet supported.\n"
   2349           "\n"
   2350           "OPTIONS (selection)\n"
   2351           "  -o PATH               Output archive (required)\n"
   2352           "  -fPIC                 Position-independent code\n"
   2353           "  -O0 -O1 -O2  -g       Optimization / debug info\n"
   2354           "  -flto                 Link-time optimization for source inputs\n"
   2355           "  -target TRIPLE        Cross-compile target\n"
   2356           "  --group [flags] -- sources...   Scope compile flags to sources\n"
   2357           "  -X<lang> FLAG         Per-language frontend flag "
   2358           "(c|asm|toy|wasm)\n"
   2359           "  -h, --help            Show this help\n")));
   2360 }
   2361 
   2362 void driver_help_build_obj(void) {
   2363   driver_printf(
   2364       "%.*s",
   2365       KIT_SLICE_ARG(KIT_SLICE_LIT(
   2366           "kit build-obj — compile sources to an object (or asm / C / IR)\n"
   2367           "\n"
   2368           "USAGE\n"
   2369           "  kit build-obj [options] sources...\n"
   2370           "\n"
   2371           "DESCRIPTION\n"
   2372           "  Compiles each source (C / asm / toy / wasm by suffix or -x) to "
   2373           "an\n"
   2374           "  object. Multiple sources with --emit=obj combine into one\n"
   2375           "  relocatable object (ld -r). The kit-native replacement for the\n"
   2376           "  retired `compile` tool.\n"
   2377           "\n"
   2378           "OPTIONS\n"
   2379           "  -o PATH               Output (default <base>.o; required for a\n"
   2380           "                        multi-source combine and for --emit=c)\n"
   2381           "  --emit=obj|asm|c|ir   Output form (ir requires -O1+)\n"
   2382           "  -S                    Alias for --emit=asm\n"
   2383           "  -fsyntax-only         Check only; write no output\n"
   2384           "  -O0 -O1 -O2  -g       Optimization / debug info\n"
   2385           "  -flto                 Link-time optimization for multi-source "
   2386           "obj\n"
   2387           "  -target TRIPLE        Cross-compile target\n"
   2388           "  -I/-isystem/-D/-U     Preprocessor flags (C/asm frontends)\n"
   2389           "  -x LANG               Force language: c | asm | toy | wasm\n"
   2390           "  --group [flags] -- sources...   Scope compile flags to sources\n"
   2391           "  -X<lang> FLAG         Per-language frontend flag "
   2392           "(c|asm|toy|wasm)\n"
   2393           "  -o -                  Write the emit to stdout\n"
   2394           "  -h, --help            Show this help\n")));
   2395 }
   2396 
   2397 int driver_build_exe(int argc, char** argv) {
   2398   if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
   2399     driver_help_build_exe();
   2400     return 0;
   2401   }
   2402   return build_main(argc, argv, BUILD_OUT_EXE, "build-exe");
   2403 }
   2404 
   2405 int driver_build_lib(int argc, char** argv) {
   2406   if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
   2407     driver_help_build_lib();
   2408     return 0;
   2409   }
   2410   return build_main(argc, argv, BUILD_OUT_LIB, "build-lib");
   2411 }
   2412 
   2413 int driver_build_obj(int argc, char** argv) {
   2414   if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
   2415     driver_help_build_obj();
   2416     return 0;
   2417   }
   2418   return build_main(argc, argv, BUILD_OUT_OBJ, "build-obj");
   2419 }