kit

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

cc.c (90641B)


      1 #include "c/c.h"
      2 
      3 #include <kit/asm_emit.h>
      4 #include <kit/compile.h>
      5 #include <kit/core.h>
      6 #include <kit/link.h>
      7 #include <kit/preprocess.h>
      8 #include <stdint.h>
      9 #include <string.h>
     10 
     11 #include "cflags.h"
     12 #include "compile_engine.h"
     13 #include "driver.h"
     14 #include "hosted.h"
     15 #include "lib_resolve.h"
     16 #include "link_engine.h"
     17 #include "link_flags.h"
     18 #include "runtime.h"
     19 
     20 /* `kit cc` — C compiler driver. With -c produces a single object;
     21  * without -c compiles all C sources, links any .o/.a inputs alongside, and
     22  * emits an executable. The flag surface is a GCC subset:
     23  *
     24  *   -c -E -o -O0/1/2 -g
     25  *   -fsyntax-only
     26  *   -I -isystem -D -U
     27  *   -M -MM -MD -MMD -MF -MT -MQ -MP
     28  *   -target TRIPLE
     29  *   -fPIC -fPIE -fpic -fpie -mcmodel=small|medium|large
     30  *   -Werror -fmax-errors=N
     31  *   --build-id=none|sha256|uuid|0xHEX
     32  *   -ffile-prefix-map=old=new
     33  *   SOURCE_DATE_EPOCH (env)
     34  *   -e symbol -T script.ld
     35  *   -static -pie -no-pie
     36  *   -l name -L dir
     37  *   -x c|asm|s|asm-cpp|S|wasm|wat
     38  *   - (stdin source)
     39  *   .c/.cc -> source; .o/.obj -> object inputs; .a -> archive inputs.
     40  *
     41  * Library resolution (-lfoo against -L paths) happens here and produces
     42  * concrete archive paths for libkit. */
     43 
     44 #define CC_TOOL "cc"
     45 
     46 /* Header-dependency emission mode (subset of GCC's -M family).
     47  *   M    — print all deps; do not compile.
     48  *   MM   — like M but skip <bracketed> includes.
     49  *   MD   — compile normally AND write all deps to a file.
     50  *   MMD  — like MD but skip <bracketed> includes.
     51  * MD/MMD currently require -c (single-source compile_obj_emit path). */
     52 typedef enum CcDepMode {
     53   CC_DEP_NONE = 0,
     54   CC_DEP_M,
     55   CC_DEP_MM,
     56   CC_DEP_MD,
     57   CC_DEP_MMD,
     58 } CcDepMode;
     59 
     60 typedef enum CcProbeKind {
     61   CC_PROBE_NONE = 0,
     62   CC_PROBE_PRINT_SEARCH_DIRS,
     63   CC_PROBE_PRINT_FILE_NAME,
     64   CC_PROBE_PRINT_PROG_NAME,
     65   CC_PROBE_PRINT_LIBGCC_FILE_NAME,
     66   CC_PROBE_PRINT_MULTI_OS_DIRECTORY,
     67   CC_PROBE_PRINT_RESOURCE_DIR,
     68   CC_PROBE_PRINT_SYSROOT,
     69   CC_PROBE_DUMPMACHINE,
     70   CC_PROBE_DUMPVERSION,
     71   CC_PROBE_DUMPSPECS,
     72 } CcProbeKind;
     73 
     74 typedef enum CcLinkItemKind {
     75   CC_LINK_SOURCE_FILE,
     76   CC_LINK_SOURCE_MEMORY,
     77   CC_LINK_OBJECT,
     78   CC_LINK_ARCHIVE,
     79   CC_LINK_DSO,
     80   CC_LINK_LIB,
     81 } CcLinkItemKind;
     82 
     83 typedef struct CcLinkItem {
     84   uint8_t kind; /* CcLinkItemKind */
     85   uint8_t pad[3];
     86   uint32_t index;
     87 } CcLinkItem;
     88 
     89 typedef struct CcArchiveInput {
     90   const char* path;
     91   int owned;
     92   size_t owned_size;
     93   uint8_t whole_archive;
     94   uint8_t link_mode;
     95   uint8_t group_id;
     96   uint8_t pad;
     97 } CcArchiveInput;
     98 
     99 typedef struct CcDsoInput {
    100   const char* path;
    101   int owned;
    102   size_t owned_size;
    103 } CcDsoInput;
    104 
    105 typedef struct CcPendingLib {
    106   const char* name;
    107   uint8_t whole_archive;
    108   uint8_t link_mode;
    109   uint8_t group_id;
    110   uint8_t resolved_kind; /* CcLinkItemKind: ARCHIVE or DSO */
    111   uint32_t resolved_index;
    112 } CcPendingLib;
    113 
    114 typedef struct CcOptions {
    115   DriverEnv* env;
    116   const char* driver_path;
    117   size_t argv_bound; /* upper bound on per-array list size */
    118 
    119   int compile_only;        /* -c               */
    120   int preprocess_only;     /* -E               */
    121   int syntax_only;         /* -fsyntax-only / check */
    122   int emit_c_source;       /* --emit=c         */
    123   int emit_ir;             /* --emit=ir        */
    124   int emit_asm_source;     /* -S               */
    125   int opt_level;           /* -O0/-O1/-O2      */
    126   int debug_info;          /* -g               */
    127   int function_sections;   /* -ffunction-sections */
    128   int data_sections;       /* -fdata-sections     */
    129   int lto;                 /* -flto/-fno-lto      */
    130   int warnings_are_errors; /* -Werror     */
    131   uint32_t max_errors;     /* -fmax-errors=N   */
    132   KitTargetSpec target;    /* -target / host   */
    133   int target_set;          /* did -target appear */
    134   const char* output_path; /* -o               */
    135   int output_path_set;
    136   char* owned_output_path;
    137   size_t owned_output_path_size;
    138   const char* sysroot;        /* --sysroot / -isysroot */
    139   int freestanding;           /* -ffreestanding (suppresses sysroot headers) */
    140   uint8_t default_visibility; /* KitSymVis; -fvisibility=... */
    141   int nostdinc;               /* -nostdinc (suppresses sysroot headers) */
    142   const char* support_dir;    /* --support-dir    */
    143   int probe_kind;             /* CcProbeKind      */
    144   const char* probe_arg;      /* -print-file-name= / -print-prog-name= */
    145 
    146   /* -ffile-prefix-map=old=new entries; old is heap-owned (split out), new
    147    * aliases argv. */
    148   KitPathPrefixMap* path_map;
    149   uint32_t npath_map;
    150   char** owned_path_map_olds;
    151   size_t* owned_path_map_old_sizes;
    152 
    153   /* Reproducibility: SOURCE_DATE_EPOCH parsed at end-of-parse. */
    154   uint64_t epoch;
    155 
    156   /* Cflags via shared helper. */
    157   DriverCflags cf;
    158   DriverTargetFeatures target_features;
    159 
    160   /* Positional inputs split by suffix. */
    161   const char** source_files; /* .c paths */
    162   KitLanguage* source_langs;
    163   uint32_t nsource_files;
    164   KitSourceInput* source_memory; /* "-" stdin slurp   */
    165   uint32_t nsource_memory;
    166   uint8_t* stdin_buf; /* owning storage for the one stdin */
    167   size_t stdin_size;
    168   const char** object_files; /* .o/.obj paths     */
    169   uint32_t nobject_files;
    170   CcArchiveInput* archives; /* .a paths + resolved -l names */
    171   uint32_t narchives;
    172   CcDsoInput* dsos;
    173   uint32_t ndsos;
    174   /* -L search paths (argv-borrowed; last slot may be owned, see
    175    * owned_sysroot_lib_dir). */
    176   const char** lib_search_paths;
    177   uint32_t nlib_search_paths;
    178   /* Owned `<sysroot>/lib` slot appended for Windows targets when a
    179    * sysroot is in effect (cmdline or KIT_SYSROOT). */
    180   char* owned_sysroot_lib_dir;
    181   size_t owned_sysroot_lib_dir_size;
    182   /* Pending -l names (resolved at end-of-parse). */
    183   CcPendingLib* pending_libs;
    184   uint32_t npending_libs;
    185   CcLinkItem* link_items;
    186   uint32_t nlink_items;
    187   uint8_t cur_whole_archive;
    188   uint8_t cur_link_mode;
    189   uint8_t cur_group_id;
    190   uint8_t next_group_id;
    191 
    192   /* -M family */
    193   int dep_mode;             /* CcDepMode */
    194   int dep_phony;            /* -MP       */
    195   const char* dep_file;     /* -MF       */
    196   const char** dep_targets; /* -MT/-MQ   */
    197   uint32_t ndep_targets;
    198 
    199   /* Link-session options and owned -Wl state. */
    200   DriverLinkFlags link;
    201   int shared; /* -shared */
    202   int static_link;
    203   int pie;
    204   int no_stdlib;
    205   int no_defaultlibs;
    206   int no_startfiles;
    207   int wants_hosted_libc;
    208   DriverHostedPlan hosted;
    209 } CcOptions;
    210 
    211 static void cc_usage(void) {
    212   driver_errf(CC_TOOL, "%.*s",
    213               KIT_SLICE_ARG(KIT_SLICE_LIT(
    214                   "usage: kit cc [-c|-E|-shared] [-o out] "
    215                   "[options...] inputs...\n"
    216                   "       kit cc --help    for full option reference")));
    217 }
    218 
    219 void driver_help_cc(void) {
    220   driver_printf(
    221       "%.*s",
    222       KIT_SLICE_ARG(KIT_SLICE_LIT(
    223           "kit cc — C compiler driver\n"
    224           "\n"
    225           "USAGE\n"
    226           "  kit cc [options] inputs...                   compile and link "
    227           "to "
    228           "exe\n"
    229           "  kit cc -c [options] input.c                  compile one source "
    230           "to "
    231           ".o\n"
    232           "  kit cc -E [options] input.c                  preprocess to -o\n"
    233           "  kit cc -fsyntax-only [options] inputs...     check only\n"
    234           "  kit cc -shared [options] inputs...           link a shared "
    235           "library\n"
    236           "  kit cc -M|-MM [options] input.c              print header deps; "
    237           "no "
    238           "compile\n"
    239           "  --sysroot DIR / -isysroot DIR                  hosted "
    240           "SDK/sysroot\n"
    241           "  --support-dir DIR                              kit support "
    242           "root\n"
    243           "  -print-search-dirs / -print-sysroot            show the dirs "
    244           "the\n"
    245           "  -print-resource-dir                            compiler will "
    246           "search\n"
    247           "  -S [options] input.c                           emit assembly "
    248           "(.s)\n"
    249           "  --emit=c [options] input.c                     emit portable C "
    250           "source\n"
    251           "  --emit=ir -O1 [options] input.c                emit semantic IR "
    252           "dump\n"
    253           "  -flto                                           link-time "
    254           "optimization for all source inputs\n"
    255           "\n"
    256           "(see source for the full GCC-subset flag reference)\n")));
    257 }
    258 
    259 void driver_help_check(void) {
    260   driver_printf("%.*s",
    261                 KIT_SLICE_ARG(KIT_SLICE_LIT(
    262                     "kit check — run frontend checks without emitting code\n"
    263                     "\n"
    264                     "USAGE\n"
    265                     "  kit check [cc-options] inputs...\n"
    266                     "\n"
    267                     "Runs the same C frontend path as `kit cc "
    268                     "-fsyntax-only`, including "
    269                     "preprocessing and diagnostics, but does not write objects "
    270                     "or link.\n")));
    271 }
    272 
    273 static int cc_alloc_arrays(CcOptions* o, int argc) {
    274   size_t bound = (size_t)argc + 16u;
    275   o->argv_bound = bound;
    276   o->source_files =
    277       driver_alloc_zeroed(o->env, bound * sizeof(*o->source_files));
    278   o->source_langs =
    279       driver_alloc_zeroed(o->env, bound * sizeof(*o->source_langs));
    280   o->source_memory =
    281       driver_alloc_zeroed(o->env, bound * sizeof(*o->source_memory));
    282   o->object_files =
    283       driver_alloc_zeroed(o->env, bound * sizeof(*o->object_files));
    284   o->archives = driver_alloc_zeroed(o->env, bound * sizeof(*o->archives));
    285   o->dsos = driver_alloc_zeroed(o->env, bound * sizeof(*o->dsos));
    286   o->lib_search_paths =
    287       driver_alloc_zeroed(o->env, bound * sizeof(*o->lib_search_paths));
    288   o->pending_libs =
    289       driver_alloc_zeroed(o->env, bound * sizeof(*o->pending_libs));
    290   o->link_items = driver_alloc_zeroed(o->env, bound * sizeof(*o->link_items));
    291   o->dep_targets = driver_alloc_zeroed(o->env, bound * sizeof(*o->dep_targets));
    292   o->path_map = driver_alloc_zeroed(o->env, bound * sizeof(*o->path_map));
    293   o->owned_path_map_olds =
    294       driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_path_map_olds));
    295   o->owned_path_map_old_sizes =
    296       driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_path_map_old_sizes));
    297   if (!o->source_files || !o->source_langs || !o->source_memory ||
    298       !o->object_files || !o->archives || !o->dsos || !o->lib_search_paths ||
    299       !o->pending_libs || !o->link_items || !o->dep_targets || !o->path_map ||
    300       !o->owned_path_map_olds || !o->owned_path_map_old_sizes) {
    301     driver_errf(CC_TOOL, "out of memory");
    302     return 1;
    303   }
    304   o->cur_link_mode = KIT_LM_DEFAULT;
    305   if (driver_link_flags_init(&o->link, o->env, CC_TOOL, (uint32_t)bound) != 0 ||
    306       driver_cflags_init(&o->cf, o->env,
    307                          (int)(bound + DRIVER_HOSTED_MAX_DEFINES +
    308                                DRIVER_HOSTED_MAX_INCLUDES)) != 0 ||
    309       driver_target_features_init(&o->target_features, o->env, argc) != 0) {
    310     driver_errf(CC_TOOL, "out of memory");
    311     return 1;
    312   }
    313   return 0;
    314 }
    315 
    316 static void cc_options_release(CcOptions* o) {
    317   uint32_t i;
    318   size_t bound = o->argv_bound;
    319   for (i = 0; i < o->narchives; ++i) {
    320     if (o->archives[i].owned) {
    321       driver_free(o->env, (void*)o->archives[i].path,
    322                   o->archives[i].owned_size);
    323     }
    324   }
    325   for (i = 0; i < o->ndsos; ++i) {
    326     if (o->dsos[i].owned) {
    327       driver_free(o->env, (void*)o->dsos[i].path, o->dsos[i].owned_size);
    328     }
    329   }
    330   for (i = 0; i < o->npath_map; ++i) {
    331     if (o->owned_path_map_olds[i]) {
    332       driver_free(o->env, o->owned_path_map_olds[i],
    333                   o->owned_path_map_old_sizes[i]);
    334     }
    335   }
    336   if (o->stdin_buf) driver_free(o->env, o->stdin_buf, o->stdin_size);
    337   if (o->owned_output_path)
    338     driver_free(o->env, o->owned_output_path, o->owned_output_path_size);
    339   if (o->owned_sysroot_lib_dir)
    340     driver_free(o->env, o->owned_sysroot_lib_dir,
    341                 o->owned_sysroot_lib_dir_size);
    342   driver_hosted_plan_fini(o->env, &o->hosted);
    343   driver_link_flags_fini(&o->link);
    344   driver_target_features_fini(&o->target_features, o->env);
    345   driver_cflags_fini(&o->cf, o->env);
    346   driver_free(o->env, o->source_files, bound * sizeof(*o->source_files));
    347   driver_free(o->env, o->source_langs, bound * sizeof(*o->source_langs));
    348   driver_free(o->env, o->source_memory, bound * sizeof(*o->source_memory));
    349   driver_free(o->env, o->object_files, bound * sizeof(*o->object_files));
    350   driver_free(o->env, o->archives, bound * sizeof(*o->archives));
    351   driver_free(o->env, o->dsos, bound * sizeof(*o->dsos));
    352   driver_free(o->env, o->lib_search_paths,
    353               bound * sizeof(*o->lib_search_paths));
    354   driver_free(o->env, o->pending_libs, bound * sizeof(*o->pending_libs));
    355   driver_free(o->env, o->link_items, bound * sizeof(*o->link_items));
    356   driver_free(o->env, o->dep_targets, bound * sizeof(*o->dep_targets));
    357   driver_free(o->env, o->path_map, bound * sizeof(*o->path_map));
    358   driver_free(o->env, o->owned_path_map_olds,
    359               bound * sizeof(*o->owned_path_map_olds));
    360   driver_free(o->env, o->owned_path_map_old_sizes,
    361               bound * sizeof(*o->owned_path_map_old_sizes));
    362 }
    363 
    364 static int cc_apply_hosted_profile(CcOptions* o);
    365 
    366 /* Routed through the shared driver_path_is_source authority (canonical
    367  * extension registry, headers excluded), so adding a frontend extension reaches
    368  * cc/build/run/dbg at once. cc still treats .h as a header, not a source — the
    369  * helper excludes it. */
    370 static int cc_is_c_source(const char* s) { return driver_path_is_source(s); }
    371 
    372 static int cc_is_dso_input(const char* s) {
    373   return driver_has_suffix(s, ".so") || driver_has_suffix(s, ".dylib") ||
    374          driver_has_suffix(s, ".tbd");
    375 }
    376 
    377 static void cc_push_link_item(CcOptions* o, uint8_t kind, uint32_t index) {
    378   CcLinkItem* it = &o->link_items[o->nlink_items++];
    379   it->kind = kind;
    380   it->index = index;
    381 }
    382 
    383 static void cc_insert_link_item(CcOptions* o, uint32_t pos, uint8_t kind,
    384                                 uint32_t index) {
    385   uint32_t i;
    386   if (pos > o->nlink_items) pos = o->nlink_items;
    387   for (i = o->nlink_items; i > pos; --i) {
    388     o->link_items[i] = o->link_items[i - 1u];
    389   }
    390   o->link_items[pos].kind = kind;
    391   o->link_items[pos].index = index;
    392   o->nlink_items++;
    393 }
    394 
    395 static int cc_append_hosted_input(CcOptions* o, const DriverHostedInput* in,
    396                                   uint32_t insert_pos, int insert) {
    397   uint32_t index;
    398   uint8_t kind;
    399   switch ((DriverHostedInputKind)in->kind) {
    400     case DRIVER_HOSTED_INPUT_OBJECT:
    401       index = o->nobject_files++;
    402       o->object_files[index] = in->path;
    403       kind = CC_LINK_OBJECT;
    404       break;
    405     case DRIVER_HOSTED_INPUT_ARCHIVE: {
    406       CcArchiveInput* ar = &o->archives[o->narchives++];
    407       ar->path = in->path;
    408       ar->whole_archive = 0;
    409       ar->link_mode = KIT_LM_DEFAULT;
    410       ar->group_id = 0;
    411       index = o->narchives - 1u;
    412       kind = CC_LINK_ARCHIVE;
    413       break;
    414     }
    415     case DRIVER_HOSTED_INPUT_DSO: {
    416       CcDsoInput* d = &o->dsos[o->ndsos++];
    417       d->path = in->path;
    418       index = o->ndsos - 1u;
    419       kind = CC_LINK_DSO;
    420       break;
    421     }
    422     default:
    423       driver_errf(CC_TOOL, "internal error: unknown hosted input kind");
    424       return 1;
    425   }
    426   if (insert)
    427     cc_insert_link_item(o, insert_pos, kind, index);
    428   else
    429     cc_push_link_item(o, kind, index);
    430   return 0;
    431 }
    432 
    433 static void cc_insert_runtime_archive(CcOptions* o, DriverRuntimeArchive* rt,
    434                                       uint32_t insert_pos) {
    435   CcArchiveInput* ar = &o->archives[o->narchives++];
    436   ar->path = rt->path;
    437   ar->owned = 1;
    438   ar->owned_size = rt->path_size;
    439   ar->whole_archive = rt->whole_archive;
    440   ar->link_mode = rt->link_mode;
    441   ar->group_id = rt->group_id;
    442   rt->path = NULL;
    443   rt->path_size = 0;
    444   cc_insert_link_item(o, insert_pos, CC_LINK_ARCHIVE, o->narchives - 1u);
    445 }
    446 
    447 static int cc_parse_u64(const char* s, uint64_t* out) {
    448   uint64_t v = 0;
    449   int any = 0;
    450   if (!s) return 1;
    451   while (*s) {
    452     unsigned d;
    453     if (*s < '0' || *s > '9') return 1;
    454     d = (unsigned)(*s - '0');
    455     if (v > (UINT64_MAX - d) / 10u) return 1;
    456     v = v * 10u + d;
    457     any = 1;
    458     s++;
    459   }
    460   if (!any) return 1;
    461   *out = v;
    462   return 0;
    463 }
    464 
    465 static int cc_record_path_map(CcOptions* o, const char* arg) {
    466   const char* eq = driver_strchr(arg, '=');
    467   KitPathPrefixMap* m = &o->path_map[o->npath_map];
    468   if (!eq) {
    469     driver_errf(CC_TOOL, "-ffile-prefix-map requires old=new");
    470     return 1;
    471   }
    472   {
    473     size_t n = (size_t)(eq - arg);
    474     size_t bytes = n + 1;
    475     char* old_ = driver_alloc(o->env, bytes);
    476     if (!old_) {
    477       driver_errf(CC_TOOL, "out of memory");
    478       return 1;
    479     }
    480     driver_memcpy(old_, arg, n);
    481     old_[n] = '\0';
    482     o->owned_path_map_olds[o->npath_map] = old_;
    483     o->owned_path_map_old_sizes[o->npath_map] = bytes;
    484     m->old_prefix = old_;
    485     m->new_prefix = eq + 1;
    486   }
    487   o->npath_map++;
    488   return 0;
    489 }
    490 
    491 static int cc_record_mcmodel(CcOptions* o, const char* val) {
    492   if (driver_streq(val, "small")) {
    493     o->target.code_model = KIT_CM_SMALL;
    494     return 0;
    495   }
    496   if (driver_streq(val, "medium")) {
    497     o->target.code_model = KIT_CM_MEDIUM;
    498     return 0;
    499   }
    500   if (driver_streq(val, "large")) {
    501     o->target.code_model = KIT_CM_LARGE;
    502     return 0;
    503   }
    504   if (driver_streq(val, "medlow")) {
    505     o->target.code_model = KIT_CM_SMALL;
    506     return 0;
    507   }
    508   if (driver_streq(val, "medany")) {
    509     o->target.code_model = KIT_CM_MEDIUM;
    510     return 0;
    511   }
    512   driver_errf(CC_TOOL, "unknown -mcmodel value: %.*s",
    513               KIT_SLICE_ARG(kit_slice_cstr(val)));
    514   return 1;
    515 }
    516 
    517 static int cc_set_probe(CcOptions* o, int kind, const char* arg) {
    518   if (o->probe_kind != CC_PROBE_NONE) {
    519     driver_errf(CC_TOOL, "only one compiler-information probe is supported");
    520     return 1;
    521   }
    522   o->probe_kind = kind;
    523   o->probe_arg = arg;
    524   return 0;
    525 }
    526 
    527 /* Emit one element of a colon-separated search path. *first tracks whether a
    528  * leading separator is needed; NULL/empty entries are skipped. */
    529 static void cc_print_path_elem(const char* dir, int* first) {
    530   if (!dir || !dir[0]) return;
    531   driver_printf("%s%.*s", *first ? "" : ":",
    532                 KIT_SLICE_ARG(kit_slice_cstr(dir)));
    533   *first = 0;
    534 }
    535 
    536 static int cc_run_probe(CcOptions* o) {
    537   char triple[64];
    538   if (driver_target_to_triple(o->target, triple, sizeof(triple)) != 0) {
    539     driver_errf(CC_TOOL, "failed to render target triple");
    540     return 1;
    541   }
    542 
    543   switch (o->probe_kind) {
    544     case CC_PROBE_PRINT_SEARCH_DIRS: {
    545       DriverRuntimeSupport rt = {0};
    546       int have_rt = (driver_runtime_resolve(o->env, o->support_dir,
    547                                             o->driver_path, &rt) == 0);
    548       DriverHostedDirs dirs;
    549       int have_dirs = 0;
    550       uint32_t i;
    551       int first;
    552       /* Resolve the hosted include/library dirs directly: a probe run skips the
    553        * parse-time hosted profile (no compile happens), so they are not yet in
    554        * cf. Gated on hosted libc being engaged (-lc / sysroot). */
    555       if (o->wants_hosted_libc) {
    556         DriverHostedRequest req = {0};
    557         req.env = o->env;
    558         req.tool = CC_TOOL;
    559         req.target = o->target;
    560         req.sysroot = o->sysroot;
    561         req.static_link = o->static_link;
    562         req.link_inputs = 1;
    563         have_dirs = (driver_hosted_dirs_resolve(&req, &dirs) == 0);
    564       }
    565       driver_printf("install: %.*s\n",
    566                     KIT_SLICE_ARG(kit_slice_cstr(
    567                         have_rt ? rt.support_root
    568                                 : (o->support_dir ? o->support_dir : ""))));
    569       driver_printf("programs: =\n");
    570       /* libraries: hosted crt/libc search dirs, then user -L dirs, then the kit
    571        * runtime dir holding libkit_rt.a. */
    572       driver_printf("libraries: =");
    573       first = 1;
    574       if (have_dirs)
    575         for (i = 0; i < dirs.nlibdirs; ++i)
    576           cc_print_path_elem(dirs.libdirs[i], &first);
    577       for (i = 0; i < o->nlib_search_paths; ++i)
    578         cc_print_path_elem(o->lib_search_paths[i], &first);
    579       if (have_rt) cc_print_path_elem(rt.rt_root, &first);
    580       driver_printf("\n");
    581       /* includes: user -I/-isystem, then the hosted system headers, then the
    582        * freestanding runtime headers. (kit extension to GCC's output.) */
    583       driver_printf("includes: =");
    584       first = 1;
    585       for (i = 0; i < o->cf.ninclude_dirs; ++i)
    586         cc_print_path_elem(o->cf.include_dirs[i], &first);
    587       for (i = 0; i < o->cf.nsystem_include_dirs; ++i)
    588         cc_print_path_elem(o->cf.system_include_dirs[i], &first);
    589       if (have_dirs)
    590         for (i = 0; i < dirs.nincdirs; ++i)
    591           cc_print_path_elem(dirs.incdirs[i], &first);
    592       if (have_rt) cc_print_path_elem(rt.include_dir, &first);
    593       driver_printf("\n");
    594       if (have_dirs) driver_hosted_dirs_fini(&dirs);
    595       if (have_rt) driver_runtime_support_fini(o->env, &rt);
    596       return 0;
    597     }
    598     case CC_PROBE_PRINT_FILE_NAME:
    599       driver_printf(
    600           "%.*s\n",
    601           KIT_SLICE_ARG(kit_slice_cstr(o->probe_arg ? o->probe_arg : "")));
    602       return 0;
    603     case CC_PROBE_PRINT_PROG_NAME:
    604       driver_printf(
    605           "%.*s\n",
    606           KIT_SLICE_ARG(kit_slice_cstr(o->probe_arg ? o->probe_arg : "")));
    607       return 0;
    608     case CC_PROBE_PRINT_LIBGCC_FILE_NAME:
    609       driver_printf("libkit_rt.a\n");
    610       return 0;
    611     case CC_PROBE_PRINT_MULTI_OS_DIRECTORY:
    612       driver_printf(".\n");
    613       return 0;
    614     case CC_PROBE_PRINT_RESOURCE_DIR: {
    615       /* clang convention: the resource-dir root, with builtin/freestanding
    616        * headers under <resource-dir>/include. */
    617       DriverRuntimeSupport rt = {0};
    618       if (driver_runtime_resolve(o->env, o->support_dir, o->driver_path, &rt) ==
    619           0) {
    620         driver_printf("%.*s\n", KIT_SLICE_ARG(kit_slice_cstr(rt.rt_root)));
    621         driver_runtime_support_fini(o->env, &rt);
    622       } else {
    623         driver_printf("%.*s\n", KIT_SLICE_ARG(kit_slice_cstr(
    624                                     o->support_dir ? o->support_dir : "")));
    625       }
    626       return 0;
    627     }
    628     case CC_PROBE_PRINT_SYSROOT: {
    629       /* The effective sysroot root: command-line --sysroot or KIT_SYSROOT, else
    630        * the native host probe when it resolves to a single tree (the macOS
    631        * SDK). Empty for a multi-dir probe (Linux/FreeBSD) or a cross target
    632        * with no sysroot, which have no single root. */
    633       DriverHostedRequest req = {0};
    634       DriverHostedDirs dirs;
    635       req.env = o->env;
    636       req.tool = CC_TOOL;
    637       req.target = o->target;
    638       req.sysroot = o->sysroot;
    639       req.static_link = o->static_link;
    640       req.link_inputs = 1;
    641       if (driver_hosted_dirs_resolve(&req, &dirs) == 0) {
    642         driver_printf(
    643             "%.*s\n",
    644             KIT_SLICE_ARG(kit_slice_cstr(dirs.root ? dirs.root : "")));
    645         driver_hosted_dirs_fini(&dirs);
    646       } else {
    647         driver_printf("\n");
    648       }
    649       return 0;
    650     }
    651     case CC_PROBE_DUMPMACHINE:
    652       driver_printf("%.*s\n", KIT_SLICE_ARG(kit_slice_cstr(triple)));
    653       return 0;
    654     case CC_PROBE_DUMPVERSION:
    655       driver_printf("0\n");
    656       return 0;
    657     case CC_PROBE_DUMPSPECS:
    658       driver_printf("*kit:\n");
    659       driver_printf("%%{!S:%%{!E:%%{!c:%%{!r:link}}}}\n");
    660       return 0;
    661     default:
    662       break;
    663   }
    664 
    665   return 0;
    666 }
    667 
    668 static int cc_record_stdin(CcOptions* o, int forced_lang) {
    669   KitSourceInput* in;
    670   if (o->stdin_buf) {
    671     driver_errf(CC_TOOL, "'-' (stdin) may appear at most once");
    672     return 1;
    673   }
    674   if (!driver_read_stdin(o->env, &o->stdin_buf, &o->stdin_size)) {
    675     driver_errf(CC_TOOL, "failed to read stdin");
    676     return 1;
    677   }
    678   in = &o->source_memory[o->nsource_memory++];
    679   in->name = KIT_SLICE_LIT("<stdin>");
    680   in->bytes.data = o->stdin_buf;
    681   in->bytes.len = o->stdin_size;
    682   in->lang = forced_lang >= 0 ? (KitLanguage)forced_lang : KIT_LANG_C;
    683   cc_push_link_item(o, CC_LINK_SOURCE_MEMORY, o->nsource_memory - 1u);
    684   return 0;
    685 }
    686 
    687 /* Stored in source_langs[] during arg parsing to mean "no -x override —
    688  * resolve from the path at compile time, once a compiler is around to
    689  * consult its frontend extension registry." */
    690 #define CC_LANG_AUTO ((KitLanguage)KIT_LANG_COUNT)
    691 
    692 static KitLanguage cc_resolve_lang(KitCompiler* c, const char* path,
    693                                    KitLanguage stored) {
    694   if (stored != CC_LANG_AUTO) return stored;
    695   return kit_language_for_path(c, path);
    696 }
    697 
    698 static int cc_classify_positional(CcOptions* o, const char* a,
    699                                   int forced_lang) {
    700   if (driver_streq(a, "-")) return cc_record_stdin(o, forced_lang);
    701   if (forced_lang >= 0 || cc_is_c_source(a)) {
    702     o->source_langs[o->nsource_files] =
    703         forced_lang >= 0 ? (KitLanguage)forced_lang : CC_LANG_AUTO;
    704     o->source_files[o->nsource_files++] = a;
    705     cc_push_link_item(o, CC_LINK_SOURCE_FILE, o->nsource_files - 1u);
    706     return 0;
    707   }
    708   if (driver_has_suffix(a, ".o") || driver_has_suffix(a, ".obj")) {
    709     o->object_files[o->nobject_files++] = a;
    710     cc_push_link_item(o, CC_LINK_OBJECT, o->nobject_files - 1u);
    711     return 0;
    712   }
    713   if (driver_has_suffix(a, ".a")) {
    714     CcArchiveInput* ar = &o->archives[o->narchives++];
    715     ar->path = a;
    716     ar->whole_archive = o->cur_whole_archive;
    717     ar->link_mode = o->cur_link_mode;
    718     ar->group_id = o->cur_group_id;
    719     cc_push_link_item(o, CC_LINK_ARCHIVE, o->narchives - 1u);
    720     return 0;
    721   }
    722   if (cc_is_dso_input(a)) {
    723     CcDsoInput* d = &o->dsos[o->ndsos++];
    724     d->path = a;
    725     cc_push_link_item(o, CC_LINK_DSO, o->ndsos - 1u);
    726     return 0;
    727   }
    728   driver_errf(CC_TOOL, "input does not have a recognized suffix: %.*s",
    729               KIT_SLICE_ARG(kit_slice_cstr(a)));
    730   return 1;
    731 }
    732 
    733 static int cc_resolve_pending_libs(CcOptions* o) {
    734   uint32_t i;
    735   for (i = 0; i < o->npending_libs; ++i) {
    736     CcPendingLib* pl = &o->pending_libs[i];
    737     char* p;
    738     size_t sz;
    739     LibResolveKind kind;
    740     LibResolveMode mode = (o->static_link || pl->link_mode == KIT_LM_STATIC)
    741                               ? LIB_RESOLVE_STATIC_ONLY
    742                               : LIB_RESOLVE_DYNAMIC_PREFER;
    743     LibResolveOS resolve_os = (o->target.os == KIT_OS_WINDOWS)
    744                                   ? LIB_RESOLVE_OS_WINDOWS
    745                                   : LIB_RESOLVE_OS_POSIX;
    746     if (driver_lib_resolve_for_os(o->env, pl->name, mode, resolve_os,
    747                                   o->lib_search_paths, o->nlib_search_paths, &p,
    748                                   &sz, &kind) != 0) {
    749       driver_errf(CC_TOOL, "library not found: -l%.*s",
    750                   KIT_SLICE_ARG(kit_slice_cstr(pl->name)));
    751       return 1;
    752     }
    753     if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) {
    754       CcDsoInput* d = &o->dsos[o->ndsos++];
    755       d->path = p;
    756       d->owned = 1;
    757       d->owned_size = sz;
    758       pl->resolved_kind = CC_LINK_DSO;
    759       pl->resolved_index = o->ndsos - 1u;
    760     } else {
    761       CcArchiveInput* ar = &o->archives[o->narchives++];
    762       ar->path = p;
    763       ar->owned = 1;
    764       ar->owned_size = sz;
    765       ar->whole_archive = pl->whole_archive;
    766       ar->link_mode = pl->link_mode;
    767       ar->group_id = pl->group_id;
    768       pl->resolved_kind = CC_LINK_ARCHIVE;
    769       pl->resolved_index = o->narchives - 1u;
    770     }
    771   }
    772   return 0;
    773 }
    774 
    775 static int cc_apply_hosted_profile(CcOptions* o) {
    776   DriverHostedRequest req;
    777   uint32_t i;
    778   uint32_t insert_pos = 0;
    779   int link_action = !o->compile_only && !o->preprocess_only &&
    780                     o->dep_mode != CC_DEP_M && o->dep_mode != CC_DEP_MM;
    781   if (!o->wants_hosted_libc || o->shared) return 0;
    782   if (o->no_stdlib || o->no_defaultlibs) {
    783     driver_errf(CC_TOOL,
    784                 "-lc hosted expansion is disabled by -nostdlib/-nodefaultlibs");
    785     return 1;
    786   }
    787   {
    788     DriverHostedRequest z = {0};
    789     req = z;
    790   }
    791   req.env = o->env;
    792   req.tool = CC_TOOL;
    793   req.target = o->target;
    794   req.sysroot = o->sysroot;
    795   req.static_link = o->static_link;
    796   req.link_inputs = link_action;
    797   if (driver_hosted_resolve(&req, &o->hosted) != 0) return 1;
    798   for (i = 0; i < o->hosted.nsystem_includes; ++i) {
    799     o->cf.system_include_dirs[o->cf.nsystem_include_dirs++] =
    800         o->hosted.system_includes[i];
    801   }
    802   for (i = 0; i < o->hosted.ndefines; ++i) {
    803     o->cf.defines[o->cf.ndefines++] = o->hosted.defines[i];
    804   }
    805   /* Add hosted lib search dirs so user -l flags (-lm, -lpthread, etc.) can be
    806    * resolved.  The strings are owned by o->hosted and outlive lib_search_paths.
    807    * Insert before any user -L dirs so sysroot libs take precedence. */
    808   for (i = 0; i < o->hosted.nlib_search_dirs; ++i)
    809     o->lib_search_paths[o->nlib_search_paths++] = o->hosted.lib_search_dirs[i];
    810   if (!link_action) return 0;
    811   for (i = 0; i < o->hosted.nbefore; ++i) {
    812     if (o->no_startfiles) break;
    813     if (cc_append_hosted_input(o, &o->hosted.before[i], insert_pos, 1) != 0)
    814       return 1;
    815     insert_pos++;
    816   }
    817   for (i = 0; i < o->hosted.nafter; ++i) {
    818     if (cc_append_hosted_input(o, &o->hosted.after[i], 0, 0) != 0) return 1;
    819   }
    820   for (i = 0; i < o->hosted.nfinal; ++i) {
    821     if (o->no_startfiles) break;
    822     if (cc_append_hosted_input(o, &o->hosted.final[i], 0, 0) != 0) return 1;
    823   }
    824   if (!o->link.interp_path && o->hosted.interp_path)
    825     o->link.interp_path = o->hosted.interp_path;
    826   return 0;
    827 }
    828 
    829 static int cc_apply_env(CcOptions* o) {
    830   const char* sde = driver_getenv("SOURCE_DATE_EPOCH");
    831   if (sde && cc_parse_u64(sde, &o->epoch) != 0) {
    832     driver_errf(CC_TOOL, "invalid SOURCE_DATE_EPOCH: %.*s",
    833                 KIT_SLICE_ARG(kit_slice_cstr(sde)));
    834     return 1;
    835   }
    836   return 0;
    837 }
    838 
    839 /* Append a default `<sysroot>/lib` to the library search path for
    840  * Windows targets. The llvm-mingw UCRT sysroot ships import archives
    841  * such as libkernel32.a, libucrt.a, and the UCRT API-set archives
    842  * under <sysroot>/lib; the user-supplied -L list is searched first,
    843  * then this appended default. Sysroot resolution order:
    844  *   1. -isysroot / --sysroot on the command line (already in
    845  *      o->sysroot at this point);
    846  *   2. KIT_SYSROOT env var (e.g. .../x86_64-w64-mingw32).
    847  *
    848  * No-op for non-Windows targets and for Windows when neither source
    849  * provides a sysroot — keeps existing tests untouched. The appended
    850  * path aliases the sysroot string for its lifetime; o->sysroot is
    851  * either argv-borrowed or env-borrowed, both stable across the
    852  * driver run, so the lib_search_paths slot remains valid. */
    853 static int cc_append_windows_lib_dirs(CcOptions* o) {
    854   const char* sysroot = o->sysroot;
    855   char* joined = NULL;
    856   size_t srlen;
    857   size_t need_slash;
    858   size_t bytes;
    859   size_t off = 0;
    860   if (!driver_target_needs_sysroot_libdir(o->target)) return 0;
    861   if (!sysroot || !sysroot[0]) {
    862     sysroot = driver_getenv("KIT_SYSROOT");
    863     if (!sysroot || !sysroot[0]) return 0;
    864     o->sysroot = sysroot;
    865   }
    866   srlen = driver_strlen(sysroot);
    867   need_slash = (srlen > 0 && sysroot[srlen - 1] != '/') ? 1u : 0u;
    868   /* "<sysroot>" + "/"? + "lib" + NUL */
    869   bytes = srlen + need_slash + 3u + 1u;
    870   joined = driver_alloc(o->env, bytes);
    871   if (!joined) {
    872     driver_errf(CC_TOOL, "out of memory");
    873     return 1;
    874   }
    875   driver_memcpy(joined + off, sysroot, srlen);
    876   off += srlen;
    877   if (need_slash) joined[off++] = '/';
    878   driver_memcpy(joined + off, "lib", 3);
    879   off += 3;
    880   joined[off] = '\0';
    881   if (o->owned_sysroot_lib_dir) {
    882     driver_free(o->env, o->owned_sysroot_lib_dir,
    883                 o->owned_sysroot_lib_dir_size);
    884   }
    885   o->owned_sysroot_lib_dir = joined;
    886   o->owned_sysroot_lib_dir_size = bytes;
    887   o->lib_search_paths[o->nlib_search_paths++] = joined;
    888   return 0;
    889 }
    890 
    891 static int cc_has_link_action(const CcOptions* o) {
    892   return !o->compile_only && !o->preprocess_only && o->dep_mode != CC_DEP_M &&
    893          o->dep_mode != CC_DEP_MM;
    894 }
    895 
    896 /* A sysroot on its own means "compile/link hosted against that root" — the
    897  * same default clang and gcc take for -isysroot/--sysroot. Engage the hosted
    898  * libc profile so the host headers, their feature-test defines (__GNUC__,
    899  * __APPLE__, __has_builtin, ...) and (for link actions) the host C runtime are
    900  * brought in. -ffreestanding and -nostdinc opt back out, keeping the
    901  * freestanding rt/include set standalone; -shared and the -nostdlib family
    902  * keep their existing meaning. The Windows-COFF default profile and an explicit
    903  * -lc already set the flag, so this is a no-op in those cases. */
    904 static void cc_enable_hosted_for_sysroot(CcOptions* o) {
    905   if (o->wants_hosted_libc || o->shared) return;
    906   if (!o->sysroot || !o->sysroot[0]) return;
    907   if (o->freestanding || o->nostdinc) return;
    908   if (o->no_stdlib || o->no_defaultlibs) return;
    909   o->wants_hosted_libc = 1;
    910 }
    911 
    912 static void cc_apply_default_hosted_profile(CcOptions* o) {
    913   if (!driver_target_default_hosted_profile(o->target)) return;
    914   if (o->no_stdlib || o->no_defaultlibs || o->wants_hosted_libc) return;
    915   if (!o->sysroot || !o->sysroot[0]) return;
    916   if (!cc_has_link_action(o) && o->nsource_files + o->nsource_memory == 0)
    917     return;
    918   o->wants_hosted_libc = 1;
    919 }
    920 
    921 static char* cc_dep_default_target(DriverEnv* env, const CcOptions* o,
    922                                    size_t* out_size);
    923 
    924 static int cc_parse(int argc, char** argv, CcOptions* o) {
    925   int forced_lang = -1;
    926   int i;
    927 
    928   if (cc_alloc_arrays(o, argc) != 0) return 1;
    929   o->target = driver_host_target();
    930 
    931   for (i = 1; i < argc; ++i) {
    932     const char* a = argv[i];
    933 
    934     {
    935       int r =
    936           driver_cflags_try_consume(&o->cf, o->env, CC_TOOL, argc, argv, &i);
    937       if (r < 0) return 1;
    938       if (r > 0) continue;
    939     }
    940 
    941     if (driver_streq(a, "-c")) {
    942       o->compile_only = 1;
    943       continue;
    944     }
    945     if (driver_streq(a, "-v") || driver_streq(a, "-###")) {
    946       continue;
    947     }
    948     if (driver_streq(a, "-E")) {
    949       o->preprocess_only = 1;
    950       continue;
    951     }
    952     if (driver_streq(a, "-S")) {
    953       o->emit_asm_source = 1;
    954       o->compile_only = 1;
    955       continue;
    956     }
    957     if (driver_streq(a, "-fsyntax-only")) {
    958       o->syntax_only = 1;
    959       continue;
    960     }
    961     if (driver_streq(a, "--emit=c")) {
    962       /* C-source output instead of object bytes. Forces -c-style single-input
    963        * compile (no link). See doc/CBACKEND.md. */
    964       o->emit_c_source = 1;
    965       o->compile_only = 1;
    966       continue;
    967     }
    968     if (driver_streq(a, "--emit=ir")) {
    969       /* Textual semantic-IR dump instead of object bytes. The IR tape is only
    970        * recorded when the optimizer runs, so this requires -O1+ (validated
    971        * after argument parsing). Forces a single-input, no-link compile. */
    972       o->emit_ir = 1;
    973       o->compile_only = 1;
    974       continue;
    975     }
    976     if (driver_streq(a, "-g")) {
    977       o->debug_info = 1;
    978       continue;
    979     }
    980     if (driver_streq(a, "-O0")) {
    981       o->opt_level = 0;
    982       continue;
    983     }
    984     if (driver_streq(a, "-O1")) {
    985       o->opt_level = 1;
    986       continue;
    987     }
    988     if (driver_streq(a, "-O2")) {
    989       o->opt_level = 2;
    990       continue;
    991     }
    992     if (driver_streq(a, "-O") || driver_streq(a, "-O3") ||
    993         driver_streq(a, "-Os") || driver_streq(a, "-Oz") ||
    994         driver_streq(a, "-Ofast")) {
    995       o->opt_level = 2;
    996       continue;
    997     }
    998 
    999     if (driver_streq(a, "-Werror")) {
   1000       o->warnings_are_errors = 1;
   1001       continue;
   1002     }
   1003     if (driver_strneq(a, "-Werror=", 8)) {
   1004       o->warnings_are_errors = 1;
   1005       continue;
   1006     }
   1007     if (driver_streq(a, "-Wall") || driver_streq(a, "-Wextra") ||
   1008         driver_streq(a, "-Wpedantic") || driver_streq(a, "-pedantic") ||
   1009         driver_streq(a, "-pedantic-errors") || driver_streq(a, "-w") ||
   1010         driver_strneq(a, "-Wno-", 5) ||
   1011         (driver_strneq(a, "-W", 2) && !driver_strneq(a, "-Wl,", 4))) {
   1012       continue;
   1013     }
   1014     if (driver_strneq(a, "-fmax-errors=", 13)) {
   1015       uint64_t v;
   1016       if (cc_parse_u64(a + 13, &v) != 0 || v > 0xFFFFFFFFu) {
   1017         driver_errf(CC_TOOL, "-fmax-errors= requires a non-negative integer");
   1018         return 1;
   1019       }
   1020       o->max_errors = (uint32_t)v;
   1021       continue;
   1022     }
   1023     if (driver_strneq(a, "-std=", 5) || driver_streq(a, "-ansi")) {
   1024       continue;
   1025     }
   1026     if (driver_streq(a, "-ffreestanding")) {
   1027       o->freestanding = 1;
   1028       continue;
   1029     }
   1030     if (driver_streq(a, "-fvisibility=hidden")) {
   1031       o->default_visibility = KIT_SV_HIDDEN;
   1032       continue;
   1033     }
   1034     if (driver_streq(a, "-fvisibility=default")) {
   1035       o->default_visibility = KIT_SV_DEFAULT;
   1036       continue;
   1037     }
   1038     if (driver_strneq(a, "-fvisibility=", 13)) {
   1039       driver_errf(CC_TOOL, "unsupported visibility: %.*s",
   1040                   KIT_SLICE_ARG(kit_slice_cstr(a + 13)));
   1041       return 1;
   1042     }
   1043     if (driver_streq(a, "-fhosted")) {
   1044       o->freestanding = 0;
   1045       continue;
   1046     }
   1047     if (driver_streq(a, "-ffunction-sections")) {
   1048       o->function_sections = 1;
   1049       continue;
   1050     }
   1051     if (driver_streq(a, "-fno-function-sections")) {
   1052       o->function_sections = 0;
   1053       continue;
   1054     }
   1055     if (driver_streq(a, "-fdata-sections")) {
   1056       o->data_sections = 1;
   1057       continue;
   1058     }
   1059     if (driver_streq(a, "-fno-data-sections")) {
   1060       o->data_sections = 0;
   1061       continue;
   1062     }
   1063     if (driver_streq(a, "-flto")) {
   1064       o->lto = 1;
   1065       continue;
   1066     }
   1067     if (driver_streq(a, "-fno-lto")) {
   1068       o->lto = 0;
   1069       continue;
   1070     }
   1071     if (driver_streq(a, "-nostdinc")) {
   1072       o->nostdinc = 1;
   1073       continue;
   1074     }
   1075     if (driver_streq(a, "-fno-builtin") || driver_streq(a, "-pipe") ||
   1076         driver_streq(a, "-pthread")) {
   1077       continue;
   1078     }
   1079     if (driver_streq(a, "-nostdlib")) {
   1080       o->no_stdlib = 1;
   1081       continue;
   1082     }
   1083     if (driver_streq(a, "-nodefaultlibs")) {
   1084       o->no_defaultlibs = 1;
   1085       continue;
   1086     }
   1087     if (driver_streq(a, "-nostartfiles")) {
   1088       o->no_startfiles = 1;
   1089       continue;
   1090     }
   1091     if (driver_streq(a, "-isysroot") || driver_streq(a, "--sysroot")) {
   1092       if (++i >= argc) {
   1093         driver_errf(CC_TOOL, "%.*s requires an argument",
   1094                     KIT_SLICE_ARG(kit_slice_cstr(a)));
   1095         return 1;
   1096       }
   1097       o->sysroot = argv[i];
   1098       continue;
   1099     }
   1100     if (driver_strneq(a, "--sysroot=", 10)) {
   1101       o->sysroot = a + 10;
   1102       continue;
   1103     }
   1104     if (driver_streq(a, "--support-dir")) {
   1105       if (++i >= argc) {
   1106         driver_errf(CC_TOOL, "--support-dir requires an argument");
   1107         return 1;
   1108       }
   1109       o->support_dir = argv[i];
   1110       continue;
   1111     }
   1112     if (driver_strneq(a, "--support-dir=", 14)) {
   1113       o->support_dir = a + 14;
   1114       continue;
   1115     }
   1116     if (driver_streq(a, "-print-search-dirs")) {
   1117       if (cc_set_probe(o, CC_PROBE_PRINT_SEARCH_DIRS, NULL) != 0) return 1;
   1118       continue;
   1119     }
   1120     if (driver_strneq(a, "-print-file-name=", 17)) {
   1121       if (cc_set_probe(o, CC_PROBE_PRINT_FILE_NAME, a + 17) != 0) return 1;
   1122       continue;
   1123     }
   1124     if (driver_strneq(a, "-print-prog-name=", 17)) {
   1125       if (cc_set_probe(o, CC_PROBE_PRINT_PROG_NAME, a + 17) != 0) return 1;
   1126       continue;
   1127     }
   1128     if (driver_streq(a, "-print-libgcc-file-name")) {
   1129       if (cc_set_probe(o, CC_PROBE_PRINT_LIBGCC_FILE_NAME, NULL) != 0) return 1;
   1130       continue;
   1131     }
   1132     if (driver_streq(a, "-print-multi-os-directory")) {
   1133       if (cc_set_probe(o, CC_PROBE_PRINT_MULTI_OS_DIRECTORY, NULL) != 0)
   1134         return 1;
   1135       continue;
   1136     }
   1137     if (driver_streq(a, "-print-resource-dir")) {
   1138       if (cc_set_probe(o, CC_PROBE_PRINT_RESOURCE_DIR, NULL) != 0) return 1;
   1139       continue;
   1140     }
   1141     if (driver_streq(a, "-print-sysroot")) {
   1142       if (cc_set_probe(o, CC_PROBE_PRINT_SYSROOT, NULL) != 0) return 1;
   1143       continue;
   1144     }
   1145     if (driver_streq(a, "-dumpmachine")) {
   1146       if (cc_set_probe(o, CC_PROBE_DUMPMACHINE, NULL) != 0) return 1;
   1147       continue;
   1148     }
   1149     if (driver_streq(a, "-dumpversion")) {
   1150       if (cc_set_probe(o, CC_PROBE_DUMPVERSION, NULL) != 0) return 1;
   1151       continue;
   1152     }
   1153     if (driver_streq(a, "-dumpspecs")) {
   1154       if (cc_set_probe(o, CC_PROBE_DUMPSPECS, NULL) != 0) return 1;
   1155       continue;
   1156     }
   1157     if (driver_streq(a, "-include")) {
   1158       if (++i >= argc) {
   1159         driver_errf(CC_TOOL, "%.*s requires an argument",
   1160                     KIT_SLICE_ARG(kit_slice_cstr(a)));
   1161         return 1;
   1162       }
   1163       continue;
   1164     }
   1165 
   1166     if (driver_streq(a, "-fPIC") || driver_streq(a, "-fpic")) {
   1167       o->target.pic = KIT_PIC_PIC;
   1168       continue;
   1169     }
   1170     if (driver_streq(a, "-fPIE") || driver_streq(a, "-fpie")) {
   1171       o->target.pic = KIT_PIC_PIE;
   1172       continue;
   1173     }
   1174     if (driver_streq(a, "-fno-PIC") || driver_streq(a, "-fno-pic") ||
   1175         driver_streq(a, "-fno-PIE") || driver_streq(a, "-fno-pie")) {
   1176       o->target.pic = KIT_PIC_NONE;
   1177       continue;
   1178     }
   1179     if (driver_streq(a, "-static")) {
   1180       o->target.pic = KIT_PIC_NONE;
   1181       o->static_link = 1;
   1182       o->cur_link_mode = KIT_LM_STATIC;
   1183       continue;
   1184     }
   1185     if (driver_streq(a, "-pie")) {
   1186       o->target.pic = KIT_PIC_PIE;
   1187       o->pie = 1;
   1188       continue;
   1189     }
   1190     if (driver_streq(a, "-no-pie")) {
   1191       o->target.pic = KIT_PIC_NONE;
   1192       o->pie = 0;
   1193       continue;
   1194     }
   1195     if (driver_streq(a, "-rdynamic") || driver_streq(a, "-export-dynamic")) {
   1196       /* GCC/clang: ask the linker to promote defined globals into .dynsym
   1197        * (--export-dynamic). FreeBSD's HOST_ENV_LDFLAGS passes -rdynamic so a
   1198        * dynamically linked exe re-exports symbols (e.g. `environ`) for libc.so
   1199        * and for runtime symbolization. kit's ELF linker already exports the
   1200        * defined symbols that the DSOs it links reference, which is what hosted
   1201        * libc startup needs, so accept the flag for toolchain compatibility
   1202        * rather than reject it. (The standalone `kit ld` carries the explicit
   1203        * -E/--export-dynamic option for the full all-globals promotion.) */
   1204       continue;
   1205     }
   1206     if (driver_streq(a, "-Bstatic")) {
   1207       o->cur_link_mode = KIT_LM_STATIC;
   1208       continue;
   1209     }
   1210     if (driver_streq(a, "-Bdynamic")) {
   1211       o->cur_link_mode = KIT_LM_DYNAMIC;
   1212       continue;
   1213     }
   1214     if (driver_streq(a, "--as-needed")) {
   1215       o->cur_link_mode = KIT_LM_AS_NEEDED;
   1216       continue;
   1217     }
   1218     if (driver_streq(a, "--no-as-needed")) {
   1219       o->cur_link_mode = KIT_LM_DYNAMIC;
   1220       continue;
   1221     }
   1222     if (driver_streq(a, "--whole-archive")) {
   1223       o->cur_whole_archive = 1;
   1224       continue;
   1225     }
   1226     if (driver_streq(a, "--no-whole-archive")) {
   1227       o->cur_whole_archive = 0;
   1228       continue;
   1229     }
   1230     if (driver_streq(a, "--start-group")) {
   1231       if (o->cur_group_id != 0) {
   1232         driver_errf(CC_TOOL, "nested --start-group is not supported");
   1233         return 1;
   1234       }
   1235       if (o->next_group_id == UINT8_MAX) {
   1236         driver_errf(CC_TOOL, "too many --start-group occurrences");
   1237         return 1;
   1238       }
   1239       o->cur_group_id = ++o->next_group_id;
   1240       continue;
   1241     }
   1242     if (driver_streq(a, "--end-group")) {
   1243       if (o->cur_group_id == 0) {
   1244         driver_errf(CC_TOOL, "--end-group without --start-group");
   1245         return 1;
   1246       }
   1247       o->cur_group_id = 0;
   1248       continue;
   1249     }
   1250 
   1251     if (driver_streq(a, "-shared")) {
   1252       o->shared = 1;
   1253       if (o->target.pic == KIT_PIC_NONE) o->target.pic = KIT_PIC_PIC;
   1254       continue;
   1255     }
   1256     if (driver_streq(a, "-mwindows")) {
   1257       o->link.pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_GUI;
   1258       continue;
   1259     }
   1260     if (driver_streq(a, "-mconsole")) {
   1261       o->link.pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_CUI;
   1262       continue;
   1263     }
   1264     if (driver_strneq(a, "-Wl,", 4)) {
   1265       if (driver_link_flags_record_wl(&o->link, a + 4) != 0) return 1;
   1266       continue;
   1267     }
   1268 
   1269     if (driver_strneq(a, "-mcmodel=", 9)) {
   1270       if (cc_record_mcmodel(o, a + 9) != 0) return 1;
   1271       continue;
   1272     }
   1273     {
   1274       int tr = driver_target_features_try_consume(&o->target_features, o->env,
   1275                                                   CC_TOOL, argc, argv, &i);
   1276       if (tr < 0) return 1;
   1277       if (tr > 0) continue;
   1278     }
   1279     if (driver_strneq(a, "--build-id=", 11)) {
   1280       if (driver_link_flags_record_build_id(&o->link, a + 11) != 0) return 1;
   1281       continue;
   1282     }
   1283     if (driver_strneq(a, "-ffile-prefix-map=", 18)) {
   1284       if (cc_record_path_map(o, a + 18) != 0) return 1;
   1285       continue;
   1286     }
   1287 
   1288     if (driver_streq(a, "-o")) {
   1289       if (++i >= argc) {
   1290         driver_errf(CC_TOOL, "-o requires an argument");
   1291         return 1;
   1292       }
   1293       o->output_path = argv[i];
   1294       o->output_path_set = 1;
   1295       continue;
   1296     }
   1297     if (driver_strneq(a, "--output=", 9)) {
   1298       o->output_path = a + 9;
   1299       o->output_path_set = 1;
   1300       continue;
   1301     }
   1302     if (driver_streq(a, "--output")) {
   1303       if (++i >= argc) {
   1304         driver_errf(CC_TOOL, "--output requires an argument");
   1305         return 1;
   1306       }
   1307       o->output_path = argv[i];
   1308       o->output_path_set = 1;
   1309       continue;
   1310     }
   1311     if (driver_streq(a, "-e")) {
   1312       if (++i >= argc) {
   1313         driver_errf(CC_TOOL, "-e requires an argument");
   1314         return 1;
   1315       }
   1316       o->link.entry = argv[i];
   1317       continue;
   1318     }
   1319     if (driver_streq(a, "-T")) {
   1320       if (++i >= argc) {
   1321         driver_errf(CC_TOOL, "-T requires an argument");
   1322         return 1;
   1323       }
   1324       o->link.linker_script = argv[i];
   1325       continue;
   1326     }
   1327     if (driver_streq(a, "-target")) {
   1328       if (++i >= argc) {
   1329         driver_errf(CC_TOOL, "-target requires an argument");
   1330         return 1;
   1331       }
   1332       if (driver_target_from_triple(argv[i], &o->target) != 0) {
   1333         driver_errf(CC_TOOL, "unrecognized target triple: %.*s",
   1334                     KIT_SLICE_ARG(kit_slice_cstr(argv[i])));
   1335         return 1;
   1336       }
   1337       o->target_set = 1;
   1338       continue;
   1339     }
   1340     if (driver_strneq(a, "--target=", 9)) {
   1341       if (driver_target_from_triple(a + 9, &o->target) != 0) {
   1342         driver_errf(CC_TOOL, "unrecognized target triple: %.*s",
   1343                     KIT_SLICE_ARG(kit_slice_cstr(a + 9)));
   1344         return 1;
   1345       }
   1346       o->target_set = 1;
   1347       continue;
   1348     }
   1349     if (driver_streq(a, "--target")) {
   1350       if (++i >= argc) {
   1351         driver_errf(CC_TOOL, "--target requires an argument");
   1352         return 1;
   1353       }
   1354       if (driver_target_from_triple(argv[i], &o->target) != 0) {
   1355         driver_errf(CC_TOOL, "unrecognized target triple: %.*s",
   1356                     KIT_SLICE_ARG(kit_slice_cstr(argv[i])));
   1357         return 1;
   1358       }
   1359       o->target_set = 1;
   1360       continue;
   1361     }
   1362     if (driver_streq(a, "-Xlinker")) {
   1363       if (++i >= argc) {
   1364         driver_errf(CC_TOOL, "-Xlinker requires an argument");
   1365         return 1;
   1366       }
   1367       if (driver_link_flags_record_wl(&o->link, argv[i]) != 0) return 1;
   1368       continue;
   1369     }
   1370     if (driver_streq(a, "-x")) {
   1371       if (++i >= argc) {
   1372         driver_errf(CC_TOOL, "-x requires an argument");
   1373         return 1;
   1374       }
   1375       if (driver_streq(argv[i], "none")) {
   1376         forced_lang = -1;
   1377         continue;
   1378       }
   1379       /* cc-only CLI aliases that have no frontend `-x` name: GCC's "asm-cpp"
   1380        * and the case-sensitive "S" (distinct from "s") both select asm. */
   1381       if (driver_streq(argv[i], "asm-cpp") || driver_streq(argv[i], "S")) {
   1382         forced_lang = KIT_LANG_ASM;
   1383         continue;
   1384       }
   1385       {
   1386         KitLanguage lang = kit_language_for_name(NULL, argv[i]);
   1387         if (lang == KIT_LANG_UNKNOWN) {
   1388           driver_errf(CC_TOOL, "unsupported -x language: %.*s",
   1389                       KIT_SLICE_ARG(kit_slice_cstr(argv[i])));
   1390           return 1;
   1391         }
   1392         forced_lang = lang;
   1393         continue;
   1394       }
   1395     }
   1396     if (driver_strneq(a, "-L", 2)) {
   1397       const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL);
   1398       if (!dir) {
   1399         driver_errf(CC_TOOL, "-L requires an argument");
   1400         return 1;
   1401       }
   1402       o->lib_search_paths[o->nlib_search_paths++] = dir;
   1403       continue;
   1404     }
   1405     if (driver_strneq(a, "-l", 2)) {
   1406       const char* name = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL);
   1407       if (!name) {
   1408         driver_errf(CC_TOOL, "-l requires an argument");
   1409         return 1;
   1410       }
   1411       if (driver_streq(name, "c") && !o->no_stdlib && !o->no_defaultlibs) {
   1412         o->wants_hosted_libc = 1;
   1413         continue;
   1414       }
   1415       {
   1416         CcPendingLib* pl = &o->pending_libs[o->npending_libs++];
   1417         pl->name = name;
   1418         pl->whole_archive = o->cur_whole_archive;
   1419         pl->link_mode = o->cur_link_mode;
   1420         pl->group_id = o->cur_group_id;
   1421         cc_push_link_item(o, CC_LINK_LIB, o->npending_libs - 1u);
   1422       }
   1423       continue;
   1424     }
   1425 
   1426     if (driver_streq(a, "-M")) {
   1427       o->dep_mode = CC_DEP_M;
   1428       continue;
   1429     }
   1430     if (driver_streq(a, "-MM")) {
   1431       o->dep_mode = CC_DEP_MM;
   1432       continue;
   1433     }
   1434     if (driver_streq(a, "-MD")) {
   1435       o->dep_mode = CC_DEP_MD;
   1436       continue;
   1437     }
   1438     if (driver_streq(a, "-MMD")) {
   1439       o->dep_mode = CC_DEP_MMD;
   1440       continue;
   1441     }
   1442     if (driver_streq(a, "-MP")) {
   1443       o->dep_phony = 1;
   1444       continue;
   1445     }
   1446     if (driver_streq(a, "-MF")) {
   1447       if (++i >= argc) {
   1448         driver_errf(CC_TOOL, "-MF requires an argument");
   1449         return 1;
   1450       }
   1451       o->dep_file = argv[i];
   1452       continue;
   1453     }
   1454     if (driver_streq(a, "-MT") || driver_streq(a, "-MQ")) {
   1455       if (++i >= argc) {
   1456         driver_errf(CC_TOOL, "%.*s requires an argument",
   1457                     KIT_SLICE_ARG(kit_slice_cstr(a)));
   1458         return 1;
   1459       }
   1460       o->dep_targets[o->ndep_targets++] = argv[i];
   1461       continue;
   1462     }
   1463 
   1464     if (driver_streq(a, "--")) {
   1465       for (++i; i < argc; ++i) {
   1466         if (cc_classify_positional(o, argv[i], forced_lang) != 0) return 1;
   1467       }
   1468       break;
   1469     }
   1470     if (driver_streq(a, "-")) {
   1471       if (cc_classify_positional(o, a, forced_lang) != 0) return 1;
   1472       continue;
   1473     }
   1474     if (a[0] == '-' && a[1] != '\0') {
   1475       driver_errf(CC_TOOL, "unknown flag: %.*s",
   1476                   KIT_SLICE_ARG(kit_slice_cstr(a)));
   1477       return 1;
   1478     }
   1479 
   1480     if (cc_classify_positional(o, a, forced_lang) != 0) return 1;
   1481   }
   1482 
   1483   if (o->probe_kind != CC_PROBE_NONE) return 0;
   1484 
   1485   if (cc_apply_env(o) != 0) return 1;
   1486   if (cc_append_windows_lib_dirs(o) != 0) return 1;
   1487 
   1488   {
   1489     uint32_t total_sources = o->nsource_files + o->nsource_memory;
   1490     uint32_t total_link =
   1491         o->nobject_files + o->narchives + o->ndsos + o->npending_libs;
   1492 
   1493     if (total_sources == 0 && total_link == 0) {
   1494       driver_errf(CC_TOOL, "no input files");
   1495       cc_usage();
   1496       return 1;
   1497     }
   1498     if ((o->compile_only && o->preprocess_only) ||
   1499         (o->emit_asm_source && o->preprocess_only) ||
   1500         (o->syntax_only &&
   1501          (o->compile_only || o->preprocess_only || o->emit_asm_source))) {
   1502       driver_errf(CC_TOOL,
   1503                   "-c, -S, -E, and -fsyntax-only are mutually exclusive");
   1504       return 1;
   1505     }
   1506     if (o->shared && (o->compile_only || o->emit_asm_source ||
   1507                       o->preprocess_only || o->syntax_only)) {
   1508       driver_errf(CC_TOOL,
   1509                   "-shared is incompatible with -c/-S/-E/-fsyntax-only");
   1510       return 1;
   1511     }
   1512     if (o->shared && o->lto) {
   1513       driver_errf(CC_TOOL,
   1514                   "-shared -flto is not supported yet "
   1515                   "(shared-library LTO output is not exercised)");
   1516       return 1;
   1517     }
   1518     if (o->shared) {
   1519       driver_errf(CC_TOOL,
   1520                   "creating dynamic/shared libraries is not yet supported");
   1521       return 1;
   1522     }
   1523     if (o->emit_ir && o->opt_level < 1) {
   1524       driver_errf(CC_TOOL,
   1525                   "--emit=ir requires -O1 or higher "
   1526                   "(the IR tape is only recorded when the optimizer runs)");
   1527       return 1;
   1528     }
   1529     if (o->syntax_only) {
   1530       if (total_sources == 0 || total_link != 0) {
   1531         driver_errf(CC_TOOL,
   1532                     "-fsyntax-only requires source inputs and no link inputs");
   1533         return 1;
   1534       }
   1535       if (o->output_path) {
   1536         driver_errf(CC_TOOL, "-o is incompatible with -fsyntax-only");
   1537         return 1;
   1538       }
   1539       if (o->dep_mode != CC_DEP_NONE) {
   1540         driver_errf(CC_TOOL, "-M* is incompatible with -fsyntax-only");
   1541         return 1;
   1542       }
   1543     }
   1544     if (!o->shared && o->link.soname) {
   1545       driver_errf(CC_TOOL, "-Wl,-soname requires -shared");
   1546       return 1;
   1547     }
   1548     if (o->cur_group_id != 0) {
   1549       driver_errf(CC_TOOL, "missing --end-group");
   1550       return 1;
   1551     }
   1552     if (o->compile_only) {
   1553       if (total_sources == 0 || total_link != 0) {
   1554         driver_errf(CC_TOOL, "-c requires source inputs and no link inputs");
   1555         return 1;
   1556       }
   1557       if (o->output_path && total_sources > 1) {
   1558         driver_errf(CC_TOOL, "-o cannot be used with -c and multiple sources");
   1559         return 1;
   1560       }
   1561     }
   1562     if (o->preprocess_only) {
   1563       if (total_sources != 1 || total_link != 0) {
   1564         driver_errf(CC_TOOL,
   1565                     "-E requires exactly one C source and no .o/.a inputs");
   1566         return 1;
   1567       }
   1568     }
   1569     {
   1570       int dep_only = (o->dep_mode == CC_DEP_M || o->dep_mode == CC_DEP_MM);
   1571       int dep_with_compile =
   1572           (o->dep_mode == CC_DEP_MD || o->dep_mode == CC_DEP_MMD);
   1573       if (o->dep_mode != CC_DEP_NONE && o->preprocess_only) {
   1574         driver_errf(CC_TOOL, "-M* is incompatible with -E");
   1575         return 1;
   1576       }
   1577       if (dep_only && total_sources != 1) {
   1578         driver_errf(CC_TOOL, "-M/-MM requires exactly one input");
   1579         return 1;
   1580       }
   1581       if (dep_with_compile && !o->compile_only) {
   1582         driver_errf(CC_TOOL, "-MD/-MMD currently requires -c");
   1583         return 1;
   1584       }
   1585       if (dep_with_compile && total_sources != 1) {
   1586         driver_errf(CC_TOOL, "-MD/-MMD currently requires exactly one source");
   1587         return 1;
   1588       }
   1589       if (!o->output_path && !dep_only) {
   1590         if (o->syntax_only) {
   1591           /* no output */
   1592         } else if (o->compile_only) {
   1593           if (total_sources == 1) {
   1594             o->owned_output_path =
   1595                 cc_dep_default_target(o->env, o, &o->owned_output_path_size);
   1596             if (!o->owned_output_path) {
   1597               driver_errf(CC_TOOL, "out of memory");
   1598               return 1;
   1599             }
   1600             o->output_path = o->owned_output_path;
   1601           }
   1602         } else if (o->preprocess_only) {
   1603           /* stdout */
   1604         } else {
   1605           o->output_path = driver_default_exe_name(o->target);
   1606         }
   1607       }
   1608     }
   1609   }
   1610   cc_enable_hosted_for_sysroot(o);
   1611   cc_apply_default_hosted_profile(o);
   1612   if (cc_apply_hosted_profile(o) != 0) return 1;
   1613   if (!o->syntax_only && cc_resolve_pending_libs(o) != 0) return 1;
   1614   return 0;
   1615 }
   1616 
   1617 static const char* cc_primary_source_name(const CcOptions* o);
   1618 
   1619 /* Borrow the single source as a KitSlice. `*loaded` is set nonzero only
   1620  * when the file was opened via file_io and must be released. */
   1621 static int cc_load_single_source(const KitContext* ctx, const CcOptions* o,
   1622                                  KitSlice* in, KitFileData* fd, int* loaded) {
   1623   *loaded = 0;
   1624   if (o->nsource_memory == 1) {
   1625     *in = o->source_memory[0].bytes;
   1626     return 0;
   1627   }
   1628   if (ctx->file_io->read_all(ctx->file_io->user, o->source_files[0], fd) !=
   1629       KIT_OK) {
   1630     driver_errf(CC_TOOL, "failed to read: %.*s",
   1631                 KIT_SLICE_ARG(kit_slice_cstr(o->source_files[0])));
   1632     return 1;
   1633   }
   1634   *loaded = 1;
   1635   in->data = fd->data;
   1636   in->len = fd->size;
   1637   return 0;
   1638 }
   1639 
   1640 static KitStatus cc_compiler_new(const CcOptions* o, const KitContext* ctx,
   1641                                  KitTarget** target_out,
   1642                                  KitCompiler** compiler_out) {
   1643   KitStatus st;
   1644   if (target_out) *target_out = NULL;
   1645   if (compiler_out) *compiler_out = NULL;
   1646   if (!o || !ctx || !target_out || !compiler_out) return KIT_INVALID;
   1647   st = driver_target_new(ctx, o->target, &o->target_features, CC_TOOL,
   1648                          target_out);
   1649   if (st != KIT_OK) return st;
   1650   st = driver_compiler_new(*target_out, ctx, compiler_out);
   1651   if (st != KIT_OK) {
   1652     kit_target_free(*target_out);
   1653     *target_out = NULL;
   1654   }
   1655   return st;
   1656 }
   1657 
   1658 static int cc_preprocess(DriverEnv* env, const CcOptions* o,
   1659                          const KitPreprocessOptions* pp_opts) {
   1660   KitContext ctx = driver_env_to_context(env);
   1661   KitTarget* target = NULL;
   1662   KitCompiler* compiler = NULL;
   1663   KitWriter* writer = NULL;
   1664   KitFileData fd = {0};
   1665   KitSlice input = {0};
   1666   int rc = 1;
   1667   int loaded = 0;
   1668 
   1669   if (cc_load_single_source(&ctx, o, &input, &fd, &loaded) != 0) goto out;
   1670 
   1671   if (o->output_path) {
   1672     if (ctx.file_io->open_writer(ctx.file_io->user, o->output_path, &writer) !=
   1673         KIT_OK) {
   1674       driver_errf(CC_TOOL, "failed to open output: %.*s",
   1675                   KIT_SLICE_ARG(kit_slice_cstr(o->output_path)));
   1676       goto out;
   1677     }
   1678   } else {
   1679     writer = driver_stdout_writer(env);
   1680     if (!writer) {
   1681       driver_errf(CC_TOOL, "out of memory");
   1682       goto out;
   1683     }
   1684   }
   1685 
   1686   if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
   1687     driver_errf(CC_TOOL, "failed to initialize compiler");
   1688     goto out;
   1689   }
   1690 
   1691   rc = kit_cpp_preprocess(compiler, pp_opts,
   1692                           kit_slice_cstr(cc_primary_source_name(o)), &input,
   1693                           writer) == KIT_OK
   1694            ? 0
   1695            : 1;
   1696 
   1697 out:
   1698   if (compiler) driver_compiler_free(compiler);
   1699   kit_target_free(target);
   1700   if (writer) kit_writer_close(writer);
   1701   if (loaded) ctx.file_io->release(ctx.file_io->user, &fd);
   1702   return rc;
   1703 }
   1704 
   1705 /* ---- header-dependency output (-M family) ---- */
   1706 
   1707 typedef struct CcDepList {
   1708   const char** items;
   1709   uint32_t n;
   1710   uint32_t cap;
   1711 } CcDepList;
   1712 
   1713 typedef struct CcDiscardWriter {
   1714   KitWriter base;
   1715   DriverEnv* env;
   1716   uint64_t pos;
   1717 } CcDiscardWriter;
   1718 
   1719 static KitStatus cc_disc_write(KitWriter* w, const void* d, size_t n) {
   1720   (void)d;
   1721   ((CcDiscardWriter*)w)->pos += (uint64_t)n;
   1722   return KIT_OK;
   1723 }
   1724 static KitStatus cc_disc_seek(KitWriter* w, uint64_t off) {
   1725   ((CcDiscardWriter*)w)->pos = off;
   1726   return KIT_OK;
   1727 }
   1728 static uint64_t cc_disc_tell(KitWriter* w) {
   1729   return ((CcDiscardWriter*)w)->pos;
   1730 }
   1731 static KitStatus cc_disc_status(KitWriter* w) {
   1732   (void)w;
   1733   return KIT_OK;
   1734 }
   1735 static void cc_disc_close(KitWriter* w) {
   1736   CcDiscardWriter* dw = (CcDiscardWriter*)w;
   1737   driver_free(dw->env, dw, sizeof(*dw));
   1738 }
   1739 
   1740 static KitWriter* cc_discard_writer_new(DriverEnv* env) {
   1741   CcDiscardWriter* dw = (CcDiscardWriter*)driver_alloc_zeroed(env, sizeof(*dw));
   1742   if (!dw) return NULL;
   1743   dw->base.write = cc_disc_write;
   1744   dw->base.seek = cc_disc_seek;
   1745   dw->base.tell = cc_disc_tell;
   1746   dw->base.status = cc_disc_status;
   1747   dw->base.close = cc_disc_close;
   1748   dw->env = env;
   1749   return &dw->base;
   1750 }
   1751 
   1752 static void cc_write_str(KitWriter* w, const char* s) {
   1753   kit_writer_write(w, s, driver_strlen(s));
   1754 }
   1755 
   1756 static int cc_dep_filters_system(int mode) {
   1757   return mode == CC_DEP_MM || mode == CC_DEP_MMD;
   1758 }
   1759 
   1760 static int cc_dep_list_push(DriverEnv* env, CcDepList* l, const char* s) {
   1761   uint32_t i;
   1762   for (i = 0; i < l->n; ++i) {
   1763     if (driver_streq(l->items[i], s)) return 0;
   1764   }
   1765   if (l->n == l->cap) {
   1766     uint32_t newcap = l->cap ? l->cap * 2 : 16;
   1767     const char** ni = driver_alloc_zeroed(env, newcap * sizeof(*ni));
   1768     if (!ni) return 1;
   1769     if (l->items) {
   1770       driver_memcpy(ni, l->items, l->n * sizeof(*l->items));
   1771       driver_free(env, l->items, l->cap * sizeof(*l->items));
   1772     }
   1773     l->items = ni;
   1774     l->cap = newcap;
   1775   }
   1776   l->items[l->n++] = s;
   1777   return 0;
   1778 }
   1779 
   1780 static void cc_dep_list_free(DriverEnv* env, CcDepList* l) {
   1781   if (l->items) driver_free(env, l->items, l->cap * sizeof(*l->items));
   1782   l->items = NULL;
   1783   l->n = 0;
   1784   l->cap = 0;
   1785 }
   1786 
   1787 static char* cc_dep_default_target(DriverEnv* env, const CcOptions* o,
   1788                                    size_t* out_size) {
   1789   const char* base = o->output_path;
   1790   size_t len;
   1791   char* buf;
   1792   if (base) {
   1793     len = driver_strlen(base);
   1794     buf = driver_alloc(env, len + 1);
   1795     if (!buf) return NULL;
   1796     driver_memcpy(buf, base, len);
   1797     buf[len] = '\0';
   1798     *out_size = len + 1;
   1799     return buf;
   1800   }
   1801   if (o->nsource_memory == 1) {
   1802     const char* fallback = "<stdin>.o";
   1803     size_t flen = driver_strlen(fallback);
   1804     buf = driver_alloc(env, flen + 1);
   1805     if (!buf) return NULL;
   1806     driver_memcpy(buf, fallback, flen);
   1807     buf[flen] = '\0';
   1808     *out_size = flen + 1;
   1809     return buf;
   1810   }
   1811   {
   1812     const char* src = o->source_files[0];
   1813     size_t srclen = driver_strlen(src);
   1814     size_t dot = srclen;
   1815     size_t slash = 0;
   1816     size_t k;
   1817     for (k = srclen; k > 0; --k) {
   1818       if (src[k - 1] == '.') {
   1819         dot = k - 1;
   1820         break;
   1821       }
   1822       if (src[k - 1] == '/') break;
   1823     }
   1824     for (k = dot; k > 0; --k) {
   1825       if (src[k - 1] == '/') {
   1826         slash = k;
   1827         break;
   1828       }
   1829     }
   1830     {
   1831       const char* ext;
   1832       size_t ext_len;
   1833       size_t name_len = dot - slash;
   1834       size_t bufsz;
   1835       driver_default_obj_ext(o->target, &ext, &ext_len);
   1836       bufsz = name_len + ext_len + 1u;
   1837       buf = driver_alloc(env, bufsz);
   1838       if (!buf) return NULL;
   1839       driver_memcpy(buf, src + slash, name_len);
   1840       driver_memcpy(buf + name_len, ext, ext_len);
   1841       buf[name_len + ext_len] = '\0';
   1842       *out_size = bufsz;
   1843       return buf;
   1844     }
   1845   }
   1846 }
   1847 
   1848 static char* cc_default_obj_path_for_name(DriverEnv* env, const CcOptions* o,
   1849                                           const char* src, size_t* out_size) {
   1850   /* -S/--emit override the object suffix; otherwise the canonical
   1851    * platform object extension (Windows `.obj`, else `.o`) via the shared
   1852    * per-target helper. */
   1853   const char* ext;
   1854   size_t ext_len;
   1855   if (o && o->emit_asm_source) {
   1856     ext = ".s";
   1857     ext_len = 2u;
   1858   } else if (o && o->emit_ir) {
   1859     ext = ".ir";
   1860     ext_len = 3u;
   1861   } else {
   1862     driver_default_obj_ext(o->target, &ext, &ext_len);
   1863   }
   1864   size_t srclen = driver_strlen(src);
   1865   size_t dot = srclen;
   1866   size_t slash = 0;
   1867   size_t k;
   1868   char* buf;
   1869   for (k = srclen; k > 0; --k) {
   1870     if (src[k - 1] == '.') {
   1871       dot = k - 1;
   1872       break;
   1873     }
   1874     if (src[k - 1] == '/') break;
   1875   }
   1876   for (k = dot; k > 0; --k) {
   1877     if (src[k - 1] == '/') {
   1878       slash = k;
   1879       break;
   1880     }
   1881   }
   1882   {
   1883     size_t name_len = dot - slash;
   1884     size_t bufsz = name_len + ext_len + 1u;
   1885     buf = driver_alloc(env, bufsz);
   1886     if (!buf) return NULL;
   1887     driver_memcpy(buf, src + slash, name_len);
   1888     driver_memcpy(buf + name_len, ext, ext_len);
   1889     buf[name_len + ext_len] = '\0';
   1890     *out_size = bufsz;
   1891     return buf;
   1892   }
   1893 }
   1894 
   1895 static char* cc_dep_default_path(DriverEnv* env, const char* out_path,
   1896                                  size_t* out_size) {
   1897   size_t len = driver_strlen(out_path);
   1898   size_t dot = len;
   1899   size_t k;
   1900   for (k = len; k > 0; --k) {
   1901     if (out_path[k - 1] == '.') {
   1902       dot = k - 1;
   1903       break;
   1904     }
   1905     if (out_path[k - 1] == '/') break;
   1906   }
   1907   {
   1908     size_t bufsz = dot + 3;
   1909     char* buf = driver_alloc(env, bufsz);
   1910     if (!buf) return NULL;
   1911     driver_memcpy(buf, out_path, dot);
   1912     buf[dot] = '.';
   1913     buf[dot + 1] = 'd';
   1914     buf[dot + 2] = '\0';
   1915     *out_size = bufsz;
   1916     return buf;
   1917   }
   1918 }
   1919 
   1920 static int cc_dep_collect(DriverEnv* env, KitCompiler* compiler,
   1921                           int system_filter, CcDepList* list) {
   1922   KitDepIter* it = NULL;
   1923   KitDepEdge e;
   1924   if (kit_dep_iter_new(compiler, &it) != KIT_OK) return 1;
   1925   for (;;) {
   1926     KitIterResult r = kit_dep_iter_next(it, &e);
   1927     if (r != KIT_ITER_ITEM) break;
   1928     if (system_filter && e.from_system_path) continue;
   1929     if (cc_dep_list_push(env, list, e.included_name.s) != 0) {
   1930       kit_dep_iter_free(it);
   1931       return 1;
   1932     }
   1933   }
   1934   kit_dep_iter_free(it);
   1935   return 0;
   1936 }
   1937 
   1938 static void cc_dep_emit_rule(KitWriter* w, const char* const* targets,
   1939                              uint32_t ntargets, const char* primary_src,
   1940                              const CcDepList* deps, int phony) {
   1941   uint32_t i;
   1942   for (i = 0; i < ntargets; ++i) {
   1943     if (i) cc_write_str(w, " ");
   1944     cc_write_str(w, targets[i]);
   1945   }
   1946   cc_write_str(w, ":");
   1947   if (primary_src) {
   1948     cc_write_str(w, " ");
   1949     cc_write_str(w, primary_src);
   1950   }
   1951   for (i = 0; i < deps->n; ++i) {
   1952     cc_write_str(w, " \\\n  ");
   1953     cc_write_str(w, deps->items[i]);
   1954   }
   1955   cc_write_str(w, "\n");
   1956   if (phony) {
   1957     for (i = 0; i < deps->n; ++i) {
   1958       cc_write_str(w, "\n");
   1959       cc_write_str(w, deps->items[i]);
   1960       cc_write_str(w, ":\n");
   1961     }
   1962   }
   1963 }
   1964 
   1965 static KitWriter* cc_dep_open_writer(DriverEnv* env, const KitContext* ctx,
   1966                                      const CcOptions* o, char** owned_path,
   1967                                      size_t* owned_path_size) {
   1968   KitWriter* w = NULL;
   1969   *owned_path = NULL;
   1970   *owned_path_size = 0;
   1971   if (o->dep_file) {
   1972     if (ctx->file_io->open_writer(ctx->file_io->user, o->dep_file, &w) !=
   1973         KIT_OK)
   1974       return NULL;
   1975     return w;
   1976   }
   1977   if (o->dep_mode == CC_DEP_M || o->dep_mode == CC_DEP_MM) {
   1978     return driver_stdout_writer(env);
   1979   }
   1980   {
   1981     char* p = cc_dep_default_path(env, o->output_path, owned_path_size);
   1982     if (!p) return NULL;
   1983     *owned_path = p;
   1984     if (ctx->file_io->open_writer(ctx->file_io->user, p, &w) != KIT_OK)
   1985       return NULL;
   1986     return w;
   1987   }
   1988 }
   1989 
   1990 static const char* cc_primary_source_name(const CcOptions* o) {
   1991   if (o->nsource_memory == 1) return o->source_memory[0].name.s;
   1992   return o->source_files[0];
   1993 }
   1994 
   1995 static int cc_dep_finish(DriverEnv* env, const KitContext* ctx,
   1996                          KitCompiler* compiler, const CcOptions* o) {
   1997   CcDepList deps = {0};
   1998   KitWriter* dep_w = NULL;
   1999   char* owned_path = NULL;
   2000   size_t owned_size = 0;
   2001   char* owned_target = NULL;
   2002   size_t owned_target_size = 0;
   2003   const char* one_target[1];
   2004   const char* const* targets;
   2005   uint32_t ntargets;
   2006   int rc = 1;
   2007 
   2008   if (cc_dep_collect(env, compiler, cc_dep_filters_system(o->dep_mode),
   2009                      &deps) != 0) {
   2010     driver_errf(CC_TOOL, "out of memory");
   2011     goto out;
   2012   }
   2013 
   2014   targets = o->dep_targets;
   2015   ntargets = o->ndep_targets;
   2016   if (ntargets == 0) {
   2017     owned_target = cc_dep_default_target(env, o, &owned_target_size);
   2018     if (!owned_target) {
   2019       driver_errf(CC_TOOL, "out of memory");
   2020       goto out;
   2021     }
   2022     one_target[0] = owned_target;
   2023     targets = one_target;
   2024     ntargets = 1;
   2025   }
   2026 
   2027   dep_w = cc_dep_open_writer(env, ctx, o, &owned_path, &owned_size);
   2028   if (!dep_w) {
   2029     driver_errf(CC_TOOL, "failed to open dep output: %.*s",
   2030                 KIT_SLICE_ARG(kit_slice_cstr(
   2031                     o->dep_file ? o->dep_file
   2032                                 : (owned_path ? owned_path : "<stdout>"))));
   2033     goto out;
   2034   }
   2035 
   2036   cc_dep_emit_rule(dep_w, targets, ntargets, cc_primary_source_name(o), &deps,
   2037                    o->dep_phony);
   2038   rc = kit_writer_status(dep_w) == KIT_OK ? 0 : 1;
   2039 
   2040 out:
   2041   if (dep_w) kit_writer_close(dep_w);
   2042   if (owned_path) driver_free(env, owned_path, owned_size);
   2043   if (owned_target) driver_free(env, owned_target, owned_target_size);
   2044   cc_dep_list_free(env, &deps);
   2045   return rc;
   2046 }
   2047 
   2048 static void cc_fill_c_opts(const CcOptions* o, KitCCompileOptions* copts) {
   2049   KitCCompileOptions zero = {0};
   2050   *copts = zero;
   2051   copts->code.opt_level = o->syntax_only ? 0 : o->opt_level;
   2052   copts->code.debug_info = o->debug_info;
   2053   copts->code.check_only = o->syntax_only ? true : false;
   2054   copts->code.default_visibility = o->default_visibility;
   2055   copts->code.emit_c_source = o->emit_c_source ? true : false;
   2056   copts->code.emit_ir = o->emit_ir ? true : false;
   2057   copts->code.emit_asm_source = o->emit_asm_source ? true : false;
   2058   copts->code.function_sections = o->function_sections ? true : false;
   2059   copts->code.data_sections = o->data_sections ? true : false;
   2060   copts->code.lto = o->lto ? true : false;
   2061   copts->code.epoch = o->epoch;
   2062   copts->code.path_map = o->npath_map ? o->path_map : NULL;
   2063   copts->code.npath_map = o->npath_map;
   2064   copts->diagnostics.warnings_are_errors = o->warnings_are_errors;
   2065   copts->diagnostics.max_errors = o->max_errors;
   2066 }
   2067 
   2068 static int cc_run_deps_only(DriverEnv* env, const CcOptions* o,
   2069                             const KitPreprocessOptions* pp) {
   2070   KitContext ctx = driver_env_to_context(env);
   2071   KitTarget* target = NULL;
   2072   KitCompiler* compiler = NULL;
   2073   KitWriter* discard = NULL;
   2074   KitFileData fd = {0};
   2075   KitSlice input = {0};
   2076   int loaded = 0;
   2077   int rc = 1;
   2078 
   2079   if (cc_load_single_source(&ctx, o, &input, &fd, &loaded) != 0) goto out;
   2080 
   2081   discard = cc_discard_writer_new(env);
   2082   if (!discard) {
   2083     driver_errf(CC_TOOL, "out of memory");
   2084     goto out;
   2085   }
   2086 
   2087   if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
   2088     driver_errf(CC_TOOL, "failed to initialize compiler");
   2089     goto out;
   2090   }
   2091 
   2092   if (kit_cpp_preprocess(compiler, pp,
   2093                          kit_slice_cstr(cc_primary_source_name(o)), &input,
   2094                          discard) != KIT_OK)
   2095     goto out;
   2096 
   2097   rc = cc_dep_finish(env, &ctx, compiler, o);
   2098 
   2099 out:
   2100   if (compiler) driver_compiler_free(compiler);
   2101   kit_target_free(target);
   2102   if (discard) kit_writer_close(discard);
   2103   if (loaded) ctx.file_io->release(ctx.file_io->user, &fd);
   2104   return rc;
   2105 }
   2106 
   2107 /* Compile one source to an object builder via the shared engine. cc never
   2108  * passes frontend-specific language_options (it has no flag surface for them);
   2109  * those are the `compile` tool's domain. */
   2110 static KitStatus cc_compile_source_obj(KitCompiler* compiler, KitLanguage lang,
   2111                                        const KitCCompileOptions* copts,
   2112                                        const KitPreprocessOptions* pp,
   2113                                        KitSlice name, const KitSlice* input,
   2114                                        KitObjBuilder** out) {
   2115   return driver_compile_run(compiler, lang, &copts->code, &copts->diagnostics,
   2116                             pp, NULL, name, input, NULL, out);
   2117 }
   2118 
   2119 static KitStatus cc_compile_source_emit(KitCompiler* compiler, KitLanguage lang,
   2120                                         const KitCCompileOptions* copts,
   2121                                         const KitPreprocessOptions* pp,
   2122                                         KitSlice name, const KitSlice* input,
   2123                                         KitWriter* out) {
   2124   return driver_compile_run(compiler, lang, &copts->code, &copts->diagnostics,
   2125                             pp, NULL, name, input, out, NULL);
   2126 }
   2127 
   2128 static int cc_run_compile_one(DriverEnv* env, const CcOptions* o,
   2129                               const KitPreprocessOptions* pp, int is_memory,
   2130                               uint32_t index, const char* out_path) {
   2131   KitContext ctx = driver_env_to_context(env);
   2132   KitTarget* target = NULL;
   2133   KitCompiler* compiler = NULL;
   2134   KitWriter* obj_w = NULL;
   2135   KitFileData fd = {0};
   2136   KitSlice input = {0};
   2137   KitCCompileOptions copts;
   2138   int loaded = 0;
   2139   int rc = 1;
   2140 
   2141   if (is_memory) {
   2142     input = o->source_memory[index].bytes;
   2143   } else {
   2144     if (ctx.file_io->read_all(ctx.file_io->user, o->source_files[index], &fd) !=
   2145         KIT_OK) {
   2146       driver_errf(CC_TOOL, "failed to read: %.*s",
   2147                   KIT_SLICE_ARG(kit_slice_cstr(o->source_files[index])));
   2148       goto out;
   2149     }
   2150     loaded = 1;
   2151     input.data = fd.data;
   2152     input.len = fd.size;
   2153   }
   2154 
   2155   if (ctx.file_io->open_writer(ctx.file_io->user, out_path, &obj_w) != KIT_OK) {
   2156     driver_errf(CC_TOOL, "failed to open output: %.*s",
   2157                 KIT_SLICE_ARG(kit_slice_cstr(out_path)));
   2158     goto out;
   2159   }
   2160 
   2161   if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
   2162     driver_errf(CC_TOOL, "failed to initialize compiler");
   2163     goto out;
   2164   }
   2165 
   2166   cc_fill_c_opts(o, &copts);
   2167   if (copts.code.emit_c_source) {
   2168     /* --emit=c routes the output writer to the C-source CGTarget instead of
   2169      * the object emitter. The downstream `kit_compile_*_emit` path will
   2170      * skip the object-serialize step when this is set. */
   2171     copts.code.c_source_writer = obj_w;
   2172   }
   2173   if (copts.code.emit_ir) {
   2174     /* --emit=ir routes the output writer to the semantic-IR dumper in the opt
   2175      * recorder instead of the object emitter. The downstream emit path skips
   2176      * the object-serialize step when this is set. */
   2177     copts.code.ir_dump_writer = obj_w;
   2178   }
   2179   {
   2180     KitLanguage lang = is_memory
   2181                            ? o->source_memory[index].lang
   2182                            : cc_resolve_lang(compiler, o->source_files[index],
   2183                                              o->source_langs[index]);
   2184     KitSlice in_name = is_memory ? o->source_memory[index].name
   2185                                  : kit_slice_cstr(o->source_files[index]);
   2186     KitStatus st;
   2187     st = cc_compile_source_emit(compiler, lang, &copts, pp, in_name, &input,
   2188                                 obj_w);
   2189     if (st != KIT_OK) goto out;
   2190   }
   2191 
   2192   rc = (o->dep_mode == CC_DEP_MD || o->dep_mode == CC_DEP_MMD)
   2193            ? cc_dep_finish(env, &ctx, compiler, o)
   2194            : 0;
   2195 
   2196 out:
   2197   if (compiler) driver_compiler_free(compiler);
   2198   kit_target_free(target);
   2199   if (obj_w) kit_writer_close(obj_w);
   2200   if (loaded) ctx.file_io->release(ctx.file_io->user, &fd);
   2201   return rc;
   2202 }
   2203 
   2204 static int cc_run_compile_obj(DriverEnv* env, const CcOptions* o,
   2205                               const KitPreprocessOptions* pp) {
   2206   return cc_run_compile_one(env, o, pp, o->nsource_memory == 1, 0,
   2207                             o->output_path);
   2208 }
   2209 
   2210 static int cc_run_compile_objs(DriverEnv* env, const CcOptions* o,
   2211                                const KitPreprocessOptions* pp) {
   2212   uint32_t i;
   2213   if (o->output_path) return cc_run_compile_obj(env, o, pp);
   2214   for (i = 0; i < o->nsource_files; ++i) {
   2215     size_t out_size = 0;
   2216     char* out =
   2217         cc_default_obj_path_for_name(env, o, o->source_files[i], &out_size);
   2218     int rc;
   2219     if (!out) {
   2220       driver_errf(CC_TOOL, "out of memory");
   2221       return 1;
   2222     }
   2223     rc = cc_run_compile_one(env, o, pp, 0, i, out);
   2224     driver_free(env, out, out_size);
   2225     if (rc != 0) return rc;
   2226   }
   2227   for (i = 0; i < o->nsource_memory; ++i) {
   2228     const char* out = o->emit_asm_source ? "<stdin>.s"
   2229                       : o->emit_ir       ? "<stdin>.ir"
   2230                                          : "<stdin>.o";
   2231     if (cc_run_compile_one(env, o, pp, 1, i, out) != 0) return 1;
   2232   }
   2233   return 0;
   2234 }
   2235 
   2236 static int cc_run_check(DriverEnv* env, const CcOptions* o,
   2237                         const KitPreprocessOptions* pp) {
   2238   KitContext ctx = driver_env_to_context(env);
   2239   const KitFileIO* io = ctx.file_io;
   2240   KitTarget* target = NULL;
   2241   KitCompiler* compiler = NULL;
   2242   DriverLoad* src_lf = NULL;
   2243   KitSlice* src_bytes = NULL;
   2244   KitCCompileOptions copts;
   2245   uint32_t i;
   2246   int rc = 1;
   2247 
   2248   if (!io || !io->read_all) {
   2249     driver_errf(CC_TOOL, "host file I/O unavailable");
   2250     return 1;
   2251   }
   2252 
   2253   if (o->nsource_files) {
   2254     src_lf = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_lf));
   2255     src_bytes = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_bytes));
   2256     if (!src_lf || !src_bytes) {
   2257       driver_errf(CC_TOOL, "out of memory");
   2258       goto out;
   2259     }
   2260   }
   2261 
   2262   for (i = 0; i < o->nsource_files; ++i) {
   2263     if (driver_load_bytes(io, CC_TOOL, o->source_files[i], &src_lf[i],
   2264                           &src_bytes[i]) != 0)
   2265       goto out;
   2266   }
   2267 
   2268   if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
   2269     driver_errf(CC_TOOL, "failed to initialize compiler");
   2270     goto out;
   2271   }
   2272 
   2273   cc_fill_c_opts(o, &copts);
   2274   for (i = 0; i < o->nsource_files; ++i) {
   2275     KitObjBuilder* ob = NULL;
   2276     KitLanguage lang =
   2277         cc_resolve_lang(compiler, o->source_files[i], o->source_langs[i]);
   2278     KitStatus st = cc_compile_source_obj(compiler, lang, &copts, pp,
   2279                                          kit_slice_cstr(o->source_files[i]),
   2280                                          &src_bytes[i], &ob);
   2281     kit_obj_builder_free(ob);
   2282     if (st != KIT_OK) goto out;
   2283   }
   2284   for (i = 0; i < o->nsource_memory; ++i) {
   2285     KitObjBuilder* ob = NULL;
   2286     KitStatus st = cc_compile_source_obj(compiler, o->source_memory[i].lang,
   2287                                          &copts, pp, o->source_memory[i].name,
   2288                                          &o->source_memory[i].bytes, &ob);
   2289     kit_obj_builder_free(ob);
   2290     if (st != KIT_OK) goto out;
   2291   }
   2292 
   2293   rc = 0;
   2294 
   2295 out:
   2296   if (compiler) driver_compiler_free(compiler);
   2297   kit_target_free(target);
   2298   if (src_lf) {
   2299     for (i = 0; i < o->nsource_files; ++i) driver_release_bytes(io, &src_lf[i]);
   2300   }
   2301   if (src_bytes)
   2302     driver_free(env, src_bytes, o->nsource_files * sizeof(*src_bytes));
   2303   if (src_lf) driver_free(env, src_lf, o->nsource_files * sizeof(*src_lf));
   2304   return rc;
   2305 }
   2306 
   2307 /* exe/shared path: compile every source via a single KitCompiler, load
   2308  * .o/.a/script inputs, and link. The link session borrows the per-source
   2309  * KitObjBuilders; this function keeps ownership and frees them after the
   2310  * session is done. */
   2311 static int cc_run_link_exe(DriverEnv* env, const CcOptions* o,
   2312                            const KitPreprocessOptions* pp) {
   2313   KitContext ctx = driver_env_to_context(env);
   2314   const KitFileIO* io = ctx.file_io;
   2315   KitTarget* target = NULL;
   2316   KitCompiler* compiler = NULL;
   2317   KitWriter* out_w = NULL;
   2318   DriverLoad* src_lf = NULL;
   2319   DriverLoad* obj_lf = NULL;
   2320   DriverLoad* arch_lf = NULL;
   2321   DriverLoad script_lf = {0};
   2322   DriverLoad* dso_lf = NULL;
   2323   KitSlice* src_bytes = NULL;
   2324   KitSlice* obj_in = NULL;
   2325   KitSlice* obj_names = NULL;
   2326   KitLinkArchiveInput* arch_in = NULL;
   2327   KitSlice* dso_in = NULL;
   2328   KitSlice* dso_names = NULL;
   2329   KitLinkInputOrder* order = NULL;
   2330   KitObjBuilder** objs = NULL;
   2331   DriverCompileSource* sources = NULL;
   2332   DriverCompilePendingLto pending_lto = {0};
   2333   uint32_t* source_obj_index = NULL;
   2334   uint8_t* source_order_keep = NULL;
   2335   KitLinkScript* script = NULL;
   2336   KitSlice* rpath_slices = NULL;
   2337   KitCCompileOptions copts;
   2338   DriverCompileBatchOptions lto_batch;
   2339   uint32_t nsrc = o->nsource_files + o->nsource_memory;
   2340   uint32_t i;
   2341   uint32_t nobjs = 0;
   2342   uint32_t norder = 0;
   2343   int rc = 1;
   2344 
   2345   if (!io || !io->read_all || !io->open_writer) {
   2346     driver_errf(CC_TOOL, "host file I/O unavailable");
   2347     return 1;
   2348   }
   2349 
   2350   if (o->nsource_files) {
   2351     src_bytes = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_bytes));
   2352     src_lf = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_lf));
   2353     if (!src_bytes || !src_lf) {
   2354       driver_errf(CC_TOOL, "out of memory");
   2355       goto out;
   2356     }
   2357   }
   2358   if (nsrc) {
   2359     objs = driver_alloc_zeroed(env, nsrc * sizeof(*objs));
   2360     sources = driver_alloc_zeroed(env, nsrc * sizeof(*sources));
   2361     source_obj_index =
   2362         driver_alloc_zeroed(env, nsrc * sizeof(*source_obj_index));
   2363     source_order_keep =
   2364         driver_alloc_zeroed(env, nsrc * sizeof(*source_order_keep));
   2365     if (!objs || !sources || !source_obj_index || !source_order_keep) {
   2366       driver_errf(CC_TOOL, "out of memory");
   2367       goto out;
   2368     }
   2369   }
   2370   if (o->nobject_files) {
   2371     obj_lf = driver_alloc_zeroed(env, o->nobject_files * sizeof(*obj_lf));
   2372     obj_in = driver_alloc_zeroed(env, o->nobject_files * sizeof(*obj_in));
   2373     obj_names = driver_alloc_zeroed(env, o->nobject_files * sizeof(*obj_names));
   2374     if (!obj_lf || !obj_in || !obj_names) {
   2375       driver_errf(CC_TOOL, "out of memory");
   2376       goto out;
   2377     }
   2378   }
   2379   if (o->narchives) {
   2380     arch_lf = driver_alloc_zeroed(env, o->narchives * sizeof(*arch_lf));
   2381     arch_in = driver_alloc_zeroed(env, o->narchives * sizeof(*arch_in));
   2382     if (!arch_lf || !arch_in) {
   2383       driver_errf(CC_TOOL, "out of memory");
   2384       goto out;
   2385     }
   2386   }
   2387   if (o->ndsos) {
   2388     dso_lf = driver_alloc_zeroed(env, o->ndsos * sizeof(*dso_lf));
   2389     dso_in = driver_alloc_zeroed(env, o->ndsos * sizeof(*dso_in));
   2390     dso_names = driver_alloc_zeroed(env, o->ndsos * sizeof(*dso_names));
   2391     if (!dso_lf || !dso_in || !dso_names) {
   2392       driver_errf(CC_TOOL, "out of memory");
   2393       goto out;
   2394     }
   2395   }
   2396   if (o->nlink_items) {
   2397     order = driver_alloc_zeroed(env, o->nlink_items * sizeof(*order));
   2398     if (!order) {
   2399       driver_errf(CC_TOOL, "out of memory");
   2400       goto out;
   2401     }
   2402   }
   2403 
   2404   for (i = 0; i < o->nsource_files; ++i) {
   2405     if (driver_load_bytes(io, CC_TOOL, o->source_files[i], &src_lf[i],
   2406                           &src_bytes[i]) != 0)
   2407       goto out;
   2408   }
   2409 
   2410   for (i = 0; i < o->nobject_files; ++i) {
   2411     if (driver_load_bytes(io, CC_TOOL, o->object_files[i], &obj_lf[i],
   2412                           &obj_in[i]) != 0)
   2413       goto out;
   2414     obj_names[i] = kit_slice_cstr(o->object_files[i]);
   2415   }
   2416   for (i = 0; i < o->narchives; ++i) {
   2417     if (driver_load_bytes(io, CC_TOOL, o->archives[i].path, &arch_lf[i],
   2418                           &arch_in[i].bytes) != 0)
   2419       goto out;
   2420     arch_in[i].link_mode = o->archives[i].link_mode;
   2421     arch_in[i].whole_archive = o->archives[i].whole_archive;
   2422     arch_in[i].group_id = o->archives[i].group_id;
   2423   }
   2424   for (i = 0; i < o->ndsos; ++i) {
   2425     if (driver_load_bytes(io, CC_TOOL, o->dsos[i].path, &dso_lf[i],
   2426                           &dso_in[i]) != 0)
   2427       goto out;
   2428     dso_names[i] = kit_slice_cstr(o->dsos[i].path);
   2429   }
   2430 
   2431   if (o->link.linker_script) {
   2432     KitSlice dummy;
   2433     if (driver_load_bytes(io, CC_TOOL, o->link.linker_script, &script_lf,
   2434                           &dummy) != 0)
   2435       goto out;
   2436   }
   2437 
   2438   if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
   2439     driver_errf(CC_TOOL, "failed to initialize compiler");
   2440     goto out;
   2441   }
   2442 
   2443   if (script_lf.loaded) {
   2444     KitSlice script_text = {.s = (const char*)script_lf.fd.data,
   2445                             .len = script_lf.fd.size};
   2446     if (kit_link_script_parse(&ctx, script_text, &script) != KIT_OK) goto out;
   2447   }
   2448 
   2449   cc_fill_c_opts(o, &copts);
   2450   memset(&lto_batch, 0, sizeof lto_batch);
   2451   lto_batch.output_kind =
   2452       o->shared ? KIT_CG_OUTPUT_SHARED : KIT_CG_OUTPUT_EXECUTABLE;
   2453   lto_batch.interposition_policy = o->shared
   2454                                        ? KIT_CG_INTERPOSITION_DEFAULT_VISIBILITY
   2455                                        : KIT_CG_INTERPOSITION_DEFAULT;
   2456   lto_batch.defer_lto_finish = 1;
   2457   for (i = 0; i < o->nsource_files; ++i) {
   2458     KitLanguage lang =
   2459         cc_resolve_lang(compiler, o->source_files[i], o->source_langs[i]);
   2460     if (lang == KIT_LANG_UNKNOWN) {
   2461       driver_errf(CC_TOOL, "cannot determine language for %.*s (use -x LANG)",
   2462                   KIT_SLICE_ARG(kit_slice_cstr(o->source_files[i])));
   2463       goto out;
   2464     }
   2465     sources[i].lang = lang;
   2466     sources[i].name = kit_slice_cstr(o->source_files[i]);
   2467     sources[i].bytes = src_bytes[i];
   2468     sources[i].pp = pp;
   2469   }
   2470   for (i = 0; i < o->nsource_memory; ++i) {
   2471     uint32_t si = o->nsource_files + i;
   2472     if (o->source_memory[i].lang == KIT_LANG_UNKNOWN) {
   2473       driver_errf(CC_TOOL, "cannot determine language for %.*s (use -x LANG)",
   2474                   KIT_SLICE_ARG(o->source_memory[i].name));
   2475       goto out;
   2476     }
   2477     sources[si].lang = o->source_memory[i].lang;
   2478     sources[si].name = o->source_memory[i].name;
   2479     sources[si].bytes = o->source_memory[i].bytes;
   2480     sources[si].pp = pp;
   2481   }
   2482   if (nsrc) {
   2483     DriverCompileObjects cout;
   2484     KitStatus st;
   2485     memset(&cout, 0, sizeof cout);
   2486     cout.objs = objs;
   2487     cout.source_obj_index = source_obj_index;
   2488     cout.source_order_keep = source_order_keep;
   2489     cout.pending_lto = &pending_lto;
   2490     st = driver_compile_sources_run(compiler, &copts.code, &copts.diagnostics,
   2491                                     sources, nsrc, &lto_batch, &cout);
   2492     nobjs = cout.nobjs;
   2493     if (st != KIT_OK) goto out;
   2494   }
   2495 
   2496   if (io->open_writer(io->user, o->output_path, &out_w) != KIT_OK) {
   2497     driver_errf(CC_TOOL, "failed to open output: %.*s",
   2498                 KIT_SLICE_ARG(kit_slice_cstr(o->output_path)));
   2499     goto out;
   2500   }
   2501 
   2502   {
   2503     KitLinkSessionOptions lopts;
   2504     KitStatus st;
   2505     if (driver_link_flags_fill_options(
   2506             &o->link, o->target, o->pie, o->shared, /*relocatable=*/0,
   2507             o->shared ? KIT_LINK_OUTPUT_SHARED : KIT_LINK_OUTPUT_EXE, script,
   2508             &lopts, &rpath_slices) != 0)
   2509       goto out;
   2510 
   2511     /* Translate the command-line link order into the engine's public
   2512      * KitLinkInputOrder list. The dead-simple fallback for o->nlink_items == 0
   2513      * never fires (a link action always has at least one input), so every add
   2514      * flows through the ordered path. */
   2515     {
   2516       uint32_t oi;
   2517       DriverLinkInputs li;
   2518       for (oi = 0; oi < o->nlink_items; ++oi) {
   2519         const CcLinkItem* item = &o->link_items[oi];
   2520         KitLinkInputOrder* ord;
   2521         switch ((CcLinkItemKind)item->kind) {
   2522           case CC_LINK_SOURCE_FILE:
   2523             if (!source_order_keep[item->index]) continue;
   2524             ord = &order[norder++];
   2525             ord->kind = KIT_LINK_INPUT_OBJ;
   2526             ord->index = source_obj_index[item->index];
   2527             break;
   2528           case CC_LINK_SOURCE_MEMORY: {
   2529             uint32_t si = o->nsource_files + item->index;
   2530             if (!source_order_keep[si]) continue;
   2531             ord = &order[norder++];
   2532             ord->kind = KIT_LINK_INPUT_OBJ;
   2533             ord->index = source_obj_index[si];
   2534             break;
   2535           }
   2536           case CC_LINK_OBJECT:
   2537             ord = &order[norder++];
   2538             ord->kind = KIT_LINK_INPUT_OBJ_BYTES;
   2539             ord->index = item->index;
   2540             break;
   2541           case CC_LINK_ARCHIVE:
   2542             ord = &order[norder++];
   2543             ord->kind = KIT_LINK_INPUT_ARCHIVE;
   2544             ord->index = item->index;
   2545             break;
   2546           case CC_LINK_DSO:
   2547             ord = &order[norder++];
   2548             ord->kind = KIT_LINK_INPUT_DSO;
   2549             ord->index = item->index;
   2550             break;
   2551           case CC_LINK_LIB: {
   2552             const CcPendingLib* pl = &o->pending_libs[item->index];
   2553             ord = &order[norder++];
   2554             if (pl->resolved_kind == CC_LINK_DSO) {
   2555               ord->kind = KIT_LINK_INPUT_DSO;
   2556               ord->index = pl->resolved_index;
   2557             } else {
   2558               ord->kind = KIT_LINK_INPUT_ARCHIVE;
   2559               ord->index = pl->resolved_index;
   2560             }
   2561             break;
   2562           }
   2563         }
   2564       }
   2565       memset(&li, 0, sizeof(li));
   2566       li.objs = objs;
   2567       li.nobjs = nobjs;
   2568       li.obj_names = obj_names;
   2569       li.obj_bytes = obj_in;
   2570       li.nobj_bytes = o->nobject_files;
   2571       li.archives = arch_in;
   2572       li.narchives = o->narchives;
   2573       li.dso_names = dso_names;
   2574       li.dso_bytes = dso_in;
   2575       li.ndsos = o->ndsos;
   2576       li.order = order;
   2577       li.norder = norder;
   2578       st = driver_link_engine_emit_with_lto(compiler, &lopts, &li, &pending_lto,
   2579                                             &lto_batch, out_w);
   2580     }
   2581     rc = st == KIT_OK ? 0 : 1;
   2582   }
   2583 
   2584 out:
   2585   if (out_w) kit_writer_close(out_w);
   2586   if (rc == 0 && o->output_path) {
   2587     if (driver_mark_executable_output(o->output_path) != 0) {
   2588       driver_errf(CC_TOOL, "failed to set executable mode: %.*s",
   2589                   KIT_SLICE_ARG(kit_slice_cstr(o->output_path)));
   2590       rc = 1;
   2591     }
   2592   }
   2593   if (script) kit_link_script_free(&ctx, script);
   2594   driver_compile_pending_lto_abort(&pending_lto);
   2595   driver_link_flags_free_rpath_slices(&o->link, rpath_slices);
   2596   if (compiler) driver_compiler_free(compiler);
   2597   kit_target_free(target);
   2598   driver_release_bytes(io, &script_lf);
   2599   if (arch_lf) {
   2600     for (i = 0; i < o->narchives; ++i) driver_release_bytes(io, &arch_lf[i]);
   2601   }
   2602   if (dso_lf) {
   2603     for (i = 0; i < o->ndsos; ++i) driver_release_bytes(io, &dso_lf[i]);
   2604   }
   2605   if (obj_lf) {
   2606     for (i = 0; i < o->nobject_files; ++i) driver_release_bytes(io, &obj_lf[i]);
   2607   }
   2608   if (src_lf) {
   2609     for (i = 0; i < o->nsource_files; ++i) driver_release_bytes(io, &src_lf[i]);
   2610   }
   2611   if (arch_in) driver_free(env, arch_in, o->narchives * sizeof(*arch_in));
   2612   if (arch_lf) driver_free(env, arch_lf, o->narchives * sizeof(*arch_lf));
   2613   if (dso_in) driver_free(env, dso_in, o->ndsos * sizeof(*dso_in));
   2614   if (dso_names) driver_free(env, dso_names, o->ndsos * sizeof(*dso_names));
   2615   if (dso_lf) driver_free(env, dso_lf, o->ndsos * sizeof(*dso_lf));
   2616   if (order) driver_free(env, order, o->nlink_items * sizeof(*order));
   2617   if (obj_in) driver_free(env, obj_in, o->nobject_files * sizeof(*obj_in));
   2618   if (obj_names)
   2619     driver_free(env, obj_names, o->nobject_files * sizeof(*obj_names));
   2620   if (obj_lf) driver_free(env, obj_lf, o->nobject_files * sizeof(*obj_lf));
   2621   if (src_lf) driver_free(env, src_lf, o->nsource_files * sizeof(*src_lf));
   2622   if (src_bytes)
   2623     driver_free(env, src_bytes, o->nsource_files * sizeof(*src_bytes));
   2624   if (objs) {
   2625     for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]);
   2626     driver_free(env, objs, nsrc * sizeof(*objs));
   2627   }
   2628   if (source_order_keep)
   2629     driver_free(env, source_order_keep, nsrc * sizeof(*source_order_keep));
   2630   if (source_obj_index)
   2631     driver_free(env, source_obj_index, nsrc * sizeof(*source_obj_index));
   2632   if (sources) driver_free(env, sources, nsrc * sizeof(*sources));
   2633   return rc;
   2634 }
   2635 
   2636 static int driver_cc_main(int argc, char** argv, int force_check) {
   2637   DriverEnv env;
   2638   CcOptions co = {0};
   2639   DriverRuntimeSupport runtime = {0};
   2640   KitPreprocessOptions pp;
   2641   int rc;
   2642   int runtime_resolved = 0;
   2643   int link_action;
   2644 
   2645   if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) {
   2646     if (force_check) {
   2647       driver_help_check();
   2648       return 0;
   2649     }
   2650     driver_help_cc();
   2651     return 0;
   2652   }
   2653 
   2654   driver_env_init(&env);
   2655   co.env = &env;
   2656   co.driver_path = argv[0];
   2657   co.syntax_only = force_check ? 1 : 0;
   2658 
   2659   if (cc_parse(argc, argv, &co) != 0) {
   2660     cc_options_release(&co);
   2661     driver_env_fini(&env);
   2662     return 2;
   2663   }
   2664   if (co.probe_kind != CC_PROBE_NONE) {
   2665     rc = cc_run_probe(&co);
   2666     cc_options_release(&co);
   2667     driver_env_fini(&env);
   2668     return rc;
   2669   }
   2670 
   2671   link_action = !co.compile_only && !co.preprocess_only && !co.syntax_only &&
   2672                 co.dep_mode != CC_DEP_M && co.dep_mode != CC_DEP_MM;
   2673   if (driver_runtime_resolve(&env, co.support_dir, co.driver_path, &runtime) ==
   2674       0) {
   2675     runtime_resolved = 1;
   2676     if (co.nsource_files || co.nsource_memory) {
   2677       int add_headers;
   2678       if (co.hosted.profile_name) {
   2679         add_headers =
   2680             driver_runtime_append_freestanding_headers(&runtime, &co.cf);
   2681       } else {
   2682         add_headers = driver_runtime_add_freestanding_headers(&runtime, &co.cf);
   2683       }
   2684       if (add_headers != 0) {
   2685         driver_errf(CC_TOOL, "failed to add freestanding headers");
   2686         driver_runtime_support_fini(&env, &runtime);
   2687         cc_options_release(&co);
   2688         driver_env_fini(&env);
   2689         return 1;
   2690       }
   2691     }
   2692   } else if (co.support_dir || link_action || co.nsource_files ||
   2693              co.nsource_memory) {
   2694     driver_errf(CC_TOOL, "support dir not found");
   2695     cc_options_release(&co);
   2696     driver_env_fini(&env);
   2697     return 1;
   2698   }
   2699 
   2700   if (link_action && !co.no_stdlib && !co.no_defaultlibs) {
   2701     DriverRuntimeArchive rt_archive = {0};
   2702     uint32_t insert_pos;
   2703     if (!runtime_resolved) {
   2704       driver_errf(CC_TOOL, "support dir not found");
   2705       cc_options_release(&co);
   2706       driver_env_fini(&env);
   2707       return 1;
   2708     }
   2709     if (driver_runtime_prepare_archive(&env, CC_TOOL, &runtime, co.target,
   2710                                        co.epoch, &rt_archive) != 0) {
   2711       driver_runtime_archive_fini(&env, &rt_archive);
   2712       driver_runtime_support_fini(&env, &runtime);
   2713       cc_options_release(&co);
   2714       driver_env_fini(&env);
   2715       return 1;
   2716     }
   2717     insert_pos = co.nlink_items;
   2718     if (co.hosted.nfinal <= insert_pos) insert_pos -= co.hosted.nfinal;
   2719     cc_insert_runtime_archive(&co, &rt_archive, insert_pos);
   2720     driver_runtime_archive_fini(&env, &rt_archive);
   2721   }
   2722 
   2723   driver_cflags_fill_pp(&co.cf, &pp);
   2724 
   2725   if (co.preprocess_only) {
   2726     rc = cc_preprocess(&env, &co, &pp);
   2727   } else if (co.dep_mode == CC_DEP_M || co.dep_mode == CC_DEP_MM) {
   2728     rc = cc_run_deps_only(&env, &co, &pp);
   2729   } else if (co.syntax_only) {
   2730     rc = cc_run_check(&env, &co, &pp);
   2731   } else if (co.compile_only) {
   2732     rc = cc_run_compile_objs(&env, &co, &pp);
   2733   } else {
   2734     rc = cc_run_link_exe(&env, &co, &pp);
   2735   }
   2736 
   2737   cc_options_release(&co);
   2738   if (runtime_resolved) driver_runtime_support_fini(&env, &runtime);
   2739   driver_env_fini(&env);
   2740   return rc;
   2741 }
   2742 
   2743 int driver_cc(int argc, char** argv) { return driver_cc_main(argc, argv, 0); }
   2744 
   2745 int driver_check(int argc, char** argv) {
   2746   return driver_cc_main(argc, argv, 1);
   2747 }