diff --git a/.cirrus.yml b/.cirrus.yml index f8e84294f..2fe3559c2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -73,19 +73,3 @@ macos_arm64_task: - brew install python@3.12 - python3.12 -m venv ${VENV_ROOT} <<: *RUN_TESTS - -macos_arm64_cp38_task: - macos_instance: - image: ghcr.io/cirruslabs/macos-runner:sequoia - env: - VENV_ROOT: ${HOME}/venv-cibuildwheel - PATH: ${VENV_ROOT}/bin:${PATH} - PYTEST_ADDOPTS: --run-cp38-universal2 -k 'test_cp38_arm64_testing_universal2_installer or test_arch_auto or test_dummy_serial' - install_pre_requirements_script: - - brew install python@3.12 - - python3.12 -m venv ${VENV_ROOT} - - curl -fsSLO https://www.python.org/ftp/python/3.8.10/python-3.8.10-macos11.pkg - - sudo installer -pkg python-3.8.10-macos11.pkg -target / - - rm python-3.8.10-macos11.pkg - - sh "/Applications/Python 3.8/Install Certificates.command" - <<: *RUN_TESTS diff --git a/README.md b/README.md index 84466c199..8fd195bbb 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,12 @@ While cibuildwheel itself requires a recent Python version to run (we support th | | macOS Intel | macOS Apple Silicon | Windows 64bit | Windows 32bit | Windows Arm64 | manylinux
musllinux x86_64 | manylinux
musllinux i686 | manylinux
musllinux aarch64 | manylinux
musllinux ppc64le | manylinux
musllinux s390x | manylinux
musllinux armv7l | Android | iOS | Pyodide | |--------------------|----|-----|----|-----|-----|----|-----|----|-----|-----|---|-----|-----|-----| -| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | N/A | | CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | N/A | | CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | N/A | | CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | N/A | | CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | N/A | N/A | ✅⁴ | | CPython 3.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | ✅ | ✅ | ✅⁴ | | CPython 3.14 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁵ | ✅ | ✅ | N/A | -| PyPy 3.8 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A | | PyPy 3.9 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A | | PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A | | PyPy 3.11 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A | N/A | diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index 72e2434bc..b7e547b8d 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -534,10 +534,13 @@ def check_for_invalid_selectors( msg += "This selector matches a group that wasn't enabled. Enable it using the `enable` option or remove this selector. " if "p2" in selector_ or "p35" in selector_: - msg += f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 1.x series or update `{selector_name}`. " + msg += f"cibuildwheel 4.x no longer supports Python < 3.9. Please use the 1.x series or update `{selector_name}`. " error_type = errors.DeprecationError if "p36" in selector_ or "p37" in selector_: - msg += f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 2.x series or update `{selector_name}`. " + msg += f"cibuildwheel 4.x no longer supports Python < 3.9. Please use the 2.x series or update `{selector_name}`. " + error_type = errors.DeprecationError + if "p38" in selector_: + msg += f"cibuildwheel 4.x no longer supports Python < 3.9. Please use the 3.x series or update `{selector_name}`. " error_type = errors.DeprecationError if selector_name == "build": diff --git a/cibuildwheel/frontend.py b/cibuildwheel/frontend.py index 6f54de550..ba38bb610 100644 --- a/cibuildwheel/frontend.py +++ b/cibuildwheel/frontend.py @@ -4,7 +4,6 @@ from collections.abc import Sequence from typing import Literal, Self, get_args -from .logger import log from .util.helpers import parse_key_value_string BuildFrontendName = Literal["pip", "build", "build[uv]", "uv"] @@ -36,12 +35,8 @@ def options_summary(self) -> str | dict[str, str]: return {"name": self.name, "args": repr(self.args)} -def _get_verbosity_flags(level: int, frontend: BuildFrontendName, *, py38: bool) -> list[str]: +def _get_verbosity_flags(level: int, frontend: BuildFrontendName) -> list[str]: if level < 0: - if frontend.startswith("build") and py38: - msg = f"build_verbosity {level} is not supported for {frontend} frontend. Ignoring." - log.warning(msg) - return [] return ["-" + -level * "q"] if level > 0: @@ -75,10 +70,10 @@ def parse_config_settings(config_settings_str: str) -> dict[str, str | list[str] def get_build_frontend_extra_flags( - build_frontend: BuildFrontendConfig, verbosity_level: int, config_settings: str, *, py38: bool + build_frontend: BuildFrontendConfig, verbosity_level: int, config_settings: str ) -> list[str]: return [ *_split_config_settings(config_settings), *build_frontend.args, - *_get_verbosity_flags(verbosity_level, build_frontend.name, py38=py38), + *_get_verbosity_flags(verbosity_level, build_frontend.name), ] diff --git a/cibuildwheel/platforms/android.py b/cibuildwheel/platforms/android.py index 5f4839e58..3d23deb16 100644 --- a/cibuildwheel/platforms/android.py +++ b/cibuildwheel/platforms/android.py @@ -457,7 +457,6 @@ def build_wheel(state: BuildState) -> Path: state.options.build_frontend, state.options.build_verbosity, state.options.config_settings, - py38=False, ), env=state.android_env, ) @@ -475,7 +474,6 @@ def build_wheel(state: BuildState) -> Path: state.options.build_frontend, state.options.build_verbosity, state.options.config_settings, - py38=False, ), env=state.android_env, ) diff --git a/cibuildwheel/platforms/ios.py b/cibuildwheel/platforms/ios.py index a4229e994..72320e165 100644 --- a/cibuildwheel/platforms/ios.py +++ b/cibuildwheel/platforms/ios.py @@ -490,7 +490,6 @@ def build(options: Options, tmp_path: Path) -> None: build_frontend, build_options.build_verbosity, build_options.config_settings, - py38=False, ) match build_frontend.name: diff --git a/cibuildwheel/platforms/linux.py b/cibuildwheel/platforms/linux.py index 818ad8f08..f9119376b 100644 --- a/cibuildwheel/platforms/linux.py +++ b/cibuildwheel/platforms/linux.py @@ -277,7 +277,6 @@ def build_in_container( build_frontend, build_options.build_verbosity, build_options.config_settings, - py38=config.identifier[1:].startswith("p38"), ) match build_frontend.name: diff --git a/cibuildwheel/platforms/macos.py b/cibuildwheel/platforms/macos.py index 137c68964..e2cc175fd 100644 --- a/cibuildwheel/platforms/macos.py +++ b/cibuildwheel/platforms/macos.py @@ -475,7 +475,6 @@ def build(options: Options, tmp_path: Path) -> None: build_frontend, build_options.build_verbosity, build_options.config_settings, - py38=config.identifier[1:].startswith("p38"), ) build_env = env.copy() @@ -568,13 +567,6 @@ def build(options: Options, tmp_path: Path) -> None: if build_options.test_command and build_options.test_selector(config.identifier): machine_arch = platform.machine() - python_arch = call( - "python", - "-sSc", - "import platform; print(platform.machine())", - env=env, - capture_stdout=True, - ).strip() testing_archs: list[Literal["x86_64", "arm64"]] if config_is_arm64: @@ -622,24 +614,6 @@ def build(options: Options, tmp_path: Path) -> None: # skip this test continue - is_cp38 = config.identifier.startswith("cp38-") - if testing_arch == "arm64" and is_cp38 and python_arch != "arm64": - log.warning( - unwrap( - """ - While cibuildwheel can build CPython 3.8 universal2/arm64 wheels, we - cannot test the arm64 part of them, even when running on an Apple - Silicon machine. This is because we use the x86_64 installer of - CPython 3.8. See the discussion in - https://github.com/pypa/cibuildwheel/pull/1169 for the details. To - silence this warning, set `CIBW_TEST_SKIP: "cp38-macosx_*:arm64"`. - """ - ) - ) - - # skip this test - continue - log.step( "Testing wheel..." if testing_arch == machine_arch @@ -696,33 +670,16 @@ def build(options: Options, tmp_path: Path) -> None: shell_with_arch(before_test_prepared, env=virtualenv_env) # install the wheel - if is_cp38 and python_arch == "x86_64": - virtualenv_env_install_wheel = virtualenv_env.copy() - virtualenv_env_install_wheel["SYSTEM_VERSION_COMPAT"] = "0" - log.notice( - unwrap( - """ - Setting SYSTEM_VERSION_COMPAT=0 to ensure CPython 3.8 can get - correct macOS version and allow installation of wheels with - MACOSX_DEPLOYMENT_TARGET >= 11.0. - See https://github.com/pypa/cibuildwheel/issues/1767 for the - details. - """ - ) - ) - else: - virtualenv_env_install_wheel = virtualenv_env - pip_install( f"{repaired_wheel}{build_options.test_extras}", - env=virtualenv_env_install_wheel, + env=virtualenv_env, ) # test the wheel if build_options.test_requires: pip_install( *build_options.test_requires, - env=virtualenv_env_install_wheel, + env=virtualenv_env, ) # run the tests from a temp dir, with an absolute path in the command diff --git a/cibuildwheel/platforms/pyodide.py b/cibuildwheel/platforms/pyodide.py index 996f0484d..c68cc6bb0 100644 --- a/cibuildwheel/platforms/pyodide.py +++ b/cibuildwheel/platforms/pyodide.py @@ -419,7 +419,6 @@ def build(options: Options, tmp_path: Path) -> None: build_frontend, build_options.build_verbosity, build_options.config_settings, - py38=False, ) call( diff --git a/cibuildwheel/platforms/windows.py b/cibuildwheel/platforms/windows.py index d13d925bf..8d1be7e21 100644 --- a/cibuildwheel/platforms/windows.py +++ b/cibuildwheel/platforms/windows.py @@ -232,11 +232,6 @@ def setup_rust_cross_compile( ) -def can_use_uv(python_configuration: PythonConfiguration) -> bool: - conditions = (not python_configuration.identifier.startswith("pp38-"),) - return all(conditions) - - def setup_python( tmp: Path, python_configuration: PythonConfiguration, @@ -268,9 +263,6 @@ def setup_python( raise ValueError(msg) assert base_python.exists() - if build_frontend == "build[uv]" and not can_use_uv(python_configuration): - build_frontend = "build" - use_uv = build_frontend in {"build[uv]", "uv"} uv_path = find_uv() @@ -405,7 +397,7 @@ def build(options: Options, tmp_path: Path) -> None: for config in python_configurations: build_options = options.build_options(config.identifier) build_frontend = build_options.build_frontend - use_uv = build_frontend.name in {"build[uv]", "uv"} and can_use_uv(config) + use_uv = build_frontend.name in {"build[uv]", "uv"} log.build_start(config.identifier) identifier_tmp_dir = tmp_path / config.identifier @@ -453,7 +445,6 @@ def build(options: Options, tmp_path: Path) -> None: build_frontend, build_options.build_verbosity, build_options.config_settings, - py38=config.identifier[1:].startswith("p38"), ) if ( diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml index 15c5afecc..f62392302 100644 --- a/cibuildwheel/resources/build-platforms.toml +++ b/cibuildwheel/resources/build-platforms.toml @@ -1,6 +1,5 @@ [linux] python_configurations = [ - { identifier = "cp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-manylinux_x86_64", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -9,7 +8,6 @@ python_configurations = [ { identifier = "cp313t-manylinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-manylinux_x86_64", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-manylinux_x86_64", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-manylinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-manylinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-manylinux_i686", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-manylinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -18,13 +16,11 @@ python_configurations = [ { identifier = "cp313t-manylinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-manylinux_i686", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-manylinux_i686", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { 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" }, { identifier = "pp310-manylinux_x86_64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" }, { identifier = "pp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" }, { identifier = "gp311_242-manylinux_x86_64", version = "3.11", path_str = "/opt/python/graalpy311-graalpy242_311_native" }, { identifier = "gp312_250-manylinux_x86_64", version = "3.12", path_str = "/opt/python/graalpy312-graalpy250_312_native" }, - { identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -33,7 +29,6 @@ python_configurations = [ { identifier = "cp313t-manylinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-manylinux_aarch64", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-manylinux_aarch64", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-manylinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-manylinux_ppc64le", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-manylinux_ppc64le", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-manylinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -42,7 +37,6 @@ python_configurations = [ { identifier = "cp313t-manylinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-manylinux_ppc64le", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-manylinux_ppc64le", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-manylinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-manylinux_s390x", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-manylinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -51,7 +45,6 @@ python_configurations = [ { identifier = "cp313t-manylinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-manylinux_s390x", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-manylinux_s390x", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-manylinux_armv7l", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-manylinux_armv7l", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-manylinux_armv7l", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-manylinux_armv7l", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -60,7 +53,6 @@ python_configurations = [ { identifier = "cp313t-manylinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-manylinux_armv7l", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-manylinux_armv7l", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-manylinux_riscv64", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-manylinux_riscv64", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-manylinux_riscv64", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-manylinux_riscv64", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -69,17 +61,14 @@ python_configurations = [ { identifier = "cp313t-manylinux_riscv64", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-manylinux_riscv64", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-manylinux_riscv64", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { 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" }, { identifier = "pp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" }, { identifier = "pp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" }, { identifier = "gp311_242-manylinux_aarch64", version = "3.11", path_str = "/opt/python/graalpy311-graalpy242_311_native" }, { identifier = "gp312_250-manylinux_aarch64", version = "3.12", path_str = "/opt/python/graalpy312-graalpy250_312_native" }, - { identifier = "pp38-manylinux_i686", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" }, { identifier = "pp39-manylinux_i686", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" }, { identifier = "pp310-manylinux_i686", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" }, { identifier = "pp311-manylinux_i686", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" }, - { identifier = "cp38-musllinux_x86_64", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-musllinux_x86_64", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-musllinux_x86_64", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-musllinux_x86_64", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -88,7 +77,6 @@ python_configurations = [ { identifier = "cp313t-musllinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-musllinux_x86_64", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-musllinux_x86_64", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-musllinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-musllinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-musllinux_i686", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-musllinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -97,7 +85,6 @@ python_configurations = [ { identifier = "cp313t-musllinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-musllinux_i686", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-musllinux_i686", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-musllinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-musllinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-musllinux_aarch64", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-musllinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -106,7 +93,6 @@ python_configurations = [ { identifier = "cp313t-musllinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-musllinux_aarch64", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-musllinux_aarch64", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-musllinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-musllinux_ppc64le", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-musllinux_ppc64le", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-musllinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -115,7 +101,6 @@ python_configurations = [ { identifier = "cp313t-musllinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-musllinux_ppc64le", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-musllinux_ppc64le", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-musllinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-musllinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-musllinux_s390x", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-musllinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -124,7 +109,6 @@ python_configurations = [ { identifier = "cp313t-musllinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-musllinux_s390x", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-musllinux_s390x", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-musllinux_armv7l", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-musllinux_armv7l", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-musllinux_armv7l", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-musllinux_armv7l", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -133,7 +117,6 @@ python_configurations = [ { identifier = "cp313t-musllinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, { identifier = "cp314-musllinux_armv7l", version = "3.14", path_str = "/opt/python/cp314-cp314" }, { identifier = "cp314t-musllinux_armv7l", version = "3.14", path_str = "/opt/python/cp314-cp314t" }, - { identifier = "cp38-musllinux_riscv64", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-musllinux_riscv64", version = "3.9", path_str = "/opt/python/cp39-cp39" }, { identifier = "cp310-musllinux_riscv64", version = "3.10", path_str = "/opt/python/cp310-cp310" }, { identifier = "cp311-musllinux_riscv64", version = "3.11", path_str = "/opt/python/cp311-cp311" }, @@ -146,9 +129,6 @@ python_configurations = [ [macos] python_configurations = [ - { identifier = "cp38-macosx_x86_64", version = "3.8", url = "https://www.python.org/ftp/python/3.8.10/python-3.8.10-macosx10.9.pkg" }, - { identifier = "cp38-macosx_arm64", version = "3.8", url = "https://www.python.org/ftp/python/3.8.10/python-3.8.10-macosx10.9.pkg" }, - { identifier = "cp38-macosx_universal2", version = "3.8", url = "https://www.python.org/ftp/python/3.8.10/python-3.8.10-macosx10.9.pkg" }, { identifier = "cp39-macosx_x86_64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.13/python-3.9.13-macos11.pkg" }, { identifier = "cp39-macosx_arm64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.13/python-3.9.13-macos11.pkg" }, { identifier = "cp39-macosx_universal2", version = "3.9", url = "https://www.python.org/ftp/python/3.9.13/python-3.9.13-macos11.pkg" }, @@ -173,8 +153,6 @@ python_configurations = [ { identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" }, { identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" }, { identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" }, - { identifier = "pp38-macosx_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_x86_64.tar.bz2" }, - { identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" }, { identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" }, { identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" }, { identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.bz2" }, @@ -189,8 +167,6 @@ python_configurations = [ [windows] python_configurations = [ - { identifier = "cp38-win32", version = "3.8.10" }, - { identifier = "cp38-win_amd64", version = "3.8.10" }, { identifier = "cp39-win32", version = "3.9.13" }, { identifier = "cp39-win_amd64", version = "3.9.13" }, { identifier = "cp310-win32", version = "3.10.11" }, @@ -215,7 +191,6 @@ python_configurations = [ { identifier = "cp313t-win_arm64", version = "3.13.12" }, { identifier = "cp314-win_arm64", version = "3.14.3" }, { identifier = "cp314t-win_arm64", version = "3.14.3" }, - { identifier = "pp38-win_amd64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-win64.zip" }, { identifier = "pp39-win_amd64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" }, { identifier = "pp310-win_amd64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" }, { identifier = "pp311-win_amd64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.20-win64.zip" }, diff --git a/cibuildwheel/resources/constraints-python38.txt b/cibuildwheel/resources/constraints-python38.txt deleted file mode 100644 index bbbf70d46..000000000 --- a/cibuildwheel/resources/constraints-python38.txt +++ /dev/null @@ -1,42 +0,0 @@ -# This file was autogenerated by uv via the following command: -# nox -s update_constraints -altgraph==0.17.5 - # via macholib -build==1.2.2.post1 - # via -r cibuildwheel/resources/constraints.in -delocate==0.12.0 - # via -r cibuildwheel/resources/constraints.in -distlib==0.4.0 - # via virtualenv -filelock==3.16.1 - # via - # python-discovery - # virtualenv -importlib-metadata==8.5.0 - # via build -macholib==1.16.4 - # via delocate -packaging==26.0 - # via - # build - # delocate -pip==25.0.1 - # via -r cibuildwheel/resources/constraints.in -platformdirs==4.3.6 - # via - # python-discovery - # virtualenv -pyproject-hooks==1.2.0 - # via build -python-discovery==1.1.0 - # via virtualenv -tomli==2.4.0 - # via build -typing-extensions==4.13.2 - # via - # delocate - # virtualenv -virtualenv==21.1.0 - # via -r cibuildwheel/resources/constraints.in -zipp==3.20.2 - # via importlib-metadata diff --git a/docs/configuration.md b/docs/configuration.md index 0bdfd01b4..0e5146505 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -142,17 +142,17 @@ which means it can be given multiple times. manylinux-x86_64-image = "manylinux_2_34" [[tool.cibuildwheel.overrides]] -select = "cp38-*" +select = "cp39-*" manylinux-x86_64-image = "manylinux2014" [[tool.cibuildwheel.overrides]] -select = "cp3{9,10}-*" +select = "cp3{10,11}-*" manylinux-x86_64-image = "manylinux_2_28" ``` -This example will build CPython 3.8 wheels on manylinux2014, CPython 3.9-3.10 +This example will build CPython 3.9 wheels on manylinux2014, CPython 3.10-3.11 wheels on manylinux_2_28, and manylinux_2_34 wheels for any newer Python -(like 3.10). +(like 3.14). ```toml [tool.cibuildwheel] diff --git a/docs/contributing.md b/docs/contributing.md index 31c879a79..14e255512 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -161,32 +161,6 @@ bin/run_example_ci_configs.py examples/github-with-qemu.yml The script then outputs a Markdown table that can be copy/pasted into a PR to monitor and record the test. -### Preparing environments - -This has been moved to using docker, so you only need the following instructions if you add `--no-docker` to avoid using docker. - -The dependency update script in the next section requires multiple python versions installed. One way to do this is to use `pyenv`: - -```bash -pyenv install 3.7.8 -# Optionally add 3.8 and make it the local version; -# otherwise assuming 3.8+ already is your current python version -``` - -Then, you need to make the required virtual environments: - -```bash -$(pyenv prefix 3.7.8)/bin/python -m venv env37 -``` - - - -And, you need to install the requirements into each environment: - -```bash -for f in env*/bin/pip; do $f install pip-tools; done -``` - ### Making a release Before making a release, ensure pinned dependencies are up-to-date. Autoupdates are run weekly, with a PR being raised with any changes as required, so just make sure the latest one is merged before continuing. diff --git a/docs/faq.md b/docs/faq.md index 25198231d..043cf410f 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -341,34 +341,6 @@ To work around this, use a different environment variable such as `REPAIR_LIBRAR See [#816](https://github.com/pypa/cibuildwheel/issues/816), thanks to @phoerious for reporting. -### macOS: Building CPython 3.8 wheels on arm64 - -If you're building on an arm64 runner, you might notice something strange about CPython 3.8 - unlike Python 3.9+, it's cross-compiled to arm64 from an x86_64 version of Python running under Rosetta emulation. This is because (despite the prevalence of arm64 versions of Python 3.8 from Apple and Homebrew) there is no officially supported Python.org installer of Python 3.8 for arm64. - -This is fine for simple C extensions, but for more complicated builds on arm64 it becomes an issue. - -So, if you want to build macOS arm64 wheels on an arm64 runner (e.g., `macos-14`) on Python 3.8, before invoking cibuildwheel, you should install a native arm64 Python 3.8 interpreter on the runner: - - -!!! tab "GitHub Actions" - - ```yaml - - uses: actions/setup-python@v5 - with: - python-version: 3.8 - if: runner.os == 'macOS' && runner.arch == 'ARM64' - ``` - -!!! tab "Generic" - - ```bash - curl -o /tmp/Python38.pkg https://www.python.org/ftp/python/3.8.10/python-3.8.10-macos11.pkg - sudo installer -pkg /tmp/Python38.pkg -target / - sh "/Applications/Python 3.8/Install Certificates.command" - ``` - -Then cibuildwheel will detect that it's installed and use it instead. However, you probably don't want to build x86_64 wheels on this Python, unless you're happy with them only supporting macOS 11+. - ### macOS: Library dependencies do not satisfy target MacOS Since delocate 0.11.0 there is added verification that the library binary dependencies match the target macOS version. This is to prevent the situation where a wheel platform tag is lower than the actual minimum macOS version required by the library. To resolve this error you need to build the library to the same macOS version as the target wheel (for example using `MACOSX_DEPLOYMENT_TARGET` environment variable). diff --git a/docs/options.md b/docs/options.md index fd84d83c0..bd7d363ec 100644 --- a/docs/options.md +++ b/docs/options.md @@ -45,7 +45,7 @@ This option can also be set using the [command-line option](#command-line) `--pl > Choose the Python versions to build -List of builds to build and skip. Each build has an identifier like `cp38-manylinux_x86_64` or `cp37-macosx_x86_64` - you can list specific ones to build and cibuildwheel will only build those, and/or list ones to skip and cibuildwheel won't try to build them. +List of builds to build and skip. Each build has an identifier like `cp314-manylinux_x86_64` or `cp313-macosx_x86_64` - you can list specific ones to build and cibuildwheel will only build those, and/or list ones to skip and cibuildwheel won't try to build them. When both options are specified, both conditions are applied and only builds with a tag that matches `build` and does not match `skip` will be built. @@ -54,14 +54,12 @@ When setting the options, you can use shell-style globbing syntax, as per [fnmat
| | macOS | Windows | Linux Intel | Linux Other | Android | iOS | pyodide (WASM) | |---------------|------------------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------|---------------------------------------------------------------------------------------------------|----------------------| -| Python 3.8 | cp38-macosx_x86_64
cp38-macosx_universal2
cp38-macosx_arm64 | cp38-win_amd64
cp38-win32 | cp38-manylinux_x86_64
cp38-manylinux_i686
cp38-musllinux_x86_64
cp38-musllinux_i686 | cp38-manylinux_aarch64
cp38-manylinux_ppc64le
cp38-manylinux_s390x
cp38-manylinux_armv7l
cp38-manylinux_riscv64
cp38-musllinux_aarch64
cp38-musllinux_ppc64le
cp38-musllinux_s390x
cp38-musllinux_armv7l
cp38-musllinux_riscv64 | | | | | Python 3.9 | cp39-macosx_x86_64
cp39-macosx_universal2
cp39-macosx_arm64 | cp39-win_amd64
cp39-win32
cp39-win_arm64 | cp39-manylinux_x86_64
cp39-manylinux_i686
cp39-musllinux_x86_64
cp39-musllinux_i686 | cp39-manylinux_aarch64
cp39-manylinux_ppc64le
cp39-manylinux_s390x
cp39-manylinux_armv7l
cp39-manylinux_riscv64
cp39-musllinux_aarch64
cp39-musllinux_ppc64le
cp39-musllinux_s390x
cp39-musllinux_armv7l
cp39-musllinux_riscv64 | | | | | Python 3.10 | cp310-macosx_x86_64
cp310-macosx_universal2
cp310-macosx_arm64 | cp310-win_amd64
cp310-win32
cp310-win_arm64 | cp310-manylinux_x86_64
cp310-manylinux_i686
cp310-musllinux_x86_64
cp310-musllinux_i686 | cp310-manylinux_aarch64
cp310-manylinux_ppc64le
cp310-manylinux_s390x
cp310-manylinux_armv7l
cp310-manylinux_riscv64
cp310-musllinux_aarch64
cp310-musllinux_ppc64le
cp310-musllinux_s390x
cp310-musllinux_armv7l
cp310-musllinux_riscv64 | | | | | Python 3.11 | cp311-macosx_x86_64
cp311-macosx_universal2
cp311-macosx_arm64 | cp311-win_amd64
cp311-win32
cp311-win_arm64 | cp311-manylinux_x86_64
cp311-manylinux_i686
cp311-musllinux_x86_64
cp311-musllinux_i686 | cp311-manylinux_aarch64
cp311-manylinux_ppc64le
cp311-manylinux_s390x
cp311-manylinux_armv7l
cp311-manylinux_riscv64
cp311-musllinux_aarch64
cp311-musllinux_ppc64le
cp311-musllinux_s390x
cp311-musllinux_armv7l
cp311-musllinux_riscv64 | | | | | Python 3.12 | cp312-macosx_x86_64
cp312-macosx_universal2
cp312-macosx_arm64 | cp312-win_amd64
cp312-win32
cp312-win_arm64 | cp312-manylinux_x86_64
cp312-manylinux_i686
cp312-musllinux_x86_64
cp312-musllinux_i686 | cp312-manylinux_aarch64
cp312-manylinux_ppc64le
cp312-manylinux_s390x
cp312-manylinux_armv7l
cp312-manylinux_riscv64
cp312-musllinux_aarch64
cp312-musllinux_ppc64le
cp312-musllinux_s390x
cp312-musllinux_armv7l
cp312-musllinux_riscv64 | | | cp312-pyodide_wasm32 | | Python 3.13 | cp313-macosx_x86_64
cp313-macosx_universal2
cp313-macosx_arm64

