From b4da0e9ab919bc6bd472f7b4ad8a5ca23a68ddc7 Mon Sep 17 00:00:00 2001 From: Benjy Weinberger Date: Sat, 11 Sep 2021 18:53:32 -0700 Subject: [PATCH] Handle a quirk when building on MacOS Big Sur. (#12857) Adds an option to set the Big Sur platform to "10.16" instead of the new scheme of "11.0", when building dists. This may be required for pip to be able to install the resulting dists. Also ensures that this will work for our own wheels, by setting this when building the native code (otherwise setup.py will warn that the native code platform is incompatible, and ignore the 10.16 setting). [ci skip-rust] [ci skip-build-wheels] --- build-support/common.sh | 4 ++++ cargo | 11 +++++++++++ pants.toml | 1 + src/python/pants/backend/python/goals/setup_py.py | 10 +++++++++- src/python/pants/python/python_setup.py | 14 ++++++++++++++ src/python/pants/util/osutil.py | 5 +++++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/build-support/common.sh b/build-support/common.sh index 5beae71b469..0601b0d047d 100644 --- a/build-support/common.sh +++ b/build-support/common.sh @@ -69,3 +69,7 @@ function determine_python() { function is_macos_arm() { [[ $(uname -sm) == "Darwin arm64" ]] } + +function is_macos_big_sur() { + [[ $(uname) == "Darwin" && $(sw_vers -productVersion) = 11\.* ]] +} diff --git a/cargo b/cargo index fe3b4307772..d9cec177ee1 100755 --- a/cargo +++ b/cargo @@ -11,6 +11,17 @@ PY="$(determine_python)" export PY export PYO3_PYTHON="${PY}" export PYTHON_SYS_EXECUTABLE="${PY}" # Consumed by the cpython crate. +if is_macos_big_sur; then + # With Big Sur, MacOS changed its versioning scheme from 10.X to 11.X. A pantsbuild.pants + # wheel built on Big Sur will declare its platform (in its name) as macosx_11_0. Unfortunately + # pip does not yet recognize that as a compatible platform for Big Sur. + # Fortunately, Big Sur may also be identified as 10.16, for backwards compatibility with the old + # versioning scheme. Setting MACOSX_DEPLOYMENT_TARGET=10.16 when building the wheel will cause + # that wheel to declare its platform as macosx_10_16, which pip will then happily install. + # However, in order to build the wheel as macosx_10_16 we must also build the native code for + # that platform string, hence this setting here. + export MACOSX_DEPLOYMENT_TARGET=10.16 +fi if ! command -v rustup &> /dev/null; then die "Please install Rustup and ensure \`rustup\` is on your PATH (usually by adding ~/.cargo/bin). See https://rustup.rs." diff --git a/pants.toml b/pants.toml index 49d2ad7c094..4be9bffa03c 100644 --- a/pants.toml +++ b/pants.toml @@ -74,6 +74,7 @@ root_patterns = [ [python-setup] experimental_lockfile = "3rdparty/python/lockfiles/user_reqs.txt" interpreter_constraints = [">=3.7,<3.10"] +macos_big_sur_compatibility = true [docformatter] args = ["--wrap-summaries=100", "--wrap-descriptions=100"] diff --git a/src/python/pants/backend/python/goals/setup_py.py b/src/python/pants/backend/python/goals/setup_py.py index d07ee4c3418..6d956fbe078 100644 --- a/src/python/pants/backend/python/goals/setup_py.py +++ b/src/python/pants/backend/python/goals/setup_py.py @@ -69,6 +69,7 @@ from pants.util.memo import memoized_property from pants.util.meta import frozen_after_init from pants.util.ordered_set import FrozenOrderedSet +from pants.util.osutil import is_macos_big_sur from pants.util.strutil import ensure_text logger = logging.getLogger(__name__) @@ -410,7 +411,9 @@ async def package_python_dist( @rule -async def run_setup_py(req: RunSetupPyRequest, setuptools: Setuptools) -> RunSetupPyResult: +async def run_setup_py( + req: RunSetupPyRequest, setuptools: Setuptools, python_setup: PythonSetup +) -> RunSetupPyResult: """Run a setup.py command on a single exported target.""" # Note that this pex has no entrypoint. We use it to run our generated setup.py, which # in turn imports from and invokes setuptools. @@ -443,12 +446,17 @@ async def run_setup_py(req: RunSetupPyRequest, setuptools: Setuptools) -> RunSet setup_script_reldir, setup_script_name = os.path.split(req.chroot.setup_script) working_directory = os.path.join(chroot_prefix, setup_script_reldir) + if python_setup.macos_big_sur_compatibility and is_macos_big_sur(): + extra_env = {"MACOSX_DEPLOYMENT_TARGET": "10.16"} + else: + extra_env = {} result = await Get( ProcessResult, VenvPexProcess( setuptools_pex, argv=(setup_script_name, *req.args), input_digest=prefixed_chroot, + extra_env=extra_env, working_directory=working_directory, # setuptools commands that create dists write them to the distdir. # TODO: Could there be other useful files to capture? diff --git a/src/python/pants/python/python_setup.py b/src/python/pants/python/python_setup.py index bfdafdb37b7..02d36cd97ff 100644 --- a/src/python/pants/python/python_setup.py +++ b/src/python/pants/python/python_setup.py @@ -216,6 +216,16 @@ def register_options(cls, register): help="Tailor pex_binary() targets for Python entry point files.", ) + register( + "--macos-big-sur-compatibility", + type=bool, + default=False, + help="If set, and if running on MacOS Big Sur, use macosx_10_16 as the platform " + "when building wheels. Otherwise, the default of macosx_11_0 will be used. " + "This may be required for pip to be able to install the resulting distribution " + "on Big Sur.", + ) + @property def interpreter_constraints(self) -> Tuple[str, ...]: return tuple(self.options.interpreter_constraints) @@ -271,6 +281,10 @@ def tailor_ignore_solitary_init_files(self) -> bool: def tailor_pex_binary_targets(self) -> bool: return cast(bool, self.options.tailor_pex_binary_targets) + @property + def macos_big_sur_compatibility(self) -> bool: + return cast(bool, self.options.macos_big_sur_compatibility) + @property def scratch_dir(self): return os.path.join(self.options.pants_workdir, *self.options_scope.split(".")) diff --git a/src/python/pants/util/osutil.py b/src/python/pants/util/osutil.py index 8ba8f6a6295..350953d62f0 100644 --- a/src/python/pants/util/osutil.py +++ b/src/python/pants/util/osutil.py @@ -6,6 +6,7 @@ import errno import logging import os +import platform import posix from functools import reduce from typing import Optional @@ -95,6 +96,10 @@ def get_normalized_arch_name() -> str: return normalize_arch_name(get_arch_name()) +def is_macos_big_sur() -> bool: + return hasattr(platform, "mac_ver") and platform.mac_ver()[0].startswith("11.") + + def _values(aliases: dict[str, set[str]]) -> set[str]: return reduce(set.union, aliases.values())