build.c (106875B)
1 #include <kit/build.h> 2 #include <kit/compile.h> 3 #include <kit/core.h> 4 #include <kit/link.h> 5 #include <kit/object.h> 6 #include <kit/preprocess.h> 7 #include <stdint.h> 8 #include <string.h> 9 10 #include "archive_engine.h" 11 #include "cflags.h" 12 #include "driver.h" 13 #include "hosted.h" 14 #include "lib_resolve.h" 15 #include "link_flags.h" 16 #include "link_inputs.h" 17 #include "runtime.h" 18 19 /* `kit build-exe` / `build-lib` / `build-obj` — the kit-native build verbs. 20 * 21 * Each command is polyglot (C / asm / wasm resolved per file), compiles 22 * entirely in memory, and writes no intermediate files. They share one 23 * parse+run parameterized by output kind: 24 * 25 * build-exe link an executable (link session, OUTPUT_EXE) 26 * build-lib static .a / single C TU (archive of compiled objects, 27 * semantic C amalgamation, or DSO) 28 * build-obj one object; or a relocatable (compile each source / link 29 * combine of N sources; or session, OUTPUT_RELOCATABLE) 30 * --emit=asm|c|ir; -fsyntax-only 31 * 32 * build-obj fully replaces the retired `compile` tool. Two flag tiers: 33 * - global / per-output flags apply to the whole build (target, -O/-g, link 34 * flags, output flags); they may appear anywhere outside a --group. 35 * - scopable flags (-I/-isystem/-D/-U, -x, -X<lang>) form a global baseline 36 * and may be overridden inside a `--group [flags] -- sources...` block. 37 * 38 * Per-language frontend flags route through `-X<lang> FLAG` (e.g. 39 * `-Xwasm -mfeature=simd128`). */ 40 41 /* Stand-in for "no -x; resolve language from the path suffix at compile time." 42 */ 43 #define BUILD_LANG_AUTO KIT_LANG_AUTO 44 45 typedef enum BuildOutputKind { 46 BUILD_OUT_EXE, 47 BUILD_OUT_LIB, 48 BUILD_OUT_OBJ, 49 } BuildOutputKind; 50 51 typedef enum BuildEmit { 52 BUILD_EMIT_OBJ = 0, 53 BUILD_EMIT_ASM, 54 BUILD_EMIT_C, 55 BUILD_EMIT_IR, 56 } BuildEmit; 57 58 /* The link-input model (link items + object/archive/dso/lib arrays) is shared 59 * with the cc driver; see driver/lib/link_inputs.h. */ 60 61 typedef struct BuildSource { 62 const char* path; /* argv-borrowed */ 63 uint32_t group; /* index into o->groups[]; 0 = global/bare baseline */ 64 } BuildSource; 65 66 /* One -X<lang> frontend flag token, scoped to a language. */ 67 typedef struct BuildFeFlag { 68 KitLanguage lang; 69 char* tok; /* argv-borrowed */ 70 } BuildFeFlag; 71 72 /* A compile-flag scope: the global baseline (groups[0]) plus one entry per 73 * `--group`. Each carries its own preprocessor delta, language override, and 74 * per-language frontend flags. */ 75 typedef struct BuildGroup { 76 DriverCflags cf; 77 int cf_inited; 78 KitLanguage forced_lang; /* BUILD_LANG_AUTO if -x not set */ 79 BuildFeFlag* fe; 80 uint32_t nfe; 81 /* Merged preprocessor view (group delta over the global baseline), filled 82 * after parsing. For groups[0] this borrows cf directly; for real groups it 83 * points at the m_* arrays below. */ 84 KitPreprocessOptions pp; 85 const char** m_inc; 86 uint32_t m_ninc; 87 const char** m_sys; 88 uint32_t m_nsys; 89 KitDefine* m_def; 90 uint32_t m_ndef; 91 uint32_t 92 m_def_cap; /* allocation size; m_ndef <= cap once globals are shadowed */ 93 KitSlice* m_und; 94 uint32_t m_nund; 95 } BuildGroup; 96 97 typedef struct BuildOptions { 98 DriverEnv* env; 99 KitFrontendRegistry* frontends; 100 const char* tool; /* "build-exe" | "build-lib" | "build-obj" */ 101 int kind; /* BuildOutputKind */ 102 const char* driver_path; /* argv[0] */ 103 size_t argv_bound; 104 105 /* Output / per-output state. */ 106 int emit; /* BuildEmit (build-obj) */ 107 int syntax_only; 108 int opt_level; 109 int debug_info; 110 int dynamic; /* -dynamic / -shared */ 111 int shared_requested; /* -shared spelling, for build-exe diagnostics */ 112 int shared; /* computed: kind==lib && dynamic */ 113 int static_link; /* -static */ 114 int pie; /* -pie */ 115 int pic_explicit; /* -fPIC/-fPIE/-static/-pie/-no-pie */ 116 int function_sections; /* -ffunction-sections */ 117 int data_sections; /* -fdata-sections */ 118 int auto_var_init; /* -ftrivial-auto-var-init= (KitAutoVarInit) */ 119 int stack_protector; /* KitStackProtectorMode */ 120 int lto; /* -flto/-fno-lto */ 121 uint64_t disabled_backend_features; 122 uint8_t default_visibility; /* KitSymVis */ 123 int warnings_are_errors; 124 uint32_t max_errors; 125 const char* output_path; 126 127 KitTargetSpec target; 128 DriverTargetFeatures target_features; 129 130 /* Link-session options and owned -Wl state. */ 131 DriverLinkFlags link; 132 uint64_t epoch; 133 134 /* Hosted libc / sysroot state. */ 135 const char* sysroot; 136 const char* support_dir; 137 int freestanding; 138 int nostdinc; 139 int no_stdlib; 140 int no_defaultlibs; 141 int no_startfiles; 142 int wants_hosted_libc; 143 DriverHostedPlan hosted; 144 145 /* Sources + compile-flag scopes. */ 146 BuildSource* sources; 147 uint32_t nsources; 148 BuildGroup* groups; 149 uint32_t ngroups; 150 uint32_t cur_group; /* scope for newly seen sources */ 151 152 /* Shared link-input model (build-exe / dynamic build-lib): 153 * object/archive/dso/ lib arrays, the ordered link item list, -L search 154 * paths, and the owned 155 * `<sysroot>/lib` Windows slot. */ 156 DriverLinkInputSet inputs; 157 } BuildOptions; 158 159 static int build_record_framework(BuildOptions* o, const char* name); 160 161 /* ===================================================================== */ 162 /* small parse helpers */ 163 /* ===================================================================== */ 164 165 static int build_lang_from_name(BuildOptions* o, const char* name, 166 KitLanguage* out) { 167 /* Resolve off the compile-time default frontend set (no compiler exists at 168 * arg-parse time). Value-equivalent to the former explicit map: 169 * c->C, asm/s->ASM, wasm/wat->WASM. */ 170 KitLanguage lang = kit_frontend_registry_language_for_name(o->frontends, name); 171 if (lang == KIT_LANG_UNKNOWN) return 1; 172 *out = lang; 173 return 0; 174 } 175 176 static void build_err_unknown_language(BuildOptions* o, const char* flag, 177 const char* value) { 178 const char* const known[] = {"c", "asm", "assembler", "s", 179 "toy", "wasm", "wat"}; 180 const char* candidates[sizeof known / sizeof known[0]]; 181 DriverSuggestion suggestions[3]; 182 size_t i, count = 0, n; 183 for (i = 0; i < sizeof known / sizeof known[0]; ++i) { 184 KitLanguage lang; 185 if (build_lang_from_name(o, known[i], &lang) == 0) 186 candidates[count++] = known[i]; 187 } 188 n = driver_suggest_values(value, candidates, count, suggestions, 3); 189 if (n) 190 driver_errf(o->tool, "unsupported %s language: %s; did you mean '%s'?", 191 flag, value, suggestions[0].value); 192 else 193 driver_errf(o->tool, "unsupported %s language: %s", flag, value); 194 } 195 196 /* ===================================================================== */ 197 /* allocation / lifetime */ 198 /* ===================================================================== */ 199 200 static int build_group_cf_init(BuildOptions* o, BuildGroup* g) { 201 if (g->cf_inited) return 0; 202 if (driver_cflags_init(&g->cf, o->env, 203 (int)(o->argv_bound + DRIVER_HOSTED_MAX_DEFINES + 204 DRIVER_HOSTED_MAX_INCLUDES)) != 0) 205 return 1; 206 g->cf_inited = 1; 207 g->forced_lang = BUILD_LANG_AUTO; 208 g->fe = driver_alloc_zeroed(o->env, o->argv_bound * sizeof(*g->fe)); 209 return g->fe ? 0 : 1; 210 } 211 212 static int build_alloc(BuildOptions* o, int argc) { 213 size_t bound = (size_t)argc + 16u; 214 o->argv_bound = bound; 215 o->sources = driver_alloc_zeroed(o->env, bound * sizeof(*o->sources)); 216 o->groups = driver_alloc_zeroed(o->env, bound * sizeof(*o->groups)); 217 if (!o->sources || !o->groups) { 218 driver_errf(o->tool, "out of memory"); 219 return 1; 220 } 221 if (driver_link_inputs_init(&o->inputs, o->env, o->tool, bound) != 0) 222 return 1; 223 /* groups[0] is the global / bare baseline. */ 224 o->ngroups = 1; 225 if (driver_link_flags_init(&o->link, o->env, o->tool, (uint32_t)bound) != 0 || 226 build_group_cf_init(o, &o->groups[0]) != 0 || 227 driver_target_features_init(&o->target_features, o->env, argc) != 0) { 228 driver_errf(o->tool, "out of memory"); 229 return 1; 230 } 231 return 0; 232 } 233 234 static void build_release(BuildOptions* o) { 235 uint32_t i; 236 size_t bound = o->argv_bound; 237 for (i = 0; i < o->ngroups; ++i) { 238 BuildGroup* g = &o->groups[i]; 239 if (g->cf_inited) driver_cflags_fini(&g->cf, o->env); 240 if (g->fe) driver_free(o->env, g->fe, bound * sizeof(*g->fe)); 241 if (g->m_inc) driver_free(o->env, g->m_inc, g->m_ninc * sizeof(*g->m_inc)); 242 if (g->m_sys) driver_free(o->env, g->m_sys, g->m_nsys * sizeof(*g->m_sys)); 243 if (g->m_def) 244 driver_free(o->env, g->m_def, g->m_def_cap * sizeof(*g->m_def)); 245 if (g->m_und) driver_free(o->env, g->m_und, g->m_nund * sizeof(*g->m_und)); 246 } 247 driver_link_inputs_fini(&o->inputs); 248 driver_hosted_plan_fini(o->env, &o->hosted); 249 driver_link_flags_fini(&o->link); 250 driver_target_features_fini(&o->target_features, o->env); 251 if (o->sources) driver_free(o->env, o->sources, bound * sizeof(*o->sources)); 252 if (o->groups) driver_free(o->env, o->groups, bound * sizeof(*o->groups)); 253 } 254 255 /* ===================================================================== */ 256 /* positional classification */ 257 /* ===================================================================== */ 258 259 /* Routed through the shared driver_path_is_source authority (canonical 260 * extension registry, headers excluded), so adding a frontend extension reaches 261 * cc/build/run/dbg at once. build still treats .h as a header, not a source — 262 * the helper excludes it. */ 263 static int build_is_source(BuildOptions* o, const char* s) { 264 return kit_frontend_registry_path_kind(o->frontends, s, NULL) == 265 KIT_FRONTEND_PATH_SOURCE; 266 } 267 268 /* The language forced (via -x) for sources in group `gi`: the group's own -x, 269 * else the global baseline's, else -1 (resolve by suffix). */ 270 static int build_scope_forced_lang(const BuildOptions* o, uint32_t gi) { 271 if (gi != 0 && o->groups[gi].forced_lang != BUILD_LANG_AUTO) 272 return (int)o->groups[gi].forced_lang; 273 if (o->groups[0].forced_lang != BUILD_LANG_AUTO) 274 return (int)o->groups[0].forced_lang; 275 return -1; 276 } 277 278 static int build_classify_positional(BuildOptions* o, const char* a) { 279 if (driver_streq(a, "-")) { 280 driver_errf(o->tool, "stdin ('-') is not supported; pass a source file"); 281 return 1; 282 } 283 /* Explicit link-input suffixes are always link inputs — never reinterpreted 284 * as sources, even when -x forces a language. */ 285 if (driver_has_suffix(a, ".o") || driver_has_suffix(a, ".obj")) { 286 o->inputs.object_files[o->inputs.nobject_files++] = a; 287 driver_link_inputs_push(&o->inputs, DRIVER_LINK_OBJECT, 288 o->inputs.nobject_files - 1u); 289 return 0; 290 } 291 if (driver_has_suffix(a, ".a")) { 292 DriverArchiveInput* ar = &o->inputs.archives[o->inputs.narchives++]; 293 ar->path = a; 294 ar->whole_archive = o->inputs.cur_whole_archive; 295 ar->link_mode = o->inputs.cur_link_mode; 296 ar->group_id = o->inputs.cur_group_id; 297 driver_link_inputs_push(&o->inputs, DRIVER_LINK_ARCHIVE, 298 o->inputs.narchives - 1u); 299 return 0; 300 } 301 if (driver_is_dso_path(a)) { 302 DriverDsoInput* d = &o->inputs.dsos[o->inputs.ndsos++]; 303 d->path = a; 304 driver_link_inputs_push(&o->inputs, DRIVER_LINK_DSO, o->inputs.ndsos - 1u); 305 return 0; 306 } 307 /* Otherwise a source: a recognized source suffix, or any file at all when a 308 * language is forced in scope (so `-x c mykernel` compiles an extensionless 309 * or odd-suffix file). */ 310 if (build_is_source(o, a) || build_scope_forced_lang(o, o->cur_group) >= 0) { 311 BuildSource* s = &o->sources[o->nsources]; 312 s->path = a; 313 s->group = o->cur_group; 314 driver_link_inputs_push(&o->inputs, DRIVER_LINK_SOURCE, o->nsources); 315 o->nsources++; 316 return 0; 317 } 318 driver_errf(o->tool, 319 "input does not have a recognized suffix: %.*s (use -x LANG)", 320 KIT_SLICE_ARG(kit_slice_cstr(a))); 321 return 1; 322 } 323 324 /* ===================================================================== */ 325 /* scopable-flag parsing (shared by global context and --group blocks) */ 326 /* ===================================================================== */ 327 328 /* Try to consume a scopable flag (-I/-isystem/-D/-U, -x, -X<lang>) at argv[*i] 329 * into group `g`. Returns 1 consumed, 0 not a scopable flag, -1 on error. */ 330 static int build_try_scopable(BuildOptions* o, BuildGroup* g, int argc, 331 char** argv, int* i) { 332 const char* a = argv[*i]; 333 int r = driver_cflags_try_consume(&g->cf, o->env, o->tool, argc, argv, i); 334 if (r != 0) return r; 335 336 if (driver_streq(a, "-x")) { 337 KitLanguage lang; 338 if (++(*i) >= argc) { 339 driver_errf(o->tool, "-x requires an argument"); 340 return -1; 341 } 342 if (driver_streq(argv[*i], "--")) { 343 driver_errf(o->tool, "-x requires an argument before `--`"); 344 return -1; 345 } 346 if (build_lang_from_name(o, argv[*i], &lang) != 0) { 347 build_err_unknown_language(o, "-x", argv[*i]); 348 return -1; 349 } 350 g->forced_lang = lang; 351 return 1; 352 } 353 if (driver_strneq(a, "-X", 2) && a[2] != '\0') { 354 KitLanguage lang; 355 BuildFeFlag* f; 356 if (build_lang_from_name(o, a + 2, &lang) != 0) { 357 build_err_unknown_language(o, "-X", a + 2); 358 return -1; 359 } 360 if (++(*i) >= argc) { 361 driver_errf(o->tool, "%.*s requires a following flag", 362 KIT_SLICE_ARG(kit_slice_cstr(a))); 363 return -1; 364 } 365 if (driver_streq(argv[*i], "--")) { 366 driver_errf(o->tool, "%.*s requires a following flag before `--`", 367 KIT_SLICE_ARG(kit_slice_cstr(a))); 368 return -1; 369 } 370 f = &g->fe[g->nfe++]; 371 f->lang = lang; 372 f->tok = argv[*i]; 373 return 1; 374 } 375 return 0; 376 } 377 378 /* Recognize the global / per-output flags, so a --group block can flag them as 379 * misplaced with a pointed diagnostic. */ 380 static int build_is_global_flag(const char* a) { 381 return driver_streq(a, "-o") || driver_strneq(a, "--output", 8) || 382 driver_strneq(a, "-O", 2) || driver_streq(a, "-g") || 383 driver_streq(a, "-S") || driver_strneq(a, "--emit=", 7) || 384 driver_streq(a, "-fsyntax-only") || driver_strneq(a, "-fPIC", 5) || 385 driver_strneq(a, "-fpic", 5) || driver_strneq(a, "-fPIE", 5) || 386 driver_strneq(a, "-fpie", 5) || 387 driver_streq(a, "-arch") || driver_streq(a, "-platform_version") || 388 driver_streq(a, "-macosx_version_min") || 389 driver_streq(a, "-ios_version_min") || 390 driver_streq(a, "-iphoneos_version_min") || 391 driver_streq(a, "-ios_simulator_version_min") || 392 driver_streq(a, "-iphonesimulator_version_min") || 393 driver_strneq(a, "-fvisibility=", 13) || 394 driver_streq(a, "-ffunction-sections") || 395 driver_streq(a, "-fdata-sections") || 396 driver_strneq(a, "-ftrivial-auto-var-init=", 24) || 397 driver_streq(a, "-fno-builtin") || 398 driver_strneq(a, "-fno-builtin-", 13) || 399 driver_streq(a, "-fno-stack-protector") || 400 driver_strneq(a, "-fstack-protector", 17) || 401 driver_streq(a, "-flto") || driver_streq(a, "-fno-lto") || 402 driver_streq(a, "-static") || driver_streq(a, "-dynamic") || 403 driver_streq(a, "-shared") || driver_streq(a, "-pie") || 404 driver_streq(a, "-no-pie") || driver_streq(a, "-target") || 405 driver_strneq(a, "--target", 8) || driver_strneq(a, "-l", 2) || 406 driver_strneq(a, "-L", 2) || driver_strneq(a, "-F", 2) || 407 driver_streq(a, "-framework") || driver_streq(a, "-e") || 408 driver_streq(a, "-T") || 409 driver_streq(a, "-Ttext") || driver_strneq(a, "-Ttext=", 7) || 410 driver_streq(a, "--gc-sections") || 411 driver_streq(a, "--no-gc-sections") || 412 driver_streq(a, "--no-undefined") || 413 driver_streq(a, "--allow-undefined") || 414 driver_streq(a, "--allow-shlib-undefined") || 415 driver_streq(a, "-z") || 416 (a[0] == '-' && a[1] == 'z' && a[2] != '\0') || 417 driver_streq(a, "--map") || driver_strneq(a, "--map=", 6) || 418 driver_streq(a, "-Map") || driver_strneq(a, "-Map=", 5) || 419 driver_streq(a, "--symbols") || 420 driver_strneq(a, "--symbols=", 10) || 421 driver_strneq(a, "--symbols-format=", 17) || 422 driver_strneq(a, "-Wl,", 4) || driver_strneq(a, "--build-id", 10) || 423 driver_streq(a, "-Werror") || driver_strneq(a, "-fmax-errors=", 13) || 424 driver_strneq(a, "-m", 2); 425 } 426 427 /* ===================================================================== */ 428 /* main parser */ 429 /* ===================================================================== */ 430 431 static int build_parse_group(BuildOptions* o, int argc, char** argv, int* i) { 432 BuildGroup* g; 433 uint32_t gid = o->ngroups++; 434 g = &o->groups[gid]; 435 if (build_group_cf_init(o, g) != 0) { 436 driver_errf(o->tool, "out of memory"); 437 return 1; 438 } 439 ++(*i); /* past --group */ 440 /* scopable flag section, terminated by `--` */ 441 for (; *i < argc && !driver_streq(argv[*i], "--"); ++(*i)) { 442 int r = build_try_scopable(o, g, argc, argv, i); 443 if (r < 0) return 1; 444 if (r > 0) continue; 445 if (build_is_global_flag(argv[*i])) { 446 driver_errf(o->tool, 447 "%.*s is a per-output flag; place it before any --group", 448 KIT_SLICE_ARG(kit_slice_cstr(argv[*i]))); 449 return 1; 450 } 451 driver_errf(o->tool, "unsupported flag in --group: %.*s", 452 KIT_SLICE_ARG(kit_slice_cstr(argv[*i]))); 453 return 1; 454 } 455 if (*i >= argc) { 456 driver_errf(o->tool, "--group requires `--` before its sources"); 457 return 1; 458 } 459 ++(*i); /* past `--` */ 460 o->cur_group = gid; /* subsequent sources belong to this group */ 461 return 0; 462 } 463 464 static int build_parse(int argc, char** argv, BuildOptions* o) { 465 int i; 466 o->target = driver_host_target(); 467 468 for (i = 1; i < argc; ++i) { 469 const char* a = argv[i]; 470 471 if (driver_streq(a, "--group")) { 472 if (build_parse_group(o, argc, argv, &i) != 0) return 1; 473 --i; /* parse_group leaves i at the next token; loop's ++i re-reads it */ 474 continue; 475 } 476 477 /* Scopable flags in the global context feed the baseline (groups[0]). */ 478 { 479 int r = build_try_scopable(o, &o->groups[0], argc, argv, &i); 480 if (r < 0) return 1; 481 if (r > 0) continue; 482 } 483 484 /* Output form. */ 485 if (driver_streq(a, "-c")) { 486 o->emit = BUILD_EMIT_OBJ; 487 continue; 488 } 489 if (driver_streq(a, "-S") || driver_streq(a, "--emit=asm")) { 490 o->emit = BUILD_EMIT_ASM; 491 continue; 492 } 493 if (driver_streq(a, "--emit=obj")) { 494 o->emit = BUILD_EMIT_OBJ; 495 continue; 496 } 497 if (driver_streq(a, "--emit=c")) { 498 o->emit = BUILD_EMIT_C; 499 continue; 500 } 501 if (driver_streq(a, "--emit=ir")) { 502 o->emit = BUILD_EMIT_IR; 503 continue; 504 } 505 if (driver_streq(a, "-fsyntax-only")) { 506 o->syntax_only = 1; 507 continue; 508 } 509 if (driver_streq(a, "-o")) { 510 if (++i >= argc) { 511 driver_errf(o->tool, "-o requires an argument"); 512 return 1; 513 } 514 o->output_path = argv[i]; 515 continue; 516 } 517 if (driver_strneq(a, "-o", 2)) { 518 o->output_path = a + 2; 519 continue; 520 } 521 if (driver_strneq(a, "--output=", 9)) { 522 o->output_path = a + 9; 523 continue; 524 } 525 if (driver_streq(a, "--output")) { 526 if (++i >= argc) { 527 driver_errf(o->tool, "--output requires an argument"); 528 return 1; 529 } 530 o->output_path = argv[i]; 531 continue; 532 } 533 534 /* Optimization / debug / codegen knobs. */ 535 if (driver_streq(a, "-g")) { 536 o->debug_info = 1; 537 continue; 538 } 539 if (driver_streq(a, "-O0")) { 540 o->opt_level = 0; 541 continue; 542 } 543 if (driver_streq(a, "-O1")) { 544 o->opt_level = 1; 545 continue; 546 } 547 if (driver_streq(a, "-O2") || driver_streq(a, "-O") || 548 driver_streq(a, "-O3") || driver_streq(a, "-Os") || 549 driver_streq(a, "-Oz") || driver_streq(a, "-Ofast")) { 550 o->opt_level = 1; 551 continue; 552 } 553 if (driver_streq(a, "-Werror") || driver_strneq(a, "-Werror=", 8)) { 554 o->warnings_are_errors = 1; 555 continue; 556 } 557 if (driver_strneq(a, "-fmax-errors=", 13)) { 558 uint64_t v; 559 if (driver_parse_u64(a + 13, &v) != 0 || v > 0xFFFFFFFFu) { 560 driver_errf(o->tool, "-fmax-errors= requires a non-negative integer"); 561 return 1; 562 } 563 o->max_errors = (uint32_t)v; 564 continue; 565 } 566 if (driver_streq(a, "-fPIC") || driver_streq(a, "-fpic")) { 567 o->target.pic = KIT_PIC_PIC; 568 o->pic_explicit = 1; 569 continue; 570 } 571 if (driver_streq(a, "-fPIE") || driver_streq(a, "-fpie")) { 572 o->target.pic = KIT_PIC_PIE; 573 o->pic_explicit = 1; 574 continue; 575 } 576 if (driver_streq(a, "-fno-PIC") || driver_streq(a, "-fno-pic") || 577 driver_streq(a, "-fno-PIE") || driver_streq(a, "-fno-pie")) { 578 o->target.pic = KIT_PIC_NONE; 579 o->pic_explicit = 1; 580 continue; 581 } 582 if (driver_streq(a, "-fvisibility=hidden")) { 583 o->default_visibility = KIT_SV_HIDDEN; 584 continue; 585 } 586 if (driver_streq(a, "-fvisibility=default")) { 587 o->default_visibility = KIT_SV_DEFAULT; 588 continue; 589 } 590 if (driver_strneq(a, "-fvisibility=", 13)) { 591 driver_errf(o->tool, "unsupported visibility: %.*s", 592 KIT_SLICE_ARG(kit_slice_cstr(a + 13))); 593 return 1; 594 } 595 if (driver_streq(a, "-ffunction-sections")) { 596 o->function_sections = 1; 597 continue; 598 } 599 if (driver_streq(a, "-fno-function-sections")) { 600 o->function_sections = 0; 601 continue; 602 } 603 if (driver_streq(a, "-fdata-sections")) { 604 o->data_sections = 1; 605 continue; 606 } 607 if (driver_strneq(a, "-ftrivial-auto-var-init=", 24)) { 608 const char* mode = a + 24; 609 if (driver_streq(mode, "zero")) { 610 o->auto_var_init = KIT_AUTOVAR_ZERO; 611 } else if (driver_streq(mode, "uninitialized")) { 612 o->auto_var_init = KIT_AUTOVAR_UNINIT; 613 } else if (driver_streq(mode, "pattern")) { 614 driver_errf(o->tool, 615 "-ftrivial-auto-var-init=pattern is not yet supported; " 616 "use =zero"); 617 return 1; 618 } else { 619 driver_errf(o->tool, 620 "-ftrivial-auto-var-init=: unknown mode '%s' " 621 "(expected zero, pattern, or uninitialized)", 622 mode); 623 return 1; 624 } 625 continue; 626 } 627 if (driver_streq(a, "-fno-data-sections")) { 628 o->data_sections = 0; 629 continue; 630 } 631 if (driver_streq(a, "-fno-builtin") || 632 driver_strneq(a, "-fno-builtin-", 13)) { 633 continue; 634 } 635 if (driver_streq(a, "-fno-stack-protector")) { 636 o->stack_protector = KIT_STACK_PROTECTOR_NONE; 637 continue; 638 } 639 if (driver_streq(a, "-fstack-protector")) { 640 o->stack_protector = KIT_STACK_PROTECTOR_BASIC; 641 continue; 642 } 643 if (driver_streq(a, "-fstack-protector-strong")) { 644 o->stack_protector = KIT_STACK_PROTECTOR_STRONG; 645 continue; 646 } 647 if (driver_streq(a, "-fstack-protector-all")) { 648 o->stack_protector = KIT_STACK_PROTECTOR_ALL; 649 continue; 650 } 651 if (driver_strneq(a, "-fstack-protector", 17)) { 652 driver_errf(o->tool, "unsupported stack protector mode: %.*s", 653 KIT_SLICE_ARG(kit_slice_cstr(a))); 654 return 1; 655 } 656 if (driver_streq(a, "-flto")) { 657 o->lto = 1; 658 continue; 659 } 660 if (driver_streq(a, "-fno-lto")) { 661 o->lto = 0; 662 continue; 663 } 664 if (driver_streq(a, "-ffreestanding")) { 665 o->freestanding = 1; 666 continue; 667 } 668 if (driver_streq(a, "-fhosted")) { 669 o->freestanding = 0; 670 continue; 671 } 672 if (driver_streq(a, "-nostdinc")) { 673 o->nostdinc = 1; 674 continue; 675 } 676 if (driver_streq(a, "-nostdlib")) { 677 o->no_stdlib = 1; 678 continue; 679 } 680 if (driver_streq(a, "-nodefaultlibs")) { 681 o->no_defaultlibs = 1; 682 continue; 683 } 684 if (driver_streq(a, "-nostartfiles")) { 685 o->no_startfiles = 1; 686 continue; 687 } 688 689 /* Link kind. */ 690 if (driver_streq(a, "-static")) { 691 o->static_link = 1; 692 o->target.pic = KIT_PIC_NONE; 693 o->pic_explicit = 1; 694 o->inputs.cur_link_mode = KIT_LM_STATIC; 695 continue; 696 } 697 if (driver_streq(a, "-dynamic")) { 698 o->dynamic = 1; 699 continue; 700 } 701 if (driver_streq(a, "-shared")) { 702 o->dynamic = 1; 703 o->shared_requested = 1; 704 continue; 705 } 706 if (driver_streq(a, "-pie")) { 707 o->target.pic = KIT_PIC_PIE; 708 o->pie = 1; 709 o->pic_explicit = 1; 710 continue; 711 } 712 if (driver_streq(a, "-no-pie")) { 713 o->target.pic = KIT_PIC_NONE; 714 o->pie = 0; 715 o->pic_explicit = 1; 716 continue; 717 } 718 719 /* Link inputs / flags. */ 720 if (driver_strneq(a, "-L", 2)) { 721 const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 722 if (!dir) { 723 driver_errf(o->tool, "-L requires an argument"); 724 return 1; 725 } 726 o->inputs.lib_search_paths[o->inputs.nlib_search_paths++] = dir; 727 continue; 728 } 729 if (driver_strneq(a, "-F", 2)) { 730 const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 731 if (!dir) { 732 driver_errf(o->tool, "-F requires an argument"); 733 return 1; 734 } 735 o->inputs.framework_search_paths[o->inputs.nframework_search_paths++] = 736 dir; 737 continue; 738 } 739 if (driver_strneq(a, "-l", 2)) { 740 const char* name = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 741 if (!name) { 742 driver_errf(o->tool, "-l requires an argument"); 743 return 1; 744 } 745 if (driver_streq(name, "c") && !o->no_stdlib && !o->no_defaultlibs) { 746 o->wants_hosted_libc = 1; 747 continue; 748 } 749 { 750 DriverPendingLib* pl = 751 &o->inputs.pending_libs[o->inputs.npending_libs++]; 752 pl->name = name; 753 pl->whole_archive = o->inputs.cur_whole_archive; 754 pl->link_mode = o->inputs.cur_link_mode; 755 pl->group_id = o->inputs.cur_group_id; 756 driver_link_inputs_push(&o->inputs, DRIVER_LINK_LIB, 757 o->inputs.npending_libs - 1u); 758 } 759 continue; 760 } 761 if (driver_streq(a, "-framework")) { 762 if (++i >= argc) { 763 driver_errf(o->tool, "-framework requires an argument"); 764 return 1; 765 } 766 if (build_record_framework(o, argv[i]) != 0) return 1; 767 continue; 768 } 769 if (driver_streq(a, "-e")) { 770 if (++i >= argc) { 771 driver_errf(o->tool, "-e requires an argument"); 772 return 1; 773 } 774 o->link.entry = argv[i]; 775 continue; 776 } 777 if (driver_streq(a, "-T")) { 778 if (++i >= argc) { 779 driver_errf(o->tool, "-T requires an argument"); 780 return 1; 781 } 782 o->link.linker_script = argv[i]; 783 continue; 784 } 785 if (driver_streq(a, "-Ttext")) { 786 if (++i >= argc) { 787 driver_errf(o->tool, "-Ttext requires an argument"); 788 return 1; 789 } 790 if (driver_link_flags_record_text_base(&o->link, argv[i]) != 0) 791 return 1; 792 continue; 793 } 794 if (driver_strneq(a, "-Ttext=", 7)) { 795 if (driver_link_flags_record_text_base(&o->link, a + 7) != 0) return 1; 796 continue; 797 } 798 if (driver_streq(a, "-Tdata") || driver_streq(a, "-Tbss")) { 799 const char* secname = driver_streq(a, "-Tdata") ? ".data" : ".bss"; 800 if (++i >= argc) { 801 driver_errf(o->tool, "%s requires an address", a); 802 return 1; 803 } 804 if (driver_link_flags_record_section_addr(&o->link, secname, argv[i]) != 0) 805 return 1; 806 continue; 807 } 808 if (driver_strneq(a, "-Tdata=", 7)) { 809 if (driver_link_flags_record_section_addr(&o->link, ".data", a + 7) != 0) 810 return 1; 811 continue; 812 } 813 if (driver_strneq(a, "-Tbss=", 6)) { 814 if (driver_link_flags_record_section_addr(&o->link, ".bss", a + 6) != 0) 815 return 1; 816 continue; 817 } 818 if (driver_streq(a, "--defsym")) { 819 if (++i >= argc) { 820 driver_errf(o->tool, "--defsym requires NAME=EXPR"); 821 return 1; 822 } 823 if (driver_link_flags_record_defsym(&o->link, argv[i], 824 driver_strlen(argv[i])) != 0) 825 return 1; 826 continue; 827 } 828 if (driver_strneq(a, "--defsym=", 9)) { 829 if (driver_link_flags_record_defsym(&o->link, a + 9, 830 driver_strlen(a + 9)) != 0) 831 return 1; 832 continue; 833 } 834 if (driver_strneq(a, "--section-start=", 16)) { 835 if (driver_link_flags_record_section_start(&o->link, a + 16, 836 driver_strlen(a + 16)) != 0) 837 return 1; 838 continue; 839 } 840 if (driver_streq(a, "--section-start")) { 841 if (++i >= argc) { 842 driver_errf(o->tool, "--section-start requires .NAME=ADDR"); 843 return 1; 844 } 845 if (driver_link_flags_record_section_start(&o->link, argv[i], 846 driver_strlen(argv[i])) != 0) 847 return 1; 848 continue; 849 } 850 if (driver_strneq(a, "--orphan-handling=", 18)) { 851 if (driver_link_flags_record_orphan_handling( 852 &o->link, a + 18, driver_strlen(a + 18)) != 0) 853 return 1; 854 continue; 855 } 856 if (driver_streq(a, "--orphan-handling")) { 857 if (++i >= argc) { 858 driver_errf(o->tool, "--orphan-handling requires a mode"); 859 return 1; 860 } 861 if (driver_link_flags_record_orphan_handling( 862 &o->link, argv[i], driver_strlen(argv[i])) != 0) 863 return 1; 864 continue; 865 } 866 if (driver_streq(a, "--fatal-warnings")) { 867 o->link.fatal_warnings = 1; 868 continue; 869 } 870 if (driver_streq(a, "--no-fatal-warnings")) { 871 o->link.fatal_warnings = 0; 872 continue; 873 } 874 if (driver_streq(a, "--print-memory-usage")) { 875 o->link.print_memory_usage = 1; 876 continue; 877 } 878 if (driver_streq(a, "--cref")) { 879 if (++i >= argc) { 880 driver_errf(o->tool, "--cref requires a path"); 881 return 1; 882 } 883 if (driver_link_flags_record_cref(&o->link, argv[i], 884 driver_strlen(argv[i])) != 0) 885 return 1; 886 continue; 887 } 888 if (driver_strneq(a, "--cref=", 7)) { 889 if (driver_link_flags_record_cref(&o->link, a + 7, 890 driver_strlen(a + 7)) != 0) 891 return 1; 892 continue; 893 } 894 if (driver_streq(a, "--gc-sections")) { 895 o->link.gc_sections = 1; 896 continue; 897 } 898 if (driver_streq(a, "--no-gc-sections")) { 899 o->link.gc_sections = 0; 900 continue; 901 } 902 if (driver_streq(a, "--no-undefined")) { 903 o->link.allow_undefined = 0; 904 continue; 905 } 906 if (driver_streq(a, "--allow-undefined") || 907 driver_streq(a, "--allow-shlib-undefined")) { 908 o->link.allow_undefined = 1; 909 continue; 910 } 911 if (driver_streq(a, "-z")) { 912 if (++i >= argc) { 913 driver_errf(o->tool, "-z requires an argument"); 914 return 1; 915 } 916 if (driver_link_flags_record_z(&o->link, argv[i], 917 driver_strlen(argv[i])) != 0) 918 return 1; 919 continue; 920 } 921 if (a[0] == '-' && a[1] == 'z' && a[2] != '\0') { 922 if (driver_link_flags_record_z(&o->link, a + 2, 923 driver_strlen(a + 2)) != 0) 924 return 1; 925 continue; 926 } 927 if (driver_streq(a, "--map") || driver_streq(a, "-Map")) { 928 if (++i >= argc) { 929 driver_errf(o->tool, "%.*s requires an argument", 930 KIT_SLICE_ARG(kit_slice_cstr(a))); 931 return 1; 932 } 933 if (driver_link_flags_record_map(&o->link, argv[i], 934 driver_strlen(argv[i])) != 0) 935 return 1; 936 continue; 937 } 938 if (driver_strneq(a, "--map=", 6)) { 939 if (driver_link_flags_record_map(&o->link, a + 6, 940 driver_strlen(a + 6)) != 0) 941 return 1; 942 continue; 943 } 944 if (driver_strneq(a, "-Map=", 5)) { 945 if (driver_link_flags_record_map(&o->link, a + 5, 946 driver_strlen(a + 5)) != 0) 947 return 1; 948 continue; 949 } 950 if (driver_streq(a, "--symbols")) { 951 if (++i >= argc) { 952 driver_errf(o->tool, "--symbols requires an argument"); 953 return 1; 954 } 955 if (driver_link_flags_record_symbols(&o->link, argv[i], 956 driver_strlen(argv[i])) != 0) 957 return 1; 958 continue; 959 } 960 if (driver_strneq(a, "--symbols=", 10)) { 961 if (driver_link_flags_record_symbols(&o->link, a + 10, 962 driver_strlen(a + 10)) != 0) 963 return 1; 964 continue; 965 } 966 if (driver_strneq(a, "--symbols-format=", 17)) { 967 if (driver_link_flags_record_symbols_format( 968 &o->link, a + 17, driver_strlen(a + 17)) != 0) 969 return 1; 970 continue; 971 } 972 if (driver_strneq(a, "-Wl,", 4)) { 973 if (driver_link_flags_record_wl(&o->link, a + 4) != 0) return 1; 974 continue; 975 } 976 if (driver_streq(a, "-Xlinker")) { 977 if (++i >= argc) { 978 driver_errf(o->tool, "-Xlinker requires an argument"); 979 return 1; 980 } 981 if (driver_link_flags_record_wl(&o->link, argv[i]) != 0) return 1; 982 continue; 983 } 984 if (driver_strneq(a, "--build-id=", 11)) { 985 if (driver_link_flags_record_build_id(&o->link, a + 11) != 0) return 1; 986 continue; 987 } 988 if (driver_streq(a, "--build-id")) { 989 if (driver_link_flags_record_build_id(&o->link, "sha256") != 0) return 1; 990 continue; 991 } 992 if (driver_streq(a, "-mwindows")) { 993 o->link.pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_GUI; 994 continue; 995 } 996 if (driver_streq(a, "-mconsole")) { 997 o->link.pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_CUI; 998 continue; 999 } 1000 if (driver_strneq(a, "-mcmodel=", 9)) { 1001 if (driver_record_mcmodel(&o->target, o->tool, a + 9) != 0) return 1; 1002 continue; 1003 } 1004 if (driver_streq(a, "-mno-red-zone")) { 1005 o->disabled_backend_features |= KIT_CG_BACKEND_RED_ZONE; 1006 continue; 1007 } 1008 if (driver_streq(a, "-mred-zone")) { 1009 o->disabled_backend_features &= ~KIT_CG_BACKEND_RED_ZONE; 1010 continue; 1011 } 1012 if (driver_streq(a, "-mgeneral-regs-only")) { 1013 o->disabled_backend_features |= KIT_CG_BACKEND_SIMD; 1014 continue; 1015 } 1016 if (driver_streq(a, "-mno-general-regs-only")) { 1017 o->disabled_backend_features &= ~KIT_CG_BACKEND_SIMD; 1018 continue; 1019 } 1020 1021 /* Target. */ 1022 { 1023 int dr = driver_darwin_platform_try_consume( 1024 o->tool, argc, argv, &i, &o->target, o->pic_explicit); 1025 if (dr < 0) return 1; 1026 if (dr > 0) continue; 1027 } 1028 if (driver_streq(a, "-target") || driver_streq(a, "--target")) { 1029 KitTargetSpec t; 1030 uint8_t pic; 1031 if (++i >= argc) { 1032 driver_errf(o->tool, "%.*s requires an argument", 1033 KIT_SLICE_ARG(kit_slice_cstr(a))); 1034 return 1; 1035 } 1036 if (driver_target_from_triple(argv[i], &t) != 0) { 1037 driver_err_unknown_target(o->tool, argv[i]); 1038 return 1; 1039 } 1040 pic = o->target.pic; 1041 o->target = t; 1042 if (o->pic_explicit) 1043 o->target.pic = pic; 1044 else 1045 o->target.pic = driver_default_pic(o->target.obj, o->target.os); 1046 continue; 1047 } 1048 if (driver_strneq(a, "--target=", 9)) { 1049 KitTargetSpec t; 1050 uint8_t pic; 1051 if (driver_target_from_triple(a + 9, &t) != 0) { 1052 driver_err_unknown_target(o->tool, a + 9); 1053 return 1; 1054 } 1055 pic = o->target.pic; 1056 o->target = t; 1057 if (o->pic_explicit) 1058 o->target.pic = pic; 1059 else 1060 o->target.pic = driver_default_pic(o->target.obj, o->target.os); 1061 continue; 1062 } 1063 { 1064 int tr = driver_target_features_try_consume(&o->target_features, o->env, 1065 o->tool, argc, argv, &i); 1066 if (tr < 0) return 1; 1067 if (tr > 0) continue; 1068 } 1069 1070 /* Support dir / sysroot. */ 1071 if (driver_streq(a, "-isysroot") || driver_streq(a, "--sysroot")) { 1072 if (++i >= argc) { 1073 driver_errf(o->tool, "%.*s requires an argument", 1074 KIT_SLICE_ARG(kit_slice_cstr(a))); 1075 return 1; 1076 } 1077 o->sysroot = argv[i]; 1078 continue; 1079 } 1080 if (driver_strneq(a, "--sysroot=", 10)) { 1081 o->sysroot = a + 10; 1082 continue; 1083 } 1084 if (driver_streq(a, "--support-dir")) { 1085 if (++i >= argc) { 1086 driver_errf(o->tool, "--support-dir requires an argument"); 1087 return 1; 1088 } 1089 o->support_dir = argv[i]; 1090 continue; 1091 } 1092 if (driver_strneq(a, "--support-dir=", 14)) { 1093 o->support_dir = a + 14; 1094 continue; 1095 } 1096 1097 if (driver_streq(a, "--")) { 1098 for (++i; i < argc; ++i) 1099 if (build_classify_positional(o, argv[i]) != 0) return 1; 1100 break; 1101 } 1102 if (a[0] == '-' && a[1] != '\0') { 1103 driver_errf(o->tool, "unknown flag: %.*s", 1104 KIT_SLICE_ARG(kit_slice_cstr(a))); 1105 return 1; 1106 } 1107 if (build_classify_positional(o, a) != 0) return 1; 1108 } 1109 return 0; 1110 } 1111 1112 /* ===================================================================== */ 1113 /* hosted libc / runtime orchestration (build-exe; shared build-lib) */ 1114 /* ===================================================================== */ 1115 1116 static int build_is_link_output(const BuildOptions* o) { 1117 if (o->kind == BUILD_OUT_EXE && o->target.obj == KIT_OBJ_WASM) return 0; 1118 return o->kind == BUILD_OUT_EXE || (o->kind == BUILD_OUT_LIB && o->dynamic); 1119 } 1120 1121 /* A sysroot on its own engages the hosted compiler profile (matching 1122 * clang/gcc). -ffreestanding / -nostdinc opt out of hosted headers; the 1123 * -nostdlib family only suppresses link additions. */ 1124 static void build_enable_hosted_for_sysroot(BuildOptions* o) { 1125 if (o->wants_hosted_libc) return; 1126 if (o->shared && !driver_target_shared_uses_hosted(o->target)) return; 1127 if (!o->sysroot || !o->sysroot[0]) return; 1128 if (o->freestanding || o->nostdinc) return; 1129 o->wants_hosted_libc = 1; 1130 } 1131 1132 static void build_apply_default_hosted_profile(BuildOptions* o) { 1133 KitTargetSpec host; 1134 int native_macos; 1135 if (!driver_target_default_hosted_profile(o->target)) return; 1136 if (o->wants_hosted_libc) return; 1137 if (o->freestanding || o->nostdinc) return; 1138 host = driver_host_target(); 1139 native_macos = host.os == KIT_OS_MACOS && o->target.os == KIT_OS_MACOS; 1140 if ((!o->sysroot || !o->sysroot[0]) && !native_macos) return; 1141 o->wants_hosted_libc = 1; 1142 } 1143 1144 static int build_apply_hosted_profile(BuildOptions* o) { 1145 int link_action; 1146 int shared_hosted = o->shared && driver_target_shared_uses_hosted(o->target); 1147 if (!o->wants_hosted_libc || (o->shared && !shared_hosted)) return 0; 1148 link_action = build_is_link_output(o) && !o->no_stdlib && !o->no_defaultlibs; 1149 /* Hosted defines/includes apply to every build-* compile. Only an executable 1150 * or dynamic-library output consumes CRT/libc link inputs. */ 1151 return driver_link_inputs_apply_hosted( 1152 &o->inputs, &o->hosted, &o->groups[0].cf, &o->link, o->target, o->sysroot, 1153 o->static_link, o->shared, o->no_startfiles, link_action); 1154 } 1155 1156 /* ===================================================================== */ 1157 /* merged preprocessor view per group */ 1158 /* ===================================================================== */ 1159 1160 static int build_group_build_pp(BuildOptions* o, uint32_t gi) { 1161 BuildGroup* g = &o->groups[gi]; 1162 BuildGroup* gl = &o->groups[0]; 1163 uint32_t k; 1164 if (gi == 0) { 1165 driver_cflags_fill_pp(&gl->cf, &g->pp); 1166 return 0; 1167 } 1168 /* include = group then global (group searched first). */ 1169 g->m_ninc = g->cf.ninclude_dirs + gl->cf.ninclude_dirs; 1170 g->m_nsys = g->cf.nsystem_include_dirs + gl->cf.nsystem_include_dirs; 1171 g->m_def_cap = gl->cf.ndefines + g->cf.ndefines; 1172 g->m_nund = gl->cf.nundefines + g->cf.nundefines; 1173 if (g->m_ninc) 1174 g->m_inc = driver_alloc_zeroed(o->env, g->m_ninc * sizeof(*g->m_inc)); 1175 if (g->m_nsys) 1176 g->m_sys = driver_alloc_zeroed(o->env, g->m_nsys * sizeof(*g->m_sys)); 1177 if (g->m_def_cap) 1178 g->m_def = driver_alloc_zeroed(o->env, g->m_def_cap * sizeof(*g->m_def)); 1179 if (g->m_nund) 1180 g->m_und = driver_alloc_zeroed(o->env, g->m_nund * sizeof(*g->m_und)); 1181 if ((g->m_ninc && !g->m_inc) || (g->m_nsys && !g->m_sys) || 1182 (g->m_def_cap && !g->m_def) || (g->m_nund && !g->m_und)) { 1183 driver_errf(o->tool, "out of memory"); 1184 return 1; 1185 } 1186 { 1187 uint32_t p = 0, j; 1188 for (k = 0; k < g->cf.ninclude_dirs; ++k) 1189 g->m_inc[p++] = g->cf.include_dirs[k]; 1190 for (k = 0; k < gl->cf.ninclude_dirs; ++k) 1191 g->m_inc[p++] = gl->cf.include_dirs[k]; 1192 p = 0; 1193 for (k = 0; k < g->cf.nsystem_include_dirs; ++k) 1194 g->m_sys[p++] = g->cf.system_include_dirs[k]; 1195 for (k = 0; k < gl->cf.nsystem_include_dirs; ++k) 1196 g->m_sys[p++] = gl->cf.system_include_dirs[k]; 1197 /* defines: each global define survives only if the group does not redefine 1198 * the same name; the group's defines then follow. This realizes "a group 1199 * -D of an already-defined name overrides it for that group" without 1200 * emitting a duplicate (which the preprocessor rejects as a conflicting 1201 * redefinition). */ 1202 p = 0; 1203 for (k = 0; k < gl->cf.ndefines; ++k) { 1204 int shadowed = 0; 1205 for (j = 0; j < g->cf.ndefines; ++j) { 1206 if (kit_slice_eq(gl->cf.defines[k].name, g->cf.defines[j].name)) { 1207 shadowed = 1; 1208 break; 1209 } 1210 } 1211 if (!shadowed) g->m_def[p++] = gl->cf.defines[k]; 1212 } 1213 for (k = 0; k < g->cf.ndefines; ++k) g->m_def[p++] = g->cf.defines[k]; 1214 g->m_ndef = p; 1215 p = 0; 1216 for (k = 0; k < gl->cf.nundefines; ++k) g->m_und[p++] = gl->cf.undefines[k]; 1217 for (k = 0; k < g->cf.nundefines; ++k) g->m_und[p++] = g->cf.undefines[k]; 1218 } 1219 { 1220 KitPreprocessOptions z = {0}; 1221 g->pp = z; 1222 g->pp.include_dirs = g->m_inc; 1223 g->pp.ninclude_dirs = g->m_ninc; 1224 g->pp.system_include_dirs = g->m_sys; 1225 g->pp.nsystem_include_dirs = g->m_nsys; 1226 g->pp.defines = g->m_def; 1227 g->pp.ndefines = g->m_ndef; 1228 g->pp.undefines = g->m_und; 1229 g->pp.nundefines = g->m_nund; 1230 } 1231 return 0; 1232 } 1233 1234 /* ===================================================================== */ 1235 /* compile one source */ 1236 /* ===================================================================== */ 1237 1238 static KitLanguage build_resolve_lang(BuildOptions* o, KitCompiler* compiler, 1239 uint32_t si) { 1240 uint32_t gi = o->sources[si].group; 1241 if (gi != 0 && o->groups[gi].forced_lang != BUILD_LANG_AUTO) 1242 return o->groups[gi].forced_lang; 1243 if (o->groups[0].forced_lang != BUILD_LANG_AUTO) 1244 return o->groups[0].forced_lang; 1245 return kit_language_for_path(compiler, o->sources[si].path); 1246 } 1247 1248 /* Collect the -X<lang> frontend tokens for a source into a fresh argv: 1249 * global (groups[0]) tokens first, then the source's group's. */ 1250 static int build_collect_fe_argv(BuildOptions* o, uint32_t si, KitLanguage lang, 1251 char*** out_argv, uint32_t* out_n) { 1252 uint32_t gi = o->sources[si].group; 1253 uint32_t n = 0, k, p = 0; 1254 char** argv; 1255 for (k = 0; k < o->groups[0].nfe; ++k) 1256 if (o->groups[0].fe[k].lang == lang) n++; 1257 if (gi != 0) 1258 for (k = 0; k < o->groups[gi].nfe; ++k) 1259 if (o->groups[gi].fe[k].lang == lang) n++; 1260 *out_argv = NULL; 1261 *out_n = 0; 1262 if (n == 0) return 0; 1263 argv = driver_alloc_zeroed(o->env, n * sizeof(*argv)); 1264 if (!argv) { 1265 driver_errf(o->tool, "out of memory"); 1266 return 1; 1267 } 1268 for (k = 0; k < o->groups[0].nfe; ++k) 1269 if (o->groups[0].fe[k].lang == lang) 1270 argv[p++] = o->groups[0].fe[k].tok; 1271 if (gi != 0) 1272 for (k = 0; k < o->groups[gi].nfe; ++k) 1273 if (o->groups[gi].fe[k].lang == lang) 1274 argv[p++] = o->groups[gi].fe[k].tok; 1275 *out_argv = argv; 1276 *out_n = n; 1277 return 0; 1278 } 1279 1280 /* Compile source[si]; emit to `emit_out` (per-source output) or return a 1281 * builder via `obj_out` (link/archive). Exactly one of the two is non-NULL. */ 1282 static int build_compile_source(BuildOptions* o, KitCompiler* compiler, 1283 const KitContext* ctx, uint32_t si, 1284 const KitCodeOptions* code, 1285 const KitDiagnosticOptions* diag, 1286 KitWriter* emit_out, KitObjBuilder** obj_out) { 1287 const char* path = o->sources[si].path; 1288 uint32_t gi = o->sources[si].group; 1289 DriverLoad load = {0}; 1290 KitSlice bytes = {0}; 1291 KitLanguage lang; 1292 char** fe_argv = NULL; 1293 uint32_t fe_n = 0; 1294 void* lang_extra = NULL; 1295 KitStatus st; 1296 int rc = 1; 1297 1298 if (driver_load_bytes(ctx->file_io, o->tool, path, &load, &bytes) != 0) 1299 return 1; 1300 1301 lang = build_resolve_lang(o, compiler, si); 1302 if (lang == KIT_LANG_UNKNOWN) { 1303 driver_errf(o->tool, "cannot determine language for %.*s (use -x LANG)", 1304 KIT_SLICE_ARG(kit_slice_cstr(path))); 1305 goto out; 1306 } 1307 if (build_collect_fe_argv(o, si, lang, &fe_argv, &fe_n) != 0) goto out; 1308 if (fe_n) { 1309 if (kit_frontend_parse_options(compiler, lang, (int)fe_n, fe_argv, 1310 &lang_extra) != KIT_OK) { 1311 driver_errf( 1312 o->tool, "unsupported -X%.*s frontend flag: %.*s", 1313 KIT_SLICE_ARG(kit_slice_cstr(kit_language_name(compiler, lang))), 1314 KIT_SLICE_ARG(kit_slice_cstr(fe_argv[0]))); 1315 goto out; 1316 } 1317 } 1318 1319 st = kit_build_compile_one(compiler, lang, code, diag, &o->groups[gi].pp, 1320 lang_extra, kit_slice_cstr(path), &bytes, emit_out, 1321 obj_out); 1322 rc = (st == KIT_OK) ? 0 : 1; 1323 1324 out: 1325 if (lang_extra) kit_frontend_free_options(compiler, lang, lang_extra); 1326 if (fe_argv) driver_free(o->env, fe_argv, fe_n * sizeof(*fe_argv)); 1327 driver_release_bytes(ctx->file_io, &load); 1328 return rc; 1329 } 1330 1331 static void build_fill_code(const BuildOptions* o, KitCodeOptions* code) { 1332 KitCodeOptions z = {0}; 1333 *code = z; 1334 code->opt_level = o->syntax_only ? 0 : o->opt_level; 1335 code->debug_info = o->debug_info ? true : false; 1336 code->check_only = o->syntax_only ? true : false; 1337 code->default_visibility = o->default_visibility; 1338 code->function_sections = o->function_sections ? true : false; 1339 code->data_sections = o->data_sections ? true : false; 1340 code->disabled_backend_features = o->disabled_backend_features; 1341 code->trivial_auto_var_init = (uint8_t)o->auto_var_init; 1342 code->stack_protector = (uint8_t)o->stack_protector; 1343 code->lto = o->lto ? true : false; 1344 code->epoch = o->epoch; 1345 } 1346 1347 /* ===================================================================== */ 1348 /* default output naming */ 1349 /* ===================================================================== */ 1350 1351 static char* build_default_obj_name(DriverEnv* env, const BuildOptions* o, 1352 const char* src, size_t* out_size) { 1353 const char* ext; 1354 size_t ext_len, srclen = driver_strlen(src), dot = driver_strlen(src), 1355 slash = 0, k; 1356 switch ((BuildEmit)o->emit) { 1357 case BUILD_EMIT_ASM: 1358 ext = ".s"; 1359 ext_len = 2u; 1360 break; 1361 case BUILD_EMIT_IR: 1362 ext = ".ir"; 1363 ext_len = 3u; 1364 break; 1365 case BUILD_EMIT_C: 1366 ext = ".c"; 1367 ext_len = 2u; 1368 break; 1369 default: 1370 driver_default_obj_ext(o->target, &ext, &ext_len); 1371 break; 1372 } 1373 for (k = srclen; k > 0; --k) { 1374 if (src[k - 1] == '.') { 1375 dot = k - 1; 1376 break; 1377 } 1378 if (src[k - 1] == '/') break; 1379 } 1380 for (k = dot; k > 0; --k) { 1381 if (src[k - 1] == '/') { 1382 slash = k; 1383 break; 1384 } 1385 } 1386 { 1387 size_t name_len = dot - slash; 1388 size_t bufsz = name_len + ext_len + 1u; 1389 char* buf = driver_alloc(env, bufsz); 1390 if (!buf) return NULL; 1391 driver_memcpy(buf, src + slash, name_len); 1392 driver_memcpy(buf + name_len, ext, ext_len); 1393 buf[name_len + ext_len] = '\0'; 1394 *out_size = bufsz; 1395 return buf; 1396 } 1397 } 1398 1399 /* Open the output: a file, or stdout for "-". */ 1400 static int build_open_output(const KitContext* ctx, DriverEnv* env, 1401 const char* tool, const char* path, 1402 KitWriter** out) { 1403 if (driver_streq(path, "-")) { 1404 *out = driver_stdout_writer(env); 1405 if (!*out) { 1406 driver_errf(tool, "out of memory"); 1407 return 1; 1408 } 1409 return 0; 1410 } 1411 if (ctx->file_io->open_writer(ctx->file_io->user, path, out) != KIT_OK) { 1412 driver_errf(tool, "failed to open output: %.*s", 1413 KIT_SLICE_ARG(kit_slice_cstr(path))); 1414 return 1; 1415 } 1416 return 0; 1417 } 1418 1419 typedef struct BuildSourceBatch { 1420 DriverLoad* loads; 1421 KitBuildSource* sources; 1422 void** lang_extras; 1423 } BuildSourceBatch; 1424 1425 static void build_source_batch_fini(BuildOptions* o, KitCompiler* compiler, 1426 const KitContext* ctx, 1427 BuildSourceBatch* batch) { 1428 uint32_t i; 1429 if (batch->lang_extras && batch->sources) { 1430 for (i = 0; i < o->nsources; ++i) 1431 if (batch->lang_extras[i]) 1432 kit_frontend_free_options(compiler, batch->sources[i].lang, 1433 batch->lang_extras[i]); 1434 } 1435 if (batch->loads) 1436 for (i = 0; i < o->nsources; ++i) 1437 driver_release_bytes(ctx->file_io, &batch->loads[i]); 1438 if (batch->lang_extras) 1439 driver_free(o->env, batch->lang_extras, 1440 o->nsources * sizeof(*batch->lang_extras)); 1441 if (batch->sources) 1442 driver_free(o->env, batch->sources, 1443 o->nsources * sizeof(*batch->sources)); 1444 if (batch->loads) 1445 driver_free(o->env, batch->loads, o->nsources * sizeof(*batch->loads)); 1446 memset(batch, 0, sizeof *batch); 1447 } 1448 1449 /* Load and resolve every source while retaining its independent preprocessing 1450 * and frontend options. Both object batching and single-TU C emission consume 1451 * this shape. */ 1452 static int build_source_batch_init(BuildOptions* o, KitCompiler* compiler, 1453 const KitContext* ctx, 1454 BuildSourceBatch* batch) { 1455 uint32_t i; 1456 1457 memset(batch, 0, sizeof *batch); 1458 if (o->nsources == 0) return 0; 1459 1460 batch->loads = 1461 driver_alloc_zeroed(o->env, o->nsources * sizeof(*batch->loads)); 1462 batch->sources = 1463 driver_alloc_zeroed(o->env, o->nsources * sizeof(*batch->sources)); 1464 batch->lang_extras = driver_alloc_zeroed( 1465 o->env, o->nsources * sizeof(*batch->lang_extras)); 1466 if (!batch->loads || !batch->sources || !batch->lang_extras) { 1467 driver_errf(o->tool, "out of memory"); 1468 build_source_batch_fini(o, compiler, ctx, batch); 1469 return 1; 1470 } 1471 1472 for (i = 0; i < o->nsources; ++i) { 1473 const char* path = o->sources[i].path; 1474 uint32_t gi = o->sources[i].group; 1475 KitLanguage lang; 1476 char** fe_argv = NULL; 1477 uint32_t fe_n = 0; 1478 1479 if (driver_load_bytes(ctx->file_io, o->tool, path, &batch->loads[i], 1480 &batch->sources[i].bytes) != 0) { 1481 build_source_batch_fini(o, compiler, ctx, batch); 1482 return 1; 1483 } 1484 lang = build_resolve_lang(o, compiler, i); 1485 if (lang == KIT_LANG_UNKNOWN) { 1486 driver_errf(o->tool, "cannot determine language for %.*s (use -x LANG)", 1487 KIT_SLICE_ARG(kit_slice_cstr(path))); 1488 build_source_batch_fini(o, compiler, ctx, batch); 1489 return 1; 1490 } 1491 batch->sources[i].lang = lang; 1492 if (build_collect_fe_argv(o, i, lang, &fe_argv, &fe_n) != 0) { 1493 if (fe_argv) driver_free(o->env, fe_argv, fe_n * sizeof(*fe_argv)); 1494 build_source_batch_fini(o, compiler, ctx, batch); 1495 return 1; 1496 } 1497 if (fe_n) { 1498 if (kit_frontend_parse_options(compiler, lang, (int)fe_n, fe_argv, 1499 &batch->lang_extras[i]) != KIT_OK) { 1500 driver_errf( 1501 o->tool, "unsupported -X%.*s frontend flag: %.*s", 1502 KIT_SLICE_ARG(kit_slice_cstr(kit_language_name(compiler, lang))), 1503 KIT_SLICE_ARG(kit_slice_cstr(fe_argv[0]))); 1504 if (fe_argv) driver_free(o->env, fe_argv, fe_n * sizeof(*fe_argv)); 1505 build_source_batch_fini(o, compiler, ctx, batch); 1506 return 1; 1507 } 1508 } 1509 if (fe_argv) driver_free(o->env, fe_argv, fe_n * sizeof(*fe_argv)); 1510 batch->sources[i].name = kit_slice_cstr(path); 1511 batch->sources[i].pp = &o->groups[gi].pp; 1512 batch->sources[i].lang_extra = batch->lang_extras[i]; 1513 } 1514 return 0; 1515 } 1516 1517 /* Compile every source to an in-memory builder; objs[] is caller-owned. */ 1518 static int build_compile_all(BuildOptions* o, KitCompiler* compiler, 1519 const KitContext* ctx, const KitCodeOptions* code, 1520 const KitDiagnosticOptions* diag, 1521 KitObjBuilder** objs, uint32_t* source_obj_index, 1522 uint8_t* source_order_keep, 1523 const KitBuildBatchOptions* batch, 1524 KitBuildPendingLto* pending_lto, 1525 uint32_t* nobjs_out) { 1526 BuildSourceBatch sources; 1527 KitBuildObjects out; 1528 KitStatus st; 1529 1530 if (nobjs_out) *nobjs_out = 0; 1531 if (o->nsources == 0) return 0; 1532 if (build_source_batch_init(o, compiler, ctx, &sources) != 0) return 1; 1533 1534 memset(&out, 0, sizeof out); 1535 out.objs = objs; 1536 out.source_obj_index = source_obj_index; 1537 out.source_order_keep = source_order_keep; 1538 out.pending_lto = pending_lto; 1539 st = kit_build_compile(compiler, code, diag, sources.sources, o->nsources, 1540 batch, &out); 1541 if (nobjs_out) *nobjs_out = out.nobjs; 1542 build_source_batch_fini(o, compiler, ctx, &sources); 1543 return st == KIT_OK ? 0 : 1; 1544 } 1545 1546 typedef struct BuildPreservedVec { 1547 KitHeap* heap; 1548 KitCgSym* syms; 1549 uint32_t nsyms; 1550 uint32_t cap; 1551 int oom; 1552 } BuildPreservedVec; 1553 1554 static void build_preserved_vec_add(void* user, KitCgSym sym) { 1555 BuildPreservedVec* v = (BuildPreservedVec*)user; 1556 KitCgSym* ns; 1557 uint32_t ncap; 1558 if (!v || v->oom) return; 1559 if (v->nsyms == v->cap) { 1560 ncap = v->cap ? v->cap * 2u : 32u; 1561 ns = (KitCgSym*)v->heap->realloc( 1562 v->heap, v->syms, sizeof(*v->syms) * v->cap, 1563 sizeof(*v->syms) * ncap, _Alignof(KitCgSym)); 1564 if (!ns) { 1565 v->oom = 1; 1566 return; 1567 } 1568 v->syms = ns; 1569 v->cap = ncap; 1570 } 1571 v->syms[v->nsyms++] = sym; 1572 } 1573 1574 static KitStatus build_link_add_inputs(KitLinkSession* link, 1575 const KitLinkInputs* in) { 1576 KitStatus st = KIT_OK; 1577 uint32_t i; 1578 if (!link || !in) return KIT_INVALID; 1579 for (i = 0; i < in->norder && st == KIT_OK; ++i) { 1580 const KitLinkInputOrder* ord = &in->order[i]; 1581 switch ((KitLinkInputOrderKind)ord->kind) { 1582 case KIT_LINK_INPUT_OBJ: 1583 st = kit_link_session_add_obj(link, in->objs[ord->index]); 1584 break; 1585 case KIT_LINK_INPUT_OBJ_BYTES: 1586 st = kit_link_session_add_obj_bytes(link, in->obj_names[ord->index], 1587 &in->obj_bytes[ord->index]); 1588 break; 1589 case KIT_LINK_INPUT_ARCHIVE: 1590 st = 1591 kit_link_session_add_archive_bytes(link, &in->archives[ord->index]); 1592 break; 1593 case KIT_LINK_INPUT_DSO: 1594 st = kit_link_session_add_dso_bytes(link, in->dso_names[ord->index], 1595 &in->dso_bytes[ord->index]); 1596 break; 1597 } 1598 } 1599 return st; 1600 } 1601 1602 static int build_write_link_report(BuildOptions* o, const KitContext* ctx, 1603 KitLinkSession* link, const char* path, 1604 int symbols) { 1605 KitWriter* w = NULL; 1606 KitStatus st; 1607 if (!path) return 0; 1608 if (build_open_output(ctx, o->env, o->tool, path, &w) != 0) return 1; 1609 st = symbols ? kit_link_session_write_symbols(link, o->link.symbols_format, w) 1610 : kit_link_session_write_map(link, w); 1611 if (st == KIT_OK) st = kit_writer_status(w); 1612 kit_writer_close(w); 1613 if (st != KIT_OK) { 1614 driver_errf(o->tool, "failed to write %s: %.*s", 1615 symbols ? "symbols" : "map", 1616 KIT_SLICE_ARG(kit_slice_cstr(path))); 1617 return 1; 1618 } 1619 return 0; 1620 } 1621 1622 static KitStatus build_link_with_lto_reports( 1623 BuildOptions* o, KitCompiler* compiler, const KitContext* ctx, 1624 const KitLinkSessionOptions* lopts, const KitLinkInputs* in, 1625 KitBuildPendingLto* pending_lto, const KitBuildBatchOptions* batch, 1626 KitWriter* out) { 1627 KitLinkSession* link = NULL; 1628 BuildPreservedVec preserved; 1629 KitStatus st; 1630 if (!compiler || !lopts || !in || !out) { 1631 if (pending_lto && pending_lto->active) kit_build_lto_abort(pending_lto); 1632 return KIT_INVALID; 1633 } 1634 memset(&preserved, 0, sizeof preserved); 1635 preserved.heap = o->env->heap; 1636 st = kit_link_session_new(compiler, lopts, &link); 1637 if (st == KIT_OK) st = build_link_add_inputs(link, in); 1638 if (st == KIT_OK && pending_lto && pending_lto->active) { 1639 st = kit_link_session_visit_lto_preserved( 1640 link, pending_lto->obj, pending_lto->cg, build_preserved_vec_add, 1641 &preserved); 1642 if (st == KIT_OK && preserved.oom) st = KIT_NOMEM; 1643 if (st == KIT_OK) 1644 st = kit_build_lto_finish(pending_lto, batch, preserved.syms, 1645 preserved.nsyms); 1646 } 1647 if (st == KIT_OK) st = kit_link_session_emit(link, out); 1648 if (st == KIT_OK && 1649 build_write_link_report(o, ctx, link, o->link.map_path, 0) != 0) 1650 st = KIT_ERR; 1651 if (st == KIT_OK && 1652 build_write_link_report(o, ctx, link, o->link.symbols_path, 1) != 0) 1653 st = KIT_ERR; 1654 /* --cref FILE: cross-reference table side file. */ 1655 if (st == KIT_OK && o->link.cref_path) { 1656 KitWriter* w = NULL; 1657 if (build_open_output(ctx, o->env, o->tool, o->link.cref_path, &w) != 0) { 1658 st = KIT_ERR; 1659 } else { 1660 KitStatus cst = kit_link_session_write_cref(link, w); 1661 if (cst == KIT_OK) cst = kit_writer_status(w); 1662 kit_writer_close(w); 1663 if (cst != KIT_OK) { 1664 driver_errf(o->tool, "failed to write cref: %.*s", 1665 KIT_SLICE_ARG(kit_slice_cstr(o->link.cref_path))); 1666 st = KIT_ERR; 1667 } 1668 } 1669 } 1670 /* --print-memory-usage: GNU-ld-style per-region summary to stdout. */ 1671 if (st == KIT_OK && o->link.print_memory_usage) { 1672 KitWriter* w = NULL; 1673 if (build_open_output(ctx, o->env, o->tool, "-", &w) != 0) { 1674 st = KIT_ERR; 1675 } else { 1676 KitStatus mst = kit_link_session_write_memory_usage(link, w); 1677 if (mst == KIT_OK) mst = kit_writer_status(w); 1678 kit_writer_close(w); 1679 if (mst != KIT_OK) { 1680 driver_errf(o->tool, "failed to print memory usage"); 1681 st = KIT_ERR; 1682 } 1683 } 1684 } 1685 kit_link_session_free(link); 1686 if (preserved.syms) 1687 preserved.heap->free(preserved.heap, preserved.syms, 1688 sizeof(*preserved.syms) * preserved.cap); 1689 if (st != KIT_OK && pending_lto && pending_lto->active) 1690 kit_build_lto_abort(pending_lto); 1691 return st; 1692 } 1693 1694 /* build-exe / shared build-lib: compile sources, load link inputs, link. */ 1695 static int build_run_link(BuildOptions* o, KitCompiler* compiler, 1696 const KitContext* ctx, const KitCodeOptions* code, 1697 const KitDiagnosticOptions* diag, 1698 uint8_t output_kind) { 1699 DriverEnv* env = o->env; 1700 const KitFileIO* io = ctx->file_io; 1701 KitWriter* out_w = NULL; 1702 DriverLoad* obj_lf = NULL; 1703 DriverLoad* arch_lf = NULL; 1704 DriverLoad* dso_lf = NULL; 1705 DriverLoad script_lf = {0}; 1706 KitSlice* obj_in = NULL; 1707 KitSlice* obj_names = NULL; 1708 KitLinkArchiveInput* arch_in = NULL; 1709 KitSlice* dso_in = NULL; 1710 KitSlice* dso_names = NULL; 1711 KitLinkInputOrder* order = NULL; 1712 KitObjBuilder** objs = NULL; 1713 KitBuildPendingLto pending_lto = {0}; 1714 uint32_t* source_obj_index = NULL; 1715 uint8_t* source_order_keep = NULL; 1716 KitLinkScript* script = NULL; 1717 KitSlice* rpath_slices = NULL; 1718 KitBuildBatchOptions lto_batch; 1719 uint32_t nobjs = 0; 1720 uint32_t i; 1721 uint32_t norder = 0; 1722 int rc = 1; 1723 /* Strict-by-default freestanding policy: a `*-none-*` target, or an explicit 1724 * -ffreestanding static non-PIE executable, must reject dynamic-link 1725 * artifacts and cross-input target/format mismatches. Computed once here (the 1726 * pie value mirrors what driver_link_flags_fill_options derives for lopts.pie) 1727 * so the per-input arch/format guard below and lopts.freestanding_strict 1728 * agree on the trigger — otherwise the hosted -ffreestanding path would set 1729 * strict yet skip the guard. The relocatable partial-link lane never imposes 1730 * it. */ 1731 int freestanding_strict = 1732 output_kind == KIT_LINK_OUTPUT_EXE && 1733 (o->target.os == KIT_OS_FREESTANDING || 1734 (o->freestanding && o->static_link && 1735 !driver_link_pie(o->target, o->pie, o->shared, 0))); 1736 1737 if (o->nsources) { 1738 objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs)); 1739 source_obj_index = 1740 driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index)); 1741 source_order_keep = 1742 driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep)); 1743 if (!objs || !source_obj_index || !source_order_keep) goto oom; 1744 } 1745 if (o->inputs.nobject_files) { 1746 obj_lf = 1747 driver_alloc_zeroed(env, o->inputs.nobject_files * sizeof(*obj_lf)); 1748 obj_in = 1749 driver_alloc_zeroed(env, o->inputs.nobject_files * sizeof(*obj_in)); 1750 obj_names = 1751 driver_alloc_zeroed(env, o->inputs.nobject_files * sizeof(*obj_names)); 1752 if (!obj_lf || !obj_in || !obj_names) goto oom; 1753 } 1754 if (o->inputs.narchives) { 1755 arch_lf = driver_alloc_zeroed(env, o->inputs.narchives * sizeof(*arch_lf)); 1756 arch_in = driver_alloc_zeroed(env, o->inputs.narchives * sizeof(*arch_in)); 1757 if (!arch_lf || !arch_in) goto oom; 1758 } 1759 if (o->inputs.ndsos) { 1760 dso_lf = driver_alloc_zeroed(env, o->inputs.ndsos * sizeof(*dso_lf)); 1761 dso_in = driver_alloc_zeroed(env, o->inputs.ndsos * sizeof(*dso_in)); 1762 dso_names = driver_alloc_zeroed(env, o->inputs.ndsos * sizeof(*dso_names)); 1763 if (!dso_lf || !dso_in || !dso_names) goto oom; 1764 } 1765 if (o->inputs.nlink_items) { 1766 order = driver_alloc_zeroed(env, o->inputs.nlink_items * sizeof(*order)); 1767 if (!order) goto oom; 1768 } 1769 1770 for (i = 0; i < o->inputs.nobject_files; ++i) { 1771 if (driver_load_bytes(io, o->tool, o->inputs.object_files[i], &obj_lf[i], 1772 &obj_in[i]) != 0) 1773 goto out; 1774 obj_names[i] = kit_slice_cstr(o->inputs.object_files[i]); 1775 } 1776 /* Strict freestanding policy: pre-built object inputs must agree with the 1777 * link target's arch and object format (a freestanding exe link must not 1778 * silently accept a foreign-arch object). Gated on the same trigger as 1779 * lopts.freestanding_strict so the hosted -ffreestanding -static -no-pie path 1780 * runs this guard too (not only the `*-none-*` target). */ 1781 if (freestanding_strict) { 1782 for (i = 0; i < o->inputs.nobject_files; ++i) { 1783 KitTargetSpec t; 1784 if (kit_detect_target(obj_in[i].data, obj_in[i].len, &t) != KIT_OK) 1785 continue; 1786 if (t.arch != o->target.arch || t.obj != o->target.obj) { 1787 driver_errf(o->tool, 1788 "freestanding link: input '%s' arch/format does not match " 1789 "the link target", 1790 o->inputs.object_files[i]); 1791 goto out; 1792 } 1793 } 1794 } 1795 for (i = 0; i < o->inputs.narchives; ++i) { 1796 if (driver_load_bytes(io, o->tool, o->inputs.archives[i].path, &arch_lf[i], 1797 &arch_in[i].bytes) != 0) 1798 goto out; 1799 arch_in[i].name = kit_slice_cstr(o->inputs.archives[i].path); 1800 arch_in[i].link_mode = o->inputs.archives[i].link_mode; 1801 arch_in[i].whole_archive = 1802 o->inputs.archives[i].whole_archive ? true : false; 1803 arch_in[i].group_id = o->inputs.archives[i].group_id; 1804 } 1805 for (i = 0; i < o->inputs.ndsos; ++i) { 1806 if (driver_load_bytes(io, o->tool, o->inputs.dsos[i].path, &dso_lf[i], 1807 &dso_in[i]) != 0) 1808 goto out; 1809 dso_names[i] = kit_slice_cstr(o->inputs.dsos[i].path); 1810 } 1811 if (o->link.linker_script) { 1812 KitSlice dummy; 1813 if (driver_load_bytes(io, o->tool, o->link.linker_script, &script_lf, 1814 &dummy) != 0) 1815 goto out; 1816 } 1817 1818 if (script_lf.loaded) { 1819 KitSlice text = {.s = (const char*)script_lf.fd.data, 1820 .len = script_lf.fd.size}; 1821 if (kit_link_script_parse(ctx, text, &script) != KIT_OK) goto out; 1822 } 1823 1824 { 1825 memset(<o_batch, 0, sizeof lto_batch); 1826 lto_batch.output_kind = output_kind == KIT_LINK_OUTPUT_SHARED 1827 ? KIT_CG_OUTPUT_SHARED 1828 : KIT_CG_OUTPUT_EXECUTABLE; 1829 lto_batch.interposition_policy = 1830 output_kind == KIT_LINK_OUTPUT_SHARED 1831 ? KIT_CG_INTERPOSITION_DEFAULT_VISIBILITY 1832 : KIT_CG_INTERPOSITION_DEFAULT; 1833 lto_batch.defer_lto_finish = 1; 1834 if (build_compile_all(o, compiler, ctx, code, diag, objs, source_obj_index, 1835 source_order_keep, <o_batch, &pending_lto, 1836 &nobjs) != 0) 1837 goto out; 1838 } 1839 1840 if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0) 1841 goto out; 1842 1843 /* Translate the recorded link order into KitLinkInputOrder. (build never 1844 * records SOURCE_MEMORY items, so nsource_files is immaterial here.) */ 1845 norder = driver_link_inputs_build_order( 1846 &o->inputs, source_obj_index, source_order_keep, o->nsources, order); 1847 1848 { 1849 KitLinkSessionOptions lopts; 1850 KitLinkInputs li; 1851 KitStatus st; 1852 if (driver_link_flags_fill_options( 1853 &o->link, o->target, o->pie, o->shared, 1854 output_kind == KIT_LINK_OUTPUT_RELOCATABLE, output_kind, script, 1855 &lopts, &rpath_slices) != 0) 1856 goto out; 1857 /* Reject dynamic-link artifacts (PT_INTERP, .dynamic/.dynsym, PLT/GOT 1858 * imports, DSO inputs) for the strict freestanding link. Same trigger as 1859 * the per-input arch/format guard above (freestanding_strict). */ 1860 if (freestanding_strict) lopts.freestanding_strict = true; 1861 memset(&li, 0, sizeof(li)); 1862 li.objs = objs; 1863 li.nobjs = nobjs; 1864 li.obj_names = obj_names; 1865 li.obj_bytes = obj_in; 1866 li.nobj_bytes = o->inputs.nobject_files; 1867 li.archives = arch_in; 1868 li.narchives = o->inputs.narchives; 1869 li.dso_names = dso_names; 1870 li.dso_bytes = dso_in; 1871 li.ndsos = o->inputs.ndsos; 1872 li.order = order; 1873 li.norder = norder; 1874 st = build_link_with_lto_reports(o, compiler, ctx, &lopts, &li, 1875 &pending_lto, <o_batch, out_w); 1876 rc = (st == KIT_OK) ? 0 : 1; 1877 } 1878 1879 out: 1880 if (out_w) kit_writer_close(out_w); 1881 if (rc == 0 && output_kind == KIT_LINK_OUTPUT_EXE && 1882 !driver_streq(o->output_path, "-")) { 1883 if (driver_mark_executable_output(o->output_path) != 0) { 1884 driver_errf(o->tool, "failed to set executable mode: %.*s", 1885 KIT_SLICE_ARG(kit_slice_cstr(o->output_path))); 1886 rc = 1; 1887 } 1888 } 1889 if (script) kit_link_script_free(ctx, script); 1890 kit_build_lto_abort(&pending_lto); 1891 driver_link_flags_free_rpath_slices(&o->link, rpath_slices); 1892 driver_release_bytes(io, &script_lf); 1893 if (arch_lf) 1894 for (i = 0; i < o->inputs.narchives; ++i) 1895 driver_release_bytes(io, &arch_lf[i]); 1896 if (dso_lf) 1897 for (i = 0; i < o->inputs.ndsos; ++i) driver_release_bytes(io, &dso_lf[i]); 1898 if (obj_lf) 1899 for (i = 0; i < o->inputs.nobject_files; ++i) 1900 driver_release_bytes(io, &obj_lf[i]); 1901 if (arch_in) 1902 driver_free(env, arch_in, o->inputs.narchives * sizeof(*arch_in)); 1903 if (arch_lf) 1904 driver_free(env, arch_lf, o->inputs.narchives * sizeof(*arch_lf)); 1905 if (dso_in) driver_free(env, dso_in, o->inputs.ndsos * sizeof(*dso_in)); 1906 if (dso_names) 1907 driver_free(env, dso_names, o->inputs.ndsos * sizeof(*dso_names)); 1908 if (dso_lf) driver_free(env, dso_lf, o->inputs.ndsos * sizeof(*dso_lf)); 1909 if (order) driver_free(env, order, o->inputs.nlink_items * sizeof(*order)); 1910 if (obj_in) 1911 driver_free(env, obj_in, o->inputs.nobject_files * sizeof(*obj_in)); 1912 if (obj_names) 1913 driver_free(env, obj_names, o->inputs.nobject_files * sizeof(*obj_names)); 1914 if (obj_lf) 1915 driver_free(env, obj_lf, o->inputs.nobject_files * sizeof(*obj_lf)); 1916 /* The link session borrows the per-source builders (it frees only its own 1917 * pointer array), so the caller still owns and must release them. */ 1918 if (objs) { 1919 for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]); 1920 driver_free(env, objs, o->nsources * sizeof(*objs)); 1921 } 1922 if (source_order_keep) 1923 driver_free(env, source_order_keep, 1924 o->nsources * sizeof(*source_order_keep)); 1925 if (source_obj_index) 1926 driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index)); 1927 return rc; 1928 1929 oom: 1930 driver_errf(o->tool, "out of memory"); 1931 goto out; 1932 } 1933 1934 /* build-obj multi-source: combine into one relocatable object (ld -r). */ 1935 static int build_run_relocatable(BuildOptions* o, KitCompiler* compiler, 1936 const KitContext* ctx, 1937 const KitCodeOptions* code, 1938 const KitDiagnosticOptions* diag) { 1939 DriverEnv* env = o->env; 1940 KitObjBuilder** objs = NULL; 1941 uint32_t* source_obj_index = NULL; 1942 uint8_t* source_order_keep = NULL; 1943 KitLinkInputOrder* order = NULL; 1944 KitBuildPendingLto pending_lto = {0}; 1945 KitWriter* out_w = NULL; 1946 KitBuildBatchOptions lto_batch; 1947 uint32_t nobjs = 0; 1948 uint32_t norder = 0; 1949 uint32_t i; 1950 int rc = 1; 1951 1952 objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs)); 1953 source_obj_index = 1954 driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index)); 1955 source_order_keep = 1956 driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep)); 1957 order = driver_alloc_zeroed(env, o->nsources * sizeof(*order)); 1958 if (!objs || !source_obj_index || !source_order_keep || !order) { 1959 driver_errf(o->tool, "out of memory"); 1960 goto out; 1961 } 1962 { 1963 memset(<o_batch, 0, sizeof lto_batch); 1964 lto_batch.output_kind = KIT_CG_OUTPUT_RELOCATABLE; 1965 lto_batch.interposition_policy = KIT_CG_INTERPOSITION_DEFAULT; 1966 lto_batch.defer_lto_finish = 1; 1967 if (build_compile_all(o, compiler, ctx, code, diag, objs, source_obj_index, 1968 source_order_keep, <o_batch, &pending_lto, 1969 &nobjs) != 0) 1970 goto out; 1971 } 1972 for (i = 0; i < o->nsources; ++i) { 1973 if (!source_order_keep[i]) continue; 1974 order[norder].kind = KIT_LINK_INPUT_OBJ; 1975 order[norder].index = source_obj_index[i]; 1976 ++norder; 1977 } 1978 if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0) 1979 goto out; 1980 { 1981 KitLinkSessionOptions lopts; 1982 KitLinkInputs li; 1983 KitStatus st; 1984 memset(&lopts, 0, sizeof(lopts)); 1985 lopts.output_kind = KIT_LINK_OUTPUT_RELOCATABLE; 1986 lopts.allow_undefined = 1; 1987 lopts.strip_debug = o->link.strip_debug ? true : false; 1988 memset(&li, 0, sizeof(li)); 1989 li.objs = objs; 1990 li.nobjs = nobjs; 1991 li.order = order; 1992 li.norder = norder; 1993 st = kit_build_link_with_lto(compiler, &lopts, &li, &pending_lto, 1994 <o_batch, out_w); 1995 rc = (st == KIT_OK) ? 0 : 1; 1996 } 1997 1998 out: 1999 if (out_w) kit_writer_close(out_w); 2000 kit_build_lto_abort(&pending_lto); 2001 if (order) driver_free(env, order, o->nsources * sizeof(*order)); 2002 /* The link session borrows the builders; release them here (see 2003 * build_run_link). */ 2004 if (objs) { 2005 for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]); 2006 driver_free(env, objs, o->nsources * sizeof(*objs)); 2007 } 2008 if (source_order_keep) 2009 driver_free(env, source_order_keep, 2010 o->nsources * sizeof(*source_order_keep)); 2011 if (source_obj_index) 2012 driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index)); 2013 return rc; 2014 } 2015 2016 /* build-obj wasm multi-source: merge all inputs into one .wasm via CG merge. */ 2017 static int build_run_wasm_module(BuildOptions* o, KitCompiler* compiler, 2018 const KitContext* ctx, 2019 const KitCodeOptions* code, 2020 const KitDiagnosticOptions* diag) { 2021 DriverEnv* env = o->env; 2022 KitObjBuilder** objs = NULL; 2023 uint32_t* source_obj_index = NULL; 2024 uint8_t* source_order_keep = NULL; 2025 KitWriter* out_w = NULL; 2026 KitCodeOptions code2 = *code; 2027 uint32_t nobjs = 0; 2028 uint32_t i; 2029 int rc = 1; 2030 2031 code2.lto = true; 2032 2033 objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs)); 2034 source_obj_index = 2035 driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index)); 2036 source_order_keep = 2037 driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep)); 2038 if (!objs || !source_obj_index || !source_order_keep) { 2039 driver_errf(o->tool, "out of memory"); 2040 goto out; 2041 } 2042 { 2043 KitBuildBatchOptions batch; 2044 memset(&batch, 0, sizeof batch); 2045 batch.output_kind = KIT_CG_OUTPUT_RELOCATABLE; 2046 batch.interposition_policy = KIT_CG_INTERPOSITION_DEFAULT; 2047 if (build_compile_all(o, compiler, ctx, &code2, diag, objs, 2048 source_obj_index, source_order_keep, &batch, NULL, 2049 &nobjs) != 0) 2050 goto out; 2051 } 2052 if (nobjs != 1) { 2053 driver_errf(o->tool, 2054 "build-obj: wasm multi-input expects a single merged module"); 2055 goto out; 2056 } 2057 if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0) 2058 goto out; 2059 rc = (kit_obj_builder_emit(objs[0], out_w) == KIT_OK) ? 0 : 1; 2060 2061 out: 2062 if (out_w) kit_writer_close(out_w); 2063 if (objs) { 2064 for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]); 2065 driver_free(env, objs, o->nsources * sizeof(*objs)); 2066 } 2067 if (source_order_keep) 2068 driver_free(env, source_order_keep, 2069 o->nsources * sizeof(*source_order_keep)); 2070 if (source_obj_index) 2071 driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index)); 2072 return rc; 2073 } 2074 2075 /* build-exe wasm: merge all sources into one .wasm with DCE/internalization. */ 2076 static int build_run_wasm_exe(BuildOptions* o, KitCompiler* compiler, 2077 const KitContext* ctx, const KitCodeOptions* code, 2078 const KitDiagnosticOptions* diag) { 2079 DriverEnv* env = o->env; 2080 KitObjBuilder** objs = NULL; 2081 uint32_t* source_obj_index = NULL; 2082 uint8_t* source_order_keep = NULL; 2083 KitBuildPendingLto pending_lto = {0}; 2084 KitWriter* out_w = NULL; 2085 KitCodeOptions code2 = *code; 2086 uint32_t nobjs = 0; 2087 uint32_t i; 2088 int rc = 1; 2089 2090 code2.lto = true; 2091 2092 objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs)); 2093 source_obj_index = 2094 driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index)); 2095 source_order_keep = 2096 driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep)); 2097 if (!objs || !source_obj_index || !source_order_keep) { 2098 driver_errf(o->tool, "out of memory"); 2099 goto out; 2100 } 2101 { 2102 KitBuildBatchOptions batch; 2103 memset(&batch, 0, sizeof batch); 2104 batch.output_kind = KIT_CG_OUTPUT_EXECUTABLE; 2105 batch.interposition_policy = KIT_CG_INTERPOSITION_NONE; 2106 batch.defer_lto_finish = 1; 2107 if (build_compile_all(o, compiler, ctx, &code2, diag, objs, 2108 source_obj_index, source_order_keep, &batch, 2109 &pending_lto, &nobjs) != 0) 2110 goto out; 2111 } 2112 if (nobjs != 1) { 2113 driver_errf(o->tool, "build-exe: wasm expects a single merged module"); 2114 goto out; 2115 } 2116 { 2117 const char* entry_name = o->link.entry ? o->link.entry : "main"; 2118 KitSym entry_interned = 2119 kit_sym_intern(compiler, kit_slice_cstr(entry_name)); 2120 KitObjSymbol entry_sym = KIT_OBJ_SYMBOL_NONE; 2121 KitBuildBatchOptions batch2; 2122 KitCgSym csym; 2123 2124 if (!entry_interned || 2125 kit_obj_builder_find_symbol(pending_lto.obj, entry_interned, 2126 &entry_sym) != KIT_OK) { 2127 driver_errf(o->tool, "build-exe: entry symbol '%s' not found in module", 2128 entry_name); 2129 goto out; 2130 } 2131 csym = (KitCgSym)entry_sym; 2132 memset(&batch2, 0, sizeof batch2); 2133 batch2.output_kind = KIT_CG_OUTPUT_EXECUTABLE; 2134 batch2.interposition_policy = KIT_CG_INTERPOSITION_NONE; 2135 if (kit_build_lto_finish(&pending_lto, &batch2, &csym, 1) != 2136 KIT_OK) { 2137 driver_errf(o->tool, "build-exe: LTO finish failed"); 2138 goto out; 2139 } 2140 kit_obj_builder_wasm_add_custom(objs[0], KIT_SLICE_LIT("kit-entry"), 2141 kit_slice_cstr(entry_name)); 2142 } 2143 if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0) 2144 goto out; 2145 rc = (kit_obj_builder_emit(objs[0], out_w) == KIT_OK) ? 0 : 1; 2146 2147 out: 2148 if (out_w) kit_writer_close(out_w); 2149 if (pending_lto.active) kit_build_lto_abort(&pending_lto); 2150 if (objs) { 2151 for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]); 2152 driver_free(env, objs, o->nsources * sizeof(*objs)); 2153 } 2154 if (source_order_keep) 2155 driver_free(env, source_order_keep, 2156 o->nsources * sizeof(*source_order_keep)); 2157 if (source_obj_index) 2158 driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index)); 2159 return rc; 2160 } 2161 2162 /* build-lib static: archive every compiled source object. */ 2163 static int build_run_archive(BuildOptions* o, KitCompiler* compiler, 2164 const KitContext* ctx, const KitCodeOptions* code, 2165 const KitDiagnosticOptions* diag) { 2166 DriverEnv* env = o->env; 2167 KitObjBuilder** objs = NULL; 2168 uint32_t* source_obj_index = NULL; 2169 uint8_t* source_order_keep = NULL; 2170 KitSlice* names = NULL; 2171 char** owned_names = NULL; 2172 size_t* owned_name_sizes = NULL; 2173 KitWriter* out_w = NULL; 2174 uint32_t nobjs = 0; 2175 uint32_t i; 2176 int rc = 1; 2177 2178 objs = driver_alloc_zeroed(env, o->nsources * sizeof(*objs)); 2179 source_obj_index = 2180 driver_alloc_zeroed(env, o->nsources * sizeof(*source_obj_index)); 2181 source_order_keep = 2182 driver_alloc_zeroed(env, o->nsources * sizeof(*source_order_keep)); 2183 names = driver_alloc_zeroed(env, o->nsources * sizeof(*names)); 2184 owned_names = driver_alloc_zeroed(env, o->nsources * sizeof(*owned_names)); 2185 owned_name_sizes = 2186 driver_alloc_zeroed(env, o->nsources * sizeof(*owned_name_sizes)); 2187 if (!objs || !source_obj_index || !source_order_keep || !names || 2188 !owned_names || !owned_name_sizes) { 2189 driver_errf(o->tool, "out of memory"); 2190 goto out; 2191 } 2192 { 2193 KitBuildBatchOptions batch; 2194 memset(&batch, 0, sizeof batch); 2195 batch.output_kind = KIT_CG_OUTPUT_ARCHIVE_MEMBER; 2196 batch.interposition_policy = KIT_CG_INTERPOSITION_DEFAULT; 2197 if (build_compile_all(o, compiler, ctx, code, diag, objs, source_obj_index, 2198 source_order_keep, &batch, NULL, &nobjs) != 0) 2199 goto out; 2200 } 2201 /* build-lib always emits objects (validated), so build_default_obj_name 2202 * yields the right `.o`/`.obj` member name. */ 2203 for (i = 0; i < o->nsources; ++i) { 2204 uint32_t oi; 2205 if (!source_order_keep[i]) continue; 2206 oi = source_obj_index[i]; 2207 owned_names[oi] = build_default_obj_name(env, o, o->sources[i].path, 2208 &owned_name_sizes[oi]); 2209 if (!owned_names[oi]) { 2210 driver_errf(o->tool, "out of memory"); 2211 goto out; 2212 } 2213 names[oi] = kit_slice_cstr(owned_names[oi]); 2214 } 2215 if (build_open_output(ctx, env, o->tool, o->output_path, &out_w) != 0) 2216 goto out; 2217 rc = driver_archive_emit(env, ctx, o->tool, objs, names, nobjs, o->epoch, 2218 out_w); 2219 2220 out: 2221 if (out_w) kit_writer_close(out_w); 2222 if (objs) 2223 for (i = 0; i < nobjs; ++i) kit_obj_builder_free(objs[i]); 2224 if (owned_names) { 2225 for (i = 0; i < o->nsources; ++i) 2226 if (owned_names[i]) driver_free(env, owned_names[i], owned_name_sizes[i]); 2227 } 2228 if (objs) driver_free(env, objs, o->nsources * sizeof(*objs)); 2229 if (source_order_keep) 2230 driver_free(env, source_order_keep, 2231 o->nsources * sizeof(*source_order_keep)); 2232 if (source_obj_index) 2233 driver_free(env, source_obj_index, o->nsources * sizeof(*source_obj_index)); 2234 if (names) driver_free(env, names, o->nsources * sizeof(*names)); 2235 if (owned_names) 2236 driver_free(env, owned_names, o->nsources * sizeof(*owned_names)); 2237 if (owned_name_sizes) 2238 driver_free(env, owned_name_sizes, o->nsources * sizeof(*owned_name_sizes)); 2239 return rc; 2240 } 2241 2242 /* build-lib --emit=c: merge semantic sources into one C translation unit. */ 2243 static int build_run_c_tu(BuildOptions* o, KitCompiler* compiler, 2244 const KitContext* ctx, const KitCodeOptions* code, 2245 const KitDiagnosticOptions* diag) { 2246 BuildSourceBatch sources; 2247 KitBuildBatchOptions batch; 2248 KitWriter* out_w = NULL; 2249 uint32_t i; 2250 int rc = 1; 2251 2252 if (build_source_batch_init(o, compiler, ctx, &sources) != 0) return 1; 2253 for (i = 0; i < o->nsources; ++i) { 2254 KitFrontendCaps caps; 2255 memset(&caps, 0, sizeof caps); 2256 if (kit_frontend_caps(compiler, sources.sources[i].lang, &caps) != KIT_OK || 2257 caps.lto_mode != KIT_FRONTEND_LTO_CG) { 2258 driver_errf(o->tool, 2259 "cannot emit C for %.*s: the %.*s frontend is object-only", 2260 KIT_SLICE_ARG(sources.sources[i].name), 2261 KIT_SLICE_ARG(kit_slice_cstr(kit_language_name( 2262 compiler, sources.sources[i].lang)))); 2263 goto out; 2264 } 2265 } 2266 if (build_open_output(ctx, o->env, o->tool, o->output_path, &out_w) != 0) 2267 goto out; 2268 2269 memset(&batch, 0, sizeof batch); 2270 batch.output_kind = KIT_CG_OUTPUT_ARCHIVE_MEMBER; 2271 batch.interposition_policy = KIT_CG_INTERPOSITION_DEFAULT; 2272 if (kit_build_emit_c(compiler, code, diag, sources.sources, o->nsources, 2273 &batch, out_w) != KIT_OK) { 2274 driver_errf(o->tool, "failed to emit C translation unit"); 2275 goto out; 2276 } 2277 rc = 0; 2278 2279 out: 2280 if (out_w) kit_writer_close(out_w); 2281 build_source_batch_fini(o, compiler, ctx, &sources); 2282 return rc; 2283 } 2284 2285 /* build-obj per-source: check-only, or one output per source (obj/asm/c/ir). */ 2286 static int build_run_per_source(BuildOptions* o, KitCompiler* compiler, 2287 const KitContext* ctx, 2288 const KitCodeOptions* code_in, 2289 const KitDiagnosticOptions* diag) { 2290 DriverEnv* env = o->env; 2291 KitCodeOptions code = *code_in; 2292 uint32_t i; 2293 2294 code.emit_asm_source = (o->emit == BUILD_EMIT_ASM) ? true : false; 2295 code.emit_c_source = (o->emit == BUILD_EMIT_C) ? true : false; 2296 code.emit_ir = (o->emit == BUILD_EMIT_IR) ? true : false; 2297 2298 for (i = 0; i < o->nsources; ++i) { 2299 if (o->syntax_only) { 2300 KitObjBuilder* ob = NULL; 2301 int rc = 2302 build_compile_source(o, compiler, ctx, i, &code, diag, NULL, &ob); 2303 kit_obj_builder_free(ob); 2304 if (rc != 0) return rc; 2305 continue; 2306 } 2307 { 2308 const char* out_path = o->output_path; 2309 char* owned = NULL; 2310 size_t owned_size = 0; 2311 KitWriter* w = NULL; 2312 int rc; 2313 if (!out_path) { 2314 owned = build_default_obj_name(env, o, o->sources[i].path, &owned_size); 2315 if (!owned) { 2316 driver_errf(o->tool, "out of memory"); 2317 return 1; 2318 } 2319 out_path = owned; 2320 } 2321 if (build_open_output(ctx, env, o->tool, out_path, &w) != 0) { 2322 if (owned) driver_free(env, owned, owned_size); 2323 return 1; 2324 } 2325 rc = build_compile_source(o, compiler, ctx, i, &code, diag, w, NULL); 2326 kit_writer_close(w); 2327 if (owned) driver_free(env, owned, owned_size); 2328 if (rc != 0) return rc; 2329 } 2330 } 2331 return 0; 2332 } 2333 2334 /* ===================================================================== */ 2335 /* validation */ 2336 /* ===================================================================== */ 2337 2338 static int build_validate(BuildOptions* o) { 2339 uint32_t total_link = o->inputs.nobject_files + o->inputs.narchives + 2340 o->inputs.ndsos + o->inputs.npending_libs + 2341 o->inputs.npending_frameworks; 2342 2343 if (o->nsources == 0 && total_link == 0) { 2344 driver_errf(o->tool, "no input files"); 2345 return 1; 2346 } 2347 if (o->kind != BUILD_OUT_EXE && (o->link.map_path || o->link.symbols_path)) { 2348 driver_errf(o->tool, "--map/--symbols are only valid for build-exe"); 2349 return 1; 2350 } 2351 2352 /* -dynamic selects the default executable link mode for build-exe and the 2353 * not-yet-supported shared-library mode for build-lib. -shared is the GCC 2354 * spelling for producing a shared library, so build-exe rejects it. */ 2355 2356 if (o->kind == BUILD_OUT_EXE) { 2357 if (o->shared_requested) { 2358 driver_errf(o->tool, "-shared is not valid for build-exe"); 2359 return 1; 2360 } 2361 if (o->emit != BUILD_EMIT_OBJ || o->syntax_only) { 2362 driver_errf(o->tool, "--emit/-S/-fsyntax-only are build-obj options"); 2363 return 1; 2364 } 2365 if (!o->output_path) { 2366 o->output_path = (o->target.obj == KIT_OBJ_WASM) 2367 ? "a.wasm" 2368 : driver_default_exe_name(o->target); 2369 } 2370 if (o->target.obj == KIT_OBJ_WASM) { 2371 uint32_t total_link = o->inputs.nobject_files + o->inputs.narchives + 2372 o->inputs.ndsos + o->inputs.npending_libs + 2373 o->inputs.npending_frameworks; 2374 if (total_link) { 2375 driver_errf(o->tool, 2376 "build-exe -target wasm32-none accepts only source files " 2377 "(no .o / .a / -l inputs)"); 2378 return 1; 2379 } 2380 if (o->link.map_path || o->link.symbols_path) { 2381 driver_errf(o->tool, 2382 "--map/--symbols require the native linker path"); 2383 return 1; 2384 } 2385 } 2386 return 0; 2387 } 2388 2389 if (o->kind == BUILD_OUT_LIB) { 2390 if ((o->emit != BUILD_EMIT_OBJ && o->emit != BUILD_EMIT_C) || 2391 o->syntax_only) { 2392 driver_errf(o->tool, 2393 "build-lib supports object output or --emit=c; " 2394 "-S/--emit=ir/-fsyntax-only are build-obj options"); 2395 return 1; 2396 } 2397 if (o->emit == BUILD_EMIT_C && o->dynamic) { 2398 driver_errf(o->tool, "--emit=c is incompatible with -dynamic/-shared"); 2399 return 1; 2400 } 2401 if (total_link != 0) { 2402 driver_errf(o->tool, 2403 "build-lib takes only sources; pass .o/.a/-l to build-exe"); 2404 return 1; 2405 } 2406 if (o->nsources == 0) { 2407 driver_errf(o->tool, "no source files"); 2408 return 1; 2409 } 2410 if (!o->output_path) { 2411 driver_errf(o->tool, "-o is required (no default library name)"); 2412 return 1; 2413 } 2414 return 0; 2415 } 2416 2417 /* build-obj */ 2418 if (total_link != 0) { 2419 driver_errf(o->tool, 2420 "build-obj takes only sources; pass .o/.a/-l to build-exe"); 2421 return 1; 2422 } 2423 if (o->nsources == 0) { 2424 driver_errf(o->tool, "no source files"); 2425 return 1; 2426 } 2427 if (o->dynamic) { 2428 driver_errf(o->tool, "-dynamic/-shared is only valid for build-lib"); 2429 return 1; 2430 } 2431 if (o->syntax_only) { 2432 if (o->output_path) { 2433 driver_errf(o->tool, "-o is incompatible with -fsyntax-only"); 2434 return 1; 2435 } 2436 return 0; 2437 } 2438 if (o->emit == BUILD_EMIT_IR && o->opt_level < 1) { 2439 driver_errf(o->tool, 2440 "--emit=ir requires -O1 or higher (the IR tape is only " 2441 "recorded when the optimizer runs)"); 2442 return 1; 2443 } 2444 if (o->emit == BUILD_EMIT_OBJ && o->nsources > 1) { 2445 /* relocatable combine */ 2446 if (!o->output_path) { 2447 driver_errf(o->tool, 2448 "-o is required to combine multiple sources into one object"); 2449 return 1; 2450 } 2451 return 0; 2452 } 2453 /* per-source emit (single obj, or asm/c/ir) */ 2454 if (o->output_path && o->nsources > 1) { 2455 driver_errf(o->tool, "-o cannot be used with multiple sources"); 2456 return 1; 2457 } 2458 if (o->emit == BUILD_EMIT_C && !o->output_path) { 2459 driver_errf(o->tool, "--emit=c requires -o"); 2460 return 1; 2461 } 2462 return 0; 2463 } 2464 2465 /* ===================================================================== */ 2466 /* driver */ 2467 /* ===================================================================== */ 2468 2469 static int build_apply_env(BuildOptions* o) { 2470 const char* sde = driver_getenv("SOURCE_DATE_EPOCH"); 2471 if (sde && driver_parse_u64(sde, &o->epoch) != 0) { 2472 driver_errf(o->tool, "invalid SOURCE_DATE_EPOCH: %.*s", 2473 KIT_SLICE_ARG(kit_slice_cstr(sde))); 2474 return 1; 2475 } 2476 return 0; 2477 } 2478 2479 static int build_record_framework(BuildOptions* o, const char* name) { 2480 DriverPendingFramework* pf; 2481 if (!name || !name[0]) { 2482 driver_errf(o->tool, "-framework requires an argument"); 2483 return 1; 2484 } 2485 pf = &o->inputs.pending_frameworks[o->inputs.npending_frameworks++]; 2486 pf->name = name; 2487 driver_link_inputs_push(&o->inputs, DRIVER_LINK_FRAMEWORK, 2488 o->inputs.npending_frameworks - 1u); 2489 return 0; 2490 } 2491 2492 static int build_main(int argc, char** argv, int kind, const char* tool, 2493 const KitDriverExtension* ext) { 2494 DriverEnv env; 2495 BuildOptions o = {0}; 2496 DriverRuntimeSupport runtime = {0}; 2497 int runtime_resolved = 0; 2498 KitContext ctx; 2499 KitTarget* target = NULL; 2500 KitCompiler* compiler = NULL; 2501 KitCodeOptions code; 2502 KitDiagnosticOptions diag = {0}; 2503 uint32_t gi; 2504 int rc = 2; 2505 2506 driver_env_init(&env); 2507 ctx = driver_env_to_context(&env); 2508 o.env = &env; 2509 o.tool = tool; 2510 o.kind = kind; 2511 o.driver_path = argv[0]; 2512 2513 if (kit_frontend_registry_new(&ctx, &o.frontends) != KIT_OK || 2514 kit_frontend_registry_add_builtin(o.frontends) != KIT_OK || 2515 (ext && ext->register_frontends && 2516 ext->register_frontends(o.frontends) != KIT_OK)) { 2517 driver_errf(tool, "failed to initialize frontend registry"); 2518 rc = 1; 2519 goto done; 2520 } 2521 2522 if (build_alloc(&o, argc) != 0) { 2523 rc = 2; 2524 goto done; 2525 } 2526 if (build_parse(argc, argv, &o) != 0) goto done; 2527 if (build_apply_env(&o) != 0) goto done; 2528 2529 o.shared = (o.kind == BUILD_OUT_LIB && o.dynamic && 2530 o.emit == BUILD_EMIT_OBJ); 2531 if (o.shared && !o.pic_explicit) o.target.pic = KIT_PIC_PIC; 2532 if (o.shared && o.target.obj != KIT_OBJ_ELF) { 2533 driver_errf(tool, "-shared output is supported only for ELF targets in v1"); 2534 goto done; 2535 } 2536 if (o.shared && o.target.pic == KIT_PIC_NONE) { 2537 driver_errf(tool, "-shared requires PIC input; remove -fno-pic/-static"); 2538 goto done; 2539 } 2540 2541 if (build_validate(&o) != 0) goto done; 2542 2543 /* Freestanding runtime headers so C/asm #includes resolve (mirrors compile); 2544 * for link outputs, also the runtime archive + hosted libc wiring. */ 2545 if (driver_runtime_resolve(&env, o.support_dir, o.driver_path, &runtime) == 2546 0) { 2547 runtime_resolved = 1; 2548 } else { 2549 driver_errf(tool, "support dir not found"); 2550 rc = 1; 2551 goto done; 2552 } 2553 2554 /* Hosted defines/includes are a compile property and therefore apply to 2555 * build-obj/build-lib as well as executable links. Link-only search paths, 2556 * CRT objects, and libraries stay inside the link-output branch below. */ 2557 build_enable_hosted_for_sysroot(&o); 2558 build_apply_default_hosted_profile(&o); 2559 if (build_apply_hosted_profile(&o) != 0) { 2560 rc = 1; 2561 goto done; 2562 } 2563 /* Hosted system headers precede Kit's freestanding fallback headers. This 2564 * keeps <stdlib.h> on the native SDK while retaining compiler builtins that 2565 * the SDK does not provide. */ 2566 if (!o.nostdinc && 2567 (o.hosted.profile_name 2568 ? driver_runtime_append_freestanding_headers(&runtime, 2569 &o.groups[0].cf) 2570 : driver_runtime_add_freestanding_headers(&runtime, 2571 &o.groups[0].cf)) != 0) { 2572 driver_errf(tool, "failed to add freestanding headers"); 2573 rc = 1; 2574 goto done; 2575 } 2576 2577 if (build_is_link_output(&o)) { 2578 if (driver_link_inputs_append_windows_lib_dirs(&o.inputs, &o.sysroot, 2579 o.target) != 0) { 2580 rc = 1; 2581 goto done; 2582 } 2583 if (driver_link_inputs_append_sysroot_framework_dirs(&o.inputs, &o.sysroot, 2584 o.target) != 0) { 2585 rc = 1; 2586 goto done; 2587 } 2588 if (driver_link_inputs_resolve_pending(&o.inputs, o.target, 2589 o.static_link) != 0) { 2590 rc = 1; 2591 goto done; 2592 } 2593 if (o.target.os == KIT_OS_FREESTANDING && o.inputs.ndsos) { 2594 driver_errf(tool, "freestanding executable links do not accept DSO inputs"); 2595 rc = 1; 2596 goto done; 2597 } 2598 if ((!o.shared || driver_target_shared_uses_hosted(o.target)) && 2599 !o.no_stdlib && !o.no_defaultlibs) { 2600 DriverRuntimeArchive rt = {0}; 2601 if (driver_runtime_prepare_archive(&env, tool, &runtime, o.target, 2602 o.epoch, &rt) != 0) { 2603 driver_runtime_archive_fini(&env, &rt); 2604 rc = 1; 2605 goto done; 2606 } 2607 driver_link_inputs_insert_runtime_archives( 2608 &o.inputs, &rt, o.target, o.hosted.nfinal, o.hosted.nafter); 2609 driver_runtime_archive_fini(&env, &rt); 2610 } 2611 } else if (o.inputs.npending_libs || o.inputs.npending_frameworks) { 2612 driver_errf(tool, "-l/-framework are only valid for build-exe"); 2613 rc = 1; 2614 goto done; 2615 } 2616 2617 /* Build per-group merged preprocessor views now that the global baseline 2618 * (groups[0]) holds the runtime/hosted includes and defines. */ 2619 for (gi = 0; gi < o.ngroups; ++gi) { 2620 if (build_group_build_pp(&o, gi) != 0) { 2621 rc = 1; 2622 goto done; 2623 } 2624 } 2625 2626 if (driver_target_new(&ctx, o.target, &o.target_features, tool, &target) != 2627 KIT_OK) { 2628 driver_errf(tool, "failed to initialize compiler"); 2629 rc = 1; 2630 goto done; 2631 } 2632 { 2633 KitCompilerOptions copts; 2634 memset(&copts, 0, sizeof copts); 2635 copts.frontends = o.frontends; 2636 if (kit_compiler_new_ex(target, &ctx, &copts, &compiler) != KIT_OK) { 2637 driver_errf(tool, "failed to initialize compiler"); 2638 rc = 1; 2639 goto done; 2640 } 2641 driver_diag_set_compiler(compiler); 2642 } 2643 2644 build_fill_code(&o, &code); 2645 diag.warnings_are_errors = o.warnings_are_errors ? true : false; 2646 diag.max_errors = o.max_errors; 2647 2648 if (o.kind == BUILD_OUT_EXE) { 2649 if (o.target.obj == KIT_OBJ_WASM) 2650 rc = build_run_wasm_exe(&o, compiler, &ctx, &code, &diag); 2651 else 2652 rc = 2653 build_run_link(&o, compiler, &ctx, &code, &diag, KIT_LINK_OUTPUT_EXE); 2654 } else if (o.kind == BUILD_OUT_LIB) { 2655 if (o.emit == BUILD_EMIT_C) 2656 rc = build_run_c_tu(&o, compiler, &ctx, &code, &diag); 2657 else if (o.shared) 2658 rc = build_run_link(&o, compiler, &ctx, &code, &diag, 2659 KIT_LINK_OUTPUT_SHARED); 2660 else 2661 rc = build_run_archive(&o, compiler, &ctx, &code, &diag); 2662 } else if (o.syntax_only) { 2663 rc = build_run_per_source(&o, compiler, &ctx, &code, &diag); 2664 } else if (o.emit == BUILD_EMIT_OBJ && o.nsources > 1 && 2665 o.target.obj == KIT_OBJ_WASM) { 2666 rc = build_run_wasm_module(&o, compiler, &ctx, &code, &diag); 2667 } else if (o.emit == BUILD_EMIT_OBJ && o.nsources > 1) { 2668 rc = build_run_relocatable(&o, compiler, &ctx, &code, &diag); 2669 } else { 2670 rc = build_run_per_source(&o, compiler, &ctx, &code, &diag); 2671 } 2672 2673 if (rc == 0 && 2674 driver_diag_finish(&env, tool, o.warnings_are_errors, o.max_errors)) 2675 rc = 1; 2676 2677 done: 2678 if (compiler) driver_compiler_free(compiler); 2679 kit_target_free(target); 2680 if (runtime_resolved) driver_runtime_support_fini(&env, &runtime); 2681 build_release(&o); 2682 if (o.frontends) kit_frontend_registry_free(o.frontends); 2683 driver_env_fini(&env); 2684 return rc; 2685 } 2686 2687 /* ===================================================================== */ 2688 /* help + entry points */ 2689 /* ===================================================================== */ 2690 2691 void driver_help_build_exe(void) { 2692 driver_printf( 2693 "%.*s", 2694 KIT_SLICE_ARG(KIT_SLICE_LIT( 2695 "kit build-exe — link a polyglot source set into an executable\n" 2696 "\n" 2697 "USAGE\n" 2698 " kit build-exe [options] inputs...\n" 2699 "\n" 2700 "DESCRIPTION\n" 2701 " Compiles registered source languages (language per file) in memory\n" 2702 " and links them with any .o/.a/.so inputs into one executable. No\n" 2703 " intermediate files. For -target wasm32-none, inputs must be\n" 2704 " sources supplied in this invocation; .o/.a/-l Wasm linking is not\n" 2705 " a v1 feature.\n" 2706 "\n" 2707 "INPUTS\n" 2708 " Registered sources are C (.c), assembly (.s/.S), and WebAssembly\n" 2709 " (.wat/.wasm), selected by suffix or -x. Native links may also\n" 2710 " consume target-compatible .o, .a, and ELF .so inputs.\n" 2711 "\n" 2712 "OPTIONS\n" 2713 " -o PATH Output (default a.out / a.exe)\n" 2714 " -O0 -O1 -O2 -g Optimization / debug info (-O2 aliases " 2715 "-O1)\n" 2716 " -target TRIPLE Cross-compile target\n" 2717 " --sysroot DIR User-supplied hosted cross sysroot\n" 2718 " -isysroot DIR Hosted SDK/sysroot include root\n" 2719 " --support-dir DIR Kit distribution support root\n" 2720 " -arch ARCH Darwin-style target architecture\n" 2721 " -platform_version P MIN SDK\n" 2722 " Darwin-style target platform\n" 2723 " -flto Link-time optimization for source inputs\n" 2724 " -static Fully static executable\n" 2725 " -l NAME -L DIR Link a library / add a search dir\n" 2726 " -framework NAME -F DIR\n" 2727 " Link a Darwin framework / add a search dir\n" 2728 " -e SYM -T script.ld Entry symbol / linker script\n" 2729 " -Wl,... Linker pass-through\n" 2730 " --group [flags] -- sources... Scope compile flags to sources\n" 2731 " -X<lang> FLAG Per-language frontend flag\n" 2732 " -h, --help Show this help\n" 2733 " --version Show Kit version\n" 2734 "\n" 2735 "DISCOVERY AND REQUIREMENTS\n" 2736 " Relocated distributions discover sibling support automatically;\n" 2737 " --support-dir remains an authoritative override. Native macOS uses\n" 2738 " the discovered SDK by default. Hosted cross builds require --sysroot.\n" 2739 "\n" 2740 "EXAMPLES\n" 2741 " kit build-exe main.c util.c -o app\n" 2742 "\n" 2743 " # Flag-scoped C groups plus an assembly source.\n" 2744 " kit build-exe --group -DLEFT=20 -- left.c \\\n" 2745 " --group -DRIGHT=22 -- right.c main.c helper.s -o grouped\n" 2746 "\n" 2747 " # Freestanding: provide startup code and a linker script.\n" 2748 " kit build-exe \\\n" 2749 " -target aarch64-none-elf -T link.ld -e _start \\\n" 2750 " start.s kernel.c -o kernel.elf\n" 2751 "\n" 2752 "EXIT CODES\n" 2753 " 0 success 1 compile/link/I/O error 2 bad usage\n"))); 2754 } 2755 2756 void driver_help_build_lib(void) { 2757 driver_printf( 2758 "%.*s", 2759 KIT_SLICE_ARG(KIT_SLICE_LIT( 2760 "kit build-lib — build a library or one C translation unit\n" 2761 "\n" 2762 "USAGE\n" 2763 " kit build-lib -o LIB.a [options] sources...\n" 2764 " kit build-lib --emit=c -o LIB.c [options] sources...\n" 2765 " kit build-lib -dynamic -o LIB.so [options] sources...\n" 2766 "\n" 2767 "DESCRIPTION\n" 2768 " Compiles a polyglot source set in memory and archives the " 2769 "objects\n" 2770 " into a static library (.a), or links an ELF shared library with\n" 2771 " -dynamic/-shared. --emit=c merges semantic sources into one\n" 2772 " target-locked C translation unit. Non-ELF shared-library output\n" 2773 " is rejected.\n" 2774 "\n" 2775 "INPUTS\n" 2776 " Registered sources are C (.c), assembly (.s/.S), and WebAssembly\n" 2777 " (.wat/.wasm), selected by suffix or -x. --emit=c accepts semantic\n" 2778 " frontends (C, Toy, Wasm), not standalone assembly. Native ELF\n" 2779 " dynamic links may also consume compatible link inputs.\n" 2780 "\n" 2781 "OPTIONS\n" 2782 " -o PATH Output path (required)\n" 2783 " --emit=c Emit one C translation unit\n" 2784 " -dynamic, -shared Build an ELF shared library\n" 2785 " -fPIC Position-independent code\n" 2786 " -O0 -O1 -O2 -g Optimization / debug info (-O2 aliases " 2787 "-O1)\n" 2788 " -flto Link-time optimization for source inputs\n" 2789 " -target TRIPLE Cross-compile target\n" 2790 " --sysroot DIR User-supplied hosted cross sysroot\n" 2791 " -isysroot DIR Hosted SDK/sysroot include root\n" 2792 " --support-dir DIR Kit distribution support root\n" 2793 " -L DIR, -l NAME Shared-link library search/input\n" 2794 " --group [flags] -- sources... Scope compile flags to sources\n" 2795 " -X<lang> FLAG Per-language frontend flag\n" 2796 " -h, --help Show this help\n" 2797 " --version Show Kit version\n" 2798 "\n" 2799 "DISCOVERY AND REQUIREMENTS\n" 2800 " Relocated distributions discover sibling support automatically.\n" 2801 " Native macOS discovers its SDK; hosted cross targets require an\n" 2802 " explicit sysroot. Static .a output is the portable library shape;\n" 2803 " -dynamic/-shared is ELF-only. Generated C must be compiled for the\n" 2804 " same target selected here because its layouts are target-locked.\n" 2805 "\n" 2806 "EXAMPLES\n" 2807 " kit build-lib \\\n" 2808 " -o libanswer.a answer.c helper.s\n" 2809 "\n" 2810 " kit build-lib --emit=c -o answer_amalgam.c answer.c helper.c\n" 2811 "\n" 2812 " # Replace SYSROOT with a supplied x86-64 Linux sysroot.\n" 2813 " SYSROOT=/replace/with/x86_64-linux-sysroot\n" 2814 " kit build-lib \\\n" 2815 " -target x86_64-linux-gnu --sysroot \"$SYSROOT\" \\\n" 2816 " -dynamic -fPIC -o libanswer.so answer.c\n" 2817 "\n" 2818 "EXIT CODES\n" 2819 " 0 success 1 compile/link/I/O error 2 bad usage\n"))); 2820 } 2821 2822 void driver_help_build_obj(void) { 2823 driver_printf( 2824 "%.*s", 2825 KIT_SLICE_ARG(KIT_SLICE_LIT( 2826 "kit build-obj — compile sources to an object (or asm / C / IR)\n" 2827 "\n" 2828 "USAGE\n" 2829 " kit build-obj [options] sources...\n" 2830 "\n" 2831 "DESCRIPTION\n" 2832 " Compiles each source (registered language by suffix or -x) to an\n" 2833 " object. Multiple sources with --emit=obj combine into one\n" 2834 " relocatable object (ld -r), except -target wasm32-none merges the\n" 2835 " same source batch into one final wasm32 module. Separate Wasm\n" 2836 " object/static linking is not a v1 feature. The kit-native\n" 2837 " replacement for the retired `compile` tool.\n" 2838 "\n" 2839 "REGISTERED LANGUAGES\n" 2840 " C (.c), assembly (.s/.S), and WebAssembly (.wat/.wasm), selected\n" 2841 " by suffix or -x c|asm|wat|wasm. Frontend-specific options use\n" 2842 " -X<lang> FLAG.\n" 2843 "\n" 2844 "OPTIONS\n" 2845 " -o PATH Output (default <base>.o; required for a\n" 2846 " multi-source combine and for --emit=c)\n" 2847 " --emit=obj|asm|c|ir Output form (ir requires -O1+)\n" 2848 " -S Alias for --emit=asm\n" 2849 " -fsyntax-only Check only; write no output\n" 2850 " -O0 -O1 -O2 -g Optimization / debug info (-O2 aliases " 2851 "-O1)\n" 2852 " -flto Link-time optimization for multi-source " 2853 "obj\n" 2854 " -target TRIPLE Cross-compile target\n" 2855 " --sysroot DIR User-supplied hosted cross sysroot\n" 2856 " -isysroot DIR Hosted SDK/sysroot include root\n" 2857 " --support-dir DIR Kit distribution support root\n" 2858 " -I/-isystem/-D/-U Preprocessor flags (C/asm frontends)\n" 2859 " -x LANG Force a registered language\n" 2860 " --group [flags] -- sources... Scope compile flags to sources\n" 2861 " -X<lang> FLAG Per-language frontend flag\n" 2862 " -o - Write the emit to stdout\n" 2863 " -h, --help Show this help\n" 2864 " --version Show Kit version\n" 2865 "\n" 2866 "OUTPUT AND RELEASE NOTES\n" 2867 " One-source object/assembly output defaults to <base>.o/.s. -o is\n" 2868 " required for multi-source object combination and --emit=c; use\n" 2869 " -o for stable IR filenames. -fsyntax-only writes nothing. A\n" 2870 " relocated distribution discovers sibling support automatically.\n" 2871 " Native macOS discovers its SDK; hosted cross targets require an\n" 2872 " explicit sysroot. Portable-C output uses the\n" 2873 " -O0 semantic pipeline; -O1/-O2 are accepted and normalized to -O0.\n" 2874 "\n" 2875 "EXAMPLES\n" 2876 " kit build-obj main.c\n" 2877 " kit build-obj \\\n" 2878 " main.c helper.c -o combined.o\n" 2879 " kit build-obj \\\n" 2880 " --emit=asm source.c -o source.s\n" 2881 " kit build-obj \\\n" 2882 " --emit=c -O0 source.c -o portable.c\n" 2883 " kit build-obj \\\n" 2884 " --emit=ir -O1 source.c -o source.ir\n" 2885 " kit build-obj \\\n" 2886 " -fsyntax-only -I include source.c\n" 2887 "\n" 2888 "EXIT CODES\n" 2889 " 0 success 1 frontend/link/I/O error 2 bad usage\n"))); 2890 } 2891 2892 int driver_build_exe_ex(int argc, char** argv, const KitDriverExtension* ext) { 2893 if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) { 2894 driver_help_build_exe(); 2895 return 0; 2896 } 2897 return build_main(argc, argv, BUILD_OUT_EXE, "build-exe", ext); 2898 } 2899 2900 int driver_build_lib_ex(int argc, char** argv, const KitDriverExtension* ext) { 2901 if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) { 2902 driver_help_build_lib(); 2903 return 0; 2904 } 2905 return build_main(argc, argv, BUILD_OUT_LIB, "build-lib", ext); 2906 } 2907 2908 int driver_build_obj_ex(int argc, char** argv, const KitDriverExtension* ext) { 2909 if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) { 2910 driver_help_build_obj(); 2911 return 0; 2912 } 2913 return build_main(argc, argv, BUILD_OUT_OBJ, "build-obj", ext); 2914 } 2915 2916 int driver_build_exe(int argc, char** argv) { 2917 return driver_build_exe_ex(argc, argv, NULL); 2918 } 2919 2920 int driver_build_lib(int argc, char** argv) { 2921 return driver_build_lib_ex(argc, argv, NULL); 2922 } 2923 2924 int driver_build_obj(int argc, char** argv) { 2925 return driver_build_obj_ex(argc, argv, NULL); 2926 }