cp313t-macosx_x86_64
cp313t-macosx_universal2
cp313t-macosx_arm64 | cp313-win_amd64
cp313-win32
cp313-win_arm64

cp313t-win_amd64
cp313t-win32
cp313t-win_arm64 | cp313-manylinux_x86_64
cp313-manylinux_i686
cp313-musllinux_x86_64
cp313-musllinux_i686

cp313t-manylinux_x86_64
cp313t-manylinux_i686
cp313t-musllinux_x86_64
cp313t-musllinux_i686 | cp313-manylinux_aarch64
cp313-manylinux_ppc64le
cp313-manylinux_s390x
cp313-manylinux_armv7l
cp313-manylinux_riscv64
cp313-musllinux_aarch64
cp313-musllinux_ppc64le
cp313-musllinux_s390x
cp313-musllinux_armv7l
cp313-musllinux_riscv64

cp313t-manylinux_aarch64
cp313t-manylinux_ppc64le
cp313t-manylinux_s390x
cp313t-manylinux_armv7l
cp313t-manylinux_riscv64
cp313t-musllinux_aarch64
cp313t-musllinux_ppc64le
cp313t-musllinux_s390x
cp313t-musllinux_armv7l
cp313t-musllinux_riscv64 | cp313-android_arm64_v8a
cp313-android_x86_64 | cp313-ios_arm64_iphoneos
cp313-ios_arm64_iphonesimulator
cp313-ios_x86_64_iphonesimulator | cp313-pyodide_wasm32 | | Python 3.14 | cp314-macosx_x86_64
cp314-macosx_universal2
cp314-macosx_arm64

