Skip to content
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
20 changes: 16 additions & 4 deletions scripts/create-arch-wheels.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
11 changes: 11 additions & 0 deletions src/auditwheel/lddtree.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 9 additions & 4 deletions src/auditwheel/libc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
13 changes: 11 additions & 2 deletions src/auditwheel/policy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]:
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
39 changes: 39 additions & 0 deletions tests/integration/test_manylinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
14 changes: 8 additions & 6 deletions tests/integration/test_nonplatform_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
11 changes: 3 additions & 8 deletions tests/unit/test_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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,
)
Expand All @@ -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():
Expand Down