Skip to content

feat: move default manylinux build to manylinux_2_28 #2330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions cibuildwheel/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -795,22 +795,19 @@ def _compute_build_options(self, identifier: str | None) -> BuildOptions:
f"manylinux-{build_platform}-image", ignore_empty=True
)
self._check_pinned_image(config_value, pinned_images)
if not config_value:
# default to manylinux2014
image = pinned_images["manylinux2014"]
elif config_value in pinned_images:
if config_value in pinned_images:
image = pinned_images[config_value]
else:
image = config_value
manylinux_images[build_platform] = image

for build_platform in MUSLLINUX_ARCHS:
pinned_images = all_pinned_container_images[build_platform]
config_value = self.reader.get(f"musllinux-{build_platform}-image")
config_value = self.reader.get(
f"musllinux-{build_platform}-image", ignore_empty=True
)
self._check_pinned_image(config_value, pinned_images)
if not config_value:
image = pinned_images["musllinux_1_2"]
elif config_value in pinned_images:
if config_value in pinned_images:
image = pinned_images[config_value]
else:
image = config_value
Expand Down
12 changes: 6 additions & 6 deletions cibuildwheel/resources/defaults.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ test-groups = []

container-engine = "docker"

manylinux-x86_64-image = "manylinux2014"
manylinux-x86_64-image = "manylinux_2_28"
manylinux-i686-image = "manylinux2014"
manylinux-aarch64-image = "manylinux2014"
manylinux-ppc64le-image = "manylinux2014"
manylinux-s390x-image = "manylinux2014"
manylinux-aarch64-image = "manylinux_2_28"
manylinux-ppc64le-image = "manylinux_2_28"
manylinux-s390x-image = "manylinux_2_28"
manylinux-armv7l-image = "manylinux_2_31"
manylinux-pypy_x86_64-image = "manylinux2014"
manylinux-pypy_x86_64-image = "manylinux_2_28"
manylinux-pypy_i686-image = "manylinux2014"
manylinux-pypy_aarch64-image = "manylinux2014"
manylinux-pypy_aarch64-image = "manylinux_2_28"

musllinux-x86_64-image = "musllinux_1_2"
musllinux-i686-image = "musllinux_1_2"
Expand Down
36 changes: 17 additions & 19 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -1168,25 +1168,23 @@ Platform-specific environment variables are also available:<br/>

The available options are:

| Option | Default | Future default* |
|-----------------------------------|----------------------------------------------------------------|-----------------------------------------------------------------|
| CIBW_MANYLINUX_X86_64_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_x86_64) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_x86_64) |
| CIBW_MANYLINUX_I686_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_i686) | |
| CIBW_MANYLINUX_PYPY_X86_64_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_x86_64) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_x86_64) |
| CIBW_MANYLINUX_AARCH64_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_aarch64) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_aarch64) |
| CIBW_MANYLINUX_PPC64LE_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_ppc64le) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_ppc64le) |
| CIBW_MANYLINUX_S390X_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_s390x) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_s390x) |
| CIBW_MANYLINUX_ARMV7L_IMAGE | [`manylinux_2_31`](https://quay.io/pypa/manylinux_2_31_armv7l) | |
| CIBW_MANYLINUX_PYPY_AARCH64_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_aarch64) | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_aarch64) |
| CIBW_MANYLINUX_PYPY_I686_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_i686) | |
| CIBW_MUSLLINUX_X86_64_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_x86_64) | |
| CIBW_MUSLLINUX_I686_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_i686) | |
| CIBW_MUSLLINUX_AARCH64_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_aarch64) | |
| CIBW_MUSLLINUX_PPC64LE_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_ppc64le) | |
| CIBW_MUSLLINUX_S390X_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_s390x) | |
| CIBW_MUSLLINUX_ARMV7L_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_armv7l) | |

