From ad261482e9c9a0b05913b3ce6e5fd5ae98cc7b7e Mon Sep 17 00:00:00 2001 From: Tobias Melcher Date: Tue, 12 May 2026 19:35:40 +0200 Subject: [PATCH] Add native method to query Mach-O SDK version at runtime The macOS runtime can report incorrect OS versions (10.16 instead of actual version) when the executable's linked SDK is too old. Add OS.getMachOSDKVersion() to extract the SDK version from the LC_BUILD_VERSION load command in the main executable's Mach-O header. This allows SWT to detect the SDK version the running JVM was built against, enabling proper diagnostics for version reporting issues. --- .../Eclipse SWT PI/cocoa/library/os_custom.c | 25 +++++++++++++++++++ .../Eclipse SWT PI/cocoa/library/os_stats.h | 1 + .../org/eclipse/swt/internal/cocoa/OS.java | 20 +++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_custom.c b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_custom.c index 99f8bae271d..27bc21a5d39 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_custom.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_custom.c @@ -15,6 +15,8 @@ #include "swt.h" #include "os_structs.h" #include "os_stats.h" +#include +#include #define OS_NATIVE(func) Java_org_eclipse_swt_internal_cocoa_OS_##func @@ -150,3 +152,26 @@ JNIEXPORT jlong JNICALL OS_NATIVE(beginSheetModalForWindow) } #endif +#ifndef NO_getMachOSDKVersion +JNIEXPORT jint JNICALL OS_NATIVE(getMachOSDKVersion) + (JNIEnv *env, jclass that) +{ + jint rc = 0; + OS_NATIVE_ENTER(env, that, getMachOSDKVersion_FUNC); + const struct mach_header_64 *header = (const struct mach_header_64 *)_NSGetMachExecuteHeader(); + const uint8_t *ptr = (const uint8_t *)header + sizeof(struct mach_header_64); + for (uint32_t i = 0; i < header->ncmds; i++) { + const struct load_command *lc = (const struct load_command *)ptr; + if (lc->cmd == LC_BUILD_VERSION) { + const struct build_version_command *bv = (const struct build_version_command *)ptr; + uint32_t sdk = bv->sdk; + rc = (jint)(((sdk >> 16) & 0xff) << 16) | (((sdk >> 8) & 0xff) << 8) | (sdk & 0xff); + break; + } + ptr += lc->cmdsize; + } + OS_NATIVE_EXIT(env, that, getMachOSDKVersion_FUNC); + return rc; +} +#endif + diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h index be2c5250070..c5d0e1e8583 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h @@ -369,6 +369,7 @@ typedef enum { class_1getMethodImplementation_FUNC, class_1getName_FUNC, class_1getSuperclass_FUNC, + getMachOSDKVersion_FUNC, getpid_FUNC, instrumentObjcMessageSends_FUNC, isFlipped_1CALLBACK_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java index cd24777ad62..eba95a9672b 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java @@ -38,6 +38,18 @@ public static int VERSION (int major, int minor, int bugfix) { return (major << 16) + (minor << 8) + bugfix; } + public static int VERSION_MAJOR (int version) { + return (version >>> 16) & 0xFF; + } + + public static int VERSION_MINOR (int version) { + return (version >>> 8) & 0xFF; + } + + public static int VERSION_BUGFIX (int version) { + return version & 0xFF; + } + public static final boolean IS_X86_64 = System.getProperty("os.arch").equals("x86_64"); //$NON-NLS-1$ /* @@ -336,6 +348,14 @@ public static boolean isSystemDarkAppearance() { public static final native int getpid(); +/** + * Returns the SDK version from LC_BUILD_VERSION in the main executable's + * Mach-O header, encoded as {@code (major << 16) + (minor << 8) + bugfix}. + * Returns 0 if LC_BUILD_VERSION is not found. + * @method flags=no_gen + */ +public static final native int getMachOSDKVersion(); + public static final native void call(long proc, long id, long sel); /** QuickDraw calls */