darwin: robust macos version detection (#28991)

Prefer `sw_vers` to `platform.mac_ver`. In anaconda3 installation, for example, the latter reports 10.16 on Monterey -- I think this is affected by how and where the python instance was built.

Use MACOSX_DEPLOYMENT_TARGET if present to override the operating system choice.
This commit is contained in:
Seth R. Johnson 2022-02-17 22:50:41 -05:00 committed by GitHub
parent b768fb85c6
commit 6c61c2695a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 7 deletions

View File

@ -3,6 +3,7 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
import platform as py_platform
import re
@ -12,10 +13,49 @@
from ._operating_system import OperatingSystem
# FIXME: store versions inside OperatingSystem as a Version instead of string
def macos_version():
"""temporary workaround to return a macOS version as a Version object
"""Get the current macOS version as a version object.
This has three mechanisms for determining the macOS version, which is used
for spack identification (the ``os`` in the spec's ``arch``) and indirectly
for setting the value of ``MACOSX_DEPLOYMENT_TARGET``, which affects the
``minos`` value of the ``LC_BUILD_VERSION`` macho header. Mixing ``minos``
values can lead to lots of linker warnings, and using a consistent version
(pinned to the major OS version) allows distribution across clients that
might be slightly behind.
The version determination is made with three mechanisms in decreasing
priority:
1. The ``MACOSX_DEPLOYMENT_TARGET`` variable overrides the actual operating
system version, just like the value can be used to build for older macOS
targets on newer systems. Spack currently will truncate this value when
building packages, but at least the major version will be the same.
2. The system ``sw_vers`` command reports the actual operating system
version.
3. The Python ``platform.mac_ver`` function is a fallback if the operating
system identification fails, because some Python versions and/or
installations report the OS
on which Python was *built* rather than the one on which it is running.
"""
env_ver = os.environ.get('MACOSX_DEPLOYMENT_TARGET', None)
if env_ver:
return Version(env_ver)
try:
output = Executable('sw_vers')(output=str, fail_on_error=False)
except Exception:
# FileNotFoundError, or spack.util.executable.ProcessError
pass
else:
match = re.search(r'ProductVersion:\s*([0-9.]+)', output)
if match:
return Version(match.group(1))
# Fall back to python-reported version, which can be inaccurate around
# macOS 11 (e.g. showing 10.16 for macOS 12)
return Version(py_platform.mac_ver()[0])
@ -26,7 +66,7 @@ def macos_cltools_version():
SDK path.
"""
pkgutil = Executable('pkgutil')
output = pkgutil('--pkg-info=com.apple.pkg.CLTools_Executables',
output = pkgutil('--pkg-info=com.apple.pkg.cltools_executables',
output=str, fail_on_error=False)
match = re.search(r'version:\s*([0-9.]+)', output)
if match:
@ -99,11 +139,13 @@ def __init__(self):
'12': 'monterey',
}
version = macos_version()
# Big Sur versions go 11.0, 11.0.1, 11.1 (vs. prior versions that
# only used the minor component)
part = 1 if macos_version() >= Version('11') else 2
part = 1 if version >= Version('11') else 2
mac_ver = str(macos_version().up_to(part))
mac_ver = str(version.up_to(part))
name = mac_releases.get(mac_ver, "macos")
super(MacOs, self).__init__(name, mac_ver)

View File

@ -3,7 +3,7 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import platform
import platform as py_platform
import archspec.cpu
@ -38,7 +38,7 @@ def __init__(self):
@classmethod
def detect(cls):
return 'darwin' in platform.system().lower()
return 'darwin' in py_platform.system().lower()
def setup_platform_environment(self, pkg, env):
"""Specify deployment target based on target OS version.