<small>* The default is scheduled to change in a cibuildwheel release on or after 6th May 2025 - if you don't want the new default, you should set the value to `manylinux2014`.</small>
| Option | Default |
|-----------------------------------|-----------------------------------------------------------------|
| CIBW_MANYLINUX_X86_64_IMAGE | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_x86_64) |
| CIBW_MANYLINUX_I686_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_i686) |
| CIBW_MANYLINUX_PYPY_X86_64_IMAGE | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_x86_64) |
| CIBW_MANYLINUX_AARCH64_IMAGE | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_aarch64) |
| CIBW_MANYLINUX_PPC64LE_IMAGE | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_ppc64le) |
| CIBW_MANYLINUX_S390X_IMAGE | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_s390x) |
| CIBW_MANYLINUX_ARMV7L_IMAGE | [`manylinux_2_31`](https://quay.io/pypa/manylinux_2_31_armv7l) |
| CIBW_MANYLINUX_PYPY_AARCH64_IMAGE | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_aarch64) |
| CIBW_MANYLINUX_PYPY_I686_IMAGE | [`manylinux2014`](https://quay.io/pypa/manylinux2014_i686) |
| CIBW_MUSLLINUX_X86_64_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_x86_64) |
| CIBW_MUSLLINUX_I686_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_i686) |
| CIBW_MUSLLINUX_AARCH64_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_aarch64) |
| CIBW_MUSLLINUX_PPC64LE_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_ppc64le) |
| CIBW_MUSLLINUX_S390X_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_s390x) |
| CIBW_MUSLLINUX_ARMV7L_IMAGE | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_armv7l) |

Set the Docker image to be used for building [manylinux / musllinux](https://github.com/pypa/manylinux) wheels.

Expand Down
5 changes: 4 additions & 1 deletion test/test_container_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ def test(tmp_path):
)

# also check that we got the right wheels built
manylinux_versions = ["manylinux_2_5", "manylinux1", "manylinux_2_17", "manylinux2014"]
expected_wheels = [
w
for w in utils.expected_wheels("spam", "0.1.0", musllinux_versions=[])
for w in utils.expected_wheels(
"spam", "0.1.0", manylinux_versions=manylinux_versions, musllinux_versions=[]
)
if "-cp38-" in w or "-cp39-" in w
]
assert set(actual_wheels) == set(expected_wheels)
126 changes: 64 additions & 62 deletions test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,57 @@ def expected_wheels(
include_universal2: bool = False,
single_python: bool = False,
single_arch: bool = False,
) -> list[str]:
"""
Returns a list of expected wheels from a run of cibuildwheel.
"""
if machine_arch is None:
machine_arch = pm.machine()
if platform == "linux":
machine_arch = arch_name_for_linux(machine_arch)

architectures = [machine_arch]
if not single_arch:
if platform == "linux":
if machine_arch == "x86_64":
architectures.append("i686")
elif (
machine_arch == "aarch64"
and sys.platform.startswith("linux")
and _AARCH64_CAN_RUN_ARMV7
):
architectures.append("armv7l")
elif platform == "windows" and machine_arch == "AMD64":
architectures.append("x86")

wheels: list[str] = []
for architecture in architectures:
wheels.extend(
_expected_wheels(
package_name,
package_version,
architecture,
manylinux_versions,
musllinux_versions,
macosx_deployment_target,
python_abi_tags,
include_universal2,
single_python,
)
)
return wheels


