Skip to content

feat: add support for manylinux_2_28 i686 image #2480

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 2 commits into from
Jul 8, 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
12 changes: 11 additions & 1 deletion bin/update_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,17 @@ def __init__(self, manylinux_version: str, platforms: list[str], tag: str | None
),
# manylinux_2_28 images
PyPAImage(
"manylinux_2_28", ["x86_64", "aarch64", "ppc64le", "s390x", "pypy_x86_64", "pypy_aarch64"]
"manylinux_2_28",
[
"x86_64",
"i686",
"aarch64",
"ppc64le",
"s390x",
"pypy_x86_64",
"pypy_i686",
"pypy_aarch64",
],
),
# manylinux_2_31 images
PyPAImage("manylinux_2_31", ["armv7l"]),
Expand Down
4 changes: 2 additions & 2 deletions cibuildwheel/resources/defaults.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ container-engine = "docker"
pyodide-version = ""

manylinux-x86_64-image = "manylinux_2_28"
manylinux-i686-image = "manylinux2014"
manylinux-i686-image = "manylinux_2_28"
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-riscv64-image = "ghcr.io/pypa/cibuildwheel/no_default_image:please_use_override"
manylinux-pypy_x86_64-image = "manylinux_2_28"
manylinux-pypy_i686-image = "manylinux2014"
manylinux-pypy_i686-image = "manylinux_2_28"
manylinux-pypy_aarch64-image = "manylinux_2_28"

musllinux-x86_64-image = "musllinux_1_2"
Expand Down
2 changes: 2 additions & 0 deletions cibuildwheel/resources/pinned_docker_images.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2025.06.28-1

