1919from elftools .elf .elffile import ELFFile
2020
2121from auditwheel .architecture import Architecture
22+ from auditwheel .libc import Libc
2223from auditwheel .policy import WheelPolicies
2324
2425logger = logging .getLogger (__name__ )
2526
26- ENCODING = "utf-8"
27- PLATFORM = Architecture . get_native_architecture (). value
27+ NATIVE_PLATFORM = Architecture . get_native_architecture (). value
28+ PLATFORM = os . environ . get ( "AUDITWHEEL_ARCH" , NATIVE_PLATFORM )
2829MANYLINUX1_IMAGE_ID = f"quay.io/pypa/manylinux1_{ PLATFORM } :latest"
2930MANYLINUX2010_IMAGE_ID = f"quay.io/pypa/manylinux2010_{ PLATFORM } :latest"
3031MANYLINUX2014_IMAGE_ID = f"quay.io/pypa/manylinux2014_{ PLATFORM } :latest"
3132MANYLINUX_2_28_IMAGE_ID = f"quay.io/pypa/manylinux_2_28_{ PLATFORM } :latest"
33+ MANYLINUX_2_31_IMAGE_ID = f"quay.io/pypa/manylinux_2_31_{ PLATFORM } :latest"
3234MANYLINUX_2_34_IMAGE_ID = f"quay.io/pypa/manylinux_2_34_{ PLATFORM } :latest"
3335if PLATFORM in {"i686" , "x86_64" }:
3436 MANYLINUX_IMAGES = {
3537 "manylinux_2_5" : MANYLINUX1_IMAGE_ID ,
3638 "manylinux_2_12" : MANYLINUX2010_IMAGE_ID ,
3739 "manylinux_2_17" : MANYLINUX2014_IMAGE_ID ,
38- "manylinux_2_28" : MANYLINUX_2_28_IMAGE_ID ,
39- "manylinux_2_34" : MANYLINUX_2_34_IMAGE_ID ,
4040 }
41+ if PLATFORM == "x86_64" :
42+ MANYLINUX_IMAGES .update (
43+ {
44+ "manylinux_2_28" : MANYLINUX_2_28_IMAGE_ID ,
45+ "manylinux_2_34" : MANYLINUX_2_34_IMAGE_ID ,
46+ }
47+ )
4148 POLICY_ALIASES = {
4249 "manylinux_2_5" : ["manylinux1" ],
4350 "manylinux_2_12" : ["manylinux2010" ],
4451 "manylinux_2_17" : ["manylinux2014" ],
4552 }
53+ elif PLATFORM == "armv7l" :
54+ MANYLINUX_IMAGES = {"manylinux_2_31" : MANYLINUX_2_31_IMAGE_ID }
55+ POLICY_ALIASES = {}
4656else :
4757 MANYLINUX_IMAGES = {
4858 "manylinux_2_17" : MANYLINUX2014_IMAGE_ID ,
4959 "manylinux_2_28" : MANYLINUX_2_28_IMAGE_ID ,
50- "manylinux_2_34" : MANYLINUX_2_34_IMAGE_ID ,
5160 }
61+ if os .environ .get ("AUDITWHEEL_QEMU" , "" ) != "true" :
62+ MANYLINUX_IMAGES .update ({"manylinux_2_34" : MANYLINUX_2_34_IMAGE_ID })
5263 POLICY_ALIASES = {
5364 "manylinux_2_17" : ["manylinux2014" ],
5465 }
6778 "manylinux_2_12" : "devtoolset-8" ,
6879 "manylinux_2_17" : "devtoolset-10" ,
6980 "manylinux_2_28" : "gcc-toolset-14" ,
81+ "manylinux_2_31" : "devtoolset-not-present" ,
7082 "manylinux_2_34" : "gcc-toolset-14" ,
7183 "musllinux_1_2" : "devtoolset-not-present" ,
7284}
@@ -265,6 +277,12 @@ def docker_start(
265277 client = docker .from_env ()
266278
267279 dvolumes = {host : {"bind" : ctr , "mode" : "rw" } for (ctr , host ) in volumes .items ()}
280+ goarch = {
281+ "x86_64" : "amd64" ,
282+ "i686" : "386" ,
283+ "aarch64" : "arm64" ,
284+ "armv7l" : "arm/v7" ,
285+ }.get (PLATFORM , PLATFORM )
268286
269287 logger .info ("Starting container with image %r" , image )
270288 con = client .containers .run (
@@ -273,6 +291,7 @@ def docker_start(
273291 detach = True ,
274292 volumes = dvolumes ,
275293 environment = env_variables ,
294+ platform = f"linux/{ goarch } " ,
276295 )
277296 logger .info ("Started container %s" , con .id [:12 ])
278297 return con
@@ -316,7 +335,7 @@ def docker_exec(
316335) -> str :
317336 logger .info ("docker exec %s: %r" , container .id [:12 ], cmd )
318337 ec , output = container .exec_run (cmd , workdir = cwd , environment = env )
319- output = output .decode (ENCODING )
338+ output = output .decode ("utf-8" )
320339 if ec != expected_retcode :
321340 print (output )
322341 raise CalledProcessError (ec , cmd , output = output )
@@ -386,12 +405,16 @@ def build_numpy(container: AnyLinuxContainer, output_dir: Path) -> str:
386405 # https://github.com/numpy/numpy/issues/27932
387406 fix_hwcap = "echo '#define HWCAP_S390_VX 2048' >> /usr/include/bits/hwcap.h"
388407 container .exec (f'sh -c "{ fix_hwcap } "' )
389- elif container .policy .startswith (( "manylinux_2_28_" , "manylinux_2_34_" )):
390- container . exec ( "dnf install -y openblas-devel " )
391- else :
408+ elif container .policy .startswith (
409+ ( "manylinux_2_5_" , "manylinux_2_12_" , "manylinux_2_17_ " )
410+ ) :
392411 if tuple (int (part ) for part in NUMPY_VERSION .split ("." )[:2 ]) >= (1 , 26 ):
393412 pytest .skip ("numpy>=1.26 requires openblas" )
394413 container .exec ("yum install -y atlas atlas-devel" )
414+ elif container .policy .startswith ("manylinux_2_31_" ):
415+ container .exec ("apt-get install -y libopenblas-dev" )
416+ else :
417+ container .exec ("dnf install -y openblas-devel" )
395418
396419 cached_wheel = container .cache_dir / ORIGINAL_NUMPY_WHEEL
397420 orig_wheel = output_dir / ORIGINAL_NUMPY_WHEEL
@@ -466,7 +489,6 @@ def test_numpy(self, anylinux: AnyLinuxContainer, python: PythonContainer) -> No
466489 if policy .startswith ("musllinux_" ):
467490 python .exec ("apk add musl-dev gfortran" )
468491 else :
469- python .exec ("apt-get update -yqq" )
470492 python .exec ("apt-get install -y gfortran" )
471493 if tuple (int (part ) for part in NUMPY_VERSION .split ("." )[:2 ]) >= (1 , 26 ):
472494 python .pip_install ("meson ninja" )
@@ -498,6 +520,8 @@ def test_with_binary_executable(
498520 policy = anylinux .policy
499521 if policy .startswith ("musllinux_" ):
500522 anylinux .exec ("apk add gsl-dev" )
523+ elif policy .startswith ("manylinux_2_31_" ):
524+ anylinux .exec ("apt-get install -y libgsl-dev" )
501525 else :
502526 anylinux .exec ("yum install -y gsl-devel" )
503527
@@ -768,9 +792,8 @@ class TestManylinux(Anylinux):
768792 @pytest .fixture (scope = "session" )
769793 def docker_python_img (self ):
770794 """The glibc Python base image with up-to-date pip"""
771- with tmp_docker_image (
772- MANYLINUX_PYTHON_IMAGE_ID , ["pip install -U pip" ]
773- ) as img_id :
795+ commnds = ["pip install -U pip" , "apt-get update -yqq" ]
796+ with tmp_docker_image (MANYLINUX_PYTHON_IMAGE_ID , commnds ) as img_id :
774797 yield img_id
775798
776799 @pytest .fixture (scope = "session" , params = MANYLINUX_IMAGES .keys ())
@@ -780,25 +803,23 @@ def any_manylinux_img(self, request):
780803 Plus up-to-date pip, setuptools and pytest-cov
781804 """
782805 policy = request .param
783- support_check_map = {
806+ check_set = {
784807 "manylinux_2_5" : {"38" , "39" },
785808 "manylinux_2_12" : {"38" , "39" , "310" },
786- }
787- check_set = support_check_map .get (policy )
809+ }.get (policy )
788810 if check_set and PYTHON_ABI_MAJ_MIN not in check_set :
789811 pytest .skip (f"{ policy } images do not support cp{ PYTHON_ABI_MAJ_MIN } " )
790812
791813 base = MANYLINUX_IMAGES [policy ]
792814 env = {"PATH" : PATH [policy ]}
793- with tmp_docker_image (
794- base ,
795- [
796- 'git config --global --add safe.directory "/auditwheel_src"' ,
797- "pip install -U pip setuptools pytest-cov" ,
798- "pip install -U -e /auditwheel_src" ,
799- ],
800- env ,
801- ) as img_id :
815+ commands = [
816+ 'git config --global --add safe.directory "/auditwheel_src"' ,
817+ "pip install -U pip setuptools pytest-cov" ,
818+ "pip install -U -e /auditwheel_src" ,
819+ ]
820+ if policy == "manylinux_2_31" :
821+ commands .append ("apt-get update -yqq" )
822+ with tmp_docker_image (base , commands , env ) as img_id :
802823 yield policy , img_id
803824
804825 @pytest .mark .parametrize ("with_dependency" , ["0" , "1" ])
@@ -824,7 +845,7 @@ def test_image_dependencies(
824845 test_path , env = {"WITH_DEPENDENCY" : with_dependency }
825846 )
826847
827- wheel_policy = WheelPolicies ()
848+ wheel_policy = WheelPolicies (libc = Libc . GLIBC , arch = Architecture ( PLATFORM ) )
828849 policy = wheel_policy .get_policy_by_name (policy_name )
829850 older_policies = [
830851 f"{ p } _{ PLATFORM } "
@@ -905,7 +926,9 @@ def test_compat(
905926
906927 def test_zlib_blacklist (self , anylinux : AnyLinuxContainer ) -> None :
907928 policy = anylinux .policy
908- if policy .startswith (("manylinux_2_17_" , "manylinux_2_28_" , "manylinux_2_34_" )):
929+ if policy .startswith (
930+ ("manylinux_2_17_" , "manylinux_2_28_" , "manylinux_2_31_" , "manylinux_2_34_" )
931+ ):
909932 pytest .skip (f"{ policy } image has no blacklist symbols in libz.so.1" )
910933
911934 test_path = "/auditwheel_src/tests/integration/testzlib"
@@ -925,9 +948,8 @@ class TestMusllinux(Anylinux):
925948 @pytest .fixture (scope = "session" )
926949 def docker_python_img (self ):
927950 """The alpine Python base image with up-to-date pip"""
928- with tmp_docker_image (
929- MUSLLINUX_PYTHON_IMAGE_ID , ["pip install -U pip" ]
930- ) as img_id :
951+ commands = ["pip install -U pip" ]
952+ with tmp_docker_image (MUSLLINUX_PYTHON_IMAGE_ID , commands ) as img_id :
931953 yield img_id
932954
933955 @pytest .fixture (scope = "session" , params = MUSLLINUX_IMAGES .keys ())
@@ -939,13 +961,10 @@ def any_manylinux_img(self, request):
939961 policy = request .param
940962 base = MUSLLINUX_IMAGES [policy ]
941963 env = {"PATH" : PATH [policy ]}
942- with tmp_docker_image (
943- base ,
944- [
945- 'git config --global --add safe.directory "/auditwheel_src"' ,
946- "pip install -U pip setuptools pytest-cov" ,
947- "pip install -U -e /auditwheel_src" ,
948- ],
949- env ,
950- ) as img_id :
964+ commands = [
965+ 'git config --global --add safe.directory "/auditwheel_src"' ,
966+ "pip install -U pip setuptools pytest-cov" ,
967+ "pip install -U -e /auditwheel_src" ,
968+ ]
969+ with tmp_docker_image (base , commands , env ) as img_id :
951970 yield policy , img_id
0 commit comments