def _expected_wheels(
package_name: str,
package_version: str,
machine_arch: str,
manylinux_versions: list[str] | None,
musllinux_versions: list[str] | None,
macosx_deployment_target: str,
python_abi_tags: list[str] | None,
include_universal2: bool,
single_python: bool,
) -> list[str]:
"""
Returns a list of expected wheels from a run of cibuildwheel.
Expand All @@ -171,24 +222,12 @@ def expected_wheels(
# {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

if machine_arch is None:
machine_arch = pm.machine()
if platform == "linux" and machine_arch.lower() == "arm64":
# we're running linux tests from macOS/Windows arm64, override platform
machine_arch = "aarch64"

if manylinux_versions is None:
if machine_arch in ("armv7l", "aarch64"):
manylinux_versions = ["manylinux_2_17", "manylinux2014", "manylinux_2_31"]
elif machine_arch == "x86_64":
manylinux_versions = [
"manylinux_2_5",
"manylinux1",
"manylinux_2_17",
"manylinux2014",
]
else:
manylinux_versions = ["manylinux_2_17", "manylinux2014"]
manylinux_versions = {
"armv7l": ["manylinux_2_17", "manylinux2014", "manylinux_2_31"],
"i686": ["manylinux_2_5", "manylinux1", "manylinux_2_17", "manylinux2014"],
"x86_64": ["manylinux_2_5", "manylinux1", "manylinux_2_28"],
}.get(machine_arch, ["manylinux_2_17", "manylinux2014", "manylinux_2_28"])

if musllinux_versions is None:
musllinux_versions = ["musllinux_1_2"]
Expand All @@ -206,30 +245,14 @@ def expected_wheels(
"cp313-cp313t",
]

if machine_arch in ["x86_64", "AMD64", "x86", "aarch64"]:
if machine_arch in ["x86_64", "i686", "AMD64", "aarch64", "arm64"]:
python_abi_tags += [
"pp38-pypy38_pp73",
"pp39-pypy39_pp73",
"pp310-pypy310_pp73",
"pp311-pypy311_pp73",
]

if platform == "macos" and machine_arch == "arm64":
# arm64 macs are only supported by cp38+
python_abi_tags = [
"cp38-cp38",
"cp39-cp39",
"cp310-cp310",
"cp311-cp311",
"cp312-cp312",
"cp313-cp313",
"cp313-cp313t",
"pp38-pypy38_pp73",
"pp39-pypy39_pp73",
"pp310-pypy310_pp73",
"pp311-pypy311_pp73",
]

if single_python:
python_tag = "cp{}{}-".format(*SINGLE_PYTHON_VERSION)
python_abi_tags = [
Expand All @@ -252,44 +275,23 @@ def expected_wheels(
platform_tags = []

if platform == "linux":
architectures = [arch_name_for_linux(machine_arch)]

if not single_arch:
if machine_arch == "x86_64":
architectures.append("i686")
elif (
machine_arch == "aarch64"
and sys.platform.startswith("linux")
and not python_abi_tag.startswith("pp")
and _AARCH64_CAN_RUN_ARMV7
):
architectures.append("armv7l")

if len(manylinux_versions) > 0:
platform_tags = [
".".join(
f"{manylinux_version}_{architecture}"
f"{manylinux_version}_{machine_arch}"
for manylinux_version in manylinux_versions
if (manylinux_version, architecture) != ("manylinux_2_31", "aarch64")
)
for architecture in architectures
]
if len(musllinux_versions) > 0 and not python_abi_tag.startswith("pp"):
platform_tags.extend(
[
".".join(
f"{musllinux_version}_{architecture}"
for musllinux_version in musllinux_versions
)
for architecture in architectures
]
platform_tags.append(
".".join(
f"{musllinux_version}_{machine_arch}"
for musllinux_version in musllinux_versions
)
)

elif platform == "windows":
if python_abi_tag.startswith("pp"):
platform_tags = ["win_amd64"]
else:
platform_tags = ["win32", "win_amd64"]
platform_tags = ["win_amd64"] if machine_arch == "AMD64" else ["win32"]

elif platform == "macos":
if python_abi_tag.startswith("pp"):
Expand Down
4 changes: 2 additions & 2 deletions unit_test/main_tests/main_options_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ def test_empty_selector(monkeypatch):
@pytest.mark.parametrize(
("architecture", "image", "full_image"),
[
("x86_64", None, "quay.io/pypa/manylinux2014_x86_64:*"),
("x86_64", None, "quay.io/pypa/manylinux_2_28_x86_64:*"),
("x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64:*"),
("x86_64", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_x86_64:*"),
("x86_64", "manylinux_2_34", "quay.io/pypa/manylinux_2_34_x86_64:*"),
("x86_64", "custom_image", "custom_image"),
("i686", None, "quay.io/pypa/manylinux2014_i686:*"),
("i686", "manylinux2014", "quay.io/pypa/manylinux2014_i686:*"),
("i686", "custom_image", "custom_image"),
("pypy_x86_64", None, "quay.io/pypa/manylinux2014_x86_64:*"),
("pypy_x86_64", None, "quay.io/pypa/manylinux_2_28_x86_64:*"),
("pypy_x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64:*"),
("pypy_x86_64", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_x86_64:*"),
("pypy_x86_64", "manylinux_2_34", "quay.io/pypa/manylinux_2_34_x86_64:*"),
Expand Down
2 changes: 1 addition & 1 deletion unit_test/option_prepare_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def test_build_default_launches(monkeypatch):

# In Python 3.8+, this can be simplified to [0].kwargs
kwargs = build_in_container.call_args_list[0][1]
assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"]
assert "quay.io/pypa/manylinux_2_28_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64

Expand Down
2 changes: 1 addition & 1 deletion unit_test/options_toml_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ def test_environment_override_empty(tmp_path):
assert options_reader.get("manylinux-i686-image") == ""
assert options_reader.get("manylinux-aarch64-image") == "manylinux1"

assert options_reader.get("manylinux-x86_64-image", ignore_empty=True) == "manylinux2014"
assert options_reader.get("manylinux-x86_64-image", ignore_empty=True) == "manylinux_2_28"
assert options_reader.get("manylinux-i686-image", ignore_empty=True) == "manylinux1"
assert options_reader.get("manylinux-aarch64-image", ignore_empty=True) == "manylinux1"

Expand Down
Loading