kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 66b750642967895f088399bec805c3260e26b4ae
parent b4f2b7450e8b321b22ebed6233929eaecbae3203
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 17 Jun 2026 11:13:43 -0700

Tier 1: OS hosted-policy predicates → KitOsHostedOps vtable fields

Eliminate driver-side OS-identity predicates by promoting them to fields on
the existing KitOsHostedOps vtable (read via kit_os_lookup), and collapse the
remaining Darwin per-OS switch pairs into single-source-of-truth tables.

- include/kit/os.h: add KitOsHostedOps.uses_framework_dirs and
  .shared_uses_hosted (imitating needs_sysroot_libdir / default_profile).
- src/os/macos/hosted.c: set uses_framework_dirs=1 on the shared Darwin hosted
  ops; collapse darwin_sdk_name / darwin_profile_name switches into one
  darwin_os_info table (the three Darwin OSes share one ops instance, so these
  cannot be plain vtable fields).
- src/os/android/hosted.c: set shared_uses_hosted=1.
- driver/lib/link_inputs.{c,h}: rewrite driver_target_uses_framework_dirs to
  read the vtable field, export it as the single shared helper.
- driver/cmd/ld.c: drop the duplicate ld_target_uses_framework_dirs; call the
  shared helper.
- driver/lib/target.c: rewrite driver_target_shared_uses_hosted to read the
  vtable field; intentionally drop the arch==ARM_64 coupling (Android shared
  libs need the hosted CRT on every arch; only aarch64 is built today so
  behavior is preserved).
- src/obj/macho/macho.h: collapse macho_platform_for_target /
  macho_os_for_platform switches into one macho_os_platform_table with two
  lookup helpers.
- driver/env/macos.c: convert the iOS/iOS-sim/macOS SDK-candidate selection
  to a static table keyed by KitOSKind.

Pure refactor except the shared_uses_hosted arch-decoupling. Builds clean
(make lib, make bin). test-driver-build 274/0, test-macho 80/0, and the
relevant test-driver-cc cases (darwin-framework-link,
macho-ios-build-version-platforms) pass. The two test-driver-cc failures
(ld-shared-rejected / -diag) are pre-existing stale tests: the base binary
at the same commit also no longer rejects `ld -shared`.

Diffstat:
Mdriver/cmd/ld.c | 8+-------
Mdriver/env/macos.c | 33++++++++++++++++++++++-----------
Mdriver/lib/link_inputs.c | 8++++----
Mdriver/lib/link_inputs.h | 5+++++
Mdriver/lib/target.c | 11+++++++++--
Minclude/kit/os.h | 7+++++++
Msrc/obj/macho/macho.h | 43+++++++++++++++++++++++++------------------
Msrc/os/android/hosted.c | 1+
Msrc/os/macos/hosted.c | 41+++++++++++++++++++++++------------------
9 files changed, 97 insertions(+), 60 deletions(-)

diff --git a/driver/cmd/ld.c b/driver/cmd/ld.c @@ -515,17 +515,11 @@ static int ld_add_sysroot_libdir(LdOptions* o) { return 0; } -static int ld_target_uses_framework_dirs(KitTargetSpec target) { - return target.obj == KIT_OBJ_MACHO && - (target.os == KIT_OS_MACOS || target.os == KIT_OS_IOS || - target.os == KIT_OS_IOS_SIMULATOR); -} - static int ld_add_sysroot_framework_dirs(LdOptions* o) { char* path; size_t size; const char* owned; - if (!ld_target_uses_framework_dirs(o->target)) return 0; + if (!driver_target_uses_framework_dirs(o->target)) return 0; if (!o->sysroot || !o->sysroot[0]) return 0; path = ld_join2(o->env, o->sysroot, "System/Library/Frameworks", &size); if (ld_own_path(o, path, size, &owned) != 0) return 1; diff --git a/driver/env/macos.c b/driver/env/macos.c @@ -192,21 +192,32 @@ int driver_default_hosted_dirs(DriverEnv* env, KitTargetSpec target, "/Applications/Xcode.app/Contents/Developer/Platforms/" "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk", }; - const char* const* candidates = macos_candidates; - size_t ncandidates = sizeof(macos_candidates) / sizeof(macos_candidates[0]); + /* Per-OS xcrun-style SDK candidate lists, keyed by KitOSKind. */ + static const struct { + KitOSKind os; + const char* const* candidates; + size_t ncandidates; + } sdk_table[] = { + {KIT_OS_MACOS, macos_candidates, + sizeof(macos_candidates) / sizeof(macos_candidates[0])}, + {KIT_OS_IOS, ios_candidates, + sizeof(ios_candidates) / sizeof(ios_candidates[0])}, + {KIT_OS_IOS_SIMULATOR, ios_sim_candidates, + sizeof(ios_sim_candidates) / sizeof(ios_sim_candidates[0])}, + }; + const char* const* candidates = NULL; + size_t ncandidates = 0; const char* sdk = NULL; size_t i; (void)env; - if (target.os == KIT_OS_IOS) { - candidates = ios_candidates; - ncandidates = sizeof(ios_candidates) / sizeof(ios_candidates[0]); - } else if (target.os == KIT_OS_IOS_SIMULATOR) { - candidates = ios_sim_candidates; - ncandidates = - sizeof(ios_sim_candidates) / sizeof(ios_sim_candidates[0]); - } else if (target.os != KIT_OS_MACOS) { - return 1; + for (i = 0; i < sizeof(sdk_table) / sizeof(sdk_table[0]); ++i) { + if (sdk_table[i].os == target.os) { + candidates = sdk_table[i].candidates; + ncandidates = sdk_table[i].ncandidates; + break; + } } + if (!candidates) return 1; for (i = 0; i < ncandidates; ++i) { if (driver_path_exists(candidates[i])) { sdk = candidates[i]; diff --git a/driver/lib/link_inputs.c b/driver/lib/link_inputs.c @@ -401,10 +401,10 @@ int driver_link_inputs_append_windows_lib_dirs(DriverLinkInputSet* set, return 0; } -static int driver_target_uses_framework_dirs(KitTargetSpec target) { - return target.obj == KIT_OBJ_MACHO && - (target.os == KIT_OS_MACOS || target.os == KIT_OS_IOS || - target.os == KIT_OS_IOS_SIMULATOR); +int driver_target_uses_framework_dirs(KitTargetSpec target) { + const KitOsImpl* o = kit_os_lookup(target.os); + return target.obj == KIT_OBJ_MACHO && o && o->hosted && + o->hosted->uses_framework_dirs; } static int driver_link_inputs_add_owned_framework_dir(DriverLinkInputSet* set, diff --git a/driver/lib/link_inputs.h b/driver/lib/link_inputs.h @@ -181,6 +181,11 @@ int driver_link_inputs_append_windows_lib_dirs(DriverLinkInputSet* set, const char** sysroot, KitTargetSpec target); +/* True when the target uses Mach-O framework search dirs (Apple SDK): obj is + * Mach-O and the target OS's hosted ops set uses_framework_dirs. Shared between + * the cc/build link-input path and the `ld` driver. */ +int driver_target_uses_framework_dirs(KitTargetSpec target); + /* For Mach-O SDK targets, append `<sysroot>/System/Library/Frameworks` and * `<sysroot>/System/Library/PrivateFrameworks` to the framework search path. * The sysroot is `*sysroot` if set, else KIT_SYSROOT (which is written back diff --git a/driver/lib/target.c b/driver/lib/target.c @@ -47,8 +47,15 @@ int driver_target_default_hosted_profile(KitTargetSpec target) { } int driver_target_shared_uses_hosted(KitTargetSpec target) { - return target.os == KIT_OS_ANDROID && target.obj == KIT_OBJ_ELF && - target.arch == KIT_ARCH_ARM_64; + /* Whether a `-shared` link still needs the hosted CRT/libc is an OS policy + * (Android bionic does; ELF/Mach-O/COFF hosts otherwise do not). Read it from + * the OS hosted-ops vtable rather than hardcoding the identity here. The obj + * gate guards against a triple that names an OS but a mismatched object + * format. Note: no arch coupling -- Android shared libs need the hosted CRT on + * every arch (only aarch64 is built today, so behavior is preserved). */ + const KitOsImpl* o = kit_os_lookup(target.os); + return o && o->hosted && o->hosted->obj == target.obj && + o->hosted->shared_uses_hosted; } static int target_features_grow(DriverTargetFeatures* tf) { diff --git a/include/kit/os.h b/include/kit/os.h @@ -99,6 +99,13 @@ typedef struct KitOsHostedOps { KitObjFmt obj; int default_profile; int needs_sysroot_libdir; + /* This OS uses Mach-O framework search dirs (Apple SDK + * System/Library/{,Private}Frameworks). Gated by obj == KIT_OBJ_MACHO at the + * call site. */ + int uses_framework_dirs; + /* Shared (-shared) links for this OS still need the hosted CRT/libc (e.g. + * Android bionic). Most OSes link shared objects without hosted startfiles. */ + int shared_uses_hosted; KitOsHostedResolveFn resolve; KitOsHostedSysrootLayoutFn sysroot_layout; } KitOsHostedOps; diff --git a/src/obj/macho/macho.h b/src/obj/macho/macho.h @@ -74,28 +74,35 @@ #define PLATFORM_IOS 2u #define PLATFORM_IOSSIMULATOR 7u +/* Single source of truth for the OS <-> LC_BUILD_VERSION platform mapping. The + * first entry (macOS) is the fallback for both directions. */ +static const struct { + KitOSKind os; + u32 platform; +} macho_os_platform_table[] = { + {KIT_OS_MACOS, PLATFORM_MACOS}, + {KIT_OS_IOS, PLATFORM_IOS}, + {KIT_OS_IOS_SIMULATOR, PLATFORM_IOSSIMULATOR}, +}; + static inline u32 macho_platform_for_target(KitTargetSpec target) { - switch (target.os) { - case KIT_OS_IOS: - return PLATFORM_IOS; - case KIT_OS_IOS_SIMULATOR: - return PLATFORM_IOSSIMULATOR; - case KIT_OS_MACOS: - default: - return PLATFORM_MACOS; - } + size_t i; + for (i = 1; + i < sizeof macho_os_platform_table / sizeof macho_os_platform_table[0]; + ++i) + if (macho_os_platform_table[i].os == target.os) + return macho_os_platform_table[i].platform; + return PLATFORM_MACOS; } static inline KitOSKind macho_os_for_platform(u32 platform) { - switch (platform) { - case PLATFORM_IOS: - return KIT_OS_IOS; - case PLATFORM_IOSSIMULATOR: - return KIT_OS_IOS_SIMULATOR; - case PLATFORM_MACOS: - default: - return KIT_OS_MACOS; - } + size_t i; + for (i = 1; + i < sizeof macho_os_platform_table / sizeof macho_os_platform_table[0]; + ++i) + if (macho_os_platform_table[i].platform == platform) + return macho_os_platform_table[i].os; + return KIT_OS_MACOS; } /* ---- VM protection bits (segment maxprot / initprot) ---- */ diff --git a/src/os/android/hosted.c b/src/os/android/hosted.c @@ -96,6 +96,7 @@ const KitOsHostedOps kit_os_android_hosted_ops = { .obj = KIT_OBJ_ELF, .default_profile = 1, .needs_sysroot_libdir = 0, + .shared_uses_hosted = 1, .resolve = hosted_resolve_android, .sysroot_layout = hosted_sysroot_layout_android, }; diff --git a/src/os/macos/hosted.c b/src/os/macos/hosted.c @@ -1,27 +1,31 @@ #include "os/hosted_internal.h" +/* The three Darwin OSes share one hosted-ops instance, so their per-OS SDK and + * profile names cannot be plain vtable fields; this single table is the source + * of truth. The first entry is the macOS / unknown-OS fallback. */ +static const struct { + KitOSKind os; + const char* sdk; + const char* profile; +} darwin_os_info[] = { + {KIT_OS_MACOS, "macosx", "macos-libSystem"}, + {KIT_OS_IOS, "iphoneos", "ios-libSystem"}, + {KIT_OS_IOS_SIMULATOR, "iphonesimulator", "ios-simulator-libSystem"}, +}; + +static size_t darwin_os_info_index(KitOSKind os) { + size_t i; + for (i = 1; i < sizeof darwin_os_info / sizeof darwin_os_info[0]; ++i) + if (darwin_os_info[i].os == os) return i; + return 0; /* macOS / default fallback */ +} + static const char* darwin_sdk_name(KitOSKind os) { - switch (os) { - case KIT_OS_IOS: - return "iphoneos"; - case KIT_OS_IOS_SIMULATOR: - return "iphonesimulator"; - case KIT_OS_MACOS: - default: - return "macosx"; - } + return darwin_os_info[darwin_os_info_index(os)].sdk; } static const char* darwin_profile_name(KitOSKind os) { - switch (os) { - case KIT_OS_IOS: - return "ios-libSystem"; - case KIT_OS_IOS_SIMULATOR: - return "ios-simulator-libSystem"; - case KIT_OS_MACOS: - default: - return "macos-libSystem"; - } + return darwin_os_info[darwin_os_info_index(os)].profile; } static int hosted_add_darwin_defines(KitOsHostedPlan* plan, @@ -109,6 +113,7 @@ const KitOsHostedOps kit_os_macos_hosted_ops = { .obj = KIT_OBJ_MACHO, .default_profile = 0, .needs_sysroot_libdir = 0, + .uses_framework_dirs = 1, .resolve = hosted_resolve_darwin, .sysroot_layout = hosted_sysroot_layout_darwin, };