[i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.06.28-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.06.28-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2025.06.28-1

[aarch64]
Expand Down Expand Up @@ -33,6 +34,7 @@ manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.06.28-1

[pypy_i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.06.28-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.06.28-1

[pypy_aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.06.28-1
Expand Down
6 changes: 3 additions & 3 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -1009,15 +1009,15 @@ The available options are:
| Option | Default |
|--------------------------------|-----------------------------------------------------------------|
| `manylinux_x86_64-image` | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_x86_64) |
| `manylinux-i686-image` | [`manylinux2014`](https://quay.io/pypa/manylinux2014_i686) |
| `manylinux-i686-image` | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_i686) |
| `manylinux-pypy_x86_64-image` | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_x86_64) |
| `manylinux-aarch64-image` | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_aarch64) |
| `manylinux-ppc64le-image` | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_ppc64le) |
| `manylinux-s390x-image` | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_s390x) |
| `manylinux-armv7l-image` | [`manylinux_2_31`](https://quay.io/pypa/manylinux_2_31_armv7l) |
| `manylinux-riscv64-image` | No default |
| `manylinux-pypy_aarch64-image` | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_aarch64) |
| `manylinux-pypy_i686-image` | [`manylinux2014`](https://quay.io/pypa/manylinux2014_i686) |
| `manylinux-pypy_i686-image` | [`manylinux_2_28`](https://quay.io/pypa/manylinux_2_28_i686) |
| `musllinux_x86_64-image` | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_x86_64) |
| `musllinux-i686-image` | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_i686) |
| `musllinux-aarch64-image` | [`musllinux_1_2`](https://quay.io/pypa/musllinux_1_2_aarch64) |
Expand All @@ -1029,7 +1029,7 @@ The available options are:
Set the Docker image to be used for building [manylinux / musllinux](https://github.com/pypa/manylinux) wheels.

For `manylinux-*-image`, except `manylinux-armv7l-image`, the value of this option can either be set to `manylinux2014`, `manylinux_2_28` or `manylinux_2_34` to use a pinned version of the [official manylinux images](https://github.com/pypa/manylinux). Alternatively, set these options to any other valid Docker image name.
`manylinux_2_28` and `manylinux_2_34` are not supported for `i686` architecture.
`manylinux_2_34` is not supported for `i686` architecture.

For `manylinux-armv7l-image`, the value of this option can either be set to `manylinux_2_31` or a custom image. Support is experimental for now. The `manylinux_2_31` value is only available for `armv7`.

Expand Down
10 changes: 5 additions & 5 deletions test/test_manylinuxXXXX_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
def test(manylinux_image, tmp_path):
if utils.get_platform() != "linux":
pytest.skip("the container image test is only relevant to the linux build")
elif manylinux_image in {"manylinux_2_28", "manylinux_2_34"} and platform.machine() == "i686":
elif manylinux_image == "manylinux_2_34" and platform.machine() == "i686":
pytest.skip(f"{manylinux_image} doesn't exist for i686 architecture")

project_dir = tmp_path / "project"
Expand All @@ -85,8 +85,8 @@ def test(manylinux_image, tmp_path):
"CIBW_MANYLINUX_PYPY_AARCH64_IMAGE": manylinux_image,
"CIBW_MANYLINUX_PYPY_I686_IMAGE": manylinux_image,
}
if manylinux_image in {"manylinux_2_28", "manylinux_2_34"} and platform.machine() == "x86_64":
# We don't have a manylinux_2_28+ image for i686
if manylinux_image == "manylinux_2_34" and platform.machine() == "x86_64":
# We don't have a manylinux_2_34+ image for i686
add_env["CIBW_ARCHS"] = "x86_64"
if platform.machine() == "aarch64":
# We just have a manylinux_2_31 image for armv7l
Expand All @@ -104,8 +104,8 @@ def test(manylinux_image, tmp_path):
musllinux_versions=[],
)

if manylinux_image in {"manylinux_2_28", "manylinux_2_34"} and platform.machine() == "x86_64":
# We don't have a manylinux_2_28+ image for i686
if manylinux_image == "manylinux_2_34" and platform.machine() == "x86_64":
# We don't have a manylinux_2_34+ image for i686
expected_wheels = [w for w in expected_wheels if "i686" not in w]

if platform.machine() == "aarch64":
Expand Down
2 changes: 1 addition & 1 deletion test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def _expected_wheels(
if manylinux_versions is None:
manylinux_versions = {
"armv7l": ["manylinux2014", "manylinux_2_17", "manylinux_2_31"],
"i686": ["manylinux1", "manylinux2014", "manylinux_2_17", "manylinux_2_5"],
"i686": ["manylinux1", "manylinux_2_28", "manylinux_2_5"],
"x86_64": ["manylinux1", "manylinux_2_28", "manylinux_2_5"],
"riscv64": ["manylinux_2_31", "manylinux_2_35"],
}.get(machine_arch, ["manylinux2014", "manylinux_2_17", "manylinux_2_28"])
Expand Down
3 changes: 2 additions & 1 deletion unit_test/main_tests/main_options_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ def test_empty_selector(monkeypatch):
("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", None, "quay.io/pypa/manylinux_2_28_i686:*"),
("i686", "manylinux2014", "quay.io/pypa/manylinux2014_i686:*"),
("i686", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_i686:*"),
("i686", "custom_image", "custom_image"),
("pypy_x86_64", None, "quay.io/pypa/manylinux_2_28_x86_64:*"),
("pypy_x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64:*"),
Expand Down
18 changes: 13 additions & 5 deletions unit_test/option_prepare_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def test_build_default_launches(monkeypatch):
assert identifiers == {f"{x}-manylinux_x86_64" for x in DEFAULT_IDS}

kwargs = build_in_container.call_args_list[1][1]
assert "quay.io/pypa/manylinux2014_i686" in kwargs["container"]["image"]
assert "quay.io/pypa/manylinux_2_28_i686" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386

Expand Down Expand Up @@ -128,7 +128,7 @@ def test_build_with_override_launches(monkeypatch, tmp_path):

build_in_container = typing.cast(mock.Mock, platforms.linux.build_in_container)

assert build_in_container.call_count == 6
assert build_in_container.call_count == 7

kwargs = build_in_container.call_args_list[0][1]
assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"]
Expand Down Expand Up @@ -189,11 +189,19 @@ def test_build_with_override_launches(monkeypatch, tmp_path):
assert "quay.io/pypa/manylinux2014_i686" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
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 if "gp" not in x}
assert identifiers == {"cp38-manylinux_i686", "cp39-manylinux_i686"}

kwargs = build_in_container.call_args_list[4][1]
assert "quay.io/pypa/manylinux_2_28_i686" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
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
}

kwargs = build_in_container.call_args_list[5][1]
assert "quay.io/pypa/musllinux_1_2_x86_64" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
Expand All @@ -202,7 +210,7 @@ def test_build_with_override_launches(monkeypatch, tmp_path):
f"{x}-musllinux_x86_64" for x in ALL_IDS if "pp" not in x and "gp" not in x
}

kwargs = build_in_container.call_args_list[5][1]
kwargs = build_in_container.call_args_list[6][1]
assert "quay.io/pypa/musllinux_1_2_i686" in kwargs["container"]["image"]
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
Expand Down
4 changes: 2 additions & 2 deletions unit_test/options_toml_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_simple_settings(tmp_path, platform, fname):
assert options_reader.get("test-groups", option_format=ListFormat(" ")) == "three four"

assert options_reader.get("manylinux-x86_64-image") == "manylinux_2_28"
assert options_reader.get("manylinux-i686-image") == "manylinux2014"
assert options_reader.get("manylinux-i686-image") == "manylinux_2_28"

with pytest.raises(OptionsReaderError):
# fails because the option is a table and the option_format only works with lists
Expand Down Expand Up @@ -104,7 +104,7 @@ def test_envvar_override(tmp_path, platform):

assert options_reader.get("build") == "cp38*"
assert options_reader.get("manylinux-x86_64-image") == "manylinux_2_24"
assert options_reader.get("manylinux-i686-image") == "manylinux2014"
assert options_reader.get("manylinux-i686-image") == "manylinux_2_28"

assert (
options_reader.get("xbuild-tools", option_format=ListFormat(" ", quote=shlex.quote))
Expand Down
Loading