cc.c (113272B)
1 #include <kit/asm_emit.h> 2 #include <kit/build.h> 3 #include <kit/compile.h> 4 #include <kit/core.h> 5 #include <kit/link.h> 6 #include <kit/preprocess.h> 7 #include <stdint.h> 8 #include <string.h> 9 10 #include "cflags.h" 11 #include "driver.h" 12 #include "hosted.h" 13 #include "lib_resolve.h" 14 #include "link_flags.h" 15 #include "link_inputs.h" 16 #include "runtime.h" 17 18 /* `kit cc` — C compiler driver. With -c produces a single object; 19 * without -c compiles all C sources, links any .o/.a inputs alongside, and 20 * emits an executable. The flag surface is a GCC subset: 21 * 22 * -c -E -o -O0/1 (-O2 aliases -O1 for v1) -g 23 * -fsyntax-only 24 * -I -isystem -D -U 25 * -M -MM -MD -MMD -MF -MT -MQ -MP 26 * -target TRIPLE 27 * -fPIC -fPIE -fpic -fpie -mcmodel=small|medium|large|kernel 28 * -Werror -fmax-errors=N 29 * --build-id=none|sha256|uuid|0xHEX 30 * -ffile-prefix-map=old=new 31 * SOURCE_DATE_EPOCH (env) 32 * -e symbol -T script.ld 33 * -static -pie -no-pie 34 * -l name -L dir -framework name -F dir 35 * -x c|asm|s|asm-cpp|S|wasm|wat 36 * - (stdin source) 37 * .c/.cc -> source; .o/.obj -> object inputs; .a -> archive inputs. 38 * 39 * Library resolution (-lfoo against -L paths) happens here and produces 40 * concrete archive paths for libkit. */ 41 42 #define CC_TOOL "cc" 43 44 /* Header-dependency emission mode (subset of GCC's -M family). 45 * M — print all deps; do not compile. 46 * MM — like M but skip headers resolved via system (-isystem) dirs. 47 * MD — compile normally AND write all deps to a file. 48 * MMD — like MD but skip headers resolved via system (-isystem) dirs. 49 * The MM/MMD filter keys on the resolved include directory (GCC semantics), 50 * not the <...>-vs-"..." spelling, so a <foo.h> found via a plain -I dir is 51 * still reported. Multi-source modes keep one rule and output path per source. */ 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 /* Link-input model (link items + object/archive/dso/lib arrays) is shared with 75 * the build-* drivers; see driver/lib/link_inputs.h. */ 76 77 typedef struct CcOptions { 78 DriverEnv* env; 79 const char* driver_path; 80 size_t argv_bound; /* upper bound on per-array list size */ 81 82 int compile_only; /* -c */ 83 int preprocess_only; /* -E */ 84 int syntax_only; /* -fsyntax-only / check */ 85 int emit_c_source; /* --emit=c */ 86 int emit_ir; /* --emit=ir */ 87 int emit_asm_source; /* -S */ 88 int opt_level; /* -O0/-O1; -O2 aliases -O1 */ 89 int debug_info; /* -g */ 90 int function_sections; /* -ffunction-sections */ 91 int data_sections; /* -fdata-sections */ 92 int auto_var_init; /* -ftrivial-auto-var-init= (KitAutoVarInit) */ 93 int stack_protector; /* KitStackProtectorMode */ 94 int lto; /* -flto/-fno-lto */ 95 uint64_t disabled_backend_features; 96 int warnings_are_errors; /* -Werror */ 97 uint32_t max_errors; /* -fmax-errors=N */ 98 KitTargetSpec target; /* -target / host */ 99 int target_set; /* did -target appear */ 100 const char* output_path; /* -o */ 101 char* owned_output_path; 102 size_t owned_output_path_size; 103 const char* sysroot; /* --sysroot / -isysroot */ 104 int freestanding; /* -ffreestanding (suppresses sysroot headers) */ 105 uint8_t default_visibility; /* KitSymVis; -fvisibility=... */ 106 int nostdinc; /* -nostdinc (suppresses sysroot headers) */ 107 const char* support_dir; /* --support-dir */ 108 int probe_kind; /* CcProbeKind */ 109 const char* probe_arg; /* -print-file-name= / -print-prog-name= */ 110 111 /* -ffile-prefix-map=old=new entries; old is heap-owned (split out), new 112 * aliases argv. */ 113 KitPathPrefixMap* path_map; 114 uint32_t npath_map; 115 char** owned_path_map_olds; 116 size_t* owned_path_map_old_sizes; 117 118 /* Reproducibility: SOURCE_DATE_EPOCH parsed at end-of-parse. */ 119 uint64_t epoch; 120 121 /* Cflags via shared helper. */ 122 DriverCflags cf; 123 DriverTargetFeatures target_features; 124 125 /* Positional inputs split by suffix. */ 126 const char** source_files; /* .c paths */ 127 KitLanguage* source_langs; 128 uint32_t nsource_files; 129 KitSourceInput* source_memory; /* "-" stdin slurp */ 130 uint32_t nsource_memory; 131 uint8_t* stdin_buf; /* owning storage for the one stdin */ 132 size_t stdin_size; 133 /* Shared link-input model: object/archive/dso/lib arrays, the ordered link 134 * item list, -L search paths, and the owned `<sysroot>/lib` Windows slot. */ 135 DriverLinkInputSet inputs; 136 uint8_t next_group_id; 137 138 /* -M family */ 139 int dep_mode; /* CcDepMode */ 140 int dep_phony; /* -MP */ 141 const char* dep_file; /* -MF */ 142 const char** dep_targets; /* -MT/-MQ */ 143 char** owned_dep_targets; /* quoted -MQ storage */ 144 size_t* owned_dep_target_sizes; 145 uint32_t ndep_targets; 146 147 /* Link-session options and owned -Wl state. */ 148 DriverLinkFlags link; 149 int shared; /* -shared */ 150 int static_link; 151 int pie; 152 int pic_explicit; 153 int no_stdlib; 154 int no_defaultlibs; 155 int no_startfiles; 156 int wants_hosted_libc; 157 DriverHostedPlan hosted; 158 } CcOptions; 159 160 static void cc_usage(void) { 161 driver_errf(CC_TOOL, "%.*s", 162 KIT_SLICE_ARG(KIT_SLICE_LIT( 163 "usage: kit cc [-c|-E|-shared] [-o out] " 164 "[options...] inputs...\n" 165 " kit cc --help for full option reference"))); 166 } 167 168 void driver_help_cc(void) { 169 driver_printf( 170 "%.*s", 171 KIT_SLICE_ARG(KIT_SLICE_LIT( 172 "kit cc — C compiler driver\n" 173 "\n" 174 "USAGE\n" 175 " kit cc [options] INPUT... compile and link\n" 176 " kit cc -c [options] INPUT.c emit an object\n" 177 " kit cc -S [options] INPUT.c emit assembly\n" 178 " kit cc -E [options] INPUT.c preprocess only\n" 179 " kit cc -M|-MM [options] INPUT.c print dependencies\n" 180 " kit cc --emit=c|ir [options] INPUT.c emit C or IR\n" 181 " kit cc -fsyntax-only [options] INPUT... check only\n" 182 "\n" 183 "DESCRIPTION\n" 184 " Compiles C and assembly sources, optionally linking compatible\n" 185 " objects, archives, and shared libraries into a program. It can\n" 186 " also stop after preprocessing, dependency generation, semantic\n" 187 " checks, assembly, object, portable C, or semantic IR output.\n" 188 "\n" 189 " .c is C source; .S is preprocessed assembly; .s is assembly.\n" 190 " Target-compatible .o, .a, and ELF .so files are accepted by the\n" 191 " link stage. A single `-` input reads stdin; use `-x c -` when an\n" 192 " input suffix is unavailable. This release does not accept `--`\n" 193 " before compiler operands; spell a leading-dash path as ./-name.c.\n" 194 "\n" 195 " Linking defaults to a.out (a.exe for Windows). -c and -S derive\n" 196 " <base>.o and <base>.s for one source. -E, -M, and -MM write stdout\n" 197 " when -o is absent. Use -o for --emit=c/ir and combined outputs.\n" 198 "\n" 199 "OPTIONS\n" 200 " -I DIR, -isystem DIR Add user/system include directories\n" 201 " -D NAME[=BODY], -U NAME Define or undefine a macro\n" 202 " -E Preprocess without compiling\n" 203 " -M, -MM Dependencies with/without system headers\n" 204 " -MD, -MMD, -MF FILE Side-effect dependencies/output file\n" 205 " -MT TARGET, -MQ TARGET Dependency target spelling\n" 206 "\n" 207 " -M/-MM emit one rule per source in input order. -MD/-MMD write\n" 208 " per-source dependency files during compile and compile-link.\n" 209 "\n" 210 "COMPILATION\n" 211 " -std=c11 Select the supported C language level\n" 212 " -fsyntax-only Diagnose only; write no output\n" 213 " -c, -S Stop after object or assembly emission\n" 214 " --emit=c Portable C output (-O1/-O2 normalize to -O0)\n" 215 " --emit=ir Semantic IR dump; requires -O1 or -O2\n" 216 " -O0, -O1, -O2 Optimize (-O2 aliases -O1)\n" 217 " -g Emit debug information\n" 218 " -flto Record source inputs for LTO at link\n" 219 " -fPIC/-fpic, -fPIE/-fpie Position-independent code/executable\n" 220 " -Werror, -fmax-errors=N Diagnostic policy\n" 221 " -ffreestanding Freestanding language/runtime mode\n" 222 " -fstack-protector[-strong|-all]\n" 223 " Select conventional stack canaries\n" 224 " -fno-stack-protector Disable stack canaries\n" 225 " -x c|assembler|assembler-with-cpp\n" 226 " Override suffix classification\n" 227 "\n" 228 "LINKING\n" 229 " -o PATH Output path\n" 230 " -L DIR, -l NAME Library search/input\n" 231 " -static, -shared Static executable / ELF shared library\n" 232 " -nostdlib, -nodefaultlibs, -nostartfiles\n" 233 " Suppress default link components\n" 234 " -T SCRIPT, -e SYMBOL Linker script and entry symbol\n" 235 " -Wl,... Forward supported linker tokens\n" 236 " -framework NAME, -F DIR Darwin framework/search directory\n" 237 "\n" 238 " Linker scripts and entries accept direct joined/equal forms,\n" 239 " -Wl comma lists, and equivalent -Xlinker sequences. Static/shared\n" 240 " availability follows the target\n" 241 " platform; non-ELF shared-library output is not provided here.\n"))); 242 driver_printf( 243 "%.*s", 244 KIT_SLICE_ARG(KIT_SLICE_LIT( 245 "\n" 246 "TARGET AND SEARCH PATHS\n" 247 " -target TRIPLE Select a canonical target below\n" 248 " -arch ARCH Darwin-style architecture selection\n" 249 " -march=ISA, -mabi=ABI Architecture/ABI selection when supported\n" 250 " --sysroot DIR, -isysroot DIR\n" 251 " Hosted SDK/sysroot supplied by the user\n" 252 " --support-dir DIR Kit distribution support root\n" 253 " -print-search-dirs Print compiler/library search paths\n" 254 " -print-sysroot Print the native SDK Kit can discover\n" 255 " -print-resource-dir Print the current compiler resource path\n" 256 "\n" 257 " Hosted: aarch64-linux-gnu, x86_64-linux-gnu, riscv64-linux-gnu;\n" 258 " aarch64-linux-musl, x86_64-linux-musl, riscv64-linux-musl;\n" 259 " aarch64-freebsd, x86_64-freebsd, riscv64-freebsd;\n" 260 " aarch64-windows, x86_64-windows; aarch64-linux-android21;\n" 261 " aarch64-apple-darwin, x86_64-apple-darwin.\n" 262 " Freestanding: aarch64-none-elf, x86_64-none-elf,\n" 263 " riscv64-none-elf, riscv32-none-elf, arm-none-eabi.\n" 264 " WebAssembly source target: wasm32-none (source-batch module; this\n" 265 " release does not link separate Wasm .o/.a inputs).\n" 266 "\n" 267 "DISCOVERY AND LIMITS\n" 268 " Kit resolves support relative to its canonical executable path;\n" 269 " --support-dir is an authoritative override. Native macOS applies\n" 270 " the discovered SDK automatically. Cross-hosted compilation still\n" 271 " requires an explicit user-supplied sysroot.\n" 272 "\n" 273 " Portable-C output currently uses the -O0 semantic pipeline; explicit\n" 274 " -O1/-O2 requests are accepted and normalized before code generation.\n" 275 "\n" 276 "GETTING HELP\n" 277 " -h, --help Show this help and exit\n" 278 " --version Show Kit version and exit\n" 279 "\n" 280 "EXAMPLES\n" 281 " # Native compile.\n" 282 " printf 'int main(void) { return 0; }\\n' > hello.c\n" 283 " kit cc hello.c -o hello\n" 284 " ./hello\n" 285 "\n" 286 " # Replace SYSROOT with a supplied hosted cross sysroot.\n" 287 " SYSROOT=/replace/with/aarch64-linux-sysroot\n" 288 " kit cc -target aarch64-linux-gnu --sysroot \"$SYSROOT\" \\\n" 289 " hello.c -o hello.aa64\n" 290 "\n" 291 " # Freestanding final link; provide startup object and linker script.\n" 292 " kit cc -target aarch64-none-elf \\\n" 293 " -ffreestanding -c kernel.c -o kernel.o\n" 294 " kit cc -target aarch64-none-elf \\\n" 295 " -ffreestanding -T link.ld -e _start start.o kernel.o -o kernel.elf\n" 296 "\n" 297 " kit cc -E -DVALUE=42 input.c\n" 298 " kit cc -MM input.c -MF input.d\n" 299 " kit cc --emit=c -O0 input.c -o input.out.c\n" 300 " kit cc --emit=ir -O1 input.c -o input.ir\n" 301 "\n" 302 "EXIT CODES\n" 303 " 0 success 1 compile/link/I/O error 2 bad usage\n"))); 304 } 305 306 void driver_help_check(void) { 307 driver_printf( 308 "%.*s", 309 KIT_SLICE_ARG(KIT_SLICE_LIT( 310 "kit check — run C frontend checks without emitting code\n" 311 "\n" 312 "USAGE\n" 313 " kit check [options] INPUT.c...\n" 314 "\n" 315 "DESCRIPTION\n" 316 " Equivalent to the preprocessing and semantic-check portion of\n" 317 " `kit cc -fsyntax-only`. It writes diagnostics only: no object,\n" 318 " assembly, executable, or dependency output is produced.\n" 319 "\n" 320 "OPTIONS\n" 321 " Accepts the cc preprocessing, target, sysroot, diagnostic, and\n" 322 " language options described by `kit cc --help`, including -I,\n" 323 " -isystem, -D, -U, -std=c11, -Werror, -fmax-errors=N,\n" 324 " -target, --sysroot/-isysroot, and --support-dir. Inputs are C\n" 325 " sources; each is preprocessed and checked independently.\n" 326 "\n" 327 " Relocated distributions discover their sibling support tree. Native\n" 328 " macOS discovers SDK headers automatically; cross-hosted checks use\n" 329 " an explicit --sysroot/-isysroot as described by `kit cc --help`.\n" 330 "\n" 331 "GETTING HELP\n" 332 " -h, --help Show this help and exit\n" 333 " --version Show Kit version and exit\n" 334 "\n" 335 "EXAMPLES\n" 336 " kit check \\\n" 337 " -I include -DDEBUG=1 src/main.c src/util.c\n" 338 "\n" 339 "EXIT CODES\n" 340 " 0 checks passed 1 frontend/I/O error 2 bad usage\n"))); 341 } 342 343 static int cc_alloc_arrays(CcOptions* o, int argc) { 344 size_t bound = (size_t)argc + 16u; 345 o->argv_bound = bound; 346 o->source_files = 347 driver_alloc_zeroed(o->env, bound * sizeof(*o->source_files)); 348 o->source_langs = 349 driver_alloc_zeroed(o->env, bound * sizeof(*o->source_langs)); 350 o->source_memory = 351 driver_alloc_zeroed(o->env, bound * sizeof(*o->source_memory)); 352 o->dep_targets = driver_alloc_zeroed(o->env, bound * sizeof(*o->dep_targets)); 353 o->owned_dep_targets = 354 driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_dep_targets)); 355 o->owned_dep_target_sizes = driver_alloc_zeroed( 356 o->env, bound * sizeof(*o->owned_dep_target_sizes)); 357 o->path_map = driver_alloc_zeroed(o->env, bound * sizeof(*o->path_map)); 358 o->owned_path_map_olds = 359 driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_path_map_olds)); 360 o->owned_path_map_old_sizes = 361 driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_path_map_old_sizes)); 362 if (!o->source_files || !o->source_langs || !o->source_memory || 363 !o->dep_targets || !o->owned_dep_targets || 364 !o->owned_dep_target_sizes || !o->path_map || !o->owned_path_map_olds || 365 !o->owned_path_map_old_sizes) { 366 driver_errf(CC_TOOL, "out of memory"); 367 return 1; 368 } 369 if (driver_link_inputs_init(&o->inputs, o->env, CC_TOOL, bound) != 0) 370 return 1; 371 if (driver_link_flags_init(&o->link, o->env, CC_TOOL, (uint32_t)bound) != 0 || 372 driver_cflags_init(&o->cf, o->env, 373 (int)(bound + DRIVER_HOSTED_MAX_DEFINES + 374 DRIVER_HOSTED_MAX_INCLUDES)) != 0 || 375 driver_target_features_init(&o->target_features, o->env, argc) != 0) { 376 driver_errf(CC_TOOL, "out of memory"); 377 return 1; 378 } 379 return 0; 380 } 381 382 static void cc_options_release(CcOptions* o) { 383 uint32_t i; 384 size_t bound = o->argv_bound; 385 for (i = 0; i < o->npath_map; ++i) { 386 if (o->owned_path_map_olds[i]) { 387 driver_free(o->env, o->owned_path_map_olds[i], 388 o->owned_path_map_old_sizes[i]); 389 } 390 } 391 for (i = 0; i < o->ndep_targets; ++i) { 392 if (o->owned_dep_targets[i]) { 393 driver_free(o->env, o->owned_dep_targets[i], 394 o->owned_dep_target_sizes[i]); 395 } 396 } 397 if (o->stdin_buf) driver_free(o->env, o->stdin_buf, o->stdin_size); 398 if (o->owned_output_path) 399 driver_free(o->env, o->owned_output_path, o->owned_output_path_size); 400 driver_link_inputs_fini(&o->inputs); 401 driver_hosted_plan_fini(o->env, &o->hosted); 402 driver_link_flags_fini(&o->link); 403 driver_target_features_fini(&o->target_features, o->env); 404 driver_cflags_fini(&o->cf, o->env); 405 driver_free(o->env, o->source_files, bound * sizeof(*o->source_files)); 406 driver_free(o->env, o->source_langs, bound * sizeof(*o->source_langs)); 407 driver_free(o->env, o->source_memory, bound * sizeof(*o->source_memory)); 408 driver_free(o->env, o->dep_targets, bound * sizeof(*o->dep_targets)); 409 driver_free(o->env, o->owned_dep_targets, 410 bound * sizeof(*o->owned_dep_targets)); 411 driver_free(o->env, o->owned_dep_target_sizes, 412 bound * sizeof(*o->owned_dep_target_sizes)); 413 driver_free(o->env, o->path_map, bound * sizeof(*o->path_map)); 414 driver_free(o->env, o->owned_path_map_olds, 415 bound * sizeof(*o->owned_path_map_olds)); 416 driver_free(o->env, o->owned_path_map_old_sizes, 417 bound * sizeof(*o->owned_path_map_old_sizes)); 418 } 419 420 static int cc_apply_hosted_profile(CcOptions* o); 421 static int cc_record_framework(CcOptions* o, const char* name) { 422 DriverPendingFramework* pf; 423 if (!name || !name[0]) { 424 driver_errf(CC_TOOL, "-framework requires an argument"); 425 return 1; 426 } 427 pf = &o->inputs.pending_frameworks[o->inputs.npending_frameworks++]; 428 pf->name = name; 429 driver_link_inputs_push(&o->inputs, DRIVER_LINK_FRAMEWORK, 430 o->inputs.npending_frameworks - 1u); 431 return 0; 432 } 433 434 /* Routed through the shared driver_path_is_source authority (canonical 435 * extension registry, headers excluded), so adding a frontend extension reaches 436 * cc/build/run/dbg at once. cc still treats .h as a header, not a source — the 437 * helper excludes it. */ 438 static int cc_is_c_source(const char* s) { return driver_path_is_source(s); } 439 440 static int cc_record_path_map(CcOptions* o, const char* arg) { 441 const char* eq = driver_strchr(arg, '='); 442 KitPathPrefixMap* m = &o->path_map[o->npath_map]; 443 if (!eq) { 444 driver_errf(CC_TOOL, "-ffile-prefix-map requires old=new"); 445 return 1; 446 } 447 { 448 size_t n = (size_t)(eq - arg); 449 size_t bytes = n + 1; 450 char* old_ = driver_alloc(o->env, bytes); 451 if (!old_) { 452 driver_errf(CC_TOOL, "out of memory"); 453 return 1; 454 } 455 driver_memcpy(old_, arg, n); 456 old_[n] = '\0'; 457 o->owned_path_map_olds[o->npath_map] = old_; 458 o->owned_path_map_old_sizes[o->npath_map] = bytes; 459 m->old_prefix = old_; 460 m->new_prefix = eq + 1; 461 } 462 o->npath_map++; 463 return 0; 464 } 465 466 static int cc_set_probe(CcOptions* o, int kind, const char* arg) { 467 if (o->probe_kind != CC_PROBE_NONE) { 468 driver_errf(CC_TOOL, "only one compiler-information probe is supported"); 469 return 1; 470 } 471 o->probe_kind = kind; 472 o->probe_arg = arg; 473 return 0; 474 } 475 476 /* Emit one element of a colon-separated search path. *first tracks whether a 477 * leading separator is needed; NULL/empty entries are skipped. */ 478 static void cc_print_path_elem(const char* dir, int* first) { 479 if (!dir || !dir[0]) return; 480 driver_printf("%s%.*s", *first ? "" : ":", 481 KIT_SLICE_ARG(kit_slice_cstr(dir))); 482 *first = 0; 483 } 484 485 static int cc_run_probe(CcOptions* o) { 486 char triple[64]; 487 if (driver_target_to_triple(o->target, triple, sizeof(triple)) != 0) { 488 driver_errf(CC_TOOL, "failed to render target triple"); 489 return 1; 490 } 491 492 switch (o->probe_kind) { 493 case CC_PROBE_PRINT_SEARCH_DIRS: { 494 DriverRuntimeSupport rt = {0}; 495 int have_rt = (driver_runtime_resolve(o->env, o->support_dir, 496 o->driver_path, &rt) == 0); 497 DriverHostedDirs dirs; 498 int have_dirs = 0; 499 uint32_t i; 500 int first; 501 /* Resolve the hosted include/library dirs directly: a probe run skips the 502 * parse-time hosted profile (no compile happens), so they are not yet in 503 * cf. Gated on hosted libc being engaged (-lc / sysroot). */ 504 if (o->wants_hosted_libc) { 505 DriverHostedRequest req = {0}; 506 req.env = o->env; 507 req.tool = CC_TOOL; 508 req.target = o->target; 509 req.sysroot = o->sysroot; 510 req.static_link = o->static_link; 511 req.link_inputs = 1; 512 have_dirs = (driver_hosted_dirs_resolve(&req, &dirs) == 0); 513 } 514 driver_printf("install: %.*s\n", 515 KIT_SLICE_ARG(kit_slice_cstr( 516 have_rt ? rt.support_root 517 : (o->support_dir ? o->support_dir : "")))); 518 driver_printf("programs: =\n"); 519 /* libraries: hosted crt/libc search dirs, then user -L dirs, then the kit 520 * runtime dir holding libkit_rt.a. */ 521 driver_printf("libraries: ="); 522 first = 1; 523 if (have_dirs) 524 for (i = 0; i < dirs.nlibdirs; ++i) 525 cc_print_path_elem(dirs.libdirs[i], &first); 526 for (i = 0; i < o->inputs.nlib_search_paths; ++i) 527 cc_print_path_elem(o->inputs.lib_search_paths[i], &first); 528 if (have_rt) cc_print_path_elem(rt.rt_root, &first); 529 driver_printf("\n"); 530 /* includes: user -I/-isystem, then the hosted system headers, then the 531 * freestanding runtime headers. (kit extension to GCC's output.) */ 532 driver_printf("includes: ="); 533 first = 1; 534 for (i = 0; i < o->cf.ninclude_dirs; ++i) 535 cc_print_path_elem(o->cf.include_dirs[i], &first); 536 for (i = 0; i < o->cf.nsystem_include_dirs; ++i) 537 cc_print_path_elem(o->cf.system_include_dirs[i], &first); 538 if (have_dirs) 539 for (i = 0; i < dirs.nincdirs; ++i) 540 cc_print_path_elem(dirs.incdirs[i], &first); 541 if (have_rt) cc_print_path_elem(rt.include_dir, &first); 542 driver_printf("\n"); 543 if (have_dirs) driver_hosted_dirs_fini(&dirs); 544 if (have_rt) driver_runtime_support_fini(o->env, &rt); 545 return 0; 546 } 547 case CC_PROBE_PRINT_FILE_NAME: 548 driver_printf( 549 "%.*s\n", 550 KIT_SLICE_ARG(kit_slice_cstr(o->probe_arg ? o->probe_arg : ""))); 551 return 0; 552 case CC_PROBE_PRINT_PROG_NAME: 553 driver_printf( 554 "%.*s\n", 555 KIT_SLICE_ARG(kit_slice_cstr(o->probe_arg ? o->probe_arg : ""))); 556 return 0; 557 case CC_PROBE_PRINT_LIBGCC_FILE_NAME: 558 driver_printf("libkit_rt.a\n"); 559 return 0; 560 case CC_PROBE_PRINT_MULTI_OS_DIRECTORY: 561 driver_printf(".\n"); 562 return 0; 563 case CC_PROBE_PRINT_RESOURCE_DIR: { 564 /* clang convention: the resource-dir root, with builtin/freestanding 565 * headers under <resource-dir>/include. */ 566 DriverRuntimeSupport rt = {0}; 567 if (driver_runtime_resolve(o->env, o->support_dir, o->driver_path, &rt) == 568 0) { 569 driver_printf("%.*s\n", KIT_SLICE_ARG(kit_slice_cstr(rt.rt_root))); 570 driver_runtime_support_fini(o->env, &rt); 571 } else { 572 driver_printf("%.*s\n", KIT_SLICE_ARG(kit_slice_cstr( 573 o->support_dir ? o->support_dir : ""))); 574 } 575 return 0; 576 } 577 case CC_PROBE_PRINT_SYSROOT: { 578 /* The effective sysroot root: command-line --sysroot or KIT_SYSROOT, else 579 * the native host probe when it resolves to a single tree (the macOS 580 * SDK). Empty for a multi-dir probe (Linux/FreeBSD) or a cross target 581 * with no sysroot, which have no single root. */ 582 DriverHostedRequest req = {0}; 583 DriverHostedDirs dirs; 584 req.env = o->env; 585 req.tool = CC_TOOL; 586 req.target = o->target; 587 req.sysroot = o->sysroot; 588 req.static_link = o->static_link; 589 req.link_inputs = 1; 590 if (driver_hosted_dirs_resolve(&req, &dirs) == 0) { 591 driver_printf( 592 "%.*s\n", 593 KIT_SLICE_ARG(kit_slice_cstr(dirs.root ? dirs.root : ""))); 594 driver_hosted_dirs_fini(&dirs); 595 } else { 596 /* An explicitly selected (argv or KIT_SYSROOT) path is authoritative. 597 * The resolver has already diagnosed an invalid one; do not turn that 598 * failure into a successful empty probe. A cross target with no 599 * supplied sysroot still resolves successfully with dirs.root == NULL 600 * and prints the conventional empty line above. */ 601 return 1; 602 } 603 return 0; 604 } 605 case CC_PROBE_DUMPMACHINE: 606 driver_printf("%.*s\n", KIT_SLICE_ARG(kit_slice_cstr(triple))); 607 return 0; 608 case CC_PROBE_DUMPVERSION: 609 driver_printf("0\n"); 610 return 0; 611 case CC_PROBE_DUMPSPECS: 612 driver_printf("*kit:\n"); 613 driver_printf("%%{!S:%%{!E:%%{!c:%%{!r:link}}}}\n"); 614 return 0; 615 default: 616 break; 617 } 618 619 return 0; 620 } 621 622 static int cc_record_stdin(CcOptions* o, int forced_lang) { 623 KitSourceInput* in; 624 if (o->stdin_buf) { 625 driver_errf(CC_TOOL, "'-' (stdin) may appear at most once"); 626 return 1; 627 } 628 if (!driver_read_stdin(o->env, &o->stdin_buf, &o->stdin_size)) { 629 driver_errf(CC_TOOL, "failed to read stdin"); 630 return 1; 631 } 632 in = &o->source_memory[o->nsource_memory++]; 633 in->name = KIT_SLICE_LIT("<stdin>"); 634 in->bytes.data = o->stdin_buf; 635 in->bytes.len = o->stdin_size; 636 in->lang = forced_lang >= 0 ? (KitLanguage)forced_lang : KIT_LANG_C; 637 driver_link_inputs_push(&o->inputs, DRIVER_LINK_SOURCE_MEMORY, 638 o->nsource_memory - 1u); 639 return 0; 640 } 641 642 /* Stored in source_langs[] during arg parsing to mean "no -x override — 643 * resolve from the path at compile time, once a compiler is around to 644 * consult its frontend extension registry." */ 645 #define CC_LANG_AUTO KIT_LANG_AUTO 646 647 static KitLanguage cc_resolve_lang(KitCompiler* c, const char* path, 648 KitLanguage stored) { 649 if (stored != CC_LANG_AUTO) return stored; 650 return kit_language_for_path(c, path); 651 } 652 653 static int cc_classify_positional(CcOptions* o, const char* a, 654 int forced_lang) { 655 if (driver_streq(a, "-")) return cc_record_stdin(o, forced_lang); 656 if (forced_lang >= 0 || cc_is_c_source(a)) { 657 o->source_langs[o->nsource_files] = 658 forced_lang >= 0 ? (KitLanguage)forced_lang : CC_LANG_AUTO; 659 o->source_files[o->nsource_files++] = a; 660 driver_link_inputs_push(&o->inputs, DRIVER_LINK_SOURCE, 661 o->nsource_files - 1u); 662 return 0; 663 } 664 if (driver_has_suffix(a, ".o") || driver_has_suffix(a, ".obj")) { 665 o->inputs.object_files[o->inputs.nobject_files++] = a; 666 driver_link_inputs_push(&o->inputs, DRIVER_LINK_OBJECT, 667 o->inputs.nobject_files - 1u); 668 return 0; 669 } 670 if (driver_has_suffix(a, ".a")) { 671 DriverArchiveInput* ar = &o->inputs.archives[o->inputs.narchives++]; 672 ar->path = a; 673 ar->whole_archive = o->inputs.cur_whole_archive; 674 ar->link_mode = o->inputs.cur_link_mode; 675 ar->group_id = o->inputs.cur_group_id; 676 driver_link_inputs_push(&o->inputs, DRIVER_LINK_ARCHIVE, 677 o->inputs.narchives - 1u); 678 return 0; 679 } 680 if (driver_is_dso_path(a)) { 681 DriverDsoInput* d = &o->inputs.dsos[o->inputs.ndsos++]; 682 d->path = a; 683 driver_link_inputs_push(&o->inputs, DRIVER_LINK_DSO, o->inputs.ndsos - 1u); 684 return 0; 685 } 686 driver_errf(CC_TOOL, "input does not have a recognized suffix: %.*s", 687 KIT_SLICE_ARG(kit_slice_cstr(a))); 688 return 1; 689 } 690 691 static int cc_apply_hosted_profile(CcOptions* o) { 692 /* A link action (not -c/-E/-M/-MM) gets crt files + interpreter; the include 693 * + define + lib-search-dir parts apply regardless. */ 694 int link_action = !o->syntax_only && !o->compile_only && 695 !o->preprocess_only && 696 o->dep_mode != CC_DEP_M && o->dep_mode != CC_DEP_MM; 697 int shared_hosted = o->shared && driver_target_shared_uses_hosted(o->target); 698 if (!o->wants_hosted_libc || (o->shared && !shared_hosted)) return 0; 699 /* -nostdlib/-nodefaultlibs suppress the link-time CRT/libc additions, not 700 * the hosted compiler profile. Native compilation still needs the SDK's 701 * defines and headers (matching clang/gcc). */ 702 if (o->no_stdlib || o->no_defaultlibs) link_action = 0; 703 return driver_link_inputs_apply_hosted( 704 &o->inputs, &o->hosted, &o->cf, &o->link, o->target, o->sysroot, 705 o->static_link, o->shared, o->no_startfiles, link_action); 706 } 707 708 static int cc_apply_env(CcOptions* o) { 709 const char* sde = driver_getenv("SOURCE_DATE_EPOCH"); 710 if (sde && driver_parse_u64(sde, &o->epoch) != 0) { 711 driver_errf(CC_TOOL, "invalid SOURCE_DATE_EPOCH: %.*s", 712 KIT_SLICE_ARG(kit_slice_cstr(sde))); 713 return 1; 714 } 715 return 0; 716 } 717 718 static int cc_has_link_action(const CcOptions* o) { 719 return !o->syntax_only && !o->compile_only && !o->preprocess_only && 720 o->dep_mode != CC_DEP_M && o->dep_mode != CC_DEP_MM; 721 } 722 723 /* A sysroot on its own means "compile/link hosted against that root" — the 724 * same default clang and gcc take for -isysroot/--sysroot. Engage the hosted 725 * libc profile so the host headers, their feature-test defines (__GNUC__, 726 * __APPLE__, __has_builtin, ...) and (for link actions) the host C runtime are 727 * brought in. -ffreestanding and -nostdinc opt back out, keeping the 728 * freestanding rt/include set standalone; -shared keeps its existing meaning. 729 * -nostdlib/-nodefaultlibs only suppress link additions. The Windows-COFF 730 * default profile and an explicit 731 * -lc already set the flag, so this is a no-op in those cases. */ 732 static void cc_enable_hosted_for_sysroot(CcOptions* o) { 733 if (o->wants_hosted_libc) return; 734 if (o->shared && !driver_target_shared_uses_hosted(o->target)) return; 735 if (!o->sysroot || !o->sysroot[0]) return; 736 if (o->freestanding || o->nostdinc) return; 737 o->wants_hosted_libc = 1; 738 } 739 740 static void cc_apply_default_hosted_profile(CcOptions* o) { 741 KitTargetSpec host; 742 int native_macos; 743 if (!driver_target_default_hosted_profile(o->target)) return; 744 if (o->wants_hosted_libc) return; 745 if (o->freestanding || o->nostdinc) return; 746 host = driver_host_target(); 747 native_macos = host.os == KIT_OS_MACOS && o->target.os == KIT_OS_MACOS; 748 if ((!o->sysroot || !o->sysroot[0]) && !native_macos) return; 749 if (!cc_has_link_action(o) && o->nsource_files + o->nsource_memory == 0) 750 return; 751 o->wants_hosted_libc = 1; 752 } 753 754 static char* cc_dep_default_target(DriverEnv* env, const CcOptions* o, 755 size_t* out_size); 756 757 /* GNU make quoting used by -MQ and by driver-derived dependency paths. -MT is 758 * intentionally left verbatim. */ 759 static char* cc_dep_quote_make_alloc(DriverEnv* env, const char* s, 760 size_t* out_size) { 761 size_t n = driver_strlen(s); 762 size_t i; 763 size_t pos = 0; 764 char* out = driver_alloc(env, n * 2u + 1u); 765 if (!out) return NULL; 766 for (i = 0; i < n; ++i) { 767 char c = s[i]; 768 if (c == '$') { 769 out[pos++] = '$'; 770 out[pos++] = '$'; 771 } else if (c == ' ' || c == '\t' || c == '#' || c == '\\') { 772 out[pos++] = '\\'; 773 out[pos++] = c; 774 } else { 775 out[pos++] = c; 776 } 777 } 778 out[pos] = '\0'; 779 if (out_size) *out_size = n * 2u + 1u; 780 return out; 781 } 782 783 static int cc_parse(int argc, char** argv, CcOptions* o) { 784 int forced_lang = -1; 785 int i; 786 787 if (cc_alloc_arrays(o, argc) != 0) return 1; 788 o->target = driver_host_target(); 789 790 for (i = 1; i < argc; ++i) { 791 const char* a = argv[i]; 792 793 { 794 int r = 795 driver_cflags_try_consume(&o->cf, o->env, CC_TOOL, argc, argv, &i); 796 if (r < 0) return 1; 797 if (r > 0) continue; 798 } 799 800 if (driver_streq(a, "-c")) { 801 o->compile_only = 1; 802 continue; 803 } 804 if (driver_streq(a, "-v") || driver_streq(a, "-###")) { 805 continue; 806 } 807 if (driver_streq(a, "-E")) { 808 o->preprocess_only = 1; 809 continue; 810 } 811 if (driver_streq(a, "-S")) { 812 o->emit_asm_source = 1; 813 o->compile_only = 1; 814 continue; 815 } 816 if (driver_streq(a, "-fsyntax-only")) { 817 o->syntax_only = 1; 818 continue; 819 } 820 if (driver_streq(a, "--emit=c")) { 821 /* C-source output instead of object bytes. Forces -c-style single-input 822 * compile (no link). See doc/CBACKEND.md. */ 823 o->emit_c_source = 1; 824 o->compile_only = 1; 825 continue; 826 } 827 if (driver_streq(a, "--emit=ir")) { 828 /* Textual semantic-IR dump instead of object bytes. The IR tape is only 829 * recorded when the optimizer runs, so this requires -O1+ (validated 830 * after argument parsing). Forces a single-input, no-link compile. */ 831 o->emit_ir = 1; 832 o->compile_only = 1; 833 continue; 834 } 835 if (driver_streq(a, "-g")) { 836 o->debug_info = 1; 837 continue; 838 } 839 if (driver_streq(a, "-O0")) { 840 o->opt_level = 0; 841 continue; 842 } 843 if (driver_streq(a, "-O1")) { 844 o->opt_level = 1; 845 continue; 846 } 847 if (driver_streq(a, "-O2")) { 848 o->opt_level = 1; 849 continue; 850 } 851 if (driver_streq(a, "-O") || driver_streq(a, "-O3") || 852 driver_streq(a, "-Os") || driver_streq(a, "-Oz") || 853 driver_streq(a, "-Ofast")) { 854 o->opt_level = 1; 855 continue; 856 } 857 858 if (driver_streq(a, "-Werror")) { 859 o->warnings_are_errors = 1; 860 continue; 861 } 862 if (driver_strneq(a, "-Werror=", 8)) { 863 o->warnings_are_errors = 1; 864 continue; 865 } 866 if (driver_streq(a, "-Wall") || driver_streq(a, "-Wextra") || 867 driver_streq(a, "-Wpedantic") || driver_streq(a, "-pedantic") || 868 driver_streq(a, "-pedantic-errors") || driver_streq(a, "-w") || 869 driver_strneq(a, "-Wno-", 5) || 870 (driver_strneq(a, "-W", 2) && !driver_strneq(a, "-Wl,", 4))) { 871 continue; 872 } 873 if (driver_strneq(a, "-fmax-errors=", 13)) { 874 uint64_t v; 875 if (driver_parse_u64(a + 13, &v) != 0 || v > 0xFFFFFFFFu) { 876 driver_errf(CC_TOOL, "-fmax-errors= requires a non-negative integer"); 877 return 1; 878 } 879 o->max_errors = (uint32_t)v; 880 continue; 881 } 882 if (driver_strneq(a, "-std=", 5) || driver_streq(a, "-ansi")) { 883 continue; 884 } 885 if (driver_streq(a, "-ffreestanding")) { 886 o->freestanding = 1; 887 continue; 888 } 889 if (driver_streq(a, "-fvisibility=hidden")) { 890 o->default_visibility = KIT_SV_HIDDEN; 891 continue; 892 } 893 if (driver_streq(a, "-fvisibility=default")) { 894 o->default_visibility = KIT_SV_DEFAULT; 895 continue; 896 } 897 if (driver_strneq(a, "-fvisibility=", 13)) { 898 driver_errf(CC_TOOL, "unsupported visibility: %.*s", 899 KIT_SLICE_ARG(kit_slice_cstr(a + 13))); 900 return 1; 901 } 902 if (driver_streq(a, "-fhosted")) { 903 o->freestanding = 0; 904 continue; 905 } 906 if (driver_streq(a, "-ffunction-sections")) { 907 o->function_sections = 1; 908 continue; 909 } 910 if (driver_streq(a, "-fno-function-sections")) { 911 o->function_sections = 0; 912 continue; 913 } 914 if (driver_streq(a, "-fdata-sections")) { 915 o->data_sections = 1; 916 continue; 917 } 918 if (driver_strneq(a, "-ftrivial-auto-var-init=", 24)) { 919 const char* mode = a + 24; 920 if (driver_streq(mode, "zero")) { 921 o->auto_var_init = KIT_AUTOVAR_ZERO; 922 } else if (driver_streq(mode, "uninitialized")) { 923 o->auto_var_init = KIT_AUTOVAR_UNINIT; 924 } else if (driver_streq(mode, "pattern")) { 925 driver_errf(CC_TOOL, 926 "-ftrivial-auto-var-init=pattern is not yet supported; " 927 "use =zero"); 928 return 1; 929 } else { 930 driver_errf(CC_TOOL, 931 "-ftrivial-auto-var-init=: unknown mode '%s' " 932 "(expected zero, pattern, or uninitialized)", 933 mode); 934 return 1; 935 } 936 continue; 937 } 938 if (driver_streq(a, "-fno-data-sections")) { 939 o->data_sections = 0; 940 continue; 941 } 942 if (driver_streq(a, "-fno-stack-protector")) { 943 o->stack_protector = KIT_STACK_PROTECTOR_NONE; 944 continue; 945 } 946 if (driver_streq(a, "-fstack-protector")) { 947 o->stack_protector = KIT_STACK_PROTECTOR_BASIC; 948 continue; 949 } 950 if (driver_streq(a, "-fstack-protector-strong")) { 951 o->stack_protector = KIT_STACK_PROTECTOR_STRONG; 952 continue; 953 } 954 if (driver_streq(a, "-fstack-protector-all")) { 955 o->stack_protector = KIT_STACK_PROTECTOR_ALL; 956 continue; 957 } 958 if (driver_strneq(a, "-fstack-protector", 17)) { 959 driver_errf(CC_TOOL, "unsupported stack protector mode: %.*s", 960 KIT_SLICE_ARG(kit_slice_cstr(a))); 961 return 1; 962 } 963 if (driver_streq(a, "-flto")) { 964 o->lto = 1; 965 continue; 966 } 967 if (driver_streq(a, "-fno-lto")) { 968 o->lto = 0; 969 continue; 970 } 971 if (driver_streq(a, "-nostdinc")) { 972 o->nostdinc = 1; 973 continue; 974 } 975 if (driver_streq(a, "-fno-builtin") || 976 driver_strneq(a, "-fno-builtin-", 13) || driver_streq(a, "-pipe") || 977 driver_streq(a, "-pthread")) { 978 continue; 979 } 980 if (driver_streq(a, "-nostdlib")) { 981 o->no_stdlib = 1; 982 continue; 983 } 984 if (driver_streq(a, "-nodefaultlibs")) { 985 o->no_defaultlibs = 1; 986 continue; 987 } 988 if (driver_streq(a, "-nostartfiles")) { 989 o->no_startfiles = 1; 990 continue; 991 } 992 if (driver_streq(a, "-isysroot") || driver_streq(a, "--sysroot")) { 993 if (++i >= argc) { 994 driver_errf(CC_TOOL, "%.*s requires an argument", 995 KIT_SLICE_ARG(kit_slice_cstr(a))); 996 return 1; 997 } 998 o->sysroot = argv[i]; 999 continue; 1000 } 1001 if (driver_strneq(a, "--sysroot=", 10)) { 1002 o->sysroot = a + 10; 1003 continue; 1004 } 1005 if (driver_streq(a, "--support-dir")) { 1006 if (++i >= argc) { 1007 driver_errf(CC_TOOL, "--support-dir requires an argument"); 1008 return 1; 1009 } 1010 o->support_dir = argv[i]; 1011 continue; 1012 } 1013 if (driver_strneq(a, "--support-dir=", 14)) { 1014 o->support_dir = a + 14; 1015 continue; 1016 } 1017 if (driver_streq(a, "-print-search-dirs")) { 1018 if (cc_set_probe(o, CC_PROBE_PRINT_SEARCH_DIRS, NULL) != 0) return 1; 1019 continue; 1020 } 1021 if (driver_strneq(a, "-print-file-name=", 17)) { 1022 if (cc_set_probe(o, CC_PROBE_PRINT_FILE_NAME, a + 17) != 0) return 1; 1023 continue; 1024 } 1025 if (driver_strneq(a, "-print-prog-name=", 17)) { 1026 if (cc_set_probe(o, CC_PROBE_PRINT_PROG_NAME, a + 17) != 0) return 1; 1027 continue; 1028 } 1029 if (driver_streq(a, "-print-libgcc-file-name")) { 1030 if (cc_set_probe(o, CC_PROBE_PRINT_LIBGCC_FILE_NAME, NULL) != 0) return 1; 1031 continue; 1032 } 1033 if (driver_streq(a, "-print-multi-os-directory")) { 1034 if (cc_set_probe(o, CC_PROBE_PRINT_MULTI_OS_DIRECTORY, NULL) != 0) 1035 return 1; 1036 continue; 1037 } 1038 if (driver_streq(a, "-print-resource-dir")) { 1039 if (cc_set_probe(o, CC_PROBE_PRINT_RESOURCE_DIR, NULL) != 0) return 1; 1040 continue; 1041 } 1042 if (driver_streq(a, "-print-sysroot")) { 1043 if (cc_set_probe(o, CC_PROBE_PRINT_SYSROOT, NULL) != 0) return 1; 1044 continue; 1045 } 1046 if (driver_streq(a, "-dumpmachine")) { 1047 if (cc_set_probe(o, CC_PROBE_DUMPMACHINE, NULL) != 0) return 1; 1048 continue; 1049 } 1050 if (driver_streq(a, "-dumpversion")) { 1051 if (cc_set_probe(o, CC_PROBE_DUMPVERSION, NULL) != 0) return 1; 1052 continue; 1053 } 1054 if (driver_streq(a, "-dumpspecs")) { 1055 if (cc_set_probe(o, CC_PROBE_DUMPSPECS, NULL) != 0) return 1; 1056 continue; 1057 } 1058 if (driver_streq(a, "-include")) { 1059 if (++i >= argc) { 1060 driver_errf(CC_TOOL, "%.*s requires an argument", 1061 KIT_SLICE_ARG(kit_slice_cstr(a))); 1062 return 1; 1063 } 1064 /* The preprocessor has no force-include hook yet (KitPreprocessOptions 1065 * carries no prefix-include list), so honoring this would silently drop 1066 * the file and miscompile. Fail loudly rather than ignore it. */ 1067 driver_errf(CC_TOOL, "-include is unimplemented: %.*s", 1068 KIT_SLICE_ARG(kit_slice_cstr(argv[i]))); 1069 return 1; 1070 } 1071 1072 if (driver_streq(a, "-fPIC") || driver_streq(a, "-fpic")) { 1073 o->target.pic = KIT_PIC_PIC; 1074 o->pic_explicit = 1; 1075 continue; 1076 } 1077 if (driver_streq(a, "-fPIE") || driver_streq(a, "-fpie")) { 1078 o->target.pic = KIT_PIC_PIE; 1079 o->pic_explicit = 1; 1080 continue; 1081 } 1082 if (driver_streq(a, "-fno-PIC") || driver_streq(a, "-fno-pic") || 1083 driver_streq(a, "-fno-PIE") || driver_streq(a, "-fno-pie")) { 1084 o->target.pic = KIT_PIC_NONE; 1085 o->pic_explicit = 1; 1086 continue; 1087 } 1088 if (driver_streq(a, "-static")) { 1089 o->target.pic = KIT_PIC_NONE; 1090 o->static_link = 1; 1091 o->pic_explicit = 1; 1092 o->inputs.cur_link_mode = KIT_LM_STATIC; 1093 continue; 1094 } 1095 if (driver_streq(a, "-pie")) { 1096 o->target.pic = KIT_PIC_PIE; 1097 o->pie = 1; 1098 o->pic_explicit = 1; 1099 continue; 1100 } 1101 if (driver_streq(a, "-no-pie")) { 1102 o->target.pic = KIT_PIC_NONE; 1103 o->pie = 0; 1104 o->pic_explicit = 1; 1105 continue; 1106 } 1107 if (driver_streq(a, "-rdynamic") || driver_streq(a, "-export-dynamic")) { 1108 /* GCC/clang: ask the linker to promote defined globals into .dynsym 1109 * (--export-dynamic). FreeBSD's HOST_ENV_LDFLAGS passes -rdynamic so a 1110 * dynamically linked exe re-exports symbols (e.g. `environ`) for libc.so 1111 * and for runtime symbolization. kit's ELF linker already exports the 1112 * defined symbols that the DSOs it links reference, which is what hosted 1113 * libc startup needs, so accept the flag for toolchain compatibility 1114 * rather than reject it. (The standalone `kit ld` carries the explicit 1115 * -E/--export-dynamic option for the full all-globals promotion.) */ 1116 continue; 1117 } 1118 if (driver_streq(a, "-Bstatic")) { 1119 o->inputs.cur_link_mode = KIT_LM_STATIC; 1120 continue; 1121 } 1122 if (driver_streq(a, "-Bdynamic")) { 1123 o->inputs.cur_link_mode = KIT_LM_DYNAMIC; 1124 continue; 1125 } 1126 if (driver_streq(a, "--as-needed")) { 1127 o->inputs.cur_link_mode = KIT_LM_AS_NEEDED; 1128 continue; 1129 } 1130 if (driver_streq(a, "--no-as-needed")) { 1131 o->inputs.cur_link_mode = KIT_LM_DYNAMIC; 1132 continue; 1133 } 1134 if (driver_streq(a, "--whole-archive")) { 1135 o->inputs.cur_whole_archive = 1; 1136 continue; 1137 } 1138 if (driver_streq(a, "--no-whole-archive")) { 1139 o->inputs.cur_whole_archive = 0; 1140 continue; 1141 } 1142 if (driver_streq(a, "--start-group")) { 1143 if (o->inputs.cur_group_id != 0) { 1144 driver_errf(CC_TOOL, "nested --start-group is not supported"); 1145 return 1; 1146 } 1147 if (o->next_group_id == UINT8_MAX) { 1148 driver_errf(CC_TOOL, "too many --start-group occurrences"); 1149 return 1; 1150 } 1151 o->inputs.cur_group_id = ++o->next_group_id; 1152 continue; 1153 } 1154 if (driver_streq(a, "--end-group")) { 1155 if (o->inputs.cur_group_id == 0) { 1156 driver_errf(CC_TOOL, "--end-group without --start-group"); 1157 return 1; 1158 } 1159 o->inputs.cur_group_id = 0; 1160 continue; 1161 } 1162 1163 if (driver_streq(a, "-shared")) { 1164 o->shared = 1; 1165 continue; 1166 } 1167 if (driver_streq(a, "-mwindows")) { 1168 o->link.pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_GUI; 1169 continue; 1170 } 1171 if (driver_streq(a, "-mconsole")) { 1172 o->link.pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_CUI; 1173 continue; 1174 } 1175 if (driver_strneq(a, "-Wl,", 4)) { 1176 if (driver_strneq(a, "-Wl,-framework,", 15)) { 1177 if (cc_record_framework(o, a + 15) != 0) return 1; 1178 continue; 1179 } 1180 if (driver_link_flags_record_wl(&o->link, a + 4) != 0) return 1; 1181 continue; 1182 } 1183 1184 if (driver_strneq(a, "-mcmodel=", 9)) { 1185 if (driver_record_mcmodel(&o->target, CC_TOOL, a + 9) != 0) return 1; 1186 continue; 1187 } 1188 if (driver_streq(a, "-mno-red-zone")) { 1189 o->disabled_backend_features |= KIT_CG_BACKEND_RED_ZONE; 1190 continue; 1191 } 1192 if (driver_streq(a, "-mred-zone")) { 1193 o->disabled_backend_features &= ~KIT_CG_BACKEND_RED_ZONE; 1194 continue; 1195 } 1196 if (driver_streq(a, "-mgeneral-regs-only")) { 1197 o->disabled_backend_features |= KIT_CG_BACKEND_SIMD; 1198 continue; 1199 } 1200 if (driver_streq(a, "-mno-general-regs-only")) { 1201 o->disabled_backend_features &= ~KIT_CG_BACKEND_SIMD; 1202 continue; 1203 } 1204 { 1205 int tr = driver_target_features_try_consume(&o->target_features, o->env, 1206 CC_TOOL, argc, argv, &i); 1207 if (tr < 0) return 1; 1208 if (tr > 0) continue; 1209 } 1210 if (driver_strneq(a, "--build-id=", 11)) { 1211 if (driver_link_flags_record_build_id(&o->link, a + 11) != 0) return 1; 1212 continue; 1213 } 1214 if (driver_strneq(a, "-ffile-prefix-map=", 18)) { 1215 if (cc_record_path_map(o, a + 18) != 0) return 1; 1216 continue; 1217 } 1218 1219 if (driver_streq(a, "-o")) { 1220 if (++i >= argc) { 1221 driver_errf(CC_TOOL, "-o requires an argument"); 1222 return 1; 1223 } 1224 o->output_path = argv[i]; 1225 continue; 1226 } 1227 if (driver_strneq(a, "--output=", 9)) { 1228 o->output_path = a + 9; 1229 continue; 1230 } 1231 if (driver_streq(a, "--output")) { 1232 if (++i >= argc) { 1233 driver_errf(CC_TOOL, "--output requires an argument"); 1234 return 1; 1235 } 1236 o->output_path = argv[i]; 1237 continue; 1238 } 1239 if (driver_streq(a, "-e")) { 1240 if (++i >= argc) { 1241 driver_errf(CC_TOOL, "-e requires an argument"); 1242 return 1; 1243 } 1244 if (driver_link_flags_record_entry(&o->link, argv[i], 1245 driver_strlen(argv[i])) != 0) 1246 return 1; 1247 continue; 1248 } 1249 if (driver_strneq(a, "--entry=", 8)) { 1250 if (driver_link_flags_record_entry(&o->link, a + 8, 1251 driver_strlen(a + 8)) != 0) 1252 return 1; 1253 continue; 1254 } 1255 if (driver_streq(a, "--entry")) { 1256 if (++i >= argc) { 1257 driver_errf(CC_TOOL, "--entry requires an argument"); 1258 return 1; 1259 } 1260 if (driver_link_flags_record_entry(&o->link, argv[i], 1261 driver_strlen(argv[i])) != 0) 1262 return 1; 1263 continue; 1264 } 1265 if (a[0] == '-' && a[1] == 'e' && a[2] != '\0') { 1266 if (driver_link_flags_record_entry(&o->link, a + 2, 1267 driver_strlen(a + 2)) != 0) 1268 return 1; 1269 continue; 1270 } 1271 if (driver_streq(a, "-T")) { 1272 if (++i >= argc) { 1273 driver_errf(CC_TOOL, "-T requires an argument"); 1274 return 1; 1275 } 1276 if (driver_link_flags_record_script(&o->link, argv[i], 1277 driver_strlen(argv[i])) != 0) 1278 return 1; 1279 continue; 1280 } 1281 if (driver_strneq(a, "--script=", 9)) { 1282 if (driver_link_flags_record_script(&o->link, a + 9, 1283 driver_strlen(a + 9)) != 0) 1284 return 1; 1285 continue; 1286 } 1287 if (driver_streq(a, "--script")) { 1288 if (++i >= argc) { 1289 driver_errf(CC_TOOL, "--script requires an argument"); 1290 return 1; 1291 } 1292 if (driver_link_flags_record_script(&o->link, argv[i], 1293 driver_strlen(argv[i])) != 0) 1294 return 1; 1295 continue; 1296 } 1297 if (a[0] == '-' && a[1] == 'T' && a[2] != '\0' && 1298 !driver_strneq(a, "-Ttext", 6) && 1299 !driver_strneq(a, "-Tdata", 6) && 1300 !driver_strneq(a, "-Tbss", 5)) { 1301 if (driver_link_flags_record_script(&o->link, a + 2, 1302 driver_strlen(a + 2)) != 0) 1303 return 1; 1304 continue; 1305 } 1306 if (driver_streq(a, "-target")) { 1307 if (++i >= argc) { 1308 driver_errf(CC_TOOL, "-target requires an argument"); 1309 return 1; 1310 } 1311 if (driver_target_from_triple(argv[i], &o->target) != 0) { 1312 driver_err_unknown_target(CC_TOOL, argv[i]); 1313 return 1; 1314 } 1315 o->target_set = 1; 1316 continue; 1317 } 1318 if (driver_strneq(a, "--target=", 9)) { 1319 if (driver_target_from_triple(a + 9, &o->target) != 0) { 1320 driver_err_unknown_target(CC_TOOL, a + 9); 1321 return 1; 1322 } 1323 o->target_set = 1; 1324 continue; 1325 } 1326 if (driver_streq(a, "--target")) { 1327 if (++i >= argc) { 1328 driver_errf(CC_TOOL, "--target requires an argument"); 1329 return 1; 1330 } 1331 if (driver_target_from_triple(argv[i], &o->target) != 0) { 1332 driver_err_unknown_target(CC_TOOL, argv[i]); 1333 return 1; 1334 } 1335 o->target_set = 1; 1336 continue; 1337 } 1338 if (driver_streq(a, "-Xlinker")) { 1339 const char* xarg; 1340 if (++i >= argc) { 1341 driver_errf(CC_TOOL, "-Xlinker requires an argument"); 1342 return 1; 1343 } 1344 xarg = argv[i]; 1345 if (driver_streq(argv[i], "-framework")) { 1346 if (++i >= argc) { 1347 driver_errf(CC_TOOL, "-framework requires an argument"); 1348 return 1; 1349 } 1350 if (driver_streq(argv[i], "-Xlinker")) { 1351 if (++i >= argc) { 1352 driver_errf(CC_TOOL, "-framework requires an argument"); 1353 return 1; 1354 } 1355 } 1356 if (cc_record_framework(o, argv[i]) != 0) return 1; 1357 continue; 1358 } 1359 if (driver_streq(xarg, "-T") || driver_streq(xarg, "--script") || 1360 driver_streq(xarg, "-e") || driver_streq(xarg, "--entry")) { 1361 const char* value; 1362 if (++i >= argc) { 1363 driver_errf(CC_TOOL, "%s passed via -Xlinker requires an argument", 1364 xarg); 1365 return 1; 1366 } 1367 if (driver_streq(argv[i], "-Xlinker")) { 1368 if (++i >= argc) { 1369 driver_errf(CC_TOOL, 1370 "%s passed via -Xlinker requires an argument", xarg); 1371 return 1; 1372 } 1373 } 1374 value = argv[i]; 1375 if ((xarg[1] == 'T' || driver_streq(xarg, "--script")) 1376 ? driver_link_flags_record_script(&o->link, value, 1377 driver_strlen(value)) 1378 : driver_link_flags_record_entry(&o->link, value, 1379 driver_strlen(value))) 1380 return 1; 1381 continue; 1382 } 1383 if (driver_link_flags_record_wl(&o->link, xarg) != 0) return 1; 1384 continue; 1385 } 1386 if (driver_streq(a, "-x")) { 1387 if (++i >= argc) { 1388 driver_errf(CC_TOOL, "-x requires an argument"); 1389 return 1; 1390 } 1391 if (driver_streq(argv[i], "none")) { 1392 forced_lang = -1; 1393 continue; 1394 } 1395 /* cc-only CLI aliases that have no frontend `-x` name: GCC's "asm-cpp" 1396 * and the case-sensitive "S" (distinct from "s") both select asm. */ 1397 if (driver_streq(argv[i], "asm-cpp") || driver_streq(argv[i], "S")) { 1398 forced_lang = KIT_LANG_ASM; 1399 continue; 1400 } 1401 { 1402 KitLanguage lang = kit_language_for_name(NULL, argv[i]); 1403 if (lang == KIT_LANG_UNKNOWN) { 1404 const char* const known[] = {"c", "asm", "assembler", 1405 "s", "toy", "wasm", 1406 "wat", "none", "asm-cpp"}; 1407 const char* candidates[sizeof known / sizeof known[0]]; 1408 DriverSuggestion suggestions[3]; 1409 size_t k, count = 0, n; 1410 for (k = 0; k < sizeof known / sizeof known[0]; ++k) { 1411 if (driver_streq(known[k], "none") || 1412 driver_streq(known[k], "asm-cpp") || 1413 kit_language_for_name(NULL, known[k]) != KIT_LANG_UNKNOWN) 1414 candidates[count++] = known[k]; 1415 } 1416 n = driver_suggest_values(argv[i], candidates, count, suggestions, 3); 1417 if (n) 1418 driver_errf(CC_TOOL, 1419 "unsupported -x language: %s; did you mean '%s'?", 1420 argv[i], suggestions[0].value); 1421 else 1422 driver_errf(CC_TOOL, "unsupported -x language: %s", argv[i]); 1423 return 1; 1424 } 1425 forced_lang = lang; 1426 continue; 1427 } 1428 } 1429 if (driver_strneq(a, "-L", 2)) { 1430 const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 1431 if (!dir) { 1432 driver_errf(CC_TOOL, "-L requires an argument"); 1433 return 1; 1434 } 1435 o->inputs.lib_search_paths[o->inputs.nlib_search_paths++] = dir; 1436 continue; 1437 } 1438 if (driver_strneq(a, "-F", 2)) { 1439 const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 1440 if (!dir) { 1441 driver_errf(CC_TOOL, "-F requires an argument"); 1442 return 1; 1443 } 1444 o->inputs.framework_search_paths[o->inputs.nframework_search_paths++] = 1445 dir; 1446 continue; 1447 } 1448 if (driver_strneq(a, "-l", 2)) { 1449 const char* name = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 1450 if (!name) { 1451 driver_errf(CC_TOOL, "-l requires an argument"); 1452 return 1; 1453 } 1454 if (driver_streq(name, "c") && !o->no_stdlib && !o->no_defaultlibs) { 1455 o->wants_hosted_libc = 1; 1456 continue; 1457 } 1458 { 1459 DriverPendingLib* pl = 1460 &o->inputs.pending_libs[o->inputs.npending_libs++]; 1461 pl->name = name; 1462 pl->whole_archive = o->inputs.cur_whole_archive; 1463 pl->link_mode = o->inputs.cur_link_mode; 1464 pl->group_id = o->inputs.cur_group_id; 1465 driver_link_inputs_push(&o->inputs, DRIVER_LINK_LIB, 1466 o->inputs.npending_libs - 1u); 1467 } 1468 continue; 1469 } 1470 if (driver_streq(a, "-framework")) { 1471 if (++i >= argc) { 1472 driver_errf(CC_TOOL, "-framework requires an argument"); 1473 return 1; 1474 } 1475 if (cc_record_framework(o, argv[i]) != 0) return 1; 1476 continue; 1477 } 1478 1479 if (driver_streq(a, "-M")) { 1480 o->dep_mode = CC_DEP_M; 1481 continue; 1482 } 1483 if (driver_streq(a, "-MM")) { 1484 o->dep_mode = CC_DEP_MM; 1485 continue; 1486 } 1487 if (driver_streq(a, "-MD")) { 1488 o->dep_mode = CC_DEP_MD; 1489 continue; 1490 } 1491 if (driver_streq(a, "-MMD")) { 1492 o->dep_mode = CC_DEP_MMD; 1493 continue; 1494 } 1495 if (driver_streq(a, "-MP")) { 1496 o->dep_phony = 1; 1497 continue; 1498 } 1499 if (driver_streq(a, "-MF")) { 1500 if (++i >= argc) { 1501 driver_errf(CC_TOOL, "-MF requires an argument"); 1502 return 1; 1503 } 1504 o->dep_file = argv[i]; 1505 continue; 1506 } 1507 if (driver_streq(a, "-MT") || driver_streq(a, "-MQ")) { 1508 int quote = driver_streq(a, "-MQ"); 1509 uint32_t slot = o->ndep_targets; 1510 if (++i >= argc) { 1511 driver_errf(CC_TOOL, "%.*s requires an argument", 1512 KIT_SLICE_ARG(kit_slice_cstr(a))); 1513 return 1; 1514 } 1515 if (quote) { 1516 o->owned_dep_targets[slot] = cc_dep_quote_make_alloc( 1517 o->env, argv[i], &o->owned_dep_target_sizes[slot]); 1518 if (!o->owned_dep_targets[slot]) { 1519 driver_errf(CC_TOOL, "out of memory"); 1520 return 1; 1521 } 1522 o->dep_targets[slot] = o->owned_dep_targets[slot]; 1523 } else { 1524 o->dep_targets[slot] = argv[i]; 1525 } 1526 o->ndep_targets++; 1527 continue; 1528 } 1529 1530 if (driver_streq(a, "--")) { 1531 for (++i; i < argc; ++i) { 1532 if (cc_classify_positional(o, argv[i], forced_lang) != 0) return 1; 1533 } 1534 break; 1535 } 1536 if (driver_streq(a, "-")) { 1537 if (cc_classify_positional(o, a, forced_lang) != 0) return 1; 1538 continue; 1539 } 1540 if (a[0] == '-' && a[1] != '\0') { 1541 const char* const valid[] = { 1542 "--help", "-h", "--version", "-target", 1543 "--target", "-o", "--output", "-T", 1544 "--script", "-e", "--entry", "-x", 1545 "-c", "-S", "-E", "-shared", 1546 "-static", "-nostdlib", "-isysroot", "--sysroot", 1547 "--start-group", "--end-group"}; 1548 DriverSuggestion suggestions[3]; 1549 size_t n = driver_suggest_values(a, valid, 1550 sizeof valid / sizeof valid[0], 1551 suggestions, 3); 1552 if (n) 1553 driver_errf(CC_TOOL, "unknown flag: %s; did you mean '%s'?", a, 1554 suggestions[0].value); 1555 else 1556 driver_errf(CC_TOOL, "unknown flag: %s", a); 1557 return 1; 1558 } 1559 1560 if (cc_classify_positional(o, a, forced_lang) != 0) return 1; 1561 } 1562 1563 if (o->probe_kind != CC_PROBE_NONE) return 0; 1564 1565 if (cc_apply_env(o) != 0) return 1; 1566 if (driver_link_inputs_append_windows_lib_dirs(&o->inputs, &o->sysroot, 1567 o->target) != 0) 1568 return 1; 1569 if (driver_link_inputs_append_sysroot_framework_dirs(&o->inputs, &o->sysroot, 1570 o->target) != 0) 1571 return 1; 1572 if (o->shared && !o->pic_explicit) o->target.pic = KIT_PIC_PIC; 1573 1574 { 1575 uint32_t total_sources = o->nsource_files + o->nsource_memory; 1576 uint32_t total_link = o->inputs.nobject_files + o->inputs.narchives + 1577 o->inputs.ndsos + o->inputs.npending_libs + 1578 o->inputs.npending_frameworks; 1579 1580 if (total_sources == 0 && total_link == 0) { 1581 driver_errf(CC_TOOL, "no input files"); 1582 cc_usage(); 1583 return 1; 1584 } 1585 if ((o->compile_only && o->preprocess_only) || 1586 (o->emit_asm_source && o->preprocess_only) || 1587 (o->syntax_only && 1588 (o->compile_only || o->preprocess_only || o->emit_asm_source))) { 1589 driver_errf(CC_TOOL, 1590 "-c, -S, -E, and -fsyntax-only are mutually exclusive"); 1591 return 1; 1592 } 1593 if (o->shared && (o->compile_only || o->emit_asm_source || 1594 o->preprocess_only || o->syntax_only)) { 1595 driver_errf(CC_TOOL, 1596 "-shared is incompatible with -c/-S/-E/-fsyntax-only"); 1597 return 1; 1598 } 1599 if (o->shared && o->lto) { 1600 driver_errf(CC_TOOL, 1601 "-shared -flto is not supported yet " 1602 "(shared-library LTO output is not exercised)"); 1603 return 1; 1604 } 1605 if (o->shared && o->target.obj != KIT_OBJ_ELF) { 1606 driver_errf(CC_TOOL, 1607 "-shared output is supported only for ELF targets in v1"); 1608 return 1; 1609 } 1610 if (o->shared && o->target.pic == KIT_PIC_NONE) { 1611 driver_errf(CC_TOOL, "-shared requires PIC input; remove -fno-pic/-static"); 1612 return 1; 1613 } 1614 if (o->emit_ir && o->opt_level < 1) { 1615 driver_errf(CC_TOOL, 1616 "--emit=ir requires -O1 or higher " 1617 "(the IR tape is only recorded when the optimizer runs)"); 1618 return 1; 1619 } 1620 if (o->syntax_only) { 1621 if (total_sources == 0 || total_link != 0) { 1622 driver_errf(CC_TOOL, 1623 "-fsyntax-only requires source inputs and no link inputs"); 1624 return 1; 1625 } 1626 if (o->output_path) { 1627 driver_errf(CC_TOOL, "-o is incompatible with -fsyntax-only"); 1628 return 1; 1629 } 1630 if (o->dep_mode != CC_DEP_NONE) { 1631 driver_errf(CC_TOOL, "-M* is incompatible with -fsyntax-only"); 1632 return 1; 1633 } 1634 } 1635 if (!o->shared && o->link.soname) { 1636 driver_errf(CC_TOOL, "-Wl,-soname requires -shared"); 1637 return 1; 1638 } 1639 if (o->inputs.cur_group_id != 0) { 1640 driver_errf(CC_TOOL, "missing --end-group"); 1641 return 1; 1642 } 1643 if (o->compile_only) { 1644 if (total_sources == 0 || total_link != 0) { 1645 driver_errf(CC_TOOL, "-c requires source inputs and no link inputs"); 1646 return 1; 1647 } 1648 if (o->output_path && total_sources > 1) { 1649 driver_errf(CC_TOOL, "-o cannot be used with -c and multiple sources"); 1650 return 1; 1651 } 1652 } 1653 if (o->preprocess_only) { 1654 if (total_sources != 1 || total_link != 0) { 1655 driver_errf(CC_TOOL, 1656 "-E requires exactly one C source and no .o/.a inputs"); 1657 return 1; 1658 } 1659 } 1660 { 1661 int dep_only = (o->dep_mode == CC_DEP_M || o->dep_mode == CC_DEP_MM); 1662 if (o->dep_mode != CC_DEP_NONE && o->preprocess_only) { 1663 driver_errf(CC_TOOL, "-M* is incompatible with -E"); 1664 return 1; 1665 } 1666 if (dep_only && (total_sources == 0 || total_link != 0)) { 1667 driver_errf(CC_TOOL, 1668 "-M/-MM requires source inputs and no link inputs"); 1669 return 1; 1670 } 1671 if (!o->output_path && !dep_only) { 1672 if (o->syntax_only) { 1673 /* no output */ 1674 } else if (o->compile_only) { 1675 if (total_sources == 1) { 1676 o->owned_output_path = 1677 cc_dep_default_target(o->env, o, &o->owned_output_path_size); 1678 if (!o->owned_output_path) { 1679 driver_errf(CC_TOOL, "out of memory"); 1680 return 1; 1681 } 1682 o->output_path = o->owned_output_path; 1683 } 1684 } else if (o->preprocess_only) { 1685 /* stdout */ 1686 } else { 1687 o->output_path = driver_default_exe_name(o->target); 1688 } 1689 } 1690 /* Windows PE/COFF executables conventionally carry a `.exe` suffix; 1691 * GCC/clang on a mingw target append it to an -o output that has no 1692 * extension. Mirror that so `kit cc -o foo` for a windows target 1693 * produces foo.exe, matching the rest of the toolchain. Only for 1694 * executable links (the default name already carries .exe; shared 1695 * libraries use the .dll convention; non-link actions are skipped). */ 1696 if (o->output_path && o->target.os == KIT_OS_WINDOWS && !o->shared && 1697 !o->syntax_only && !o->compile_only && !o->preprocess_only && 1698 !dep_only) { 1699 const char* base = o->output_path; 1700 for (const char* q = o->output_path; *q; q++) 1701 if (*q == '/' || *q == '\\') base = q + 1; 1702 int has_ext = 0; 1703 for (const char* q = base; *q; q++) 1704 if (*q == '.') { 1705 has_ext = 1; 1706 break; 1707 } 1708 if (*base && !has_ext) { 1709 size_t len = strlen(o->output_path); 1710 size_t nsize = len + 5; /* ".exe" + NUL */ 1711 char* buf = driver_alloc(o->env, nsize); 1712 if (!buf) { 1713 driver_errf(CC_TOOL, "out of memory"); 1714 return 1; 1715 } 1716 memcpy(buf, o->output_path, len); 1717 memcpy(buf + len, ".exe", 4); 1718 buf[len + 4] = '\0'; 1719 o->owned_output_path = buf; 1720 o->owned_output_path_size = nsize; 1721 o->output_path = o->owned_output_path; 1722 } 1723 } 1724 } 1725 } 1726 cc_enable_hosted_for_sysroot(o); 1727 cc_apply_default_hosted_profile(o); 1728 if (cc_apply_hosted_profile(o) != 0) return 1; 1729 if (!o->syntax_only && driver_link_inputs_resolve_pending( 1730 &o->inputs, o->target, o->static_link) != 0) 1731 return 1; 1732 return 0; 1733 } 1734 1735 static const char* cc_primary_source_name(const CcOptions* o); 1736 1737 /* Borrow the single source as a KitSlice. `*loaded` is set nonzero only 1738 * when the file was opened via file_io and must be released. */ 1739 static int cc_load_single_source(const KitContext* ctx, const CcOptions* o, 1740 KitSlice* in, KitFileData* fd, int* loaded) { 1741 *loaded = 0; 1742 if (o->nsource_memory == 1) { 1743 *in = o->source_memory[0].bytes; 1744 return 0; 1745 } 1746 if (ctx->file_io->read_all(ctx->file_io->user, o->source_files[0], fd) != 1747 KIT_OK) { 1748 driver_errf(CC_TOOL, "failed to read: %.*s", 1749 KIT_SLICE_ARG(kit_slice_cstr(o->source_files[0]))); 1750 return 1; 1751 } 1752 *loaded = 1; 1753 in->data = fd->data; 1754 in->len = fd->size; 1755 return 0; 1756 } 1757 1758 static KitStatus cc_compiler_new(const CcOptions* o, const KitContext* ctx, 1759 KitTarget** target_out, 1760 KitCompiler** compiler_out) { 1761 KitStatus st; 1762 if (target_out) *target_out = NULL; 1763 if (compiler_out) *compiler_out = NULL; 1764 if (!o || !ctx || !target_out || !compiler_out) return KIT_INVALID; 1765 st = driver_target_new(ctx, o->target, &o->target_features, CC_TOOL, 1766 target_out); 1767 if (st != KIT_OK) return st; 1768 st = driver_compiler_new(*target_out, ctx, compiler_out); 1769 if (st != KIT_OK) { 1770 kit_target_free(*target_out); 1771 *target_out = NULL; 1772 } 1773 return st; 1774 } 1775 1776 static void cc_close_output(KitWriter** writer, const char* output_path, 1777 int* rc) { 1778 if (writer && *writer && rc && kit_writer_status(*writer) != KIT_OK) *rc = 1; 1779 if (writer && *writer && rc && *rc != 0 && output_path) 1780 driver_writer_abort(*writer); 1781 if (writer && *writer) { 1782 kit_writer_close(*writer); 1783 *writer = NULL; 1784 } 1785 } 1786 1787 static int cc_preprocess(DriverEnv* env, const CcOptions* o, 1788 const KitPreprocessOptions* pp_opts) { 1789 KitContext ctx = driver_env_to_context(env); 1790 KitTarget* target = NULL; 1791 KitCompiler* compiler = NULL; 1792 KitWriter* writer = NULL; 1793 KitFileData fd = {0}; 1794 KitSlice input = {0}; 1795 int rc = 1; 1796 int loaded = 0; 1797 1798 if (cc_load_single_source(&ctx, o, &input, &fd, &loaded) != 0) goto out; 1799 1800 if (o->output_path) { 1801 if (ctx.file_io->open_writer(ctx.file_io->user, o->output_path, &writer) != 1802 KIT_OK) { 1803 driver_errf(CC_TOOL, "failed to open output: %.*s", 1804 KIT_SLICE_ARG(kit_slice_cstr(o->output_path))); 1805 goto out; 1806 } 1807 } else { 1808 writer = driver_stdout_writer(env); 1809 if (!writer) { 1810 driver_errf(CC_TOOL, "out of memory"); 1811 goto out; 1812 } 1813 } 1814 1815 if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) { 1816 driver_errf(CC_TOOL, "failed to initialize compiler"); 1817 goto out; 1818 } 1819 1820 rc = kit_cpp_preprocess(compiler, pp_opts, 1821 kit_slice_cstr(cc_primary_source_name(o)), &input, 1822 writer) == KIT_OK 1823 ? 0 1824 : 1; 1825 1826 out: 1827 if (compiler) driver_compiler_free(compiler); 1828 kit_target_free(target); 1829 cc_close_output(&writer, o->output_path, &rc); 1830 if (loaded) ctx.file_io->release(ctx.file_io->user, &fd); 1831 return rc; 1832 } 1833 1834 /* ---- header-dependency output (-M family) ---- */ 1835 1836 typedef struct CcDepList { 1837 const char** items; 1838 uint32_t n; 1839 uint32_t cap; 1840 } CcDepList; 1841 1842 typedef struct CcDiscardWriter { 1843 KitWriter base; 1844 DriverEnv* env; 1845 uint64_t pos; 1846 } CcDiscardWriter; 1847 1848 static KitStatus cc_disc_write(KitWriter* w, const void* d, size_t n) { 1849 (void)d; 1850 ((CcDiscardWriter*)w)->pos += (uint64_t)n; 1851 return KIT_OK; 1852 } 1853 static KitStatus cc_disc_seek(KitWriter* w, uint64_t off) { 1854 ((CcDiscardWriter*)w)->pos = off; 1855 return KIT_OK; 1856 } 1857 static uint64_t cc_disc_tell(KitWriter* w) { 1858 return ((CcDiscardWriter*)w)->pos; 1859 } 1860 static KitStatus cc_disc_status(KitWriter* w) { 1861 (void)w; 1862 return KIT_OK; 1863 } 1864 static void cc_disc_close(KitWriter* w) { 1865 CcDiscardWriter* dw = (CcDiscardWriter*)w; 1866 driver_free(dw->env, dw, sizeof(*dw)); 1867 } 1868 1869 static KitWriter* cc_discard_writer_new(DriverEnv* env) { 1870 CcDiscardWriter* dw = (CcDiscardWriter*)driver_alloc_zeroed(env, sizeof(*dw)); 1871 if (!dw) return NULL; 1872 dw->base.write = cc_disc_write; 1873 dw->base.seek = cc_disc_seek; 1874 dw->base.tell = cc_disc_tell; 1875 dw->base.status = cc_disc_status; 1876 dw->base.close = cc_disc_close; 1877 dw->env = env; 1878 return &dw->base; 1879 } 1880 1881 static void cc_write_str(KitWriter* w, const char* s) { 1882 kit_writer_write(w, s, driver_strlen(s)); 1883 } 1884 1885 static int cc_dep_filters_system(int mode) { 1886 return mode == CC_DEP_MM || mode == CC_DEP_MMD; 1887 } 1888 1889 static int cc_dep_list_push(DriverEnv* env, CcDepList* l, const char* s) { 1890 uint32_t i; 1891 for (i = 0; i < l->n; ++i) { 1892 if (driver_streq(l->items[i], s)) return 0; 1893 } 1894 if (l->n == l->cap) { 1895 uint32_t newcap = l->cap ? l->cap * 2 : 16; 1896 const char** ni = driver_alloc_zeroed(env, newcap * sizeof(*ni)); 1897 if (!ni) return 1; 1898 if (l->items) { 1899 driver_memcpy(ni, l->items, l->n * sizeof(*l->items)); 1900 driver_free(env, l->items, l->cap * sizeof(*l->items)); 1901 } 1902 l->items = ni; 1903 l->cap = newcap; 1904 } 1905 l->items[l->n++] = s; 1906 return 0; 1907 } 1908 1909 static void cc_dep_list_free(DriverEnv* env, CcDepList* l) { 1910 if (l->items) driver_free(env, l->items, l->cap * sizeof(*l->items)); 1911 l->items = NULL; 1912 l->n = 0; 1913 l->cap = 0; 1914 } 1915 1916 static char* cc_dep_default_target(DriverEnv* env, const CcOptions* o, 1917 size_t* out_size) { 1918 const char* base = o->output_path; 1919 size_t len; 1920 char* buf; 1921 if (base) { 1922 len = driver_strlen(base); 1923 buf = driver_alloc(env, len + 1); 1924 if (!buf) return NULL; 1925 driver_memcpy(buf, base, len); 1926 buf[len] = '\0'; 1927 *out_size = len + 1; 1928 return buf; 1929 } 1930 if (o->nsource_memory == 1) { 1931 const char* fallback = "<stdin>.o"; 1932 size_t flen = driver_strlen(fallback); 1933 buf = driver_alloc(env, flen + 1); 1934 if (!buf) return NULL; 1935 driver_memcpy(buf, fallback, flen); 1936 buf[flen] = '\0'; 1937 *out_size = flen + 1; 1938 return buf; 1939 } 1940 { 1941 const char* src = o->source_files[0]; 1942 size_t srclen = driver_strlen(src); 1943 size_t dot = srclen; 1944 size_t slash = 0; 1945 size_t k; 1946 for (k = srclen; k > 0; --k) { 1947 if (src[k - 1] == '.') { 1948 dot = k - 1; 1949 break; 1950 } 1951 if (src[k - 1] == '/') break; 1952 } 1953 for (k = dot; k > 0; --k) { 1954 if (src[k - 1] == '/') { 1955 slash = k; 1956 break; 1957 } 1958 } 1959 { 1960 const char* ext; 1961 size_t ext_len; 1962 size_t name_len = dot - slash; 1963 size_t bufsz; 1964 driver_default_obj_ext(o->target, &ext, &ext_len); 1965 bufsz = name_len + ext_len + 1u; 1966 buf = driver_alloc(env, bufsz); 1967 if (!buf) return NULL; 1968 driver_memcpy(buf, src + slash, name_len); 1969 driver_memcpy(buf + name_len, ext, ext_len); 1970 buf[name_len + ext_len] = '\0'; 1971 *out_size = bufsz; 1972 return buf; 1973 } 1974 } 1975 } 1976 1977 static char* cc_default_obj_path_for_name(DriverEnv* env, const CcOptions* o, 1978 const char* src, size_t* out_size) { 1979 /* -S/--emit override the object suffix; otherwise the canonical 1980 * platform object extension (Windows `.obj`, else `.o`) via the shared 1981 * per-target helper. */ 1982 const char* ext; 1983 size_t ext_len; 1984 if (o && o->emit_asm_source) { 1985 ext = ".s"; 1986 ext_len = 2u; 1987 } else if (o && o->emit_ir) { 1988 ext = ".ir"; 1989 ext_len = 3u; 1990 } else { 1991 driver_default_obj_ext(o->target, &ext, &ext_len); 1992 } 1993 size_t srclen = driver_strlen(src); 1994 size_t dot = srclen; 1995 size_t slash = 0; 1996 size_t k; 1997 char* buf; 1998 for (k = srclen; k > 0; --k) { 1999 if (src[k - 1] == '.') { 2000 dot = k - 1; 2001 break; 2002 } 2003 if (src[k - 1] == '/') break; 2004 } 2005 for (k = dot; k > 0; --k) { 2006 if (src[k - 1] == '/') { 2007 slash = k; 2008 break; 2009 } 2010 } 2011 { 2012 size_t name_len = dot - slash; 2013 size_t bufsz = name_len + ext_len + 1u; 2014 buf = driver_alloc(env, bufsz); 2015 if (!buf) return NULL; 2016 driver_memcpy(buf, src + slash, name_len); 2017 driver_memcpy(buf + name_len, ext, ext_len); 2018 buf[name_len + ext_len] = '\0'; 2019 *out_size = bufsz; 2020 return buf; 2021 } 2022 } 2023 2024 static char* cc_dep_default_path(DriverEnv* env, const char* out_path, 2025 size_t* out_size) { 2026 size_t len = driver_strlen(out_path); 2027 size_t dot = len; 2028 size_t k; 2029 for (k = len; k > 0; --k) { 2030 if (out_path[k - 1] == '.') { 2031 dot = k - 1; 2032 break; 2033 } 2034 if (out_path[k - 1] == '/') break; 2035 } 2036 { 2037 size_t bufsz = dot + 3; 2038 char* buf = driver_alloc(env, bufsz); 2039 if (!buf) return NULL; 2040 driver_memcpy(buf, out_path, dot); 2041 buf[dot] = '.'; 2042 buf[dot + 1] = 'd'; 2043 buf[dot + 2] = '\0'; 2044 *out_size = bufsz; 2045 return buf; 2046 } 2047 } 2048 2049 /* Collect the include-dependency edges into `list`. Returns 0 on success, 2050 * CC_DEP_COLLECT_OOM on allocation failure (caller reports it generically), or 2051 * CC_DEP_COLLECT_DIAGNOSED when the iterator faulted mid-scan -- in that case a 2052 * specific diagnostic naming the offending dependency has already been emitted, 2053 * so the caller must not overwrite it with a generic message. */ 2054 #define CC_DEP_COLLECT_OOM 1 2055 #define CC_DEP_COLLECT_DIAGNOSED 2 2056 2057 static int cc_dep_collect(DriverEnv* env, KitCompiler* compiler, 2058 int system_filter, CcDepList* list) { 2059 KitDepIter* it = NULL; 2060 KitDepEdge e = {0}; 2061 if (kit_dep_iter_new(compiler, &it) != KIT_OK) return CC_DEP_COLLECT_OOM; 2062 for (;;) { 2063 KitIterResult r = kit_dep_iter_next(it, &e); 2064 if (r == KIT_ITER_ERROR) { 2065 /* Name the most recently scanned dependency so the failure is actionable 2066 * instead of a silent short read of the dep list. `e` is zero-initialized 2067 * and only ever written by kit_dep_iter_next, so it is never garbage: on 2068 * an error before any edge it is empty (-> generic message), otherwise it 2069 * holds the last edge we saw. */ 2070 if (e.included_name.len) 2071 driver_errf(CC_TOOL, "failed while scanning dependency: %.*s", 2072 KIT_SLICE_ARG(e.included_name)); 2073 else 2074 driver_errf(CC_TOOL, "failed to scan include dependencies"); 2075 kit_dep_iter_free(it); 2076 return CC_DEP_COLLECT_DIAGNOSED; 2077 } 2078 if (r != KIT_ITER_ITEM) break; 2079 if (system_filter && e.from_system_path) continue; 2080 if (cc_dep_list_push(env, list, e.included_name.s) != 0) { 2081 kit_dep_iter_free(it); 2082 return CC_DEP_COLLECT_OOM; 2083 } 2084 } 2085 kit_dep_iter_free(it); 2086 return 0; 2087 } 2088 2089 static void cc_dep_emit_rule(KitWriter* w, const char* const* targets, 2090 uint32_t ntargets, const char* primary_src, 2091 const CcDepList* deps, int phony, 2092 int quote_default_target) { 2093 uint32_t i; 2094 for (i = 0; i < ntargets; ++i) { 2095 const char* s; 2096 if (i) cc_write_str(w, " "); 2097 s = targets[i]; 2098 if (!quote_default_target) { 2099 cc_write_str(w, s); 2100 } else { 2101 for (; *s; ++s) { 2102 char c = *s; 2103 if (c == '$') { 2104 cc_write_str(w, "$$"); 2105 } else if (c == ' ' || c == '\t' || c == '#' || c == '\\') { 2106 kit_writer_write(w, "\\", 1); 2107 kit_writer_write(w, &c, 1); 2108 } else { 2109 kit_writer_write(w, &c, 1); 2110 } 2111 } 2112 } 2113 } 2114 cc_write_str(w, ":"); 2115 if (primary_src) { 2116 const char* s = primary_src; 2117 cc_write_str(w, " "); 2118 for (; *s; ++s) { 2119 char c = *s; 2120 if (c == '$') { 2121 cc_write_str(w, "$$"); 2122 } else if (c == ' ' || c == '\t' || c == '#' || c == '\\') { 2123 kit_writer_write(w, "\\", 1); 2124 kit_writer_write(w, &c, 1); 2125 } else { 2126 kit_writer_write(w, &c, 1); 2127 } 2128 } 2129 } 2130 for (i = 0; i < deps->n; ++i) { 2131 const char* s = deps->items[i]; 2132 cc_write_str(w, " \\\n "); 2133 for (; *s; ++s) { 2134 char c = *s; 2135 if (c == '$') { 2136 cc_write_str(w, "$$"); 2137 } else if (c == ' ' || c == '\t' || c == '#' || c == '\\') { 2138 kit_writer_write(w, "\\", 1); 2139 kit_writer_write(w, &c, 1); 2140 } else { 2141 kit_writer_write(w, &c, 1); 2142 } 2143 } 2144 } 2145 cc_write_str(w, "\n"); 2146 if (phony) { 2147 for (i = 0; i < deps->n; ++i) { 2148 const char* s = deps->items[i]; 2149 cc_write_str(w, "\n"); 2150 for (; *s; ++s) { 2151 char c = *s; 2152 if (c == '$') { 2153 cc_write_str(w, "$$"); 2154 } else if (c == ' ' || c == '\t' || c == '#' || c == '\\') { 2155 kit_writer_write(w, "\\", 1); 2156 kit_writer_write(w, &c, 1); 2157 } else { 2158 kit_writer_write(w, &c, 1); 2159 } 2160 } 2161 cc_write_str(w, ":\n"); 2162 } 2163 } 2164 } 2165 2166 static const char* cc_primary_source_name(const CcOptions* o) { 2167 if (o->nsource_memory == 1) return o->source_memory[0].name.s; 2168 return o->source_files[0]; 2169 } 2170 2171 static char* cc_dep_default_target_for(DriverEnv* env, const CcOptions* o, 2172 const char* source_name, 2173 const char* output_path, 2174 size_t* out_size) { 2175 CcOptions view = *o; 2176 const char* one_file[1]; 2177 KitSourceInput one_memory[1]; 2178 view.output_path = output_path; 2179 view.nsource_files = 0; 2180 view.nsource_memory = 0; 2181 if (driver_streq(source_name, "<stdin>")) { 2182 memset(one_memory, 0, sizeof(one_memory)); 2183 one_memory[0].name = kit_slice_cstr(source_name); 2184 view.source_memory = one_memory; 2185 view.nsource_memory = 1; 2186 } else { 2187 one_file[0] = source_name; 2188 view.source_files = one_file; 2189 view.nsource_files = 1; 2190 } 2191 return cc_dep_default_target(env, &view, out_size); 2192 } 2193 2194 static int cc_dep_finish_to(DriverEnv* env, KitCompiler* compiler, 2195 const CcOptions* o, const char* source_name, 2196 const char* output_path, KitWriter* dep_w) { 2197 CcDepList deps = {0}; 2198 char* owned_target = NULL; 2199 size_t owned_target_size = 0; 2200 const char* one_target[1]; 2201 const char* const* targets; 2202 uint32_t ntargets; 2203 int rc = 1; 2204 2205 { 2206 int cr = cc_dep_collect(env, compiler, cc_dep_filters_system(o->dep_mode), 2207 &deps); 2208 if (cr == CC_DEP_COLLECT_OOM) { 2209 driver_errf(CC_TOOL, "out of memory"); 2210 goto out; 2211 } 2212 if (cr != 0) goto out; /* CC_DEP_COLLECT_DIAGNOSED: already reported */ 2213 } 2214 2215 targets = o->dep_targets; 2216 ntargets = o->ndep_targets; 2217 if (ntargets == 0) { 2218 owned_target = cc_dep_default_target_for( 2219 env, o, source_name, output_path, &owned_target_size); 2220 if (!owned_target) { 2221 driver_errf(CC_TOOL, "out of memory"); 2222 goto out; 2223 } 2224 one_target[0] = owned_target; 2225 targets = one_target; 2226 ntargets = 1; 2227 } 2228 2229 cc_dep_emit_rule(dep_w, targets, ntargets, source_name, &deps, o->dep_phony, 2230 o->ndep_targets == 0); 2231 rc = kit_writer_status(dep_w) == KIT_OK ? 0 : 1; 2232 2233 out: 2234 if (owned_target) driver_free(env, owned_target, owned_target_size); 2235 cc_dep_list_free(env, &deps); 2236 return rc; 2237 } 2238 2239 static KitWriter* cc_dep_buffer_new(const KitContext* ctx) { 2240 KitWriter* w = NULL; 2241 if (!ctx || !ctx->heap || kit_writer_mem(ctx->heap, &w) != KIT_OK) return NULL; 2242 return w; 2243 } 2244 2245 static int cc_dep_commit_buffer(DriverEnv* env, const KitContext* ctx, 2246 KitWriter* mem, const char* path) { 2247 KitWriter* out = NULL; 2248 const uint8_t* bytes; 2249 size_t len = 0; 2250 int rc = 1; 2251 bytes = kit_writer_mem_bytes(mem, &len); 2252 if (path) { 2253 if (ctx->file_io->open_writer(ctx->file_io->user, path, &out) != KIT_OK) { 2254 driver_errf(CC_TOOL, "failed to open dep output: %.*s", 2255 KIT_SLICE_ARG(kit_slice_cstr(path))); 2256 return 1; 2257 } 2258 } else { 2259 out = driver_stdout_writer(env); 2260 if (!out) { 2261 driver_errf(CC_TOOL, "out of memory"); 2262 return 1; 2263 } 2264 } 2265 if (kit_writer_write(out, bytes, len) == KIT_OK && 2266 kit_writer_status(out) == KIT_OK) 2267 rc = 0; 2268 if (rc != 0 && path) driver_writer_abort(out); 2269 kit_writer_close(out); 2270 return rc; 2271 } 2272 2273 static int cc_dep_finish_default_file(DriverEnv* env, const KitContext* ctx, 2274 KitCompiler* compiler, 2275 const CcOptions* o, 2276 const char* source_name, 2277 const char* output_path) { 2278 KitWriter* mem = NULL; 2279 char* dep_path = NULL; 2280 size_t dep_path_size = 0; 2281 int rc = 1; 2282 mem = cc_dep_buffer_new(ctx); 2283 if (!mem) { 2284 driver_errf(CC_TOOL, "out of memory"); 2285 goto out; 2286 } 2287 if (cc_dep_finish_to(env, compiler, o, source_name, output_path, mem) != 0) 2288 goto out; 2289 dep_path = cc_dep_default_path(env, output_path, &dep_path_size); 2290 if (!dep_path) { 2291 driver_errf(CC_TOOL, "out of memory"); 2292 goto out; 2293 } 2294 rc = cc_dep_commit_buffer(env, ctx, mem, dep_path); 2295 out: 2296 if (dep_path) driver_free(env, dep_path, dep_path_size); 2297 if (mem) kit_writer_close(mem); 2298 return rc; 2299 } 2300 2301 static void cc_fill_c_opts(const CcOptions* o, KitCCompileOptions* copts) { 2302 KitCCompileOptions zero = {0}; 2303 *copts = zero; 2304 copts->code.opt_level = o->syntax_only ? 0 : o->opt_level; 2305 copts->code.debug_info = o->debug_info; 2306 copts->code.check_only = o->syntax_only ? true : false; 2307 copts->code.default_visibility = o->default_visibility; 2308 copts->code.emit_c_source = o->emit_c_source ? true : false; 2309 copts->code.emit_ir = o->emit_ir ? true : false; 2310 copts->code.emit_asm_source = o->emit_asm_source ? true : false; 2311 copts->code.function_sections = o->function_sections ? true : false; 2312 copts->code.data_sections = o->data_sections ? true : false; 2313 copts->code.disabled_backend_features = o->disabled_backend_features; 2314 copts->code.trivial_auto_var_init = (uint8_t)o->auto_var_init; 2315 copts->code.stack_protector = (uint8_t)o->stack_protector; 2316 copts->code.lto = o->lto ? true : false; 2317 copts->code.epoch = o->epoch; 2318 copts->code.path_map = o->npath_map ? o->path_map : NULL; 2319 copts->code.npath_map = o->npath_map; 2320 copts->diagnostics.warnings_are_errors = o->warnings_are_errors; 2321 copts->diagnostics.max_errors = o->max_errors; 2322 } 2323 2324 static const char* cc_source_name(const CcOptions* o, int is_memory, 2325 uint32_t index) { 2326 return is_memory ? o->source_memory[index].name.s : o->source_files[index]; 2327 } 2328 2329 static int cc_dep_scan_one(DriverEnv* env, const CcOptions* o, 2330 const KitPreprocessOptions* pp, int is_memory, 2331 uint32_t index, const char* output_path, 2332 KitWriter* rules) { 2333 KitContext ctx = driver_env_to_context(env); 2334 KitTarget* target = NULL; 2335 KitCompiler* compiler = NULL; 2336 KitWriter* discard = NULL; 2337 KitFileData fd = {0}; 2338 KitSlice input = {0}; 2339 int loaded = 0; 2340 int rc = 1; 2341 const char* source_name = cc_source_name(o, is_memory, index); 2342 2343 if (is_memory) { 2344 input = o->source_memory[index].bytes; 2345 } else { 2346 if (ctx.file_io->read_all(ctx.file_io->user, o->source_files[index], &fd) != 2347 KIT_OK) { 2348 driver_errf(CC_TOOL, "failed to read: %.*s", 2349 KIT_SLICE_ARG(kit_slice_cstr(o->source_files[index]))); 2350 goto out; 2351 } 2352 loaded = 1; 2353 input.data = fd.data; 2354 input.len = fd.size; 2355 } 2356 2357 discard = cc_discard_writer_new(env); 2358 if (!discard) { 2359 driver_errf(CC_TOOL, "out of memory"); 2360 goto out; 2361 } 2362 2363 if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) { 2364 driver_errf(CC_TOOL, "failed to initialize compiler"); 2365 goto out; 2366 } 2367 2368 if (kit_cpp_preprocess(compiler, pp, kit_slice_cstr(source_name), &input, 2369 discard) != KIT_OK) 2370 goto out; 2371 2372 rc = cc_dep_finish_to(env, compiler, o, source_name, output_path, rules); 2373 2374 out: 2375 if (compiler) driver_compiler_free(compiler); 2376 kit_target_free(target); 2377 if (discard) kit_writer_close(discard); 2378 if (loaded) ctx.file_io->release(ctx.file_io->user, &fd); 2379 return rc; 2380 } 2381 2382 static int cc_run_deps_only(DriverEnv* env, const CcOptions* o, 2383 const KitPreprocessOptions* pp) { 2384 KitContext ctx = driver_env_to_context(env); 2385 KitWriter* rules = NULL; 2386 uint32_t i; 2387 int rc = 1; 2388 rules = cc_dep_buffer_new(&ctx); 2389 if (!rules) { 2390 driver_errf(CC_TOOL, "out of memory"); 2391 return 1; 2392 } 2393 for (i = 0; i < o->inputs.nlink_items; ++i) { 2394 const DriverLinkItem* item = &o->inputs.link_items[i]; 2395 if (item->kind == DRIVER_LINK_SOURCE) { 2396 if (cc_dep_scan_one(env, o, pp, 0, item->index, NULL, rules) != 0) 2397 goto out; 2398 } else if (item->kind == DRIVER_LINK_SOURCE_MEMORY) { 2399 if (cc_dep_scan_one(env, o, pp, 1, item->index, NULL, rules) != 0) 2400 goto out; 2401 } 2402 } 2403 rc = cc_dep_commit_buffer(env, &ctx, rules, o->dep_file); 2404 out: 2405 kit_writer_close(rules); 2406 return rc; 2407 } 2408 2409 static int cc_dep_scan_default_file(DriverEnv* env, const CcOptions* o, 2410 const KitPreprocessOptions* pp, 2411 int is_memory, uint32_t index, 2412 const char* output_path) { 2413 KitContext ctx = driver_env_to_context(env); 2414 KitWriter* rules = NULL; 2415 char* dep_path = NULL; 2416 size_t dep_path_size = 0; 2417 int rc = 1; 2418 rules = cc_dep_buffer_new(&ctx); 2419 if (!rules) { 2420 driver_errf(CC_TOOL, "out of memory"); 2421 goto out; 2422 } 2423 if (cc_dep_scan_one(env, o, pp, is_memory, index, output_path, rules) != 0) 2424 goto out; 2425 dep_path = cc_dep_default_path(env, output_path, &dep_path_size); 2426 if (!dep_path) { 2427 driver_errf(CC_TOOL, "out of memory"); 2428 goto out; 2429 } 2430 rc = cc_dep_commit_buffer(env, &ctx, rules, dep_path); 2431 out: 2432 if (dep_path) driver_free(env, dep_path, dep_path_size); 2433 if (rules) kit_writer_close(rules); 2434 return rc; 2435 } 2436 2437 static int cc_run_link_dependencies(DriverEnv* env, const CcOptions* o, 2438 const KitPreprocessOptions* pp) { 2439 KitContext ctx = driver_env_to_context(env); 2440 KitWriter* shared = NULL; 2441 uint32_t i; 2442 int rc = 1; 2443 if (o->dep_file) { 2444 shared = cc_dep_buffer_new(&ctx); 2445 if (!shared) { 2446 driver_errf(CC_TOOL, "out of memory"); 2447 return 1; 2448 } 2449 } 2450 for (i = 0; i < o->inputs.nlink_items; ++i) { 2451 const DriverLinkItem* item = &o->inputs.link_items[i]; 2452 int is_memory; 2453 const char* source_name; 2454 const char* obj_path; 2455 char* owned_obj = NULL; 2456 size_t owned_obj_size = 0; 2457 if (item->kind != DRIVER_LINK_SOURCE && 2458 item->kind != DRIVER_LINK_SOURCE_MEMORY) 2459 continue; 2460 is_memory = item->kind == DRIVER_LINK_SOURCE_MEMORY; 2461 source_name = cc_source_name(o, is_memory, item->index); 2462 if (is_memory) { 2463 obj_path = "<stdin>.o"; 2464 } else { 2465 owned_obj = 2466 cc_default_obj_path_for_name(env, o, source_name, &owned_obj_size); 2467 if (!owned_obj) { 2468 driver_errf(CC_TOOL, "out of memory"); 2469 goto out; 2470 } 2471 obj_path = owned_obj; 2472 } 2473 if (shared) { 2474 rc = cc_dep_scan_one(env, o, pp, is_memory, item->index, obj_path, 2475 shared); 2476 } else { 2477 rc = cc_dep_scan_default_file(env, o, pp, is_memory, item->index, 2478 obj_path); 2479 } 2480 if (owned_obj) driver_free(env, owned_obj, owned_obj_size); 2481 if (rc != 0) goto out; 2482 } 2483 if (shared) rc = cc_dep_commit_buffer(env, &ctx, shared, o->dep_file); 2484 else rc = 0; 2485 out: 2486 if (shared) kit_writer_close(shared); 2487 return rc; 2488 } 2489 2490 /* Compile one source to an object builder via the shared engine. cc never 2491 * passes frontend-specific language_options (it has no flag surface for them); 2492 * those are the `compile` tool's domain. */ 2493 static KitStatus cc_compile_source_obj(KitCompiler* compiler, KitLanguage lang, 2494 const KitCCompileOptions* copts, 2495 const KitPreprocessOptions* pp, 2496 KitSlice name, const KitSlice* input, 2497 KitObjBuilder** out) { 2498 return kit_build_compile_one(compiler, lang, &copts->code, 2499 &copts->diagnostics, pp, NULL, name, input, NULL, 2500 out); 2501 } 2502 2503 static KitStatus cc_compile_source_emit(KitCompiler* compiler, KitLanguage lang, 2504 const KitCCompileOptions* copts, 2505 const KitPreprocessOptions* pp, 2506 KitSlice name, const KitSlice* input, 2507 KitWriter* out) { 2508 return kit_build_compile_one(compiler, lang, &copts->code, 2509 &copts->diagnostics, pp, NULL, name, input, out, 2510 NULL); 2511 } 2512 2513 static int cc_run_compile_one(DriverEnv* env, const CcOptions* o, 2514 const KitPreprocessOptions* pp, int is_memory, 2515 uint32_t index, const char* out_path, 2516 KitWriter* dep_rules) { 2517 KitContext ctx = driver_env_to_context(env); 2518 KitTarget* target = NULL; 2519 KitCompiler* compiler = NULL; 2520 KitWriter* obj_w = NULL; 2521 KitFileData fd = {0}; 2522 KitSlice input = {0}; 2523 KitCCompileOptions copts; 2524 int loaded = 0; 2525 int rc = 1; 2526 const char* source_name = cc_source_name(o, is_memory, index); 2527 2528 if (is_memory) { 2529 input = o->source_memory[index].bytes; 2530 } else { 2531 if (ctx.file_io->read_all(ctx.file_io->user, o->source_files[index], &fd) != 2532 KIT_OK) { 2533 driver_errf(CC_TOOL, "failed to read: %.*s", 2534 KIT_SLICE_ARG(kit_slice_cstr(o->source_files[index]))); 2535 goto out; 2536 } 2537 loaded = 1; 2538 input.data = fd.data; 2539 input.len = fd.size; 2540 } 2541 2542 if (ctx.file_io->open_writer(ctx.file_io->user, out_path, &obj_w) != KIT_OK) { 2543 driver_errf(CC_TOOL, "failed to open output: %.*s", 2544 KIT_SLICE_ARG(kit_slice_cstr(out_path))); 2545 goto out; 2546 } 2547 2548 if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) { 2549 driver_errf(CC_TOOL, "failed to initialize compiler"); 2550 goto out; 2551 } 2552 2553 cc_fill_c_opts(o, &copts); 2554 if (copts.code.emit_c_source) { 2555 /* --emit=c routes the output writer to the C-source CGTarget instead of 2556 * the object emitter. The downstream `kit_compile_*_emit` path will 2557 * skip the object-serialize step when this is set. */ 2558 copts.code.c_source_writer = obj_w; 2559 } 2560 if (copts.code.emit_ir) { 2561 /* --emit=ir routes the output writer to the semantic-IR dumper in the opt 2562 * recorder instead of the object emitter. The downstream emit path skips 2563 * the object-serialize step when this is set. */ 2564 copts.code.ir_dump_writer = obj_w; 2565 } 2566 { 2567 KitLanguage lang = is_memory 2568 ? o->source_memory[index].lang 2569 : cc_resolve_lang(compiler, o->source_files[index], 2570 o->source_langs[index]); 2571 KitSlice in_name = kit_slice_cstr(source_name); 2572 KitStatus st; 2573 st = cc_compile_source_emit(compiler, lang, &copts, pp, in_name, &input, 2574 obj_w); 2575 if (st != KIT_OK) goto out; 2576 } 2577 2578 if (o->dep_mode == CC_DEP_MD || o->dep_mode == CC_DEP_MMD) { 2579 rc = dep_rules ? cc_dep_finish_to(env, compiler, o, source_name, out_path, 2580 dep_rules) 2581 : cc_dep_finish_default_file(env, &ctx, compiler, o, 2582 source_name, out_path); 2583 } else { 2584 rc = 0; 2585 } 2586 2587 out: 2588 if (compiler) driver_compiler_free(compiler); 2589 kit_target_free(target); 2590 cc_close_output(&obj_w, out_path, &rc); 2591 if (loaded) ctx.file_io->release(ctx.file_io->user, &fd); 2592 return rc; 2593 } 2594 2595 static int cc_run_compile_objs(DriverEnv* env, const CcOptions* o, 2596 const KitPreprocessOptions* pp) { 2597 KitContext ctx = driver_env_to_context(env); 2598 KitWriter* dep_rules = NULL; 2599 uint32_t i; 2600 int rc = 1; 2601 if ((o->dep_mode == CC_DEP_MD || o->dep_mode == CC_DEP_MMD) && 2602 o->dep_file) { 2603 dep_rules = cc_dep_buffer_new(&ctx); 2604 if (!dep_rules) { 2605 driver_errf(CC_TOOL, "out of memory"); 2606 return 1; 2607 } 2608 } 2609 for (i = 0; i < o->inputs.nlink_items; ++i) { 2610 const DriverLinkItem* item = &o->inputs.link_items[i]; 2611 int is_memory; 2612 const char* source_name; 2613 const char* out; 2614 char* owned_out = NULL; 2615 size_t owned_out_size = 0; 2616 if (item->kind != DRIVER_LINK_SOURCE && 2617 item->kind != DRIVER_LINK_SOURCE_MEMORY) 2618 continue; 2619 is_memory = item->kind == DRIVER_LINK_SOURCE_MEMORY; 2620 source_name = cc_source_name(o, is_memory, item->index); 2621 if (o->output_path) { 2622 out = o->output_path; 2623 } else if (is_memory) { 2624 out = o->emit_asm_source ? "<stdin>.s" 2625 : o->emit_ir ? "<stdin>.ir" 2626 : "<stdin>.o"; 2627 } else { 2628 owned_out = cc_default_obj_path_for_name(env, o, source_name, 2629 &owned_out_size); 2630 if (!owned_out) { 2631 driver_errf(CC_TOOL, "out of memory"); 2632 goto out; 2633 } 2634 out = owned_out; 2635 } 2636 rc = cc_run_compile_one(env, o, pp, is_memory, item->index, out, 2637 dep_rules); 2638 if (owned_out) driver_free(env, owned_out, owned_out_size); 2639 if (rc != 0) goto out; 2640 } 2641 if (dep_rules) rc = cc_dep_commit_buffer(env, &ctx, dep_rules, o->dep_file); 2642 else rc = 0; 2643 out: 2644 if (dep_rules) kit_writer_close(dep_rules); 2645 return rc; 2646 } 2647 2648 static int cc_run_check(DriverEnv* env, const CcOptions* o, 2649 const KitPreprocessOptions* pp) { 2650 KitContext ctx = driver_env_to_context(env); 2651 const KitFileIO* io = ctx.file_io; 2652 KitTarget* target = NULL; 2653 KitCompiler* compiler = NULL; 2654 DriverLoad* src_lf = NULL; 2655 KitSlice* src_bytes = NULL; 2656 KitCCompileOptions copts; 2657 uint32_t i; 2658 int rc = 1; 2659 2660 if (!io || !io->read_all) { 2661 driver_errf(CC_TOOL, "host file I/O unavailable"); 2662 return 1; 2663 } 2664 2665 if (o->nsource_files) { 2666 src_lf = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_lf)); 2667 src_bytes = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_bytes)); 2668 if (!src_lf || !src_bytes) { 2669 driver_errf(CC_TOOL, "out of memory"); 2670 goto out; 2671 } 2672 } 2673 2674 for (i = 0; i < o->nsource_files; ++i) { 2675 if (driver_load_bytes(io, CC_TOOL, o->source_files[i], &src_lf[i], 2676 &src_bytes[i]) != 0) 2677 goto out; 2678 } 2679 2680 if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) { 2681 driver_errf(CC_TOOL, "failed to initialize compiler"); 2682 goto out; 2683 } 2684 2685 cc_fill_c_opts(o, &copts); 2686 for (i = 0; i < o->nsource_files; ++i) { 2687 KitObjBuilder* ob = NULL; 2688 KitLanguage lang = 2689 cc_resolve_lang(compiler, o->source_files[i], o->source_langs[i]); 2690 KitStatus st = cc_compile_source_obj(compiler, lang, &copts, pp, 2691 kit_slice_cstr(o->source_files[i]), 2692 &src_bytes[i], &ob); 2693 kit_obj_builder_free(ob); 2694 if (st != KIT_OK) goto out; 2695 } 2696 for (i = 0; i < o->nsource_memory; ++i) { 2697 KitObjBuilder* ob = NULL; 2698 KitStatus st = cc_compile_source_obj(compiler, o->source_memory[i].lang, 2699 &copts, pp, o->source_memory[i].name, 2700 &o->source_memory[i].bytes, &ob); 2701 kit_obj_builder_free(ob); 2702 if (st != KIT_OK) goto out; 2703 } 2704 2705 rc = 0; 2706 2707 out: 2708 if (compiler) driver_compiler_free(compiler); 2709 kit_target_free(target); 2710 if (src_lf) { 2711 for (i = 0; i < o->nsource_files; ++i) driver_release_bytes(io, &src_lf[i]); 2712 } 2713 if (src_bytes) 2714 driver_free(env, src_bytes, o->nsource_files * sizeof(*src_bytes)); 2715 if (src_lf) driver_free(env, src_lf, o->nsource_files * sizeof(*src_lf)); 2716 return rc; 2717 } 2718 2719 /* Side-report writer for the link session: -Wl,-Map / --symbols / --cref FILE 2720 * and --print-memory-usage. cc routes these through driver_link_flags but the 2721 * link runs inside kit_build_link_with_lto_report, which hands back the live 2722 * session here so the reports actually get written (rather than being silently 2723 * dropped). Kept parallel to ld and build-exe's report writers. */ 2724 typedef struct CcLinkReports { 2725 DriverEnv* env; 2726 const KitFileIO* io; 2727 const CcOptions* o; 2728 } CcLinkReports; 2729 2730 static KitStatus cc_write_link_report(const CcLinkReports* r, 2731 KitLinkSession* link, const char* path, 2732 int symbols) { 2733 KitWriter* w = NULL; 2734 KitStatus st; 2735 if (!path) return KIT_OK; 2736 if (r->io->open_writer(r->io->user, path, &w) != KIT_OK) { 2737 driver_errf(CC_TOOL, "failed to open %s output: %.*s", 2738 symbols ? "symbols" : "map", 2739 KIT_SLICE_ARG(kit_slice_cstr(path))); 2740 return KIT_IO; 2741 } 2742 st = symbols 2743 ? kit_link_session_write_symbols(link, r->o->link.symbols_format, w) 2744 : kit_link_session_write_map(link, w); 2745 if (st == KIT_OK) st = kit_writer_status(w); 2746 kit_writer_close(w); 2747 if (st != KIT_OK) 2748 driver_errf(CC_TOOL, "failed to write %s: %.*s", symbols ? "symbols" : "map", 2749 KIT_SLICE_ARG(kit_slice_cstr(path))); 2750 return st; 2751 } 2752 2753 static KitStatus cc_link_write_reports(void* user, KitLinkSession* link) { 2754 const CcLinkReports* r = (const CcLinkReports*)user; 2755 KitStatus st; 2756 st = cc_write_link_report(r, link, r->o->link.map_path, 0); 2757 if (st == KIT_OK) 2758 st = cc_write_link_report(r, link, r->o->link.symbols_path, 1); 2759 if (st == KIT_OK && r->o->link.cref_path) { 2760 KitWriter* w = NULL; 2761 if (r->io->open_writer(r->io->user, r->o->link.cref_path, &w) != KIT_OK) { 2762 driver_errf(CC_TOOL, "failed to open cref output: %.*s", 2763 KIT_SLICE_ARG(kit_slice_cstr(r->o->link.cref_path))); 2764 st = KIT_IO; 2765 } else { 2766 st = kit_link_session_write_cref(link, w); 2767 if (st == KIT_OK) st = kit_writer_status(w); 2768 kit_writer_close(w); 2769 if (st != KIT_OK) 2770 driver_errf(CC_TOOL, "failed to write cref: %.*s", 2771 KIT_SLICE_ARG(kit_slice_cstr(r->o->link.cref_path))); 2772 } 2773 } 2774 if (st == KIT_OK && r->o->link.print_memory_usage) { 2775 KitWriter* w = driver_stdout_writer(r->env); 2776 if (!w) { 2777 driver_errf(CC_TOOL, "failed to print memory usage"); 2778 st = KIT_IO; 2779 } else { 2780 st = kit_link_session_write_memory_usage(link, w); 2781 if (st == KIT_OK) st = kit_writer_status(w); 2782 kit_writer_close(w); 2783 if (st != KIT_OK) driver_errf(CC_TOOL, "failed to print memory usage"); 2784 } 2785 } 2786 return st; 2787 } 2788 2789 /* exe/shared path: compile every source via a single KitCompiler, load 2790 * .o/.a/script inputs, and link. The link session borrows the per-source 2791 * KitObjBuilders; this function keeps ownership and frees them after the 2792 * session is done. */ 2793 static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, 2794 const KitPreprocessOptions* pp) { 2795 KitContext ctx = driver_env_to_context(env); 2796 const KitFileIO* io = ctx.file_io; 2797 KitTarget* target = NULL; 2798 KitCompiler* compiler = NULL; 2799 KitWriter* out_w = NULL; 2800 DriverLoad* src_lf = NULL; 2801 DriverLoad* obj_lf = NULL; 2802 DriverLoad* arch_lf = NULL; 2803 DriverLoad script_lf = {0}; 2804 DriverLoad* dso_lf = NULL; 2805 KitSlice* src_bytes = NULL; 2806 KitSlice* obj_in = NULL; 2807 KitSlice* obj_names = NULL; 2808 KitLinkArchiveInput* arch_in = NULL; 2809 KitSlice* dso_in = NULL; 2810 KitSlice* dso_names = NULL; 2811 KitLinkInputOrder* order = NULL; 2812 KitObjBuilder** objs = NULL; 2813 KitBuildSource* sources = NULL; 2814 KitBuildPendingLto pending_lto = {0}; 2815 uint32_t* source_obj_index = NULL; 2816 uint8_t* source_order_keep = NULL; 2817 KitLinkScript* script = NULL; 2818 KitSlice* rpath_slices = NULL; 2819 KitCCompileOptions copts; 2820 KitBuildBatchOptions lto_batch; 2821 uint32_t nsrc = o->nsource_files + o->nsource_memory; 2822 uint32_t i; 2823 uint32_t nobjs = 0; 2824 uint32_t norder = 0; 2825 int rc = 1; 2826 2827 if (!io || !io->read_all || !io->open_writer) { 2828 driver_errf(CC_TOOL, "host file I/O unavailable"); 2829 return 1; 2830 } 2831 2832 if (o->nsource_files) { 2833 src_bytes = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_bytes)); 2834 src_lf = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_lf)); 2835 if (!src_bytes || !src_lf) { 2836 driver_errf(CC_TOOL, "out of memory"); 2837 goto out; 2838 } 2839 } 2840 if (nsrc) { 2841 objs = driver_alloc_zeroed(env, nsrc * sizeof(*objs)); 2842 sources = driver_alloc_zeroed(env, nsrc * sizeof(*sources)); 2843 source_obj_index = 2844 driver_alloc_zeroed(env, nsrc * sizeof(*source_obj_index)); 2845 source_order_keep = 2846 driver_alloc_zeroed(env, nsrc * sizeof(*source_order_keep)); 2847 if (!objs || !sources || !source_obj_index || !source_order_keep) { 2848 driver_errf(CC_TOOL, "out of memory"); 2849 goto out; 2850 } 2851 } 2852 if (o->inputs.nobject_files) { 2853 obj_lf = 2854 driver_alloc_zeroed(env, o->inputs.nobject_files * sizeof(*obj_lf)); 2855 obj_in = 2856 driver_alloc_zeroed(env, o->inputs.nobject_files * sizeof(*obj_in)); 2857 obj_names = 2858 driver_alloc_zeroed(env, o->inputs.nobject_files * sizeof(*obj_names)); 2859 if (!obj_lf || !obj_in || !obj_names) { 2860 driver_errf(CC_TOOL, "out of memory"); 2861 goto out; 2862 } 2863 } 2864 if (o->inputs.narchives) { 2865 arch_lf = driver_alloc_zeroed(env, o->inputs.narchives * sizeof(*arch_lf)); 2866 arch_in = driver_alloc_zeroed(env, o->inputs.narchives * sizeof(*arch_in)); 2867 if (!arch_lf || !arch_in) { 2868 driver_errf(CC_TOOL, "out of memory"); 2869 goto out; 2870 } 2871 } 2872 if (o->inputs.ndsos) { 2873 dso_lf = driver_alloc_zeroed(env, o->inputs.ndsos * sizeof(*dso_lf)); 2874 dso_in = driver_alloc_zeroed(env, o->inputs.ndsos * sizeof(*dso_in)); 2875 dso_names = driver_alloc_zeroed(env, o->inputs.ndsos * sizeof(*dso_names)); 2876 if (!dso_lf || !dso_in || !dso_names) { 2877 driver_errf(CC_TOOL, "out of memory"); 2878 goto out; 2879 } 2880 } 2881 if (o->inputs.nlink_items) { 2882 order = driver_alloc_zeroed(env, o->inputs.nlink_items * sizeof(*order)); 2883 if (!order) { 2884 driver_errf(CC_TOOL, "out of memory"); 2885 goto out; 2886 } 2887 } 2888 2889 for (i = 0; i < o->nsource_files; ++i) { 2890 if (driver_load_bytes(io, CC_TOOL, o->source_files[i], &src_lf[i], 2891 &src_bytes[i]) != 0) 2892 goto out; 2893 } 2894 2895 for (i = 0; i < o->inputs.nobject_files; ++i) { 2896 if (driver_load_bytes(io, CC_TOOL, o->inputs.object_files[i], &obj_lf[i], 2897 &obj_in[i]) != 0) 2898 goto out; 2899 obj_names[i] = kit_slice_cstr(o->inputs.object_files[i]); 2900 } 2901 for (i = 0; i < o->inputs.narchives; ++i) { 2902 if (driver_load_bytes(io, CC_TOOL, o->inputs.archives[i].path, &arch_lf[i], 2903 &arch_in[i].bytes) != 0) 2904 goto out; 2905 arch_in[i].name = kit_slice_cstr(o->inputs.archives[i].path); 2906 arch_in[i].link_mode = o->inputs.archives[i].link_mode; 2907 arch_in[i].whole_archive = 2908 o->inputs.archives[i].whole_archive ? true : false; 2909 arch_in[i].group_id = o->inputs.archives[i].group_id; 2910 } 2911 for (i = 0; i < o->inputs.ndsos; ++i) { 2912 if (driver_load_bytes(io, CC_TOOL, o->inputs.dsos[i].path, &dso_lf[i], 2913 &dso_in[i]) != 0) 2914 goto out; 2915 dso_names[i] = kit_slice_cstr(o->inputs.dsos[i].path); 2916 } 2917 2918 if (o->link.linker_script) { 2919 KitSlice dummy; 2920 if (driver_load_bytes(io, CC_TOOL, o->link.linker_script, &script_lf, 2921 &dummy) != 0) 2922 goto out; 2923 } 2924 2925 if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) { 2926 driver_errf(CC_TOOL, "failed to initialize compiler"); 2927 goto out; 2928 } 2929 2930 if (script_lf.loaded) { 2931 KitSlice script_text = {.s = (const char*)script_lf.fd.data, 2932 .len = script_lf.fd.size}; 2933 if (kit_link_script_parse(&ctx, script_text, &script) != KIT_OK) goto out; 2934 } 2935 2936 cc_fill_c_opts(o, &copts); 2937 memset(<o_batch, 0, sizeof lto_batch); 2938 lto_batch.output_kind = 2939 o->shared ? KIT_CG_OUTPUT_SHARED : KIT_CG_OUTPUT_EXECUTABLE; 2940 lto_batch.interposition_policy = o->shared 2941 ? KIT_CG_INTERPOSITION_DEFAULT_VISIBILITY 2942 : KIT_CG_INTERPOSITION_DEFAULT; 2943 lto_batch.defer_lto_finish = 1; 2944 for (i = 0; i < o->nsource_files; ++i) { 2945 KitLanguage lang = 2946 cc_resolve_lang(compiler, o->source_files[i], o->source_langs[i]); 2947 if (lang == KIT_LANG_UNKNOWN) { 2948 driver_errf(CC_TOOL, "cannot determine language for %.*s (use -x LANG)", 2949 KIT_SLICE_ARG(kit_slice_cstr(o->source_files[i]))); 2950 goto out; 2951 } 2952 sources[i].lang = lang; 2953 sources[i].name = kit_slice_cstr(o->source_files[i]); 2954 sources[i].bytes = src_bytes[i]; 2955 sources[i].pp = pp; 2956 } 2957 for (i = 0; i < o->nsource_memory; ++i) { 2958 uint32_t si = o->nsource_files + i; 2959 if (o->source_memory[i].lang == KIT_LANG_UNKNOWN) { 2960 driver_errf(CC_TOOL, "cannot determine language for %.*s (use -x LANG)", 2961 KIT_SLICE_ARG(o->source_memory[i].name)); 2962 goto out; 2963 } 2964 sources[si].lang = o->source_memory[i].lang; 2965 sources[si].name = o->source_memory[i].name; 2966 sources[si].bytes = o->source_memory[i].bytes; 2967 sources[si].pp = pp; 2968 } 2969 if (nsrc) { 2970 KitBuildObjects cout; 2971 KitStatus st; 2972 memset(&cout, 0, sizeof cout); 2973 cout.objs = objs; 2974 cout.source_obj_index = source_obj_index; 2975 cout.source_order_keep = source_order_keep; 2976 cout.pending_lto = &pending_lto; 2977 st = kit_build_compile(compiler, &copts.code, &copts.diagnostics, sources, 2978 nsrc, <o_batch, &cout); 2979 nobjs = cout.nobjs; 2980 if (st != KIT_OK) goto out; 2981 } 2982 2983 if ((o->dep_mode == CC_DEP_MD || o->dep_mode == CC_DEP_MMD) && 2984 cc_run_link_dependencies(env, o, pp) != 0) 2985 goto out; 2986 2987 if (io->open_writer(io->user, o->output_path, &out_w) != KIT_OK) { 2988 driver_errf(CC_TOOL, "failed to open output: %.*s", 2989 KIT_SLICE_ARG(kit_slice_cstr(o->output_path))); 2990 goto out; 2991 } 2992 2993 { 2994 KitLinkSessionOptions lopts; 2995 KitStatus st; 2996 if (driver_link_flags_fill_options( 2997 &o->link, o->target, o->pie, o->shared, /*relocatable=*/0, 2998 o->shared ? KIT_LINK_OUTPUT_SHARED : KIT_LINK_OUTPUT_EXE, script, 2999 &lopts, &rpath_slices) != 0) 3000 goto out; 3001 3002 /* Translate the command-line link order into the engine's public 3003 * KitLinkInputOrder list. The dead-simple fallback for 3004 * o->inputs.nlink_items == 0 never fires (a link action always has at least 3005 * one input), so every add flows through the ordered path. */ 3006 { 3007 KitLinkInputs li; 3008 norder = driver_link_inputs_build_order(&o->inputs, source_obj_index, 3009 source_order_keep, 3010 o->nsource_files, order); 3011 memset(&li, 0, sizeof(li)); 3012 li.objs = objs; 3013 li.nobjs = nobjs; 3014 li.obj_names = obj_names; 3015 li.obj_bytes = obj_in; 3016 li.nobj_bytes = o->inputs.nobject_files; 3017 li.archives = arch_in; 3018 li.narchives = o->inputs.narchives; 3019 li.dso_names = dso_names; 3020 li.dso_bytes = dso_in; 3021 li.ndsos = o->inputs.ndsos; 3022 li.order = order; 3023 li.norder = norder; 3024 { 3025 /* Honor the link side-reports (-Wl,-Map / --symbols / --cref / 3026 * --print-memory-usage) that flowed in via driver_link_flags by 3027 * writing them from the live session — matching ld and build-exe. */ 3028 CcLinkReports reports; 3029 int want_reports = o->link.map_path || o->link.symbols_path || 3030 o->link.cref_path || o->link.print_memory_usage; 3031 reports.env = env; 3032 reports.io = io; 3033 reports.o = o; 3034 st = kit_build_link_with_lto_report( 3035 compiler, &lopts, &li, &pending_lto, <o_batch, out_w, 3036 want_reports ? cc_link_write_reports : NULL, 3037 want_reports ? (void*)&reports : NULL); 3038 } 3039 } 3040 rc = st == KIT_OK ? 0 : 1; 3041 } 3042 3043 out: 3044 cc_close_output(&out_w, o->output_path, &rc); 3045 if (rc == 0 && o->output_path) { 3046 if (driver_mark_executable_output(o->output_path) != 0) { 3047 driver_errf(CC_TOOL, "failed to set executable mode: %.*s", 3048 KIT_SLICE_ARG(kit_slice_cstr(o->output_path))); 3049 rc = 1; 3050 } 3051 } 3052 if (script) kit_link_script_free(&ctx, script); 3053 kit_build_lto_abort(&pending_lto); 3054 driver_link_flags_free_rpath_slices(&o->link, rpath_slices); 3055 if (compiler) driver_compiler_free(compiler); 3056 kit_target_free(target); 3057 driver_release_bytes(io, &script_lf); 3058 if (arch_lf) { 3059 for (i = 0; i < o->inputs.narchives; ++i) 3060 driver_release_bytes(io, &arch_lf[i]); 3061 } 3062 if (dso_lf) { 3063 for (i = 0; i < o->inputs.ndsos; ++i) driver_release_bytes(io, &dso_lf[i]); 3064 } 3065 if (obj_lf) { 3066 for (i = 0; i < o->inputs.nobject_files; ++i) 3067 driver_release_bytes(io, &obj_lf[i]); 3068 } 3069 if (src_lf) { 3070 for (i = 0; i < o->nsource_files; ++i) driver_release_bytes(io, &src_lf[i]); 3071 } 3072 if (arch_in) 3073 driver_free(env, arch_in, o->inputs.narchives * sizeof(*arch_in)); 3074 if (arch_lf) 3075 driver_free(env, arch_lf, o->inputs.narchives * sizeof(*arch_lf)); 3076 if (dso_in) driver_free(env, dso_in, o->inputs.ndsos * sizeof(*dso_in)); 3077 if (dso_names) 3078 driver_free(env, dso_names, o->inputs.ndsos * sizeof(*dso_names)); 3079 if (dso_lf) driver_free(env, dso_lf, o->inputs.ndsos * sizeof(*dso_lf)); 3080 if (order) driver_free(env, order, o->inputs.nlink_items * sizeof(*order)); 3081 if (obj_in) 3082 driver_free(env, obj_in, o->inputs.nobject_files * sizeof(*obj_in)); 3083 if (obj_names) 3084 driver_free(env, obj_names, o->inputs.nobject_files * sizeof(*obj_names)); 3085 if (obj_lf) 3086 driver_free(env, obj_lf, o->inputs.nobject_files * sizeof(*obj_lf)); 3087 if (src_lf) driver_free(env, src_lf, o->nsource_files * sizeof(*src_lf)); 3088 if (src_bytes) 3089 driver_free(env, src_bytes, o->nsource_files * sizeof(*src_bytes)); 3090 if (objs) { 3091 for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]); 3092 driver_free(env, objs, nsrc * sizeof(*objs)); 3093 } 3094 if (source_order_keep) 3095 driver_free(env, source_order_keep, nsrc * sizeof(*source_order_keep)); 3096 if (source_obj_index) 3097 driver_free(env, source_obj_index, nsrc * sizeof(*source_obj_index)); 3098 if (sources) driver_free(env, sources, nsrc * sizeof(*sources)); 3099 return rc; 3100 } 3101 3102 static int driver_cc_main(int argc, char** argv, int force_check) { 3103 DriverEnv env; 3104 CcOptions co = {0}; 3105 DriverRuntimeSupport runtime = {0}; 3106 KitPreprocessOptions pp; 3107 int rc; 3108 int runtime_resolved = 0; 3109 int link_action; 3110 3111 if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) { 3112 if (force_check) { 3113 driver_help_check(); 3114 return 0; 3115 } 3116 driver_help_cc(); 3117 return 0; 3118 } 3119 3120 driver_env_init(&env); 3121 co.env = &env; 3122 co.driver_path = argv[0]; 3123 co.syntax_only = force_check ? 1 : 0; 3124 3125 if (cc_parse(argc, argv, &co) != 0) { 3126 cc_options_release(&co); 3127 driver_env_fini(&env); 3128 return 2; 3129 } 3130 if (co.probe_kind != CC_PROBE_NONE) { 3131 rc = cc_run_probe(&co); 3132 cc_options_release(&co); 3133 driver_env_fini(&env); 3134 return rc; 3135 } 3136 3137 link_action = !co.compile_only && !co.preprocess_only && !co.syntax_only && 3138 co.dep_mode != CC_DEP_M && co.dep_mode != CC_DEP_MM; 3139 if (driver_runtime_resolve(&env, co.support_dir, co.driver_path, &runtime) == 3140 0) { 3141 runtime_resolved = 1; 3142 if ((co.nsource_files || co.nsource_memory) && !co.nostdinc) { 3143 int add_headers; 3144 if (co.hosted.profile_name) { 3145 add_headers = 3146 driver_runtime_append_freestanding_headers(&runtime, &co.cf); 3147 } else { 3148 add_headers = driver_runtime_add_freestanding_headers(&runtime, &co.cf); 3149 } 3150 if (add_headers != 0) { 3151 driver_errf(CC_TOOL, "failed to add freestanding headers"); 3152 driver_runtime_support_fini(&env, &runtime); 3153 cc_options_release(&co); 3154 driver_env_fini(&env); 3155 return 1; 3156 } 3157 } 3158 } else if (co.support_dir || link_action || co.nsource_files || 3159 co.nsource_memory) { 3160 driver_errf(CC_TOOL, "support dir not found"); 3161 cc_options_release(&co); 3162 driver_env_fini(&env); 3163 return 1; 3164 } 3165 3166 if (link_action && 3167 (!co.shared || driver_target_shared_uses_hosted(co.target)) && 3168 !co.no_stdlib && !co.no_defaultlibs) { 3169 DriverRuntimeArchive rt_archive = {0}; 3170 if (!runtime_resolved) { 3171 driver_errf(CC_TOOL, "support dir not found"); 3172 cc_options_release(&co); 3173 driver_env_fini(&env); 3174 return 1; 3175 } 3176 if (driver_runtime_prepare_archive(&env, CC_TOOL, &runtime, co.target, 3177 co.epoch, &rt_archive) != 0) { 3178 driver_runtime_archive_fini(&env, &rt_archive); 3179 driver_runtime_support_fini(&env, &runtime); 3180 cc_options_release(&co); 3181 driver_env_fini(&env); 3182 return 1; 3183 } 3184 driver_link_inputs_insert_runtime_archives( 3185 &co.inputs, &rt_archive, co.target, co.hosted.nfinal, co.hosted.nafter); 3186 driver_runtime_archive_fini(&env, &rt_archive); 3187 } 3188 3189 driver_cflags_fill_pp(&co.cf, &pp); 3190 3191 if (co.preprocess_only) { 3192 rc = cc_preprocess(&env, &co, &pp); 3193 } else if (co.dep_mode == CC_DEP_M || co.dep_mode == CC_DEP_MM) { 3194 rc = cc_run_deps_only(&env, &co, &pp); 3195 } else if (co.syntax_only) { 3196 rc = cc_run_check(&env, &co, &pp); 3197 } else if (co.compile_only) { 3198 rc = cc_run_compile_objs(&env, &co, &pp); 3199 } else { 3200 rc = cc_run_link_exe(&env, &co, &pp); 3201 } 3202 3203 if (rc == 0 && 3204 driver_diag_finish(&env, CC_TOOL, co.warnings_are_errors, co.max_errors)) 3205 rc = 1; 3206 3207 cc_options_release(&co); 3208 if (runtime_resolved) driver_runtime_support_fini(&env, &runtime); 3209 driver_env_fini(&env); 3210 return rc; 3211 } 3212 3213 int driver_cc(int argc, char** argv) { return driver_cc_main(argc, argv, 0); } 3214 3215 int driver_check(int argc, char** argv) { 3216 return driver_cc_main(argc, argv, 1); 3217 }