Files
cibuildwheel/test/utils.py
T

195 lines
6.2 KiB
Python
Raw Normal View History

2021-05-03 11:45:43 -04:00
"""
Utility functions used by the cibuildwheel tests.
This file is added to the PYTHONPATH in the test runner at bin/run_test.py.
2021-05-03 11:45:43 -04:00
"""
2019-11-12 23:51:27 +00:00
import os
2020-02-20 16:12:54 -05:00
import platform as pm
2019-11-12 23:51:27 +00:00
import subprocess
import sys
2021-02-14 20:44:20 +01:00
from tempfile import TemporaryDirectory
platform: str
2021-05-03 11:45:43 -04:00
if "CIBW_PLATFORM" in os.environ:
platform = os.environ["CIBW_PLATFORM"]
elif sys.platform.startswith("linux"):
platform = "linux"
elif sys.platform.startswith("darwin"):
platform = "macos"
elif sys.platform in ["win32", "cygwin"]:
platform = "windows"
else:
2021-05-03 11:45:43 -04:00
raise Exception("Unsupported platform")
2019-04-27 12:12:02 +01:00
def cibuildwheel_get_build_identifiers(project_path, env=None):
2021-05-03 11:45:43 -04:00
"""
Returns the list of build identifiers that cibuildwheel will try to build
for the current platform.
2021-05-03 11:45:43 -04:00
"""
2021-02-14 12:56:33 -05:00
cmd_output = subprocess.run(
2021-05-03 11:45:43 -04:00
[sys.executable, "-m", "cibuildwheel", "--print-build-identifiers", str(project_path)],
universal_newlines=True,
env=env,
2021-02-14 12:56:33 -05:00
check=True,
stdout=subprocess.PIPE,
).stdout
2021-05-03 11:45:43 -04:00
return cmd_output.strip().split("\n")
2021-05-03 11:45:43 -04:00
def cibuildwheel_run(project_path, package_dir=".", env=None, add_env=None, output_dir=None):
"""
2019-09-28 19:24:16 +02:00
Runs cibuildwheel as a subprocess, building the project at project_path.
Uses the current Python interpreter.
:param project_path: path of the project to be built.
:param package_dir: path of the package to be built. Can be absolute, or
relative to project_path.
:param env: full environment to be used, os.environ if None
:param add_env: environment used to update env
:param output_dir: directory where wheels are saved. If None, a temporary
directory will be used for the duration of the command.
:return: list of built wheels (file names).
2021-05-03 11:45:43 -04:00
"""
if env is None:
env = os.environ.copy()
# If present in the host environment, remove the MACOSX_DEPLOYMENT_TARGET for consistency
2021-05-03 11:45:43 -04:00
env.pop("MACOSX_DEPLOYMENT_TARGET", None)
2019-09-28 19:24:16 +02:00
if add_env is not None:
env.update(add_env)
2021-02-14 20:44:20 +01:00
with TemporaryDirectory() as tmp_output_dir:
2021-02-14 12:56:33 -05:00
subprocess.run(
2021-04-30 17:56:34 -04:00
[
sys.executable,
2021-05-03 11:45:43 -04:00
"-m",
"cibuildwheel",
"--output-dir",
2021-02-14 20:44:20 +01:00
str(output_dir or tmp_output_dir),
2021-04-30 17:56:34 -04:00
str(package_dir),
],
env=env,
cwd=project_path,
2021-02-14 12:56:33 -05:00
check=True,
)
2021-02-14 20:44:20 +01:00
wheels = os.listdir(output_dir or tmp_output_dir)
return wheels
2021-01-08 14:59:16 +00:00
def _get_arm64_macosx_deployment_target(macosx_deployment_target: str) -> str:
2021-05-03 11:45:43 -04:00
"""
2021-01-08 14:59:16 +00:00
The first version of macOS that supports arm is 11.0. So the wheel tag
cannot contain an earlier deployment target, even if
MACOSX_DEPLOYMENT_TARGET sets it.
2021-05-03 11:45:43 -04:00
"""
version_tuple = tuple(map(int, macosx_deployment_target.split(".")))
2021-01-08 14:59:16 +00:00
if version_tuple <= (11, 0):
2021-05-03 11:45:43 -04:00
return "11.0"
2021-01-08 14:59:16 +00:00
else:
return macosx_deployment_target
2021-04-30 17:56:34 -04:00
def expected_wheels(
package_name,
package_version,
manylinux_versions=None,
2021-05-03 11:45:43 -04:00
macosx_deployment_target="10.9",
2021-04-30 17:56:34 -04:00
machine_arch=None,
):
2021-05-03 11:45:43 -04:00
"""
Returns a list of expected wheels from a run of cibuildwheel.
2021-05-03 11:45:43 -04:00
"""
2019-12-02 11:07:56 +01:00
# per PEP 425 (https://www.python.org/dev/peps/pep-0425/), wheel files shall have name of the form
# {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
# {python tag} and {abi tag} are closely related to the python interpreter used to build the wheel
# so we'll merge them below as python_abi_tag
2020-02-20 16:12:54 -05:00
2020-12-21 11:06:25 +00:00
if machine_arch is None:
machine_arch = pm.machine()
2020-04-06 23:10:19 +01:00
if manylinux_versions is None:
2021-05-03 11:45:43 -04:00
if machine_arch == "x86_64":
manylinux_versions = ["manylinux_2_5", "manylinux1", "manylinux_2_12", "manylinux2010"]
2020-02-20 16:12:54 -05:00
else:
manylinux_versions = ["manylinux_2_17", "manylinux2014"]
2020-04-06 23:10:19 +01:00
2021-05-01 17:11:09 +02:00
python_abi_tags = ["cp36-cp36m", "cp37-cp37m", "cp38-cp38", "cp39-cp39"]
2020-04-06 23:10:19 +01:00
2021-05-24 09:28:18 +02:00
if machine_arch in ["x86_64", "AMD64", "x86", "aarch64"]:
python_abi_tags += ["pp37-pypy37_pp73"]
2020-04-06 23:10:19 +01:00
2021-05-03 11:45:43 -04:00
if platform == "macos" and get_macos_version() >= (10, 16):
2021-01-08 14:59:16 +00:00
# 10.16 is sometimes reported as the macOS version on macOS 11.
# pypy not supported on macOS 11.
2021-05-03 11:45:43 -04:00
python_abi_tags = [t for t in python_abi_tags if not t.startswith("pp")]
2021-01-01 18:56:36 +00:00
2021-05-03 11:45:43 -04:00
if platform == "macos" and machine_arch == "arm64":
2021-01-08 14:59:16 +00:00
# currently, arm64 macs are only supported by cp39
2021-05-03 11:45:43 -04:00
python_abi_tags = ["cp39-cp39"]
2021-01-08 14:59:16 +00:00
2020-04-06 23:10:19 +01:00
wheels = []
for python_abi_tag in python_abi_tags:
platform_tags = []
2021-05-03 11:45:43 -04:00
if platform == "linux":
2020-12-21 11:06:25 +00:00
architectures = [machine_arch]
2020-04-06 23:10:19 +01:00
2021-05-24 09:44:50 +02:00
if machine_arch == "x86_64":
2021-05-03 11:45:43 -04:00
architectures.append("i686")
2020-04-06 23:10:19 +01:00
platform_tags = [
".".join(
[
f"{manylinux_version}_{architecture}"
for manylinux_version in manylinux_versions
]
)
2020-04-06 23:10:19 +01:00
for architecture in architectures
]
2021-05-03 11:45:43 -04:00
elif platform == "windows":
if python_abi_tag.startswith("cp"):
platform_tags = ["win32", "win_amd64"]
2020-04-06 23:10:19 +01:00
else:
platform_tags = ["win_amd64"]
2021-05-03 11:45:43 -04:00
elif platform == "macos":
if python_abi_tag == "cp39-cp39" and machine_arch == "arm64":
2021-04-30 17:56:34 -04:00
arm64_macosx_deployment_target = _get_arm64_macosx_deployment_target(
macosx_deployment_target
)
2021-01-08 14:59:16 +00:00
platform_tags = [
2021-01-30 17:22:26 +00:00
f'macosx_{macosx_deployment_target.replace(".", "_")}_universal2',
2021-01-08 14:59:16 +00:00
f'macosx_{arm64_macosx_deployment_target.replace(".", "_")}_arm64',
]
2021-01-01 18:56:36 +00:00
else:
platform_tags = [
f'macosx_{macosx_deployment_target.replace(".", "_")}_x86_64',
]
2019-11-19 23:36:20 +01:00
2020-04-06 23:10:19 +01:00
else:
2021-05-03 11:45:43 -04:00
raise Exception("unsupported platform")
2020-02-20 16:17:51 -05:00
2020-04-06 23:10:19 +01:00
for platform_tag in platform_tags:
2021-05-03 11:45:43 -04:00
wheels.append(f"{package_name}-{package_version}-{python_abi_tag}-{platform_tag}.whl")
2019-12-02 11:07:56 +01:00
2020-04-06 23:10:19 +01:00
return wheels
2019-12-02 11:07:56 +01:00
def get_macos_version():
2021-05-03 11:45:43 -04:00
"""
Returns the macOS major/minor version, as a tuple, e.g. (10, 15) or (11, 0)
These tuples can be used in comparisons, e.g.
(10, 14) <= (11, 0) == True
(11, 2) <= (11, 0) != True
2021-05-03 11:45:43 -04:00
"""
version_str, _, _ = pm.mac_ver()
return tuple(map(int, version_str.split(".")[:2]))