Function detect [src]
Detect macOS version.
target_os is not modified in case of error.
Prototype
pub fn detect(target_os: *Target.Os) !void
Parameters
target_os: *Target.Os
Source
pub fn detect(target_os: *Target.Os) !void {
// Drop use of osproductversion sysctl because:
// 1. only available 10.13.4 High Sierra and later
// 2. when used from a binary built against < SDK 11.0 it returns 10.16 and masks Big Sur 11.x version
//
// NEW APPROACH, STEP 1, parse file:
//
// /System/Library/CoreServices/SystemVersion.plist
//
// NOTE: Historically `SystemVersion.plist` first appeared circa '2003
// with the release of Mac OS X 10.3.0 Panther.
//
// and if it contains a `10.16` value where the `16` is `>= 16` then it is non-canonical,
// discarded, and we move on to next step. Otherwise we accept the version.
//
// BACKGROUND: `10.(16+)` is not a proper version and does not have enough fidelity to
// indicate minor/point version of Big Sur and later. It is a context-sensitive result
// issued by the kernel for backwards compatibility purposes. Likely the kernel checks
// if the executable was linked against an SDK older than Big Sur.
//
// STEP 2, parse next file:
//
// /System/Library/CoreServices/.SystemVersionPlatform.plist
//
// NOTE: Historically `SystemVersionPlatform.plist` first appeared circa '2020
// with the release of macOS 11.0 Big Sur.
//
// Accessing the content via this path circumvents a context-sensitive result and
// yields a canonical Big Sur version.
//
// At this time there is no other known way for a < SDK 11.0 executable to obtain a
// canonical Big Sur version.
//
// This implementation uses a reasonably simplified approach to parse .plist file
// that while it is an xml document, we have good history on the file and its format
// such that I am comfortable with implementing a minimalistic parser.
// Things like string and general escapes are not supported.
const prefixSlash = "/System/Library/CoreServices/";
const paths = [_][]const u8{
prefixSlash ++ "SystemVersion.plist",
prefixSlash ++ ".SystemVersionPlatform.plist",
};
for (paths) |path| {
// approx. 4 times historical file size
var buf: [2048]u8 = undefined;
if (std.fs.cwd().readFile(path, &buf)) |bytes| {
if (parseSystemVersion(bytes)) |ver| {
// never return non-canonical `10.(16+)`
if (!(ver.major == 10 and ver.minor >= 16)) {
target_os.version_range.semver.min = ver;
target_os.version_range.semver.max = ver;
return;
}
continue;
} else |_| {
return error.OSVersionDetectionFail;
}
} else |_| {
return error.OSVersionDetectionFail;
}
}
return error.OSVersionDetectionFail;
}