macOS (formerly branded Mac OS X) has been versioned fairly consistently since the initial 10.0 release about 20 years ago. Since then the major release number 10 has been used up until the release of Big Sur which bumped major to 11.
Apple no doubt recognized that many existing applications need to detect macOS version at configure/build/runtime and decided to put in place a backwards compatible versioning scheme that is activated by two different means:
- executables built against 10.15 SDK and earlier
- executables launched with environ
SYSTEM_VERSION_COMPAT=1
If either of these is true then the OS/kernel make it very difficult to obtain real versioning for Big Sur. In other words, Apple made it super easy for backwards version compatibility for ignorant executables, but made it nigh impossible for knowledgeable executables to detect Big Sur versioning.
But how and why is this important to Zig? Here's the problem statement:
Zig posts release and CI binaries that are built on pre-Big Sur hosts and out of the box these binaries will not work on Big Sur as expected. Some of the issues have been worked around, but ultimately, host and (default) target information will be incorrect because the host will be detected as 10.16.
Considered and Failed Workarounds
use sysctl MIB kern.osproductversion
Returns 10.16 inside a backwards compatibility context.
use sysctl MIB kern.osversion instead
We have a "temporary" fallback measure in place to convert macOS build strings to product versions and up to and including 10.15 it was formulaic and robust. By formulaic I mean that it would work with future versions. Unfortunately Big Sur completely breaks any formulaic pattern and build strings essentially are monotonically increasing. For example, we cannot predict when the first "letter" in the string will indicate a new minor or patch or both minor+patch change. As of this writing here are Big Sur known builds:
| Version |
Build |
| 11.0 |
20A2411 |
| 11.0.1 |
20B29 |
| 11.0.1 |
20B50 |
| 11.1 |
20C69 |
| 11.2 beta |
20D5029f |
detect sysctl MIB kern.osproductversioncompat
It is possible to detect a new MIB that indicates current process is in backwards compatibility context. While this might be useful to emit a warning to find a better binary or some such, that's about as far as it goes. We still cannot determine Big Sur real version.
setenv SYSTEM_VERSION_COMPAT=0 in zig compiler main
Does not work in the current process; it must be set in parent process of the executable.
have the user setenv SYSTEM_VERSION_COMPAT=0 in their shell
This reeks. We'd like Zig binaries to just work out-of-the-box as much as possible.
read/parse file /System/Library/CoreServices/SystemVersion.plist
This was intended to be the go-to long term solution (see #5125) and is no longer viable. The file contents indicate 10.16 when in a backwards compatibility context.
parse output from sw_vers
Returns 10.16 inside a backwards compatibility context.
Solution: a dotfile symlink
I did a deep search on a 11.1 system and found the following .plist files:
▸ ls -al /System/Library/CoreServices | grep ' SystemVersion.*plist'
lrwxr-xr-x 1 root wheel 19 Jan 1 2020 .SystemVersionPlatform.plist -> SystemVersion.plist
-r--r--r-- 1 root wheel 524 Jan 1 2020 SystemVersion.plist
-r--r--r-- 1 root wheel 529 Jan 1 2020 SystemVersionCompat.plist
It turns out that even though the symlink points to SystemVersion.plist reading/parsing file by that symlink path bypasses backwards compatibility context and always returns Big Sur real version info.
Thus our logic can have a single branch with something as straightforward as:
// `10.16` is only returned when in backwards compatible context
if sysctl MIB `kern.osproductversion` == `10.16` {
parse_via_dotfile_simlink_path
}
macOS (formerly branded Mac OS X) has been versioned fairly consistently since the initial
10.0release about 20 years ago. Since then the major release number10has been used up until the release of Big Sur which bumped major to11.Apple no doubt recognized that many existing applications need to detect macOS version at configure/build/runtime and decided to put in place a backwards compatible versioning scheme that is activated by two different means:
SYSTEM_VERSION_COMPAT=1If either of these is true then the OS/kernel make it very difficult to obtain real versioning for Big Sur. In other words, Apple made it super easy for backwards version compatibility for ignorant executables, but made it nigh impossible for knowledgeable executables to detect Big Sur versioning.
But how and why is this important to Zig? Here's the problem statement:
Zig posts release and CI binaries that are built on pre-Big Sur hosts and out of the box these binaries will not work on Big Sur as expected. Some of the issues have been worked around, but ultimately, host and (default) target information will be incorrect because the host will be detected as
10.16.Considered and Failed Workarounds
use sysctl MIB
kern.osproductversionReturns
10.16inside a backwards compatibility context.use sysctl MIB
kern.osversioninsteadWe have a "temporary" fallback measure in place to convert macOS build strings to product versions and up to and including
10.15it was formulaic and robust. By formulaic I mean that it would work with future versions. Unfortunately Big Sur completely breaks any formulaic pattern and build strings essentially are monotonically increasing. For example, we cannot predict when the first "letter" in the string will indicate a new minor or patch or both minor+patch change. As of this writing here are Big Sur known builds:detect sysctl MIB
kern.osproductversioncompatIt is possible to detect a new MIB that indicates current process is in backwards compatibility context. While this might be useful to emit a warning to find a better binary or some such, that's about as far as it goes. We still cannot determine Big Sur real version.
setenv
SYSTEM_VERSION_COMPAT=0in zig compiler mainDoes not work in the current process; it must be set in parent process of the executable.
have the user setenv
SYSTEM_VERSION_COMPAT=0in their shellThis reeks. We'd like Zig binaries to just work out-of-the-box as much as possible.
read/parse file
/System/Library/CoreServices/SystemVersion.plistThis was intended to be the go-to long term solution (see #5125) and is no longer viable. The file contents indicate
10.16when in a backwards compatibility context.parse output from
sw_versReturns
10.16inside a backwards compatibility context.Solution: a dotfile symlink
I did a deep search on a
11.1system and found the following.plistfiles:It turns out that even though the symlink points to
SystemVersion.plistreading/parsing file by that symlink path bypasses backwards compatibility context and always returns Big Sur real version info.Thus our logic can have a single branch with something as straightforward as: