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())