feat: add support for free-threaded (no-gil) Python 3.13
This commit is contained in:
@@ -337,6 +337,10 @@ def build_in_container(
|
||||
virtualenv_env = env.copy()
|
||||
virtualenv_env["PATH"] = f"{venv_dir / 'bin'}:{virtualenv_env['PATH']}"
|
||||
|
||||
# TODO remove me once virtualenv provides pip>=24.1b1
|
||||
if config.version == "3.13":
|
||||
container.call(["pip", "install", "pip>=24.1b1"], env=virtualenv_env)
|
||||
|
||||
if build_options.before_test:
|
||||
before_test_prepared = prepare_command(
|
||||
build_options.before_test,
|
||||
|
||||
@@ -575,6 +575,10 @@ def build(options: Options, tmp_path: Path) -> None:
|
||||
# check that we are using the Python from the virtual environment
|
||||
call_with_arch("which", "python", env=virtualenv_env)
|
||||
|
||||
# TODO remove me once virtualenv provides pip>=24.1b1
|
||||
if config.version == "3.13":
|
||||
call("python", "-m", "pip", "install", "pip>=24.1b1", env=virtualenv_env)
|
||||
|
||||
if build_options.before_test:
|
||||
before_test_prepared = prepare_command(
|
||||
build_options.before_test,
|
||||
|
||||
@@ -8,6 +8,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-manylinux_x86_64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-manylinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-manylinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "cp36-manylinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||
{ identifier = "cp37-manylinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||
{ identifier = "cp38-manylinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||
@@ -16,6 +17,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-manylinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-manylinux_i686", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-manylinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-manylinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "pp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
|
||||
{ identifier = "pp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
|
||||
{ identifier = "pp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
||||
@@ -28,6 +30,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-manylinux_aarch64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-manylinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-manylinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "cp36-manylinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||
{ identifier = "cp37-manylinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||
{ identifier = "cp38-manylinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||
@@ -36,6 +39,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-manylinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-manylinux_ppc64le", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-manylinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-manylinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "cp36-manylinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||
{ identifier = "cp37-manylinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||
{ identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||
@@ -44,6 +48,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-manylinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-manylinux_s390x", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-manylinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-manylinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "pp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
|
||||
{ identifier = "pp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
|
||||
{ identifier = "pp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
||||
@@ -60,6 +65,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-musllinux_x86_64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-musllinux_x86_64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-musllinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-musllinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "cp36-musllinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||
{ identifier = "cp37-musllinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||
{ identifier = "cp38-musllinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||
@@ -68,6 +74,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-musllinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-musllinux_i686", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-musllinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-musllinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "cp36-musllinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||
{ identifier = "cp37-musllinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||
{ identifier = "cp38-musllinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||
@@ -76,6 +83,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-musllinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-musllinux_aarch64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-musllinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-musllinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "cp36-musllinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||
{ identifier = "cp37-musllinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||
{ identifier = "cp38-musllinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||
@@ -84,6 +92,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-musllinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-musllinux_ppc64le", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-musllinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-musllinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
{ identifier = "cp36-musllinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||
{ identifier = "cp37-musllinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||
{ identifier = "cp38-musllinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||
@@ -92,6 +101,7 @@ python_configurations = [
|
||||
{ identifier = "cp311-musllinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||
{ identifier = "cp312-musllinux_s390x", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||
{ identifier = "cp313-musllinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||
{ identifier = "cp313t-musllinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||
]
|
||||
|
||||
[macos]
|
||||
@@ -142,12 +152,15 @@ python_configurations = [
|
||||
{ identifier = "cp312-win32", version = "3.12.3", arch = "32" },
|
||||
{ identifier = "cp312-win_amd64", version = "3.12.3", arch = "64" },
|
||||
{ identifier = "cp313-win32", version = "3.13.0-b1", arch = "32" },
|
||||
{ identifier = "cp313t-win32", version = "3.13.0-b1", arch = "32" },
|
||||
{ identifier = "cp313-win_amd64", version = "3.13.0-b1", arch = "64" },
|
||||
{ identifier = "cp313t-win_amd64", version = "3.13.0-b1", arch = "64" },
|
||||
{ identifier = "cp39-win_arm64", version = "3.9.10", arch = "ARM64" },
|
||||
{ identifier = "cp310-win_arm64", version = "3.10.11", arch = "ARM64" },
|
||||
{ identifier = "cp311-win_arm64", version = "3.11.9", arch = "ARM64" },
|
||||
{ identifier = "cp312-win_arm64", version = "3.12.3", arch = "ARM64" },
|
||||
{ identifier = "cp313-win_arm64", version = "3.13.0-b1", arch = "ARM64" },
|
||||
{ identifier = "cp313t-win_arm64", version = "3.13.0-b1", arch = "ARM64" },
|
||||
{ identifier = "pp37-win_amd64", version = "3.7", arch = "64", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.9-win64.zip" },
|
||||
{ identifier = "pp38-win_amd64", version = "3.8", arch = "64", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-win64.zip" },
|
||||
{ identifier = "pp39-win_amd64", version = "3.9", arch = "64", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
|
||||
|
||||
@@ -16,7 +16,7 @@ packaging==24.0
|
||||
# via
|
||||
# build
|
||||
# delocate
|
||||
pip==24.0
|
||||
pip==24.1b1
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
platformdirs==4.2.2
|
||||
# via virtualenv
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pip
|
||||
pip>=24.1b1 ; python_version >= '3.13'
|
||||
pip ; python_version < '3.13'
|
||||
build
|
||||
delocate
|
||||
virtualenv
|
||||
|
||||
@@ -238,13 +238,15 @@ class BuildSelector:
|
||||
requires_python: SpecifierSet | None = None
|
||||
|
||||
# a pattern that skips prerelease versions, when include_prereleases is False.
|
||||
PRERELEASE_SKIP: ClassVar[str] = "cp313-*"
|
||||
PRERELEASE_SKIP: ClassVar[str] = "cp313-* cp313t-*"
|
||||
prerelease_pythons: bool = False
|
||||
|
||||
def __call__(self, build_id: str) -> bool:
|
||||
# Filter build selectors by python_requires if set
|
||||
if self.requires_python is not None:
|
||||
py_ver_str = build_id.split("-")[0]
|
||||
if py_ver_str.endswith("t"):
|
||||
py_ver_str = py_ver_str[:-1]
|
||||
major = int(py_ver_str[2])
|
||||
minor = int(py_ver_str[3:])
|
||||
version = Version(f"{major}.{minor}.99")
|
||||
@@ -645,10 +647,13 @@ def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> T | None:
|
||||
"""
|
||||
|
||||
interpreter, platform = identifier.split("-")
|
||||
free_threaded = interpreter.endswith("t")
|
||||
if free_threaded:
|
||||
interpreter = interpreter[:-1]
|
||||
for wheel in wheels:
|
||||
_, _, _, tags = parse_wheel_filename(wheel.name)
|
||||
for tag in tags:
|
||||
if tag.abi == "abi3":
|
||||
if tag.abi == "abi3" and not free_threaded:
|
||||
# ABI3 wheels must start with cp3 for impl and tag
|
||||
if not (interpreter.startswith("cp3") and tag.interpreter.startswith("cp3")):
|
||||
continue
|
||||
|
||||
+19
-7
@@ -44,7 +44,9 @@ from .util import (
|
||||
)
|
||||
|
||||
|
||||
def get_nuget_args(version: str, arch: str, output_directory: Path) -> list[str]:
|
||||
def get_nuget_args(
|
||||
version: str, arch: str, free_threaded: bool, output_directory: Path
|
||||
) -> list[str]:
|
||||
package_name = {
|
||||
"32": "pythonx86",
|
||||
"64": "python",
|
||||
@@ -53,6 +55,8 @@ def get_nuget_args(version: str, arch: str, output_directory: Path) -> list[str]
|
||||
"x86": "pythonx86",
|
||||
"AMD64": "python",
|
||||
}[arch]
|
||||
if free_threaded:
|
||||
package_name = f"{package_name}-freethreaded"
|
||||
return [
|
||||
package_name,
|
||||
"-Version",
|
||||
@@ -106,11 +110,12 @@ def _ensure_nuget() -> Path:
|
||||
return nuget
|
||||
|
||||
|
||||
def install_cpython(version: str, arch: str) -> Path:
|
||||
def install_cpython(version: str, arch: str, free_threaded: bool) -> Path:
|
||||
base_output_dir = CIBW_CACHE_PATH / "nuget-cpython"
|
||||
nuget_args = get_nuget_args(version, arch, base_output_dir)
|
||||
nuget_args = get_nuget_args(version, arch, free_threaded, base_output_dir)
|
||||
installation_path = base_output_dir / (nuget_args[0] + "." + version) / "tools"
|
||||
with FileLock(str(base_output_dir) + f"-{version}-{arch}.lock"):
|
||||
free_threaded_str = "-freethreaded" if free_threaded else ""
|
||||
with FileLock(str(base_output_dir) + f"-{version}{free_threaded_str}-{arch}.lock"):
|
||||
if not installation_path.exists():
|
||||
nuget = _ensure_nuget()
|
||||
call(nuget, "install", *nuget_args)
|
||||
@@ -224,18 +229,21 @@ def setup_python(
|
||||
log.step(f"Installing Python {implementation_id}...")
|
||||
if implementation_id.startswith("cp"):
|
||||
native_arch = platform_module.machine()
|
||||
free_threaded = implementation_id.endswith("t")
|
||||
if python_configuration.arch == "ARM64" != native_arch:
|
||||
# To cross-compile for ARM64, we need a native CPython to run the
|
||||
# build, and a copy of the ARM64 import libraries ('.\libs\*.lib')
|
||||
# for any extension modules.
|
||||
python_libs_base = install_cpython(
|
||||
python_configuration.version, python_configuration.arch
|
||||
python_configuration.version, python_configuration.arch, free_threaded
|
||||
)
|
||||
python_libs_base = python_libs_base.parent / "libs"
|
||||
log.step(f"Installing native Python {native_arch} for cross-compilation...")
|
||||
base_python = install_cpython(python_configuration.version, native_arch)
|
||||
base_python = install_cpython(python_configuration.version, native_arch, free_threaded)
|
||||
else:
|
||||
base_python = install_cpython(python_configuration.version, python_configuration.arch)
|
||||
base_python = install_cpython(
|
||||
python_configuration.version, python_configuration.arch, free_threaded
|
||||
)
|
||||
elif implementation_id.startswith("pp"):
|
||||
assert python_configuration.url is not None
|
||||
base_python = install_pypy(tmp, python_configuration.arch, python_configuration.url)
|
||||
@@ -521,6 +529,10 @@ def build(options: Options, tmp_path: Path) -> None:
|
||||
# check that we are using the Python from the virtual environment
|
||||
call("where", "python", env=virtualenv_env)
|
||||
|
||||
# TODO remove me once virtualenv provides pip>=24.1b1
|
||||
if config.version.startswith("3.13."):
|
||||
call("python", "-m", "pip", "install", "--pre", "-U", "pip", env=virtualenv_env)
|
||||
|
||||
if build_options.before_test:
|
||||
before_test_prepared = prepare_command(
|
||||
build_options.before_test,
|
||||
|
||||
Reference in New Issue
Block a user