|
| 1 | +From 0934b8fc91e3f08369d98fb9dcc24a1a5521a132 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Dimitri John Ledkov < [email protected]> |
| 3 | +Date: Wed, 4 Jun 2025 22:30:07 +0100 |
| 4 | +Subject: [PATCH 1/4] test_analyze_wheel_abi: refactor test with explicit env |
| 5 | + |
| 6 | +Be explicit in the test-case matrix when to set env variable. This |
| 7 | +enables to check if environment variable is actually correctly reset. |
| 8 | + |
| 9 | +This commit passes unit tests. |
| 10 | +--- |
| 11 | + tests/integration/test_bundled_wheels.py | 25 ++++++++++++++---------- |
| 12 | + 1 file changed, 15 insertions(+), 10 deletions(-) |
| 13 | + |
| 14 | +diff --git a/tests/integration/test_bundled_wheels.py b/tests/integration/test_bundled_wheels.py |
| 15 | +index 046b8fc0..f7bc6296 100644 |
| 16 | +--- a/tests/integration/test_bundled_wheels.py |
| 17 | ++++ b/tests/integration/test_bundled_wheels.py |
| 18 | +@@ -1,13 +1,11 @@ |
| 19 | + from __future__ import annotations |
| 20 | + |
| 21 | + import importlib |
| 22 | +-import os |
| 23 | + import platform |
| 24 | + import sys |
| 25 | + import zipfile |
| 26 | + from argparse import Namespace |
| 27 | + from datetime import datetime, timezone |
| 28 | +-from os.path import isabs |
| 29 | + from pathlib import Path |
| 30 | + from unittest.mock import Mock |
| 31 | + |
| 32 | +@@ -23,69 +21,76 @@ |
| 33 | + |
| 34 | + |
| 35 | + @pytest.mark.parametrize( |
| 36 | +- ("file", "external_libs", "exclude"), |
| 37 | ++ ("file", "external_libs", "exclude", "env"), |
| 38 | + [ |
| 39 | + ( |
| 40 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 41 | + {"libffi.so.5", "libpython2.7.so.1.0"}, |
| 42 | + frozenset(), |
| 43 | ++ None, |
| 44 | + ), |
| 45 | + ( |
| 46 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 47 | + set(), |
| 48 | + frozenset(["libffi.so.5", "libpython2.7.so.1.0"]), |
| 49 | ++ None, |
| 50 | + ), |
| 51 | + ( |
| 52 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 53 | + {"libffi.so.5", "libpython2.7.so.1.0"}, |
| 54 | + frozenset(["libffi.so.noexist", "libnoexist.so.*"]), |
| 55 | ++ None, |
| 56 | + ), |
| 57 | + ( |
| 58 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 59 | + {"libpython2.7.so.1.0"}, |
| 60 | + frozenset(["libffi.so.[4,5]"]), |
| 61 | ++ None, |
| 62 | + ), |
| 63 | + ( |
| 64 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 65 | + {"libffi.so.5", "libpython2.7.so.1.0"}, |
| 66 | + frozenset(["libffi.so.[6,7]"]), |
| 67 | ++ None, |
| 68 | + ), |
| 69 | + ( |
| 70 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 71 | + {"libpython2.7.so.1.0"}, |
| 72 | + frozenset([f"{HERE}/*"]), |
| 73 | ++ "LD_LIBRARY_PATH", |
| 74 | + ), |
| 75 | + ( |
| 76 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 77 | + {"libpython2.7.so.1.0"}, |
| 78 | + frozenset(["libffi.so.*"]), |
| 79 | ++ None, |
| 80 | + ), |
| 81 | +- ("cffi-1.5.0-cp27-none-linux_x86_64.whl", set(), frozenset(["*"])), |
| 82 | ++ ("cffi-1.5.0-cp27-none-linux_x86_64.whl", set(), frozenset(["*"]), None), |
| 83 | + ( |
| 84 | + "python_snappy-0.5.2-pp260-pypy_41-linux_x86_64.whl", |
| 85 | + {"libsnappy.so.1"}, |
| 86 | + frozenset(), |
| 87 | ++ None, |
| 88 | + ), |
| 89 | + ], |
| 90 | + ) |
| 91 | +-def test_analyze_wheel_abi(file, external_libs, exclude): |
| 92 | ++def test_analyze_wheel_abi(file, external_libs, exclude, env): |
| 93 | + # If exclude libs contain path, LD_LIBRARY_PATH need to be modified to find the libs |
| 94 | + # `lddtree.load_ld_paths` needs to be reloaded for it's `lru_cache`-ed. |
| 95 | +- modify_ld_library_path = any(isabs(e) for e in exclude) |
| 96 | + |
| 97 | + with pytest.MonkeyPatch.context() as cp: |
| 98 | +- if modify_ld_library_path: |
| 99 | +- cp.setenv("LD_LIBRARY_PATH", f"{HERE}") |
| 100 | ++ if env: |
| 101 | ++ cp.setenv(env, f"{HERE}") |
| 102 | + importlib.reload(lddtree) |
| 103 | + |
| 104 | + winfo = analyze_wheel_abi( |
| 105 | + Libc.GLIBC, Architecture.x86_64, HERE / file, exclude, False, True |
| 106 | + ) |
| 107 | + assert set(winfo.external_refs["manylinux_2_5_x86_64"].libs) == external_libs, ( |
| 108 | +- f"{HERE}, {exclude}, {os.environ}" |
| 109 | ++ f"{HERE}, {exclude}, {env}" |
| 110 | + ) |
| 111 | + |
| 112 | +- if modify_ld_library_path: |
| 113 | ++ if env: |
| 114 | + importlib.reload(lddtree) |
| 115 | + |
| 116 | + |
| 117 | + |
| 118 | +From 9f06c60d451a1b92bda33eaca25f882634b9d5e7 Mon Sep 17 00:00:00 2001 |
| 119 | +From: Dimitri John Ledkov < [email protected]> |
| 120 | +Date: Wed, 4 Jun 2025 22:39:22 +0100 |
| 121 | +Subject: [PATCH 2/4] test_analyze_wheel_abi: add failing test case |
| 122 | + |
| 123 | +Add a failing test case confiring that environment is not being |
| 124 | +correctly reset. |
| 125 | +--- |
| 126 | + tests/integration/test_bundled_wheels.py | 6 ++++++ |
| 127 | + 1 file changed, 6 insertions(+) |
| 128 | + |
| 129 | +diff --git a/tests/integration/test_bundled_wheels.py b/tests/integration/test_bundled_wheels.py |
| 130 | +index f7bc6296..0c1d2227 100644 |
| 131 | +--- a/tests/integration/test_bundled_wheels.py |
| 132 | ++++ b/tests/integration/test_bundled_wheels.py |
| 133 | +@@ -59,6 +59,12 @@ |
| 134 | + frozenset([f"{HERE}/*"]), |
| 135 | + "LD_LIBRARY_PATH", |
| 136 | + ), |
| 137 | ++ ( |
| 138 | ++ "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 139 | ++ {"libffi.so.5", "libpython2.7.so.1.0"}, |
| 140 | ++ frozenset([f"{HERE}/*"]), |
| 141 | ++ None, |
| 142 | ++ ), |
| 143 | + ( |
| 144 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 145 | + {"libpython2.7.so.1.0"}, |
| 146 | + |
| 147 | +From e2063e3893b01268c5821b47a663334e0ecc8c4e Mon Sep 17 00:00:00 2001 |
| 148 | +From: Dimitri John Ledkov < [email protected]> |
| 149 | +Date: Wed, 4 Jun 2025 22:46:52 +0100 |
| 150 | +Subject: [PATCH 3/4] test_analyze_wheel_abi: reload and reimport wheel_abi |
| 151 | + |
| 152 | +It seems that in addition to reloading lddtree, reload of |
| 153 | +auditwheel.wheel_abi is needed to full flush and reset |
| 154 | +analyze_wheel_abi() lru_caches. |
| 155 | +--- |
| 156 | + tests/integration/test_bundled_wheels.py | 8 +++++--- |
| 157 | + 1 file changed, 5 insertions(+), 3 deletions(-) |
| 158 | + |
| 159 | +diff --git a/tests/integration/test_bundled_wheels.py b/tests/integration/test_bundled_wheels.py |
| 160 | +index 0c1d2227..7fa01700 100644 |
| 161 | +--- a/tests/integration/test_bundled_wheels.py |
| 162 | ++++ b/tests/integration/test_bundled_wheels.py |
| 163 | +@@ -11,6 +11,7 @@ |
| 164 | + |
| 165 | + import pytest |
| 166 | + |
| 167 | ++import auditwheel.wheel_abi |
| 168 | + from auditwheel import lddtree, main_repair |
| 169 | + from auditwheel.architecture import Architecture |
| 170 | + from auditwheel.libc import Libc |
| 171 | +@@ -87,7 +88,8 @@ def test_analyze_wheel_abi(file, external_libs, exclude, env): |
| 172 | + with pytest.MonkeyPatch.context() as cp: |
| 173 | + if env: |
| 174 | + cp.setenv(env, f"{HERE}") |
| 175 | +- importlib.reload(lddtree) |
| 176 | ++ importlib.reload(lddtree) |
| 177 | ++ importlib.reload(auditwheel.wheel_abi) |
| 178 | + |
| 179 | + winfo = analyze_wheel_abi( |
| 180 | + Libc.GLIBC, Architecture.x86_64, HERE / file, exclude, False, True |
| 181 | +@@ -96,8 +98,8 @@ def test_analyze_wheel_abi(file, external_libs, exclude, env): |
| 182 | + f"{HERE}, {exclude}, {env}" |
| 183 | + ) |
| 184 | + |
| 185 | +- if env: |
| 186 | +- importlib.reload(lddtree) |
| 187 | ++ importlib.reload(lddtree) |
| 188 | ++ importlib.reload(auditwheel.wheel_abi) |
| 189 | + |
| 190 | + |
| 191 | + def test_analyze_wheel_abi_pyfpe(): |
| 192 | + |
| 193 | +From 496e92ef4e00cbb34e1b18394f0d993eb233b764 Mon Sep 17 00:00:00 2001 |
| 194 | +From: Dimitri John Ledkov < [email protected]> |
| 195 | +Date: Wed, 16 Apr 2025 12:36:33 +0100 |
| 196 | +Subject: [PATCH 4/4] lddtree: support alternative LD_LIBRARY_PATH called |
| 197 | + AUDITWHEEL_LD_LIBRARY_PATH |
| 198 | + |
| 199 | +Sometimes wheels are different only just by shared libraries that are |
| 200 | +vendored in. Sometimes the wheel being repaired and the libraries that |
| 201 | +need to be vendored in are accessible on the host that was not used |
| 202 | +for building the wheel. In such cases, it could be the case that |
| 203 | +shared libraries used by python that is executing the auditwheel |
| 204 | +script, are incompatible (too old or too new) than those that need to |
| 205 | +be vendored. |
| 206 | + |
| 207 | +In such cases, LD_LIBRARY_PATH is not convenient to use, as the python |
| 208 | +interpreter for the auditwheel script is crashing. |
| 209 | + |
| 210 | +Add an AUDITWHEEL_LD_LIBRARY_PATH whichis used by lddtree, but |
| 211 | +otherwise does not affect the python interpreter executing auditwheel |
| 212 | +script. |
| 213 | + |
| 214 | +This helps vendoring in older libraries from an alternative path, into |
| 215 | +a wheel built against an older python, whilst otherwise running |
| 216 | +auditwheel repair on a modern system with a much newer python. This is |
| 217 | +particularly useful when stripping a wheel of vendored libraries, and |
| 218 | +repair it again to update the shared library dependencies coming from |
| 219 | +an unpacked chroot. |
| 220 | + |
| 221 | +Separately it also helps creating alternative wheels with shared |
| 222 | +libraries rebuilt with higher march settings. Given that python |
| 223 | +upstream doesn't support loading optimised libraries as has been |
| 224 | +implemented and supported in Intel ClearLinux Python which allows one |
| 225 | +to have alternative march setting shared library deps. |
| 226 | +--- |
| 227 | + src/auditwheel/lddtree.py | 13 +++++++++++-- |
| 228 | + tests/integration/test_bundled_wheels.py | 6 ++++++ |
| 229 | + 2 files changed, 17 insertions(+), 2 deletions(-) |
| 230 | + |
| 231 | +diff --git a/src/auditwheel/lddtree.py b/src/auditwheel/lddtree.py |
| 232 | +index 44785791..661446a4 100644 |
| 233 | +--- a/src/auditwheel/lddtree.py |
| 234 | ++++ b/src/auditwheel/lddtree.py |
| 235 | +@@ -321,8 +321,17 @@ def load_ld_paths( |
| 236 | + """ |
| 237 | + ldpaths: dict[str, list[str]] = {"conf": [], "env": [], "interp": []} |
| 238 | + |
| 239 | +- # Load up $LD_LIBRARY_PATH. |
| 240 | +- env_ldpath = os.environ.get("LD_LIBRARY_PATH") |
| 241 | ++ # Load up $AUDITWHEEL_LD_LIBRARY_PATH and $LD_LIBRARY_PATH |
| 242 | ++ env_ldpath = ":".join( |
| 243 | ++ filter( |
| 244 | ++ None, |
| 245 | ++ ( |
| 246 | ++ os.environ.get("AUDITWHEEL_LD_LIBRARY_PATH"), |
| 247 | ++ os.environ.get("LD_LIBRARY_PATH"), |
| 248 | ++ ), |
| 249 | ++ ) |
| 250 | ++ ) |
| 251 | ++ |
| 252 | + if env_ldpath is not None: |
| 253 | + if root != "/": |
| 254 | + log.warning("ignoring LD_LIBRARY_PATH due to ROOT usage") |
| 255 | +diff --git a/tests/integration/test_bundled_wheels.py b/tests/integration/test_bundled_wheels.py |
| 256 | +index 7fa01700..97f12487 100644 |
| 257 | +--- a/tests/integration/test_bundled_wheels.py |
| 258 | ++++ b/tests/integration/test_bundled_wheels.py |
| 259 | +@@ -60,6 +60,12 @@ |
| 260 | + frozenset([f"{HERE}/*"]), |
| 261 | + "LD_LIBRARY_PATH", |
| 262 | + ), |
| 263 | ++ ( |
| 264 | ++ "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 265 | ++ {"libpython2.7.so.1.0"}, |
| 266 | ++ frozenset([f"{HERE}/*"]), |
| 267 | ++ "AUDITWHEEL_LD_LIBRARY_PATH", |
| 268 | ++ ), |
| 269 | + ( |
| 270 | + "cffi-1.5.0-cp27-none-linux_x86_64.whl", |
| 271 | + {"libffi.so.5", "libpython2.7.so.1.0"}, |
0 commit comments