target.c (28511B)
1 /* Public target-triple parsing + per-target defaults. 2 * 3 * The triple<->KitTargetSpec string layer and the spec-derived defaults 4 * (PIC/PIE, default output names/extensions, hosted-profile gating). Pure 5 * computation: no host I/O, no diagnostics — callers turn a false/0 return into 6 * whatever message they like. Hoisted out of the CLI driver so the spelling 7 * tables here are the single authority every embedder shares. 8 */ 9 10 #include <kit/target.h> 11 12 #include <kit/config.h> 13 #include <kit/os.h> 14 #include <stddef.h> 15 #include <stdint.h> 16 #include <stdio.h> 17 #include <string.h> 18 19 static bool triple_tok_eq(const char* s, size_t n, const char* lit) { 20 size_t l = strlen(lit); 21 return n == l && memcmp(s, lit, n) == 0; 22 } 23 24 /* Prefix match for OS tokens that carry a trailing version, e.g. clang emits 25 * "freebsd15.0" / "freebsd14" rather than a bare "freebsd". */ 26 static bool triple_tok_prefix(const char* s, size_t n, const char* lit) { 27 size_t l = strlen(lit); 28 return n >= l && memcmp(s, lit, l) == 0; 29 } 30 31 static bool triple_tok_is_ios(const char* s, size_t n) { 32 if (triple_tok_eq(s, n, "iphoneos")) return true; 33 if (!triple_tok_prefix(s, n, "ios")) return false; 34 if (n == 3) return true; 35 return (s[3] >= '0' && s[3] <= '9') || s[3] == '.'; 36 } 37 38 static bool triple_tok_is_ios_sim(const char* s, size_t n) { 39 return triple_tok_eq(s, n, "simulator") || 40 triple_tok_eq(s, n, "iossim") || 41 triple_tok_eq(s, n, "ios-simulator") || 42 triple_tok_eq(s, n, "iossimulator") || 43 triple_tok_eq(s, n, "iphonesimulator"); 44 } 45 46 static bool triple_tok_is_android(const char* s, size_t n, 47 uint8_t* api_out) { 48 size_t l = strlen("android"); 49 unsigned v = 0; 50 size_t i; 51 if (n < l || memcmp(s, "android", l) != 0) return false; 52 for (i = l; i < n && s[i] >= '0' && s[i] <= '9'; ++i) 53 v = v * 10u + (unsigned)(s[i] - '0'); 54 if (i != n) return false; 55 if (api_out) *api_out = (uint8_t)(v > 255u ? 0u : v); 56 return true; 57 } 58 59 static bool riscv_arch_tok(const char* s, size_t n, const char* base) { 60 size_t l = strlen(base); 61 size_t i; 62 if (!base) return false; 63 if (n < l || memcmp(s, base, l) != 0) return false; 64 for (i = l; i < n; ++i) { 65 if ((s[i] < 'a' || s[i] > 'z') && (s[i] < '0' || s[i] > '9')) 66 return false; 67 } 68 return true; 69 } 70 71 /* Single arch descriptor table: the one place that enumerates the arch set for 72 * triple parsing, triple rendering, and diagnostic naming. 73 * 74 * - `aliases` : every exact arch-component spelling arch_from_tok accepts. 75 * NULL-terminated; pad unused slots with NULL. 76 * - `riscv_base`: optional ISA-string prefix also accepted (e.g. "riscv64gc" 77 * on top of the riscv64 base), NULL when there is none. 78 * - `triple_name`: the canonical spelling kit_target_to_triple emits. NULL 79 * means the renderer derives it from pointer size (wasm). 80 * - `diag_name` : the human-facing name arch_kind_name returns. 81 * - `ptr_size` : natural pointer size; 0 means "derive from the spelling" 82 * (wasm32 vs wasm64), handled per-alias below. 83 */ 84 #define ARCH_ALIAS_MAX 4 85 struct ArchSpec { 86 KitArchKind kind; 87 const char* triple_name; 88 const char* diag_name; 89 uint8_t ptr_size; 90 const char* riscv_base; 91 const char* aliases[ARCH_ALIAS_MAX]; 92 }; 93 94 static const struct ArchSpec arch_specs[] = { 95 {KIT_ARCH_X86_64, "x86_64", "x86_64", 8, NULL, 96 {"x86_64", "amd64", "x64", NULL}}, 97 {KIT_ARCH_X86_32, "i386", "x86_32", 4, NULL, 98 {"i386", "i486", "i586", "i686"}}, 99 {KIT_ARCH_ARM_64, "aarch64", "aarch64", 8, NULL, 100 {"aarch64", "arm64", "aa64", NULL}}, 101 {KIT_ARCH_ARM_32, "arm", "arm32", 4, NULL, {"arm", "armv7", NULL, NULL}}, 102 {KIT_ARCH_RV64, "riscv64", "riscv64", 8, "riscv64", 103 {"riscv64", "rv64", NULL, NULL}}, 104 {KIT_ARCH_RV32, "riscv32", "riscv32", 4, "riscv32", 105 {"riscv32", "rv32", NULL, NULL}}, 106 /* wasm carries two spellings differing only by pointer size; triple_name 107 * is NULL so the renderer picks wasm64/wasm32 from ptr_size. */ 108 {KIT_ARCH_WASM, NULL, "wasm", 4, NULL, {"wasm32", NULL, NULL, NULL}}, 109 {KIT_ARCH_WASM, NULL, "wasm", 8, NULL, {"wasm64", NULL, NULL, NULL}}, 110 }; 111 112 static const size_t arch_specs_count = 113 sizeof arch_specs / sizeof arch_specs[0]; 114 115 /* Recognize an architecture token, the single authority for the arch-name 116 * spellings kit accepts. Writes arch + natural pointer size on a hit. Returns 117 * true on success, false for an unrecognized token. Shared by the triple parser 118 * and the public kit_arch_from_name. */ 119 static bool arch_from_tok(const char* s, size_t n, KitArchKind* arch_out, 120 uint8_t* ptr_size_out) { 121 size_t si; 122 for (si = 0; si < arch_specs_count; ++si) { 123 const struct ArchSpec* a = &arch_specs[si]; 124 size_t ai; 125 bool hit = false; 126 for (ai = 0; ai < ARCH_ALIAS_MAX && a->aliases[ai]; ++ai) { 127 if (triple_tok_eq(s, n, a->aliases[ai])) { 128 hit = true; 129 break; 130 } 131 } 132 if (!hit && a->riscv_base && riscv_arch_tok(s, n, a->riscv_base)) 133 hit = true; 134 if (hit) { 135 if (arch_out) *arch_out = a->kind; 136 if (ptr_size_out) *ptr_size_out = a->ptr_size; 137 return true; 138 } 139 } 140 return false; 141 } 142 143 const char* kit_target_arch_diag_name(KitArchKind arch) { 144 size_t si; 145 for (si = 0; si < arch_specs_count; ++si) { 146 if (arch_specs[si].kind == arch) return arch_specs[si].diag_name; 147 } 148 return "unknown"; 149 } 150 151 /* Canonical arch component for the triple renderer: the table's triple_name, 152 * or the pointer-size-derived spelling when triple_name is NULL (wasm). 153 * For the ptr-size-derived case (wasm) the historical rule is "8 -> wasm64, 154 * everything else -> wasm32", so we select the alias of the row whose ptr_size 155 * matches, falling back to the smallest-ptr-size row. */ 156 static const char* arch_triple_name(KitArchKind arch, uint8_t ptr_size) { 157 size_t si; 158 const char* fallback = "unknown"; 159 for (si = 0; si < arch_specs_count; ++si) { 160 const struct ArchSpec* a = &arch_specs[si]; 161 if (a->kind != arch) continue; 162 if (a->triple_name) return a->triple_name; 163 /* triple_name == NULL: pick the row whose pointer size matches, but keep 164 * the 4-byte (wasm32) spelling as the default for any other size. */ 165 if (a->ptr_size == ptr_size) return a->aliases[0]; 166 if (a->ptr_size == 4) fallback = a->aliases[0]; 167 } 168 return fallback; 169 } 170 171 bool kit_arch_from_name(const char* name, KitArchKind* arch_out, 172 uint8_t* ptr_size_out) { 173 if (!name) return false; 174 return arch_from_tok(name, strlen(name), arch_out, ptr_size_out); 175 } 176 177 /* Single OS descriptor table: the one place that ties an OS to its object 178 * format and its canonical triple-render spelling. 179 * 180 * - `triple_render`: the OS component kit_target_to_triple emits. Android is 181 * special-cased in the renderer (it carries an API-level 182 * suffix), so its triple_render is unused/NULL here. 183 * - `obj` : the object format the OS implies. KIT_OBJ_WASM is used as 184 * a sentinel on KIT_OS_FREESTANDING meaning "derive from 185 * arch" (wasm -> WASM, otherwise ELF); see os_objfmt. 186 * 187 * The token-matching for OSes with version suffixes (android API level, the iOS 188 * version, the ios-simulator look-ahead) stays in the triple_tok_* helpers, 189 * which set the os; the obj and the render spelling come from this table. */ 190 struct OsSpec { 191 KitOSKind os; 192 const char* triple_render; 193 KitObjFmt obj; 194 }; 195 196 static const struct OsSpec os_specs[] = { 197 {KIT_OS_LINUX, "linux", KIT_OBJ_ELF}, 198 {KIT_OS_MACOS, "apple-darwin", KIT_OBJ_MACHO}, 199 {KIT_OS_IOS, "apple-ios", KIT_OBJ_MACHO}, 200 {KIT_OS_IOS_SIMULATOR, "apple-ios-simulator", KIT_OBJ_MACHO}, 201 {KIT_OS_WINDOWS, "windows", KIT_OBJ_COFF}, 202 {KIT_OS_FREEBSD, "freebsd", KIT_OBJ_ELF}, 203 {KIT_OS_ANDROID, NULL, KIT_OBJ_ELF}, 204 {KIT_OS_WASI, "wasi", KIT_OBJ_WASM}, 205 /* FREESTANDING carries no fixed object format: WASM arch -> WASM, else ELF. 206 * The WASM entry here is a sentinel resolved by os_objfmt(). The renderer 207 * emits the historical "elf" spelling for this OS. */ 208 {KIT_OS_FREESTANDING, "elf", KIT_OBJ_WASM}, 209 }; 210 211 static const size_t os_specs_count = sizeof os_specs / sizeof os_specs[0]; 212 213 const char* kit_target_arch_name(KitArchKind arch) { 214 switch (arch) { 215 case KIT_ARCH_X86_32: 216 return "x86_32"; 217 case KIT_ARCH_X86_64: 218 return "x86_64"; 219 case KIT_ARCH_ARM_32: 220 return "arm32"; 221 case KIT_ARCH_ARM_64: 222 return "aarch64"; 223 case KIT_ARCH_RV32: 224 return "riscv32"; 225 case KIT_ARCH_RV64: 226 return "riscv64"; 227 case KIT_ARCH_WASM: 228 return "wasm32"; 229 } 230 return "unknown"; 231 } 232 233 const char* kit_target_os_name(KitOSKind os) { 234 switch (os) { 235 case KIT_OS_FREESTANDING: 236 return "freestanding"; 237 case KIT_OS_LINUX: 238 return "linux"; 239 case KIT_OS_MACOS: 240 return "macos"; 241 case KIT_OS_IOS: 242 return "ios"; 243 case KIT_OS_IOS_SIMULATOR: 244 return "ios-simulator"; 245 case KIT_OS_WINDOWS: 246 return "windows"; 247 case KIT_OS_FREEBSD: 248 return "freebsd"; 249 case KIT_OS_ANDROID: 250 return "android"; 251 case KIT_OS_WASI: 252 return "wasi"; 253 } 254 return "unknown"; 255 } 256 257 const char* kit_target_obj_name(KitObjFmt obj) { 258 switch (obj) { 259 case KIT_OBJ_ELF: 260 return "elf"; 261 case KIT_OBJ_COFF: 262 return "coff"; 263 case KIT_OBJ_MACHO: 264 return "macho"; 265 case KIT_OBJ_WASM: 266 return "wasm"; 267 } 268 return "unknown"; 269 } 270 271 const char* kit_target_libc_name(uint8_t libc) { 272 switch ((KitTargetLibcModel)libc) { 273 case KIT_TARGET_LIBC_NONE: 274 return "none"; 275 case KIT_TARGET_LIBC_GLIBC: 276 return "glibc"; 277 case KIT_TARGET_LIBC_MUSL: 278 return "musl"; 279 case KIT_TARGET_LIBC_FREEBSD: 280 return "freebsd-libc"; 281 case KIT_TARGET_LIBC_UCRT: 282 return "ucrt"; 283 case KIT_TARGET_LIBC_BIONIC: 284 return "bionic"; 285 case KIT_TARGET_LIBC_DARWIN: 286 return "darwin-libsystem"; 287 case KIT_TARGET_LIBC_WASI: 288 return "wasi-libc"; 289 } 290 return "unknown"; 291 } 292 293 const char* kit_target_sysroot_name(uint8_t sysroot) { 294 switch ((KitTargetSysrootModel)sysroot) { 295 case KIT_TARGET_SYSROOT_NONE: 296 return "none"; 297 case KIT_TARGET_SYSROOT_EXTERNAL: 298 return "external"; 299 case KIT_TARGET_SYSROOT_NATIVE_SDK: 300 return "native-sdk"; 301 } 302 return "unknown"; 303 } 304 305 const char* kit_target_provisioning_name(uint8_t provisioning) { 306 switch ((KitTargetProvisioningModel)provisioning) { 307 case KIT_TARGET_PROVISION_BUILTIN: 308 return "built-in"; 309 case KIT_TARGET_PROVISION_SYSROOT: 310 return "sysroot"; 311 case KIT_TARGET_PROVISION_NATIVE: 312 return "native"; 313 case KIT_TARGET_PROVISION_VM: 314 return "vm"; 315 case KIT_TARGET_PROVISION_QEMU: 316 return "qemu"; 317 } 318 return "unknown"; 319 } 320 321 static const struct OsSpec* os_spec_for(KitOSKind os) { 322 size_t i; 323 for (i = 0; i < os_specs_count; ++i) { 324 if (os_specs[i].os == os) return &os_specs[i]; 325 } 326 return NULL; 327 } 328 329 /* Object format an OS implies for a given arch. Pure table lookup, except 330 * FREESTANDING which derives from the arch (wasm -> WASM, otherwise ELF). */ 331 static KitObjFmt os_objfmt(KitOSKind os, KitArchKind arch) { 332 const struct OsSpec* s = os_spec_for(os); 333 if (os == KIT_OS_FREESTANDING) 334 return (arch == KIT_ARCH_WASM) ? KIT_OBJ_WASM : KIT_OBJ_ELF; 335 return s ? s->obj : KIT_OBJ_ELF; 336 } 337 338 KitPic kit_target_default_pic(KitObjFmt obj, KitOSKind os) { 339 /* WASM has no PIC/PIE concept; freestanding targets have no dynamic 340 * loader to apply load-time relocations. Everything else is hosted and 341 * defaults to PIE. */ 342 if (obj == KIT_OBJ_WASM) return KIT_PIC_NONE; 343 if (os == KIT_OS_FREESTANDING) return KIT_PIC_NONE; 344 return KIT_PIC_PIE; 345 } 346 347 int kit_target_link_pie(KitTargetSpec target, int explicit_pie, int shared, 348 int relocatable) { 349 if (explicit_pie) return 1; 350 if (shared || relocatable) return 0; 351 return target.pic == KIT_PIC_PIE; 352 } 353 354 const char* kit_target_default_exe_name(KitTargetSpec target) { 355 /* PE/COFF executables conventionally carry a `.exe` suffix; ELF/Mach-O 356 * default link output is the historical `a.out`. */ 357 return target.os == KIT_OS_WINDOWS ? "a.exe" : "a.out"; 358 } 359 360 void kit_target_default_obj_ext(KitTargetSpec target, const char** ext_out, 361 size_t* ext_len_out) { 362 /* Windows targets default to a `.obj` suffix; everyone else `.o`. Drivers 363 * accept both spellings as inputs, but tooling that scrapes default outputs 364 * expects the canonical platform extension. */ 365 if (target.os == KIT_OS_WINDOWS) { 366 if (ext_out) *ext_out = ".obj"; 367 if (ext_len_out) *ext_len_out = 4u; 368 } else { 369 if (ext_out) *ext_out = ".o"; 370 if (ext_len_out) *ext_len_out = 2u; 371 } 372 } 373 374 int kit_target_needs_sysroot_libdir(KitTargetSpec target) { 375 const KitOsImpl* os = kit_os_lookup(target.os); 376 if (!os || !os->hosted || os->hosted->obj != target.obj) return 0; 377 return os->hosted->needs_sysroot_libdir; 378 } 379 380 int kit_target_default_hosted_profile(KitTargetSpec target) { 381 const KitOsImpl* os = kit_os_lookup(target.os); 382 if (!os || !os->hosted || os->hosted->obj != target.obj) return 0; 383 return os->hosted->default_profile; 384 } 385 386 bool kit_target_from_triple(const char* triple, KitTargetSpec* out) { 387 const char* parts[4]; 388 size_t plen[4]; 389 int np = 0; 390 const char* p; 391 KitTargetSpec t; 392 int os_set; 393 int i; 394 395 if (!triple || !out) return false; 396 memset(&t, 0, sizeof(t)); 397 398 p = triple; 399 while (np < 4) { 400 const char* dash = strchr(p, '-'); 401 parts[np] = p; 402 plen[np] = dash ? (size_t)(dash - p) : strlen(p); 403 if (plen[np] == 0) return false; 404 np++; 405 if (!dash) break; 406 p = dash + 1; 407 } 408 409 if (!arch_from_tok(parts[0], plen[0], &t.arch, &t.ptr_size)) return false; 410 411 /* Match an OS token, set t.os (+ any version suffix), then derive t.obj from 412 * the OS table via os_objfmt() rather than open-coding the format per branch. 413 * The token matchers (android API level, iOS version, ios-simulator 414 * look-ahead) stay as triple_tok_* helpers. */ 415 os_set = 0; 416 for (i = 1; i < np; ++i) { 417 { 418 uint8_t api = 0; 419 if (triple_tok_is_android(parts[i], plen[i], &api)) { 420 t.os = KIT_OS_ANDROID; 421 t.os_version_major = api; 422 os_set = 1; 423 break; 424 } 425 } 426 if (triple_tok_eq(parts[i], plen[i], "linux")) { 427 int android = 0; 428 uint8_t api = 0; 429 int j; 430 for (j = i + 1; j < np; ++j) { 431 if (triple_tok_is_android(parts[j], plen[j], &api)) { 432 android = 1; 433 break; 434 } 435 } 436 t.os = android ? KIT_OS_ANDROID : KIT_OS_LINUX; 437 t.os_version_major = android ? api : 0; 438 os_set = 1; 439 break; 440 } 441 if (triple_tok_eq(parts[i], plen[i], "darwin") || 442 triple_tok_eq(parts[i], plen[i], "macos")) { 443 t.os = KIT_OS_MACOS; 444 os_set = 1; 445 break; 446 } 447 if (triple_tok_is_ios_sim(parts[i], plen[i])) { 448 t.os = KIT_OS_IOS_SIMULATOR; 449 os_set = 1; 450 break; 451 } 452 if (triple_tok_is_ios(parts[i], plen[i])) { 453 int sim = 0; 454 int j; 455 for (j = i + 1; j < np; ++j) { 456 if (triple_tok_is_ios_sim(parts[j], plen[j])) { 457 sim = 1; 458 break; 459 } 460 } 461 t.os = sim ? KIT_OS_IOS_SIMULATOR : KIT_OS_IOS; 462 os_set = 1; 463 break; 464 } 465 if (triple_tok_eq(parts[i], plen[i], "windows") || 466 triple_tok_eq(parts[i], plen[i], "win32")) { 467 t.os = KIT_OS_WINDOWS; 468 os_set = 1; 469 break; 470 } 471 if (triple_tok_prefix(parts[i], plen[i], "freebsd")) { 472 const char* ver = parts[i] + 7; /* skip "freebsd" */ 473 size_t rem = plen[i] - 7; 474 unsigned v = 0; 475 size_t j; 476 for (j = 0; j < rem && ver[j] >= '0' && ver[j] <= '9'; ++j) 477 v = v * 10 + (unsigned)(ver[j] - '0'); 478 t.os = KIT_OS_FREEBSD; 479 t.os_version_major = (uint8_t)(v > 255 ? 0 : v); 480 os_set = 1; 481 break; 482 } 483 if (triple_tok_eq(parts[i], plen[i], "wasi")) { 484 t.os = KIT_OS_WASI; 485 os_set = 1; 486 break; 487 } 488 if (triple_tok_eq(parts[i], plen[i], "none") || 489 triple_tok_eq(parts[i], plen[i], "freestanding")) { 490 t.os = KIT_OS_FREESTANDING; 491 os_set = 1; 492 break; 493 } 494 } 495 if (!os_set) { 496 /* No recognized OS token. This deliberately also covers bare-metal and 497 * vendor-only triples that carry no OS at all -- e.g. "x86_64", 498 * "aarch64-unknown", "riscv64-unknown-elf" -- which must keep resolving to 499 * a freestanding ELF/WASM target. We cannot tell an unrecognized OS token 500 * (e.g. "x86_64-pc-frobnicate") apart from those without a vendor/env token 501 * table, so erroring here would regress valid bare-metal triples. Left as a 502 * silent freestanding default by design; see findings note for B15. */ 503 t.os = KIT_OS_FREESTANDING; 504 } 505 t.obj = os_objfmt(t.os, t.arch); 506 507 t.ptr_align = t.ptr_size; 508 t.big_endian = 0; 509 t.pic = kit_target_default_pic(t.obj, t.os); 510 t.code_model = KIT_CM_DEFAULT; 511 512 *out = t; 513 return true; 514 } 515 516 bool kit_target_to_triple(KitTargetSpec target, char* buf, size_t cap) { 517 const char* arch; 518 const char* os; 519 const struct OsSpec* os_spec; 520 int n; 521 if (!buf || cap == 0) return false; 522 523 arch = arch_triple_name(target.arch, target.ptr_size); 524 525 /* Android renders the "<arch>-linux-android[<api>]" form with an optional 526 * API-level suffix; it is the one OS whose spelling is not a plain table 527 * literal, so it stays special-cased here. */ 528 if (target.os == KIT_OS_ANDROID) { 529 if (target.os_version_major) 530 n = snprintf(buf, cap, "%s-linux-android%u", arch, 531 (unsigned)target.os_version_major); 532 else 533 n = snprintf(buf, cap, "%s-linux-android", arch); 534 return !(n < 0 || (size_t)n >= cap); 535 } 536 537 os_spec = os_spec_for(target.os); 538 /* Unknown OS or one without a render spelling falls back to the historical 539 * freestanding "elf" component. */ 540 os = (os_spec && os_spec->triple_render) ? os_spec->triple_render : "elf"; 541 542 n = snprintf(buf, cap, "%s-%s", arch, os); 543 return !(n < 0 || (size_t)n >= cap); 544 } 545 546 bool kit_target_code_model_from_name(const char* val, KitCodeModel* out) { 547 KitCodeModel cm; 548 if (!val) return false; 549 if (strcmp(val, "small") == 0 || strcmp(val, "medlow") == 0) { 550 cm = KIT_CM_SMALL; 551 } else if (strcmp(val, "medium") == 0 || strcmp(val, "medany") == 0) { 552 cm = KIT_CM_MEDIUM; 553 } else if (strcmp(val, "large") == 0 || strcmp(val, "kernel") == 0) { 554 cm = KIT_CM_LARGE; 555 } else { 556 return false; 557 } 558 if (out) *out = cm; 559 return true; 560 } 561 562 /* The registry is intentionally data-only. Triple parsing remains the 563 * authority for arbitrary user spellings; these rows describe the supported 564 * release/provisioning profiles (which additionally distinguish libc lanes). 565 */ 566 #define PROFILE_CAP_HOSTED_ELF \ 567 (KIT_TARGET_CAP_COMPILE | KIT_TARGET_CAP_ASSEMBLE | KIT_TARGET_CAP_LINK | \ 568 KIT_TARGET_CAP_SHARED | KIT_TARGET_CAP_EXECUTE | KIT_TARGET_CAP_SELFHOST) 569 #define PROFILE_CAP_HOSTED_IMAGE \ 570 (KIT_TARGET_CAP_COMPILE | KIT_TARGET_CAP_ASSEMBLE | KIT_TARGET_CAP_LINK | \ 571 KIT_TARGET_CAP_EXECUTE | KIT_TARGET_CAP_SELFHOST) 572 #define PROFILE_CAP_CROSS_ELF \ 573 (KIT_TARGET_CAP_COMPILE | KIT_TARGET_CAP_ASSEMBLE | KIT_TARGET_CAP_LINK | \ 574 KIT_TARGET_CAP_SHARED) 575 #define PROFILE_CAP_CROSS_IMAGE \ 576 (KIT_TARGET_CAP_COMPILE | KIT_TARGET_CAP_ASSEMBLE | KIT_TARGET_CAP_LINK) 577 #define PROFILE_CAP_BARE \ 578 (KIT_TARGET_CAP_COMPILE | KIT_TARGET_CAP_ASSEMBLE | KIT_TARGET_CAP_LINK | \ 579 KIT_TARGET_CAP_EXECUTE) 580 #define PROFILE(sel_, triple_, arch_, os_, obj_, ptr_, libc_, sysroot_, \ 581 provision_, hosted_, caps_) \ 582 { \ 583 .selector = (sel_), .triple = (triple_), \ 584 .spec = {.arch = (arch_), \ 585 .os = (os_), \ 586 .obj = (obj_), \ 587 .ptr_size = (ptr_), \ 588 .ptr_align = (ptr_), \ 589 .big_endian = false, \ 590 .pic = ((os_) == KIT_OS_FREESTANDING ? KIT_PIC_NONE \ 591 : KIT_PIC_PIE), \ 592 .code_model = KIT_CM_DEFAULT, \ 593 .float_abi = KIT_FLOAT_ABI_DEFAULT}, \ 594 .libc = (libc_), .sysroot = (sysroot_), .provisioning = (provision_), \ 595 .hosted = (hosted_), .capabilities = (caps_) \ 596 } 597 598 static const KitTargetProfile target_profiles[] = { 599 #if KIT_OBJ_ELF_ENABLED && KIT_ARCH_AA64_ENABLED 600 PROFILE("linux-glibc-aa64", "aarch64-linux-gnu", KIT_ARCH_ARM_64, 601 KIT_OS_LINUX, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_GLIBC, 602 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_SYSROOT, 1, 603 PROFILE_CAP_HOSTED_ELF), 604 PROFILE("linux-musl-aa64", "aarch64-linux-musl", KIT_ARCH_ARM_64, 605 KIT_OS_LINUX, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_MUSL, 606 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_SYSROOT, 1, 607 PROFILE_CAP_HOSTED_ELF), 608 PROFILE("freebsd-aa64", "aarch64-freebsd", KIT_ARCH_ARM_64, 609 KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_FREEBSD, 610 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_VM, 1, 611 PROFILE_CAP_HOSTED_ELF), 612 PROFILE("android-aa64", "aarch64-linux-android21", KIT_ARCH_ARM_64, 613 KIT_OS_ANDROID, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_BIONIC, 614 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_SYSROOT, 1, 615 PROFILE_CAP_CROSS_ELF), 616 PROFILE("freestanding-aa64", "aarch64-none-elf", KIT_ARCH_ARM_64, 617 KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_NONE, 618 KIT_TARGET_SYSROOT_NONE, KIT_TARGET_PROVISION_QEMU, 0, 619 PROFILE_CAP_BARE), 620 #endif 621 #if KIT_OBJ_ELF_ENABLED && KIT_ARCH_X64_ENABLED 622 PROFILE("linux-glibc-x64", "x86_64-linux-gnu", KIT_ARCH_X86_64, 623 KIT_OS_LINUX, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_GLIBC, 624 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_SYSROOT, 1, 625 PROFILE_CAP_HOSTED_ELF), 626 PROFILE("linux-musl-x64", "x86_64-linux-musl", KIT_ARCH_X86_64, 627 KIT_OS_LINUX, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_MUSL, 628 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_SYSROOT, 1, 629 PROFILE_CAP_HOSTED_ELF), 630 PROFILE("freebsd-x64", "x86_64-freebsd", KIT_ARCH_X86_64, 631 KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_FREEBSD, 632 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_VM, 1, 633 PROFILE_CAP_HOSTED_ELF), 634 PROFILE("freestanding-x64", "x86_64-none-elf", KIT_ARCH_X86_64, 635 KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_NONE, 636 KIT_TARGET_SYSROOT_NONE, KIT_TARGET_PROVISION_QEMU, 0, 637 PROFILE_CAP_BARE), 638 #endif 639 #if KIT_OBJ_ELF_ENABLED && KIT_ARCH_RV64_ENABLED 640 PROFILE("linux-glibc-rv64", "riscv64-linux-gnu", KIT_ARCH_RV64, 641 KIT_OS_LINUX, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_GLIBC, 642 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_SYSROOT, 1, 643 PROFILE_CAP_HOSTED_ELF), 644 PROFILE("linux-musl-rv64", "riscv64-linux-musl", KIT_ARCH_RV64, 645 KIT_OS_LINUX, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_MUSL, 646 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_SYSROOT, 1, 647 PROFILE_CAP_HOSTED_ELF), 648 PROFILE("freebsd-rv64", "riscv64-freebsd", KIT_ARCH_RV64, 649 KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_FREEBSD, 650 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_VM, 1, 651 PROFILE_CAP_HOSTED_ELF), 652 PROFILE("freestanding-rv64", "riscv64-none-elf", KIT_ARCH_RV64, 653 KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, KIT_TARGET_LIBC_NONE, 654 KIT_TARGET_SYSROOT_NONE, KIT_TARGET_PROVISION_QEMU, 0, 655 PROFILE_CAP_BARE), 656 #endif 657 #if KIT_OBJ_ELF_ENABLED && KIT_ARCH_RV32_ENABLED 658 PROFILE("freestanding-rv32", "riscv32-none-elf", KIT_ARCH_RV32, 659 KIT_OS_FREESTANDING, KIT_OBJ_ELF, 4, KIT_TARGET_LIBC_NONE, 660 KIT_TARGET_SYSROOT_NONE, KIT_TARGET_PROVISION_QEMU, 0, 661 PROFILE_CAP_BARE), 662 #endif 663 #if KIT_OBJ_ELF_ENABLED && KIT_ARCH_ARM32_ENABLED 664 PROFILE("freestanding-arm32", "arm-none-eabi", KIT_ARCH_ARM_32, 665 KIT_OS_FREESTANDING, KIT_OBJ_ELF, 4, KIT_TARGET_LIBC_NONE, 666 KIT_TARGET_SYSROOT_NONE, KIT_TARGET_PROVISION_QEMU, 0, 667 PROFILE_CAP_BARE), 668 #endif 669 #if KIT_OBJ_COFF_ENABLED && KIT_ARCH_AA64_ENABLED 670 PROFILE("windows-aa64", "aarch64-windows", KIT_ARCH_ARM_64, 671 KIT_OS_WINDOWS, KIT_OBJ_COFF, 8, KIT_TARGET_LIBC_UCRT, 672 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_VM, 1, 673 PROFILE_CAP_HOSTED_IMAGE), 674 #endif 675 #if KIT_OBJ_COFF_ENABLED && KIT_ARCH_X64_ENABLED 676 PROFILE("windows-x64", "x86_64-windows", KIT_ARCH_X86_64, 677 KIT_OS_WINDOWS, KIT_OBJ_COFF, 8, KIT_TARGET_LIBC_UCRT, 678 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_VM, 1, 679 PROFILE_CAP_HOSTED_IMAGE), 680 #endif 681 #if KIT_OBJ_MACHO_ENABLED && KIT_ARCH_AA64_ENABLED 682 PROFILE("macos-aa64", "aarch64-apple-darwin", KIT_ARCH_ARM_64, 683 KIT_OS_MACOS, KIT_OBJ_MACHO, 8, KIT_TARGET_LIBC_DARWIN, 684 KIT_TARGET_SYSROOT_NATIVE_SDK, KIT_TARGET_PROVISION_NATIVE, 1, 685 PROFILE_CAP_HOSTED_IMAGE), 686 PROFILE("ios-aa64", "aarch64-apple-ios", KIT_ARCH_ARM_64, KIT_OS_IOS, 687 KIT_OBJ_MACHO, 8, KIT_TARGET_LIBC_DARWIN, 688 KIT_TARGET_SYSROOT_NATIVE_SDK, KIT_TARGET_PROVISION_SYSROOT, 1, 689 PROFILE_CAP_CROSS_IMAGE), 690 PROFILE("ios-simulator-aa64", "aarch64-apple-ios-simulator", 691 KIT_ARCH_ARM_64, KIT_OS_IOS_SIMULATOR, KIT_OBJ_MACHO, 8, 692 KIT_TARGET_LIBC_DARWIN, KIT_TARGET_SYSROOT_NATIVE_SDK, 693 KIT_TARGET_PROVISION_SYSROOT, 1, PROFILE_CAP_CROSS_IMAGE), 694 #endif 695 #if KIT_OBJ_MACHO_ENABLED && KIT_ARCH_X64_ENABLED 696 PROFILE("macos-x64", "x86_64-apple-darwin", KIT_ARCH_X86_64, 697 KIT_OS_MACOS, KIT_OBJ_MACHO, 8, KIT_TARGET_LIBC_DARWIN, 698 KIT_TARGET_SYSROOT_NATIVE_SDK, KIT_TARGET_PROVISION_NATIVE, 1, 699 PROFILE_CAP_HOSTED_IMAGE), 700 PROFILE("ios-simulator-x64", "x86_64-apple-ios-simulator", 701 KIT_ARCH_X86_64, KIT_OS_IOS_SIMULATOR, KIT_OBJ_MACHO, 8, 702 KIT_TARGET_LIBC_DARWIN, KIT_TARGET_SYSROOT_NATIVE_SDK, 703 KIT_TARGET_PROVISION_SYSROOT, 1, PROFILE_CAP_CROSS_IMAGE), 704 #endif 705 #if KIT_OBJ_WASM_ENABLED && KIT_ARCH_WASM_ENABLED 706 PROFILE("wasm32-wasi", "wasm32-wasi", KIT_ARCH_WASM, KIT_OS_WASI, 707 KIT_OBJ_WASM, 4, KIT_TARGET_LIBC_WASI, 708 KIT_TARGET_SYSROOT_EXTERNAL, KIT_TARGET_PROVISION_SYSROOT, 1, 709 KIT_TARGET_CAP_COMPILE | KIT_TARGET_CAP_LINK | 710 KIT_TARGET_CAP_EXECUTE), 711 PROFILE("wasm32-freestanding", "wasm32-none", KIT_ARCH_WASM, 712 KIT_OS_FREESTANDING, KIT_OBJ_WASM, 4, KIT_TARGET_LIBC_NONE, 713 KIT_TARGET_SYSROOT_NONE, KIT_TARGET_PROVISION_BUILTIN, 0, 714 KIT_TARGET_CAP_COMPILE | KIT_TARGET_CAP_LINK | 715 KIT_TARGET_CAP_EXECUTE), 716 #endif 717 /* A sentinel keeps the definition valid for component-minimal builds. */ 718 {0}, 719 }; 720 721 const KitTargetProfile* kit_target_profiles(size_t* count) { 722 size_t n = sizeof target_profiles / sizeof target_profiles[0] - 1u; 723 if (count) *count = n; 724 return target_profiles; 725 } 726 727 const KitTargetProfile* kit_target_profile_lookup(const char* name) { 728 size_t i, n; 729 if (!name) return NULL; 730 n = sizeof target_profiles / sizeof target_profiles[0] - 1u; 731 for (i = 0; i < n; ++i) { 732 if (strcmp(name, target_profiles[i].selector) == 0 || 733 strcmp(name, target_profiles[i].triple) == 0) 734 return &target_profiles[i]; 735 } 736 return NULL; 737 } 738 739 #undef PROFILE 740 #undef PROFILE_CAP_BARE 741 #undef PROFILE_CAP_CROSS_IMAGE 742 #undef PROFILE_CAP_CROSS_ELF 743 #undef PROFILE_CAP_HOSTED_IMAGE 744 #undef PROFILE_CAP_HOSTED_ELF