From 9fad66fcfb699a9f2ee7fcadbe3631a6cc409cb1 Mon Sep 17 00:00:00 2001 From: Matthieu Darbois Date: Tue, 1 Oct 2024 16:33:57 +0200 Subject: [PATCH] feat: add musllinux armv7l (#2017) * feature: add musllinux armv7l * fix: local armv7l images * fix python 3.8 tests * address review comments --------- Co-authored-by: Henry Schreiner --- README.md | 28 +++++----- bin/generate_schema.py | 3 ++ bin/update_docker.py | 1 + cibuildwheel/architecture.py | 10 ++-- cibuildwheel/linux.py | 1 + cibuildwheel/logger.py | 3 +- cibuildwheel/oci_container.py | 24 +++++---- cibuildwheel/resources/build-platforms.toml | 9 ++++ .../resources/cibuildwheel.schema.json | 11 ++++ cibuildwheel/resources/defaults.toml | 1 + .../resources/pinned_docker_images.cfg | 3 ++ cibuildwheel/util.py | 1 + docs/options.md | 35 ++++++------ test/utils.py | 4 +- unit_test/main_tests/main_platform_test.py | 1 + unit_test/oci_container_test.py | 54 +++++++++++++------ 16 files changed, 126 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 5e86ca72b..a2f970fa1 100644 --- a/README.md +++ b/README.md @@ -22,20 +22,20 @@ Python wheels are great. Building them across **Mac, Linux, Windows**, on **mult What does it do? ---------------- -| | 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 | Pyodide | -|----------------|----|-----|-----|-----|-----|----|-----|----|-----|-----|-----| -| CPython 3.6 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | -| CPython 3.7 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | -| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | -| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | -| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | -| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | -| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁴ | -| CPython 3.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | -| PyPy 3.7 v7.3 | ✅ | N/A | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | -| PyPy 3.8 v7.3 | ✅ | ✅ | ✅ | 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 | -| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | +| | 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 | musllinux armv7l | Pyodide | +|----------------|----|-----|-----|-----|-----|----|-----|----|-----|-----|---|-----| +| CPython 3.6 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | +| CPython 3.7 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | +| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | +| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | +| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | +| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | +| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁴ | +| CPython 3.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | +| PyPy 3.7 v7.3 | ✅ | N/A | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | +| PyPy 3.8 v7.3 | ✅ | ✅ | ✅ | 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 | +| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | ¹ PyPy is only supported for manylinux wheels.
² Windows arm64 support is experimental.
diff --git a/bin/generate_schema.py b/bin/generate_schema.py index 2c90fe925..41f4ad4cd 100755 --- a/bin/generate_schema.py +++ b/bin/generate_schema.py @@ -137,6 +137,9 @@ musllinux-aarch64-image: type: string description: Specify alternative manylinux / musllinux container images + musllinux-armv7l-image: + type: string + description: Specify alternative manylinux / musllinux container images musllinux-i686-image: type: string description: Specify alternative manylinux / musllinux container images diff --git a/bin/update_docker.py b/bin/update_docker.py index 9be3ae03d..a455afb72 100755 --- a/bin/update_docker.py +++ b/bin/update_docker.py @@ -65,6 +65,7 @@ class Image: Image("musllinux_1_2", "aarch64", "quay.io/pypa/musllinux_1_2_aarch64", None), Image("musllinux_1_2", "ppc64le", "quay.io/pypa/musllinux_1_2_ppc64le", None), Image("musllinux_1_2", "s390x", "quay.io/pypa/musllinux_1_2_s390x", None), + Image("musllinux_1_2", "armv7l", "quay.io/pypa/musllinux_1_2_armv7l", None), ] config = configparser.ConfigParser() diff --git a/cibuildwheel/architecture.py b/cibuildwheel/architecture.py index c6c4b623f..0f622def9 100644 --- a/cibuildwheel/architecture.py +++ b/cibuildwheel/architecture.py @@ -37,6 +37,7 @@ class Architecture(Enum): aarch64 = "aarch64" ppc64le = "ppc64le" s390x = "s390x" + armv7l = "armv7l" # mac archs universal2 = "universal2" @@ -132,6 +133,7 @@ def all_archs(platform: PlatformName) -> set[Architecture]: Architecture.aarch64, Architecture.ppc64le, Architecture.s390x, + Architecture.armv7l, }, "macos": {Architecture.x86_64, Architecture.arm64, Architecture.universal2}, "windows": {Architecture.x86, Architecture.AMD64, Architecture.ARM64}, @@ -140,17 +142,15 @@ def all_archs(platform: PlatformName) -> set[Architecture]: return all_archs_map[platform] @staticmethod - # pylint: disable-next=inconsistent-return-statements def bitness_archs(platform: PlatformName, bitness: Literal["64", "32"]) -> set[Architecture]: - archs_32 = {Architecture.i686, Architecture.x86} + archs_32 = {Architecture.i686, Architecture.x86, Architecture.armv7l} auto_archs = Architecture.auto_archs(platform) if bitness == "64": return auto_archs - archs_32 - elif bitness == "32": + if bitness == "32": return auto_archs & archs_32 - else: - assert_never(bitness) + assert_never(bitness) def allowed_architectures_check( diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 863536c92..ce6b930d1 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -35,6 +35,7 @@ Architecture.aarch64: OCIPlatform.ARM64, Architecture.ppc64le: OCIPlatform.PPC64LE, Architecture.s390x: OCIPlatform.S390X, + Architecture.armv7l: OCIPlatform.ARMV7, } diff --git a/cibuildwheel/logger.py b/cibuildwheel/logger.py index 312e2f559..0b32fe35b 100644 --- a/cibuildwheel/logger.py +++ b/cibuildwheel/logger.py @@ -27,7 +27,8 @@ "musllinux_i686": "musllinux i686", "musllinux_aarch64": "musllinux aarch64", "musllinux_ppc64le": "musllinux ppc64le", - "musllinux_s390x": "manylinux s390x", + "musllinux_s390x": "musllinux s390x", + "musllinux_armv7l": "musllinux armv7l", "win32": "Windows 32bit", "win_amd64": "Windows 64bit", "win_arm64": "Windows on ARM 64bit", diff --git a/cibuildwheel/oci_container.py b/cibuildwheel/oci_container.py index bdd663b30..a93079f14 100644 --- a/cibuildwheel/oci_container.py +++ b/cibuildwheel/oci_container.py @@ -38,6 +38,7 @@ class OCIPlatform(Enum): i386 = "linux/386" AMD64 = "linux/amd64" + ARMV7 = "linux/arm/v7" ARM64 = "linux/arm64" PPC64LE = "linux/ppc64le" S390X = "linux/s390x" @@ -208,7 +209,11 @@ def _get_platform_args(self, *, oci_platform: OCIPlatform | None = None) -> tupl "inspect", self.image, "--format", - "{{.Os}}/{{.Architecture}}", + ( + "{{.Os}}/{{.Architecture}}/{{.Variant}}" + if len(oci_platform.value.split("/")) == 3 + else "{{.Os}}/{{.Architecture}}" + ), capture_stdout=True, ).strip() if image_platform == oci_platform.value: @@ -235,7 +240,7 @@ def __enter__(self) -> Self: platform_args = self._get_platform_args() simulate_32_bit = False - if self.oci_platform == OCIPlatform.i386: + if self.oci_platform in {OCIPlatform.i386, OCIPlatform.ARMV7}: # If the architecture running the image is already the right one # or the image entrypoint takes care of enforcing this, then we don't need to # simulate this @@ -246,13 +251,14 @@ def __enter__(self) -> Self: *run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True ).strip() except subprocess.CalledProcessError: - # The image might have been built with amd64 architecture - # Let's try that - platform_args = self._get_platform_args(oci_platform=OCIPlatform.AMD64) - container_machine = call( - *run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True - ).strip() - simulate_32_bit = container_machine != "i686" + if self.oci_platform == OCIPlatform.i386: + # The image might have been built with amd64 architecture + # Let's try that + platform_args = self._get_platform_args(oci_platform=OCIPlatform.AMD64) + container_machine = call( + *run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True + ).strip() + simulate_32_bit = container_machine not in {"i686", "armv7l", "armv8l"} shell_args = ["linux32", "/bin/bash"] if simulate_32_bit else ["/bin/bash"] diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml index 2c8e1e5c1..0a27238ca 100644 --- a/cibuildwheel/resources/build-platforms.toml +++ b/cibuildwheel/resources/build-platforms.toml @@ -102,6 +102,15 @@ python_configurations = [ { 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" }, + { identifier = "cp36-musllinux_armv7l", version = "3.6", path_str = "/opt/python/cp36-cp36m" }, + { identifier = "cp37-musllinux_armv7l", version = "3.7", path_str = "/opt/python/cp37-cp37m" }, + { 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" }, + { identifier = "cp312-musllinux_armv7l", version = "3.12", path_str = "/opt/python/cp312-cp312" }, + { identifier = "cp313-musllinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313" }, + { identifier = "cp313t-musllinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313t" }, ] [macos] diff --git a/cibuildwheel/resources/cibuildwheel.schema.json b/cibuildwheel/resources/cibuildwheel.schema.json index 976751a55..8e2508bc9 100644 --- a/cibuildwheel/resources/cibuildwheel.schema.json +++ b/cibuildwheel/resources/cibuildwheel.schema.json @@ -312,6 +312,11 @@ "description": "Specify alternative manylinux / musllinux container images", "title": "CIBW_MUSLLINUX_AARCH64_IMAGE" }, + "musllinux-armv7l-image": { + "type": "string", + "description": "Specify alternative manylinux / musllinux container images", + "title": "CIBW_MUSLLINUX_ARMV7L_IMAGE" + }, "musllinux-i686-image": { "type": "string", "description": "Specify alternative manylinux / musllinux container images", @@ -542,6 +547,9 @@ "musllinux-aarch64-image": { "$ref": "#/properties/musllinux-aarch64-image" }, + "musllinux-armv7l-image": { + "$ref": "#/properties/musllinux-armv7l-image" + }, "musllinux-i686-image": { "$ref": "#/properties/musllinux-i686-image" }, @@ -630,6 +638,9 @@ "musllinux-aarch64-image": { "$ref": "#/properties/musllinux-aarch64-image" }, + "musllinux-armv7l-image": { + "$ref": "#/properties/musllinux-armv7l-image" + }, "musllinux-i686-image": { "$ref": "#/properties/musllinux-i686-image" }, diff --git a/cibuildwheel/resources/defaults.toml b/cibuildwheel/resources/defaults.toml index 984af48ea..21bac7a0c 100644 --- a/cibuildwheel/resources/defaults.toml +++ b/cibuildwheel/resources/defaults.toml @@ -37,6 +37,7 @@ musllinux-i686-image = "musllinux_1_2" musllinux-aarch64-image = "musllinux_1_2" musllinux-ppc64le-image = "musllinux_1_2" musllinux-s390x-image = "musllinux_1_2" +musllinux-armv7l-image = "musllinux_1_2" [tool.cibuildwheel.linux] diff --git a/cibuildwheel/resources/pinned_docker_images.cfg b/cibuildwheel/resources/pinned_docker_images.cfg index 9a18d48d4..6a094a8ba 100644 --- a/cibuildwheel/resources/pinned_docker_images.cfg +++ b/cibuildwheel/resources/pinned_docker_images.cfg @@ -52,3 +52,6 @@ manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.09.28-3 manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-12-26-0d38463 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.09.28-3 +[armv7l] +musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2024.09.22-4 + diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index b9db4268b..bfbe50c7a 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -83,6 +83,7 @@ "aarch64", "ppc64le", "s390x", + "armv7l", ) DEFAULT_CIBW_CACHE_PATH: Final[Path] = user_cache_path(appname="cibuildwheel", appauthor="pypa") diff --git a/docs/options.md b/docs/options.md index 5cb238784..fa2fb7003 100644 --- a/docs/options.md +++ b/docs/options.md @@ -288,20 +288,20 @@ When setting the options, you can use shell-style globbing syntax, as per [fnmat
-| | macOS | Windows | Linux Intel | Linux Other | -|---------------|------------------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Python 3.6 | cp36-macosx_x86_64 | cp36-win_amd64
cp36-win32 | cp36-manylinux_x86_64
cp36-manylinux_i686
cp36-musllinux_x86_64
cp36-musllinux_i686 | cp36-manylinux_aarch64
cp36-manylinux_ppc64le
cp36-manylinux_s390x
cp36-musllinux_aarch64
cp36-musllinux_ppc64le
cp36-musllinux_s390x | -| Python 3.7 | cp37-macosx_x86_64 | cp37-win_amd64
cp37-win32 | cp37-manylinux_x86_64
cp37-manylinux_i686
cp37-musllinux_x86_64
cp37-musllinux_i686 | cp37-manylinux_aarch64
cp37-manylinux_ppc64le
cp37-manylinux_s390x
cp37-musllinux_aarch64
cp37-musllinux_ppc64le
cp37-musllinux_s390x | -| 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-musllinux_aarch64
cp38-musllinux_ppc64le
cp38-musllinux_s390x | -| 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-musllinux_aarch64
cp39-musllinux_ppc64le
cp39-musllinux_s390x | -| 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-musllinux_aarch64
cp310-musllinux_ppc64le
cp310-musllinux_s390x | -| 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-musllinux_aarch64
cp311-musllinux_ppc64le
cp311-musllinux_s390x | -| 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-musllinux_aarch64
cp312-musllinux_ppc64le
cp312-musllinux_s390x | -| Python 3.13 | cp313-macosx_x86_64
cp313-macosx_universal2
cp313-macosx_arm64 | cp313-win_amd64
cp313-win32
cp313-win_arm64 | cp313-manylinux_x86_64
cp313-manylinux_i686
cp313-musllinux_x86_64
cp313-musllinux_i686 | cp313-manylinux_aarch64
cp313-manylinux_ppc64le
cp313-manylinux_s390x
cp313-musllinux_aarch64
cp313-musllinux_ppc64le
cp313-musllinux_s390x | -| PyPy3.7 v7.3 | pp37-macosx_x86_64 | pp37-win_amd64 | pp37-manylinux_x86_64
pp37-manylinux_i686 | pp37-manylinux_aarch64 | -| 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 | +| | macOS | Windows | Linux Intel | Linux Other | +|---------------|------------------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Python 3.6 | cp36-macosx_x86_64 | cp36-win_amd64
cp36-win32 | cp36-manylinux_x86_64
cp36-manylinux_i686
cp36-musllinux_x86_64
cp36-musllinux_i686 | cp36-manylinux_aarch64
cp36-manylinux_ppc64le
cp36-manylinux_s390x
cp36-musllinux_aarch64
cp36-musllinux_ppc64le
cp36-musllinux_s390x
cp36-musllinux_armv7l | +| Python 3.7 | cp37-macosx_x86_64 | cp37-win_amd64
cp37-win32 | cp37-manylinux_x86_64
cp37-manylinux_i686
cp37-musllinux_x86_64
cp37-musllinux_i686 | cp37-manylinux_aarch64
cp37-manylinux_ppc64le
cp37-manylinux_s390x
cp37-musllinux_aarch64
cp37-musllinux_ppc64le
cp37-musllinux_s390x
cp37-musllinux_armv7l | +| 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-musllinux_aarch64
cp38-musllinux_ppc64le
cp38-musllinux_s390x
cp38-musllinux_armv7l | +| 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-musllinux_aarch64
cp39-musllinux_ppc64le
cp39-musllinux_s390x
cp39-musllinux_armv7l | +| 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-musllinux_aarch64
cp310-musllinux_ppc64le
cp310-musllinux_s390x
cp310-musllinux_armv7l | +| 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-musllinux_aarch64
cp311-musllinux_ppc64le
cp311-musllinux_s390x
cp311-musllinux_armv7l | +| 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-musllinux_aarch64
cp312-musllinux_ppc64le
cp312-musllinux_s390x
cp312-musllinux_armv7l | +| Python 3.13 | cp313-macosx_x86_64
cp313-macosx_universal2
cp313-macosx_arm64 | cp313-win_amd64
cp313-win32
cp313-win_arm64 | cp313-manylinux_x86_64
cp313-manylinux_i686
cp313-musllinux_x86_64
cp313-musllinux_i686 | cp313-manylinux_aarch64
cp313-manylinux_ppc64le
cp313-manylinux_s390x
cp313-musllinux_aarch64
cp313-musllinux_ppc64le
cp313-musllinux_s390x
cp313-musllinux_armv7l | +| PyPy3.7 v7.3 | pp37-macosx_x86_64 | pp37-win_amd64 | pp37-manylinux_x86_64
pp37-manylinux_i686 | pp37-manylinux_aarch64 | +| 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 | The list of supported and currently selected build identifiers can also be retrieved by passing the `--print-build-identifiers` flag to cibuildwheel. The format is `python_tag-platform_tag`, with tags similar to those in [PEP 425](https://www.python.org/dev/peps/pep-0425/#details). @@ -475,7 +475,7 @@ machine, provided the cross-compiling tools are installed. Options: -- Linux: `x86_64` `i686` `aarch64` `ppc64le` `s390x` +- Linux: `x86_64` `i686` `aarch64` `ppc64le` `s390x` `armv7l` - macOS: `x86_64` `arm64` `universal2` - Windows: `AMD64` `x86` `ARM64` - Pyodide: `wasm32` @@ -1174,6 +1174,7 @@ The available options are (default value): - `CIBW_MUSLLINUX_AARCH64_IMAGE` ([`quay.io/pypa/musllinux_1_2_aarch64`](https://quay.io/pypa/musllinux_1_2_aarch64)) - `CIBW_MUSLLINUX_PPC64LE_IMAGE` ([`quay.io/pypa/musllinux_1_2_ppc64le`](https://quay.io/pypa/musllinux_1_2_ppc64le)) - `CIBW_MUSLLINUX_S390X_IMAGE` ([`quay.io/pypa/musllinux_1_2_s390x`](https://quay.io/pypa/musllinux_1_2_s390x)) +- `CIBW_MUSLLINUX_ARMV7L_IMAGE` ([`quay.io/pypa/musllinux_1_2_armv7l`](https://quay.io/pypa/musllinux_1_2_armv7l)) Set an alternative Docker image to be used for building [manylinux / musllinux](https://github.com/pypa/manylinux) wheels. @@ -1599,7 +1600,7 @@ This option is not supported in the overrides section in `pyproject.toml`. ```yaml # Will avoid testing on emulated architectures - CIBW_TEST_SKIP: "*-*linux_{aarch64,ppc64le,s390x}" + CIBW_TEST_SKIP: "*-*linux_{aarch64,ppc64le,s390x,armv7l}" # Skip trying to test arm64 builds on Intel Macs CIBW_TEST_SKIP: "*-macosx_arm64 *-macosx_universal2:arm64" @@ -1610,7 +1611,7 @@ This option is not supported in the overrides section in `pyproject.toml`. ```toml [tool.cibuildwheel] # Will avoid testing on emulated architectures - test-skip = "*-*linux_{aarch64,ppc64le,s390x}" + test-skip = "*-*linux_{aarch64,ppc64le,s390x,armv7l}" # Skip trying to test arm64 builds on Intel Macs test-skip = "*-macosx_arm64 *-macosx_universal2:arm64" diff --git a/test/utils.py b/test/utils.py index 158527e81..f007069c2 100644 --- a/test/utils.py +++ b/test/utils.py @@ -170,7 +170,9 @@ def expected_wheels( machine_arch = "aarch64" if manylinux_versions is None: - if machine_arch == "x86_64": + if machine_arch == "armv7l": + manylinux_versions = [] + elif machine_arch == "x86_64": manylinux_versions = [ "manylinux_2_5", "manylinux1", diff --git a/unit_test/main_tests/main_platform_test.py b/unit_test/main_tests/main_platform_test.py index 5dca47d01..cdc2bebc6 100644 --- a/unit_test/main_tests/main_platform_test.py +++ b/unit_test/main_tests/main_platform_test.py @@ -179,6 +179,7 @@ def test_archs_platform_all(platform, intercepted_build_args, monkeypatch): Architecture.aarch64, Architecture.ppc64le, Architecture.s390x, + Architecture.armv7l, } elif platform == "windows": assert options.globals.architectures == { diff --git a/unit_test/oci_container_test.py b/unit_test/oci_container_test.py index 0f99618a6..f43a3641c 100644 --- a/unit_test/oci_container_test.py +++ b/unit_test/oci_container_test.py @@ -535,16 +535,33 @@ def test_disable_host_mount(tmp_path: Path, container_engine, config, should_hav container.call(["cat", host_mount_path], capture_output=True) -def test_local_image(container_engine): - local_image = f"cibw_test_{container_engine.name}_local:latest" +@pytest.mark.parametrize("platform", list(OCIPlatform)) +def test_local_image(container_engine, platform, tmp_path: Path): + if ( + detect_ci_provider() in {CIProvider.travis_ci} + and pm in {"s390x", "ppc64le"} + and platform != DEFAULT_OCI_PLATFORM + ): + pytest.skip("Skipping test because docker on this platform does not support QEMU") + if container_engine.name == "podman" and platform == OCIPlatform.ARMV7: + # both GHA & local macOS arm64 podman desktop are failing + pytest.xfail("podman fails with armv7l images") + + remote_image = "debian:12-slim" + platform_name = platform.value.replace("/", "_") + local_image = f"cibw_{container_engine.name}_{platform_name}_local:latest" + dockerfile = tmp_path / "Dockerfile" + dockerfile.write_text(f"FROM {remote_image}") subprocess.run( - [container_engine.name, "pull", f"--platform={DEFAULT_OCI_PLATFORM.value}", DEFAULT_IMAGE], + [container_engine.name, "pull", f"--platform={platform.value}", remote_image], check=True, ) - subprocess.run([container_engine.name, "image", "tag", DEFAULT_IMAGE, local_image], check=True) - with OCIContainer( - engine=container_engine, image=local_image, oci_platform=DEFAULT_OCI_PLATFORM - ): + subprocess.run( + [container_engine.name, "build", f"--platform={platform.value}", "-t", local_image, "."], + check=True, + cwd=tmp_path, + ) + with OCIContainer(engine=container_engine, image=local_image, oci_platform=platform): pass @@ -556,27 +573,32 @@ def test_multiarch_image(container_engine, platform): and platform != DEFAULT_OCI_PLATFORM ): pytest.skip("Skipping test because docker on this platform does not support QEMU") + if container_engine.name == "podman" and platform == OCIPlatform.ARMV7: + # both GHA & local macOS arm64 podman desktop are failing + pytest.xfail("podman fails with armv7l images") with OCIContainer( engine=container_engine, image="debian:12-slim", oci_platform=platform ) as container: output = container.call(["uname", "-m"], capture_output=True) - output_map = { - OCIPlatform.i386: "i686", - OCIPlatform.AMD64: "x86_64", - OCIPlatform.ARM64: "aarch64", - OCIPlatform.PPC64LE: "ppc64le", - OCIPlatform.S390X: "s390x", + output_map_kernel = { + OCIPlatform.i386: ("i686",), + OCIPlatform.AMD64: ("x86_64",), + OCIPlatform.ARMV7: ("armv7l", "armv8l"), + OCIPlatform.ARM64: ("aarch64",), + OCIPlatform.PPC64LE: ("ppc64le",), + OCIPlatform.S390X: ("s390x",), } - assert output_map[platform] == output.strip() + assert output.strip() in output_map_kernel[platform] output = container.call(["dpkg", "--print-architecture"], capture_output=True) - output_map = { + output_map_dpkg = { OCIPlatform.i386: "i386", OCIPlatform.AMD64: "amd64", + OCIPlatform.ARMV7: "armhf", OCIPlatform.ARM64: "arm64", OCIPlatform.PPC64LE: "ppc64el", OCIPlatform.S390X: "s390x", } - assert output_map[platform] == output.strip() + assert output_map_dpkg[platform] == output.strip() @pytest.mark.parametrize(