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