diff --git a/scripts/create-arch-wheels.sh b/scripts/create-arch-wheels.sh index 55c7f982..054d70df 100755 --- a/scripts/create-arch-wheels.sh +++ b/scripts/create-arch-wheels.sh @@ -7,11 +7,11 @@ set -eux SCRIPT_DIR="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd -P)" INTEGRATION_TEST_DIR="${SCRIPT_DIR}/../tests/integration" -mkdir -p "${INTEGRATION_TEST_DIR}/arch-wheels" +mkdir -p "${INTEGRATION_TEST_DIR}/arch-wheels/glibc" +mkdir -p "${INTEGRATION_TEST_DIR}/arch-wheels/musllinux_1_2" # "mips64le" built with buildpack-deps:bookworm and renamed cp313-cp313 -# "386" "amd64" "arm/v5" "arm/v7" "arm64/v8" -for ARCH in "ppc64le" "riscv64" "s390x"; do +for ARCH in "386" "amd64" "arm/v5" "arm/v7" "arm64/v8" "ppc64le" "riscv64" "s390x"; do docker run --platform linux/${ARCH} -i --rm -v "${INTEGRATION_TEST_DIR}:/tests" debian:trixie-20250203 << "EOF" # for, "arm/v5" QEMU will report armv7l, running on aarch64 will report aarch64, force armv5l/armv7l case "$(dpkg --print-architecture)" in @@ -21,7 +21,19 @@ case "$(dpkg --print-architecture)" in esac DEBIAN_FRONTEND=noninteractive apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gcc python3-pip python3-dev -python3 -m pip wheel --no-deps -w /tests/arch-wheels /tests/testsimple +python3 -m pip wheel --no-deps -w /tests/arch-wheels/glibc /tests/testsimple EOF +done +for ARCH in "386" "amd64" "arm/v6" "arm/v7" "arm64/v8" "ppc64le" "riscv64" "s390x"; do + docker run --platform linux/${ARCH} -i --rm -v "${INTEGRATION_TEST_DIR}:/tests" alpine:3.21 << "EOF" +# for, "arm/v5" QEMU will report armv7l, running on aarch64 will report aarch64, force armv5l/armv7l +case "$(cat /etc/apk/arch)" in + armhf) export _PYTHON_HOST_PLATFORM="linux-armv6l";; + armv7) export _PYTHON_HOST_PLATFORM="linux-armv7l";; + *) ;; +esac +apk add gcc binutils musl-dev python3-dev py3-pip +python3 -m pip wheel --no-deps -w /tests/arch-wheels/musllinux_1_2 /tests/testsimple +EOF done diff --git a/src/auditwheel/lddtree.py b/src/auditwheel/lddtree.py index 96f4dbc0..07326341 100644 --- a/src/auditwheel/lddtree.py +++ b/src/auditwheel/lddtree.py @@ -522,6 +522,17 @@ def ldd( if libc != Libc.GLIBC: msg = f"found a dependency on GLIBC but the libc is already set to {libc}" raise InvalidLibc(msg) + if libc is None: + # try the filename as a last resort + if path.name.endswith(("-arm-linux-musleabihf.so", "-linux-musl.so")): + libc = Libc.MUSL + elif path.name.endswith(("-arm-linux-gnueabihf.so", "-linux-gnu.so")): + # before python 3.11, musl was also using gnu + soabi = path.stem.split(".")[-1].split("-") + valid_python = tuple(f"3{minor}" for minor in range(11, 100)) + if soabi[0] == "cpython" and soabi[1].startswith(valid_python): + libc = Libc.GLIBC + if ldpaths is None: ldpaths = load_ld_paths(libc).copy() # Propagate the rpaths used by the main ELF since those will be diff --git a/src/auditwheel/libc.py b/src/auditwheel/libc.py index bcce2850..82682df5 100644 --- a/src/auditwheel/libc.py +++ b/src/auditwheel/libc.py @@ -5,7 +5,7 @@ import re import subprocess from dataclasses import dataclass -from enum import IntEnum +from enum import Enum from pathlib import Path from .error import InvalidLibc @@ -19,9 +19,14 @@ class LibcVersion: minor: int -class Libc(IntEnum): - GLIBC = (1,) - MUSL = (2,) +class Libc(Enum): + value: str + + GLIBC = "glibc" + MUSL = "musl" + + def __str__(self) -> str: + return self.value def get_current_version(self) -> LibcVersion: if self == Libc.MUSL: diff --git a/src/auditwheel/policy/__init__.py b/src/auditwheel/policy/__init__.py index 8f82e01c..8536cf4a 100644 --- a/src/auditwheel/policy/__init__.py +++ b/src/auditwheel/policy/__init__.py @@ -11,6 +11,7 @@ from ..architecture import Architecture from ..elfutils import filter_undefined_symbols +from ..error import InvalidLibc from ..lddtree import DynamicExecutable from ..libc import Libc from ..tools import is_subdir @@ -62,8 +63,13 @@ def __init__( raise ValueError(msg) if libc == Libc.MUSL: if musl_policy is None: - musl_version = libc.get_current_version() - musl_policy = f"musllinux_{musl_version.major}_{musl_version.minor}" + try: + musl_version = libc.get_current_version() + musl_policy = f"musllinux_{musl_version.major}_{musl_version.minor}" + except InvalidLibc: + logger.warning( + "can't determine musl libc version, latest known version will be used." + ) elif _MUSL_POLICY_RE.match(musl_policy) is None: msg = f"Invalid 'musl_policy': '{musl_policy}'" raise ValueError(msg) @@ -106,6 +112,9 @@ def __init__( self._policies.sort() if self._libc_variant == Libc.MUSL: + if musl_policy is None: + self._musl_policy = "_".join(self._policies[1].name.split("_")[0:3]) + self._policies = [self._policies[0], self._policies[1]] assert len(self._policies) == 2, self._policies def __iter__(self) -> Generator[Policy]: diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_aarch64.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_aarch64.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_aarch64.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_aarch64.whl diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_armv5l.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_armv5l.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_armv5l.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_armv5l.whl diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_armv7l.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_armv7l.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_armv7l.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_armv7l.whl diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_i686.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_i686.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_i686.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_i686.whl diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_mips64.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_mips64.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_mips64.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_mips64.whl diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_ppc64le.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_ppc64le.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_ppc64le.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_ppc64le.whl diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_riscv64.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_riscv64.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_riscv64.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_riscv64.whl diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_s390x.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_s390x.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_s390x.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_s390x.whl diff --git a/tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_x86_64.whl b/tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_x86_64.whl similarity index 100% rename from tests/integration/arch-wheels/testsimple-0.0.1-cp313-cp313-linux_x86_64.whl rename to tests/integration/arch-wheels/glibc/testsimple-0.0.1-cp313-cp313-linux_x86_64.whl diff --git a/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_aarch64.whl b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_aarch64.whl new file mode 100644 index 00000000..a5a40b9b Binary files /dev/null and b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_aarch64.whl differ diff --git a/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_armv6l.whl b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_armv6l.whl new file mode 100644 index 00000000..49ca14a8 Binary files /dev/null and b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_armv6l.whl differ diff --git a/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_armv7l.whl b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_armv7l.whl new file mode 100644 index 00000000..da5acddc Binary files /dev/null and b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_armv7l.whl differ diff --git a/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_i686.whl b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_i686.whl new file mode 100644 index 00000000..304a4949 Binary files /dev/null and b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_i686.whl differ diff --git a/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_ppc64le.whl b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_ppc64le.whl new file mode 100644 index 00000000..aeb85623 Binary files /dev/null and b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_ppc64le.whl differ diff --git a/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_riscv64.whl b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_riscv64.whl new file mode 100644 index 00000000..86555e61 Binary files /dev/null and b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_riscv64.whl differ diff --git a/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_s390x.whl b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_s390x.whl new file mode 100644 index 00000000..0a2e8d81 Binary files /dev/null and b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_s390x.whl differ diff --git a/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_x86_64.whl b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_x86_64.whl new file mode 100644 index 00000000..cf1db3d4 Binary files /dev/null and b/tests/integration/arch-wheels/musllinux_1_2/testsimple-0.0.1-cp312-cp312-linux_x86_64.whl differ diff --git a/tests/integration/test_manylinux.py b/tests/integration/test_manylinux.py index 76983813..e3097db4 100644 --- a/tests/integration/test_manylinux.py +++ b/tests/integration/test_manylinux.py @@ -786,6 +786,45 @@ def test_isa_variants(self, anylinux: AnyLinuxContainer, isa_ext: str) -> None: # with ISA check, we shall not report a manylinux/musllinux policy assert_show_output(anylinux, repaired_wheel, f"linux_{PLATFORM}", True) + @pytest.mark.parametrize( + "arch", + [ + Architecture.aarch64, + Architecture.armv7l, + Architecture.i686, + Architecture.ppc64le, + Architecture.riscv64, + Architecture.s390x, + Architecture.x86_64, + ], + ) + @pytest.mark.parametrize("libc", [Libc.GLIBC, Libc.MUSL]) + def test_cross_repair( + self, anylinux: AnyLinuxContainer, libc: Libc, arch: Architecture + ) -> None: + if libc == Libc.MUSL: + source = "musllinux_1_2" + platform_tag = f"musllinux_1_2_{arch.value}" + python_abi = "cp312-cp312" + else: + assert libc == Libc.GLIBC + source = "glibc" + platform_tag = f"manylinux_2_17_{arch.value}.manylinux2014_{arch.value}" + if arch in {Architecture.x86_64, Architecture.i686}: + platform_tag = f"manylinux_2_5_{arch.value}.manylinux1_{arch.value}" + elif arch == Architecture.riscv64: + platform_tag = f"manylinux_2_31_{arch.value}" + python_abi = "cp313-cp313" + test_path = f"/auditwheel_src/tests/integration/arch-wheels/{source}" + orig_wheel = f"testsimple-0.0.1-{python_abi}-linux_{arch.value}.whl" + anylinux.exec(["cp", "-f", f"{test_path}/{orig_wheel}", f"/io/{orig_wheel}"]) + anylinux.repair(orig_wheel, plat="auto", only_plat=False) + anylinux.check_wheel( + "testsimple", + python_abi=python_abi, + platform_tag=platform_tag, + ) + class TestManylinux(Anylinux): @pytest.fixture(scope="session") diff --git a/tests/integration/test_nonplatform_wheel.py b/tests/integration/test_nonplatform_wheel.py index ef5ec536..8fb5830e 100644 --- a/tests/integration/test_nonplatform_wheel.py +++ b/tests/integration/test_nonplatform_wheel.py @@ -27,9 +27,10 @@ def test_non_platform_wheel_pure(mode): @pytest.mark.parametrize("mode", ["repair", "show"]) @pytest.mark.parametrize("arch", ["armv5l", "mips64"]) def test_non_platform_wheel_unknown_arch(mode, arch, tmp_path): - wheel = HERE / "arch-wheels" / f"testsimple-0.0.1-cp313-cp313-linux_{arch}.whl" - wheel_x86_64 = tmp_path / f"{wheel.stem}_x86_64.whl" - wheel_x86_64.symlink_to(wheel) + wheel_name = f"testsimple-0.0.1-cp313-cp313-linux_{arch}.whl" + wheel_path = HERE / "arch-wheels" / "glibc" / wheel_name + wheel_x86_64 = tmp_path / f"{wheel_path.stem}_x86_64.whl" + wheel_x86_64.symlink_to(wheel_path) proc = subprocess.run( ["auditwheel", mode, str(wheel_x86_64)], stderr=subprocess.PIPE, @@ -50,9 +51,10 @@ def test_non_platform_wheel_bad_arch(mode, arch, tmp_path): host_arch = Architecture.detect().value if host_arch == arch: pytest.skip("host architecture") - wheel = HERE / "arch-wheels" / f"testsimple-0.0.1-cp313-cp313-linux_{arch}.whl" - wheel_host = tmp_path / f"{wheel.stem}_{host_arch}.whl" - wheel_host.symlink_to(wheel) + wheel_name = f"testsimple-0.0.1-cp313-cp313-linux_{arch}.whl" + wheel_path = HERE / "arch-wheels" / "glibc" / wheel_name + wheel_host = tmp_path / f"{wheel_path.stem}_{host_arch}.whl" + wheel_host.symlink_to(wheel_path) proc = subprocess.run( ["auditwheel", mode, str(wheel_host)], stderr=subprocess.PIPE, diff --git a/tests/unit/test_policy.py b/tests/unit/test_policy.py index 015eba41..e996a2d3 100644 --- a/tests/unit/test_policy.py +++ b/tests/unit/test_policy.py @@ -7,7 +7,6 @@ import pytest from auditwheel.architecture import Architecture -from auditwheel.error import InvalidLibc from auditwheel.lddtree import DynamicExecutable, DynamicLibrary, Platform from auditwheel.libc import Libc from auditwheel.policy import ( @@ -231,13 +230,7 @@ def test_filter_libs(self): raises(ValueError, "Invalid 'musl_policy'"), ), (Libc.MUSL, "musllinux_5_1", Architecture.x86_64, raises(AssertionError)), - # platform dependant - ( - Libc.MUSL, - None, - Architecture.x86_64, - does_not_raise() if Libc.detect() == Libc.MUSL else raises(InvalidLibc), - ), + (Libc.MUSL, None, Architecture.x86_64, does_not_raise()), ], ids=ids, ) @@ -248,6 +241,8 @@ def test_wheel_policies_args(libc, musl_policy, arch, exception): assert policies.architecture == arch if musl_policy is not None: assert policies._musl_policy == musl_policy + elif libc == Libc.MUSL: + assert policies._musl_policy == "musllinux_1_2" def test_policy_checks_glibc():