cp314t-macosx_x86_64
cp314t-macosx_universal2
cp314t-macosx_arm64 | cp314-win_amd64
cp314-win32
cp314-win_arm64

cp314t-win_amd64
cp314t-win32
cp314t-win_arm64 | cp314-manylinux_x86_64
cp314-manylinux_i686
cp314-musllinux_x86_64
cp314-musllinux_i686

cp314t-manylinux_x86_64
cp314t-manylinux_i686
cp314t-musllinux_x86_64
cp314t-musllinux_i686 | cp314-manylinux_aarch64
cp314-manylinux_ppc64le
cp314-manylinux_s390x
cp314-manylinux_armv7l
cp314-manylinux_riscv64
cp314-musllinux_aarch64
cp314-musllinux_ppc64le
cp314-musllinux_s390x
cp314-musllinux_armv7l
cp314-musllinux_riscv64

cp314t-manylinux_aarch64
cp314t-manylinux_ppc64le
cp314t-manylinux_s390x
cp314t-manylinux_armv7l
cp314t-manylinux_riscv64
cp314t-musllinux_aarch64
cp314t-musllinux_ppc64le
cp314t-musllinux_s390x
cp314t-musllinux_armv7l
cp314t-musllinux_riscv64 | cp314-android_arm64_v8a
cp314-android_x86_64 | cp314-ios_arm64_iphoneos
cp314-ios_arm64_iphonesimulator
cp314-ios_x86_64_iphonesimulator | | -| PyPy3.8 v7.3 | pp38-macosx_x86_64
pp38-macosx_arm64 | pp38-win_amd64 | pp38-manylinux_x86_64
pp38-manylinux_i686 | pp38-manylinux_aarch64 | | | | | PyPy3.9 v7.3 | pp39-macosx_x86_64
pp39-macosx_arm64 | pp39-win_amd64 | pp39-manylinux_x86_64
pp39-manylinux_i686 | pp39-manylinux_aarch64 | | | | | PyPy3.10 v7.3 | pp310-macosx_x86_64
pp310-macosx_arm64 | pp310-win_amd64 | pp310-manylinux_x86_64
pp310-manylinux_i686 | pp310-manylinux_aarch64 | | | | | PyPy3.11 v7.3 | pp311-macosx_x86_64
pp311-macosx_arm64 | pp311-win_amd64 | pp311-manylinux_x86_64
pp311-manylinux_i686 | pp311-manylinux_aarch64 | | | | @@ -81,29 +79,29 @@ See the [cibuildwheel 2 documentation](https://cibuildwheel.pypa.io/en/2.x/) for ```toml [tool.cibuildwheel] - # Only build on CPython 3.8 - build = "cp38-*" + # Only build on CPython 3.14 + build = "cp314-*" - # Skip building on CPython 3.8 on the Mac - skip = "cp38-macosx_x86_64" + # Skip building on CPython 3.9 on the Mac + skip = "cp39-macosx_x86_64" - # Skip building on CPython 3.8 on all platforms - skip = "cp38-*" + # Skip building on CPython 3.9 on all platforms + skip = "cp39-*" - # Skip CPython 3.8 on Windows - skip = "cp38-win*" + # Skip CPython 3.9 on Windows + skip = "cp39-win*" - # Skip CPython 3.8 on 32-bit Windows - skip = "cp38-win32" + # Skip CPython 3.9 on 32-bit Windows + skip = "cp39-win32" - # Skip CPython 3.8 and CPython 3.9 - skip = ["cp38-*", "cp39-*"] + # Skip CPython 3.9 and CPython 3.10 + skip = ["cp39-*", "cp310-*"] - # Skip Python 3.8 on Linux - skip = "cp38-manylinux*" + # Skip Python 3.9 on Linux + skip = "cp39-*linux*" # Skip 32-bit builds - skip = ["*-win32", "*-manylinux_i686"] + skip = ["*-win32", "*-*linux_i686"] # Disable building PyPy wheels on all platforms skip = "pp*" @@ -118,29 +116,29 @@ See the [cibuildwheel 2 documentation](https://cibuildwheel.pypa.io/en/2.x/) for !!! tab examples "Environment variables" ```yaml - # Only build on CPython 3.8 - CIBW_BUILD: cp38-* + # Only build on CPython 3.14 + CIBW_BUILD: cp314-* - # Skip building on CPython 3.8 on the Mac - CIBW_SKIP: cp38-macosx_x86_64 + # Skip building on CPython 3.9 on the Mac + CIBW_SKIP: cp39-macosx_x86_64 - # Skip building on CPython 3.8 on all platforms - CIBW_SKIP: cp38-* + # Skip building on CPython 3.9 on all platforms + CIBW_SKIP: cp39-* - # Skip CPython 3.8 on Windows - CIBW_SKIP: cp38-win* + # Skip CPython 3.9 on Windows + CIBW_SKIP: cp39-win* - # Skip CPython 3.8 on 32-bit Windows - CIBW_SKIP: cp38-win32 + # Skip CPython 3.9 on 32-bit Windows + CIBW_SKIP: cp39-win32 - # Skip CPython 3.8 and CPython 3.9 - CIBW_SKIP: cp38-* cp39-* + # Skip CPython 3.9 and CPython 3.10 + CIBW_SKIP: cp39-* cp310-* - # Skip Python 3.8 on Linux - CIBW_SKIP: cp38-manylinux* + # Skip Python 3.9 on Linux + CIBW_SKIP: cp39-*linux* # Skip 32-bit builds - CIBW_SKIP: "*-win32 *-manylinux_i686" + CIBW_SKIP: "*-win32 *-*linux_i686" # Disable building PyPy wheels on all platforms CIBW_SKIP: pp* @@ -304,7 +302,7 @@ simple keyword assignment in a top level function call. If you need to override this behaviour for some reason, you can use this option. When setting this option, the syntax is the same as `project.requires-python`, -using 'version specifiers' like `>=3.8`, according to +using 'version specifiers' like `>=3.12`, according to [PEP440](https://www.python.org/dev/peps/pep-0440/#version-specifiers). Default: reads your package's Python compatibility from `pyproject.toml` @@ -325,7 +323,7 @@ the package is compatible with all versions of Python that it can build. ```toml [project] ... - requires-python = ">=3.8" + requires-python = ">=3.12" ``` Note that not all build backends fully support using a `[project]` table yet; @@ -341,7 +339,7 @@ the package is compatible with all versions of Python that it can build. !!! tab examples "Environment variables" ```yaml - CIBW_PROJECT_REQUIRES_PYTHON: ">=3.8" + CIBW_PROJECT_REQUIRES_PYTHON: ">=3.12" ``` ### `enable` {: #enable toml env-var} @@ -1223,7 +1221,7 @@ specifiers inline with the `packages: SPECIFIER...` syntax. If you need different dependencies for each python version, provide them in the same folder with a `-pythonXY` suffix. e.g. if your `dependency-versions="./constraints.txt"`, cibuildwheel will use - `./constraints-python38.txt` on Python 3.8, or fallback to + `./constraints-python314.txt` on Python 3.14, or fallback to `./constraints.txt` if that's not found. Platform-specific environment variables are also available:
@@ -1765,16 +1763,14 @@ will not produce more logging about the build itself. Other levels only affect the build frontend output, which is usually things like resolving and downloading dependencies. The settings are: -| | build | pip | uv | desc | -|-------------|-------|--------|-------|----------------------------------| -| -2 | `-qq`[^1] | `-qq` | `-qq` | even more quiet, where supported | -| -1 | `-q`[^1] | `-q` | `-q` | quiet mode, where supported | -| 0 (default) | | | | default for build tool | -| 1 | | `-v` | | print backend output | +| | build | pip | uv | desc | +|-------------|-------|--------|-------|----------------------------------------| +| -2 | `-qq` | `-qq` | `-qq` | even more quiet, where supported | +| -1 | `-q` | `-q` | `-q` | quiet mode, where supported | +| 0 (default) | | | | default for build tool | +| 1 | | `-v` | | print backend output | | 2 | `-v` | `-vv` | `-v` | print log messages e.g. resolving info | -| 3 | `-vv` | `-vvv` | `-vv` | print even more debug info | - -[^1]: Not supported on Python 3.8, will be ignored with a warning. +| 3 | `-vv` | `-vvv` | `-vv` | print even more debug info | Settings that are not supported for a specific frontend will log a warning. The default build frontend is `build`, which does show build backend output by diff --git a/docs/platforms.md b/docs/platforms.md index 44d8afbf5..51ad197fc 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -62,11 +62,10 @@ macOS builds will honor the `MACOSX_DEPLOYMENT_TARGET` environment variable to c | Arch | Python version range | Minimum target | |-------|----------------------|----------------| -| Intel | CPython 3.8-3.11 | 10.9 | +| Intel | CPython 3.9-3.11 | 10.9 | | Intel | CPython 3.12-3.13 | 10.13 | | Intel | CPython 3.14+ | 10.15 | | AS | CPython or PyPy | 11 | -| Intel | PyPy 3.8 | 10.13 | | Intel | PyPy 3.9+ | 10.15 | If you set the value lower, cibuildwheel will cap it to the lowest supported value for each target as needed. @@ -74,7 +73,7 @@ If you set the value lower, cibuildwheel will cap it to the lowest supported val !!! note For Rust-based extensions, `Rustc` requires `MACOSX_DEPLOYMENT_TARGET` to be at least 10.12. However, `cibuildwheel` defaults to 10.9 for - **Intel / CPython 3.8-3.11** builds. Users must manually set + **Intel / CPython 3.9-3.11** builds. Users must manually set `MACOSX_DEPLOYMENT_TARGET` to 10.12 or higher when building Rust extensions. ### macOS architectures diff --git a/examples/circleci-minimal.yml b/examples/circleci-minimal.yml index 1c9f072ba..dfb553d3e 100644 --- a/examples/circleci-minimal.yml +++ b/examples/circleci-minimal.yml @@ -43,7 +43,7 @@ jobs: - run: name: Build the OS X wheels. command: | - sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests + sudo softwareupdate --install-rosetta --agree-to-license # for x86_64/universal2 tests pip3 install cibuildwheel==3.4.0 cibuildwheel --output-dir wheelhouse - store_artifacts: diff --git a/noxfile.py b/noxfile.py index 798a3f8f2..ad66d4d25 100755 --- a/noxfile.py +++ b/noxfile.py @@ -81,7 +81,7 @@ def update_constraints(session: nox.Session) -> None: env = os.environ.copy() env["UV_CUSTOM_COMPILE_COMMAND"] = f"nox -s {session.name}" - for minor_version in range(8, 15): + for minor_version in range(9, 15): python_version = f"3.{minor_version}" output_file = resources / f"constraints-python{python_version.replace('.', '')}.txt" session.run( diff --git a/test/conftest.py b/test/conftest.py index 2a80e770f..e0a4687e9 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -26,12 +26,6 @@ def pytest_addoption(parser: pytest.Parser) -> None: choices=("all", *EMULATED_ARCHS), ) parser.addoption("--run-podman", action="store_true", default=False, help="run podman tests") - parser.addoption( - "--run-cp38-universal2", - action="store_true", - default=False, - help="macOS cp38 uses the universal2 installer", - ) parser.addoption( "--enable", action="store", diff --git a/test/test_abi_variants.py b/test/test_abi_variants.py index 999323ae0..0acf1055c 100644 --- a/test/test_abi_variants.py +++ b/test/test_abi_variants.py @@ -189,7 +189,7 @@ def test_abi_none(tmp_path, capfd): "CIBW_TEST_REQUIRES": "pytest", "CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test", # limit the number of builds for test performance reasons - "CIBW_BUILD": "cp38-* cp{}{}-* cp313t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION), + "CIBW_BUILD": "cp39-* cp{}{}-* cp313t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION), "CIBW_ENABLE": "all", }, ) diff --git a/test/test_container_images.py b/test/test_container_images.py index 02263c649..c10c9c652 100644 --- a/test/test_container_images.py +++ b/test/test_container_images.py @@ -49,6 +49,6 @@ def test(tmp_path): for w in utils.expected_wheels( "spam", "0.1.0", manylinux_versions=manylinux_versions, musllinux_versions=[] ) - if "-cp38-" in w or "-cp39-" in w + if "-cp39-" in w ] assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index 86dd6f227..8efc8c51c 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -1,5 +1,4 @@ import json -import platform import re import subprocess import textwrap @@ -75,18 +74,12 @@ def get_versions_from_constraint_file(constraint_file: Path) -> dict[str, str]: return dict(re.findall(VERSION_REGEX, constraint_file_text)) -@pytest.mark.parametrize("python_version", ["3.8", "3.12"]) +@pytest.mark.parametrize("python_version", ["3.9", "3.12"]) def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv): if utils.get_platform() == "linux": pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead") if python_version != "3.12" and utils.get_platform() == "pyodide": pytest.skip(f"pyodide does not support Python {python_version}") - if ( - python_version == "3.8" - and utils.get_platform() == "windows" - and platform.machine() == "ARM64" - ): - pytest.skip(f"Windows ARM64 does not support Python {python_version}") project_dir = tmp_path / "project" test_projects.new_c_project().generate(project_dir) diff --git a/test/test_macos_archs.py b/test/test_macos_archs.py index f799e55b0..8afe51017 100644 --- a/test/test_macos_archs.py +++ b/test/test_macos_archs.py @@ -201,68 +201,3 @@ def test_universal2_testing_on_arm64(build_frontend_env, tmp_path, capfd): python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION) expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w and "universal2" in w] assert set(actual_wheels) == set(expected_wheels) - - -def test_cp38_arm64_testing(tmp_path, capfd, request): - if utils.get_platform() != "macos": - pytest.skip("this test is only relevant to macos") - if utils.get_xcode_version() < (12, 2): - pytest.skip("this test only works with Xcode 12.2 or greater") - if platform.machine() != "arm64": - pytest.skip("this test only works on arm64") - if request.config.getoption("--run-cp38-universal2"): - pytest.skip("--run-cp38-universal2 option skips this test") - - project_dir = tmp_path / "project" - basic_project.generate(project_dir) - - actual_wheels = utils.cibuildwheel_run( - project_dir, - add_env={ - "CIBW_BUILD": "cp38-*", - "CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''', - "CIBW_ARCHS": "x86_64,universal2,arm64", - }, - ) - - captured = capfd.readouterr() - - assert "running tests on x86_64" in captured.out - assert "running tests on arm64" not in captured.out - - warning_message = "While cibuildwheel can build CPython 3.8 universal2/arm64 wheels, we cannot test the arm64 part of them" - assert warning_message in captured.err - - expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp38" in w] - - assert set(actual_wheels) == set(expected_wheels) - - -def test_cp38_arm64_testing_universal2_installer(tmp_path, capfd, request): - if not request.config.getoption("--run-cp38-universal2"): - pytest.skip("needs --run-cp38-universal2 option to run") - - project_dir = tmp_path / "project" - basic_project.generate(project_dir) - - actual_wheels = utils.cibuildwheel_run( - project_dir, - add_env={ - "CIBW_BUILD": "cp38-*", - "CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''', - "CIBW_ARCHS": "x86_64,universal2,arm64", - "MACOSX_DEPLOYMENT_TARGET": "11.0", - }, - ) - - captured = capfd.readouterr() - - assert "running tests on x86_64" in captured.out - assert "running tests on arm64" in captured.out - - warning_message = "While cibuildwheel can build CPython 3.8 universal2/arm64 wheels, we cannot test the arm64 part of them" - assert warning_message not in captured.err - - expected_wheels = [w.replace("10_9", "11_0") for w in ALL_MACOS_WHEELS if "cp38" in w] - - assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_testing.py b/test/test_testing.py index 65cb66bae..4541dd6f6 100644 --- a/test/test_testing.py +++ b/test/test_testing.py @@ -167,11 +167,6 @@ def test_failing_test(tmp_path): add_env={ "CIBW_TEST_REQUIRES": "pytest", "CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test", - # CPython 3.8 when running on macOS arm64 is unusual. The build - # always runs in x86_64, so the arm64 tests are not run. See - # #1169 for reasons why. That means the build succeeds, which - # we don't want. So we skip that build. - "CIBW_SKIP": "cp38-macosx_arm64", }, ) @@ -199,9 +194,6 @@ def test_bare_pytest_invocation( "CIBW_TEST_COMMAND": ( "python -m pytest" if test_runner == "pytest" else "python -m unittest" ), - # Skip CPython 3.8 on macOS arm64, see comment above in - # 'test_failing_test' - "CIBW_SKIP": "cp38-macosx_arm64", }, ) diff --git a/test/utils.py b/test/utils.py index bb599abd3..6a802f1be 100644 --- a/test/utils.py +++ b/test/utils.py @@ -281,7 +281,6 @@ def _expected_wheels( ] elif python_abi_tags is None: python_abi_tags = [ - "cp38-cp38", "cp39-cp39", "cp310-cp310", "cp311-cp311", @@ -300,7 +299,6 @@ def _expected_wheels( if EnableGroup.PyPyEoL in enable_groups: python_abi_tags += [ - "pp38-pypy38_pp73", "pp39-pypy39_pp73", "pp310-pypy310_pp73", ] @@ -315,10 +313,6 @@ def _expected_wheels( "graalpy312-graalpy250_312_native", ] - if machine_arch == "ARM64" and platform == "windows": - # no CPython 3.8 on Windows ARM64 - python_abi_tags = [t for t in python_abi_tags if not t.startswith("cp38")] - if machine_arch not in PYPY_ARCHS: python_abi_tags = [tag for tag in python_abi_tags if not tag.startswith("pp")] @@ -363,12 +357,9 @@ def _expected_wheels( elif platform == "macos": if python_abi_tag.startswith("pp"): - if python_abi_tag.startswith("pp38"): - min_macosx = macosx_deployment_target - else: - min_macosx = _floor_macosx(macosx_deployment_target, "10.15") + min_macosx = _floor_macosx(macosx_deployment_target, "10.15") elif python_abi_tag.startswith("cp"): - if python_abi_tag.startswith(("cp38", "cp39", "cp310", "cp311")): + if python_abi_tag.startswith(("cp39", "cp310", "cp311")): min_macosx = macosx_deployment_target elif python_abi_tag.startswith(("cp312", "cp313")): min_macosx = _floor_macosx(macosx_deployment_target, "10.13") diff --git a/unit_test/conftest.py b/unit_test/conftest.py index a51f10d8d..3d98c30b0 100644 --- a/unit_test/conftest.py +++ b/unit_test/conftest.py @@ -9,12 +9,6 @@ def pytest_addoption(parser): parser.addoption("--run-docker", action="store_true", default=False, help="run docker tests") parser.addoption("--run-podman", action="store_true", default=False, help="run podman tests") - parser.addoption( - "--run-cp38-universal2", - action="store_true", - default=False, - help="macOS cp38 uses the universal2 installer", - ) @pytest.fixture diff --git a/unit_test/linux_build_steps_test.py b/unit_test/linux_build_steps_test.py index 0595a6840..237ab1713 100644 --- a/unit_test/linux_build_steps_test.py +++ b/unit_test/linux_build_steps_test.py @@ -28,16 +28,16 @@ def test_linux_container_split(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) archs = "x86_64 i686" [[tool.cibuildwheel.overrides]] - select = "cp{38,39,310}-*" + select = "cp{39,310,311}-*" manylinux-x86_64-image = "other_container_image" manylinux-i686-image = "other_container_image" [[tool.cibuildwheel.overrides]] - select = "cp39-*" - before-all = "echo 'a cp39-only command'" + select = "cp310-*" + before-all = "echo 'a cp310-only command'" [[tool.cibuildwheel.overrides]] - select = "cp310-*" + select = "cp311-*" container-engine = "docker; create_args: --privileged" """ ) @@ -69,17 +69,17 @@ def container_engines( default_container_engine = OCIContainerEngineConfig(name="docker") assert build_steps[0].container_image == "other_container_image" - assert identifiers(build_steps[0]) == ["cp38-manylinux_x86_64"] + assert identifiers(build_steps[0]) == ["cp39-manylinux_x86_64"] assert before_alls(build_steps[0]) == [""] assert container_engines(build_steps[0]) == [default_container_engine] assert build_steps[1].container_image == "other_container_image" - assert identifiers(build_steps[1]) == ["cp39-manylinux_x86_64"] - assert before_alls(build_steps[1]) == ["echo 'a cp39-only command'"] + assert identifiers(build_steps[1]) == ["cp310-manylinux_x86_64"] + assert before_alls(build_steps[1]) == ["echo 'a cp310-only command'"] assert container_engines(build_steps[1]) == [default_container_engine] assert build_steps[2].container_image == "other_container_image" - assert identifiers(build_steps[2]) == ["cp310-manylinux_x86_64"] + assert identifiers(build_steps[2]) == ["cp311-manylinux_x86_64"] assert before_alls(build_steps[2]) == [""] assert container_engines(build_steps[2]) == [ OCIContainerEngineConfig(name="docker", create_args=("--privileged",)) @@ -87,11 +87,10 @@ def container_engines( assert build_steps[3].container_image == "normal_container_image" assert identifiers(build_steps[3]) == [ - "cp311-manylinux_x86_64", "cp312-manylinux_x86_64", "cp313-manylinux_x86_64", "cp314-manylinux_x86_64", "cp314t-manylinux_x86_64", ] - assert before_alls(build_steps[3]) == [""] * 5 - assert container_engines(build_steps[3]) == [default_container_engine] * 5 + assert before_alls(build_steps[3]) == [""] * 4 + assert container_engines(build_steps[3]) == [default_container_engine] * 4 diff --git a/unit_test/main_tests/main_options_test.py b/unit_test/main_tests/main_options_test.py index 7c8a6dde9..6ddadaa32 100644 --- a/unit_test/main_tests/main_options_test.py +++ b/unit_test/main_tests/main_options_test.py @@ -365,18 +365,20 @@ def test_config_settings(platform_specific, platform, intercepted_build_args, mo ], ) @pytest.mark.parametrize( - "pattern", + ("pattern", "series"), [ - "cp27-*", - "cp35-*", - "?p36-*", - "?p27*", - "?p2*", - "?p35*", + ("cp27-*", 1), + ("cp35-*", 1), + ("?p36-*", 2), + ("?p37-*", 2), + ("?p38-*", 3), + ("?p27*", 1), + ("?p2*", 1), + ("?p35*", 1), ], ) @pytest.mark.usefixtures("platform", "intercepted_build_args", "allow_empty") -def test_build_selector_deprecated_error(monkeypatch, selector, pattern, capsys): +def test_build_selector_deprecated_error(monkeypatch, selector, pattern, series, capsys): monkeypatch.setenv(selector, pattern) monkeypatch.delenv("CIBW_ENABLE", raising=False) @@ -389,8 +391,7 @@ def test_build_selector_deprecated_error(monkeypatch, selector, pattern, capsys) main() stderr = capsys.readouterr().err - series = "2" if "6" in pattern else "1" - msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the {series}.x series or update" + msg = f"cibuildwheel 4.x no longer supports Python < 3.9. Please use the {series}.x series or update" assert msg in stderr diff --git a/unit_test/option_prepare_test.py b/unit_test/option_prepare_test.py index e209178a1..7ea9d1323 100644 --- a/unit_test/option_prepare_test.py +++ b/unit_test/option_prepare_test.py @@ -13,8 +13,8 @@ from cibuildwheel.oci_container import OCIPlatform from cibuildwheel.util import file -DEFAULT_IDS = {"cp38", "cp39", "cp310", "cp311", "cp312", "cp313", "cp314", "cp314t"} -ALL_IDS = DEFAULT_IDS | {"cp313t", "pp38", "pp39", "pp310", "pp311", "gp311_242", "gp312_250"} +DEFAULT_IDS = {"cp39", "cp310", "cp311", "cp312", "cp313", "cp314", "cp314t"} +ALL_IDS = DEFAULT_IDS | {"cp313t", "pp39", "pp310", "pp311", "gp311_242", "gp312_250"} @pytest.fixture @@ -110,12 +110,12 @@ def test_build_with_override_launches(monkeypatch, tmp_path): # Before Python 3.10, use manylinux2014 [[tool.cibuildwheel.overrides]] -select = "cp3?-*" +select = "cp3?-* cp310-*" manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" [[tool.cibuildwheel.overrides]] -select = "cp38-manylinux_x86_64" +select = "cp39-manylinux_x86_64" before-all = "true" """ ) @@ -136,8 +136,8 @@ def test_build_with_override_launches(monkeypatch, tmp_path): assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64 identifiers = {x.identifier for x in kwargs["platform_configs"]} - assert identifiers == {"cp38-manylinux_x86_64"} - assert kwargs["options"].build_options("cp38-manylinux_x86_64").before_all == "true" + assert identifiers == {"cp39-manylinux_x86_64"} + assert kwargs["options"].build_options("cp39-manylinux_x86_64").before_all == "true" kwargs = build_in_container.call_args_list[1][1] assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"] @@ -149,15 +149,13 @@ def test_build_with_override_launches(monkeypatch, tmp_path): f"{x}-manylinux_x86_64" for x in ALL_IDS - { - "cp38", - "cp310", + "cp39", "cp311", "cp312", "cp313", "cp313t", "cp314", "cp314t", - "pp38", "pp39", "pp310", "pp311", @@ -165,7 +163,7 @@ def test_build_with_override_launches(monkeypatch, tmp_path): "gp312_250", } } - assert kwargs["options"].build_options("cp39-manylinux_x86_64").before_all == "" + assert kwargs["options"].build_options("cp310-manylinux_x86_64").before_all == "" kwargs = build_in_container.call_args_list[2][1] assert "quay.io/pypa/manylinux_2_28_x86_64" in kwargs["container"]["image"] @@ -175,14 +173,12 @@ def test_build_with_override_launches(monkeypatch, tmp_path): assert identifiers == { f"{x}-manylinux_x86_64" for x in [ - "cp310", "cp311", "cp312", "cp313", "cp313t", "cp314", "cp314t", - "pp38", "pp39", "pp310", "pp311", @@ -196,7 +192,7 @@ def test_build_with_override_launches(monkeypatch, tmp_path): assert kwargs["container"]["cwd"] == PurePosixPath("/project") assert kwargs["container"]["oci_platform"] == OCIPlatform.i386 identifiers = {x.identifier for x in kwargs["platform_configs"]} - assert identifiers == {"cp38-manylinux_i686", "cp39-manylinux_i686"} + assert identifiers == {"cp39-manylinux_i686", "cp310-manylinux_i686"} kwargs = build_in_container.call_args_list[4][1] assert "quay.io/pypa/manylinux_2_28_i686" in kwargs["container"]["image"] @@ -204,7 +200,7 @@ def test_build_with_override_launches(monkeypatch, tmp_path): assert kwargs["container"]["oci_platform"] == OCIPlatform.i386 identifiers = {x.identifier for x in kwargs["platform_configs"]} assert identifiers == { - f"{x}-manylinux_i686" for x in ALL_IDS - {"cp38", "cp39"} if "gp" not in x + f"{x}-manylinux_i686" for x in ALL_IDS - {"cp39", "cp310"} if "gp" not in x } kwargs = build_in_container.call_args_list[5][1] diff --git a/unit_test/options_test.py b/unit_test/options_test.py index 160825000..cffb2e3b0 100644 --- a/unit_test/options_test.py +++ b/unit_test/options_test.py @@ -615,27 +615,13 @@ def test_get_build_frontend_extra_flags( monkeypatch.setattr(Logger, "warning", mock_warning) build_frontend = BuildFrontendConfig(frontend, ["-1"]) args = get_build_frontend_extra_flags( - build_frontend=build_frontend, verbosity_level=verbosity, config_settings="a b", py38=False + build_frontend=build_frontend, verbosity_level=verbosity, config_settings="a b" ) assert args == result mock_warning.assert_not_called() -@pytest.mark.parametrize("frontend", ["build", "build[uv]"]) -def test_get_build_frontend_extra_flags_warning( - frontend: Literal["build", "build[uv]"], monkeypatch: pytest.MonkeyPatch -) -> None: - mock_warning = unittest.mock.MagicMock() - monkeypatch.setattr(Logger, "warning", mock_warning) - build_frontend = BuildFrontendConfig(frontend, ["-1"]) - args = get_build_frontend_extra_flags( - build_frontend=build_frontend, verbosity_level=-1, config_settings="a b", py38=True - ) - assert args == ["-Ca", "-Cb", "-1"] - mock_warning.assert_called_once() - - @pytest.mark.parametrize( ("definition", "expected_args"), [