macOS version numbering isn’t so simple

A couple of weeks ago, it all looked settled and simple: Big Sur is both macOS 10.16 and 11.0 according to the context of the question. It turns out that, despite another of Apple’s sleights of hand, things aren’t always as straightforward.

The rules

There are two fundamental rules which Apple has provided:

  • In compiled languages, the version returned by macOS depends on the SDK which the software has been built against. When built against the 10.15 SDK or earlier, Big Sur returns 10.16 for compatibility with previous numbering and all existing apps; when built against the 11.0 SDK, it returns 11.0 for forward compatibility.
  • In scripted languages which run within a shell environment, there’s an environmental variable which controls the version number given. Set SYSTEM_VERSION_COMPAT=1 and Big Sur returns 10.16; leave that variable unset, or SYSTEM_VERSION_COMPAT=0, and it returns 11.0.

AppleScript

This is a good example of knowing how to interpret those rules. Move a script across to Big Sur, and it will be compiled in the 11.0 environment, so
system version of (system info)
returns 11.0, as will that code inside an AppleScript app built on Big Sur.

Build an AppleScript app on 10.15, though, and when that runs on Big Sur, it sees the system version as 10.16. Thus, AppleScript apps should get what they expect, according to the SDK against which they’re built.

Shell Scripts

These are also straightforward, as you get what you ask for: set SYSTEM_VERSION_COMPAT=1 for 10.16, or leave that variable unset for 11.0.

Other compiled languages

Any language compiled outside the Xcode SDK should be built against an SDK equivalent, and the first rule applies. If you’re unsure of which SDK version your development tools use, contact the supplier.

Interpreted and JIT languages

This is where it gets less well-defined, and I’m grateful to @gregneagle for drawing attention to the problem with languages like Python.

One method commonly used to look up the macOS version number is to obtain the string value for the ProductVersion key in /System/Library/CoreServices/SystemVersion.plist. However, depending on the environment of the caller, Big Sur plays tricks with that file, which should return a version of 11.0. If the caller has set SYSTEM_VERSION_COMPAT=1, then the version number returned isn’t obtained from that property list at all, but its companion SystemVersionCompat.plist, which is 10.16.

You can test this at the command line, by entering the two commands
SYSTEM_VERSION_COMPAT=1 cat /System/Library/CoreServices/SystemVersion.plist
and
SYSTEM_VERSION_COMPAT=0 cat /System/Library/CoreServices/SystemVersion.plist

versionnumbers

Although both should read the same file, in the first case you’ll be shown the contents of SystemVersionCompat.plist instead, where ProductVersion isn’t 11.0 but 10.16.

If you really want to be sure of getting a consistent version, then don’t read SystemVersion.plist but SystemVersionCompat.plist: macOS doesn’t pull any tricks with that, and you’ll always get 10.16 when running on Big Sur.

The alternative is just to say to hell with it all, and look for either 10.16 or 11.0, knowing that your code should be safe for a while.

Which version comes next?

What Apple hasn’t yet made clear, as far as I can tell, is which version of macOS will be the first update to Big Sur a couple of months after the release of 11.0. If Apple has returned to the version numbering which it used before Mac OS X, that update should be 11.1, and then next summer we should all be enjoying 12.0 beta. Perhaps that’s thinking too far ahead.