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:
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,
};