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(<o_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, <o_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 <o_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 }