diff --git a/src/auditwheel/lddtree.py b/src/auditwheel/lddtree.py index 44785791..87a97148 100644 --- a/src/auditwheel/lddtree.py +++ b/src/auditwheel/lddtree.py @@ -559,7 +559,7 @@ def ldd( ) _excluded_libs: set[str] = set() for soname in needed: - if soname in _all_libs: + if soname in _all_libs and _all_libs[soname].realpath is not None: continue if soname in _excluded_libs: continue @@ -578,12 +578,15 @@ def ldd( continue realpath, fullpath = find_lib(platform, soname, all_ldpaths, root) - if realpath is not None and any(fnmatch(str(realpath), e) for e in exclude): + if soname not in _all_libs: + _all_libs[soname] = DynamicLibrary(soname, fullpath, realpath) + if realpath is None: + log.debug("Could not locate %s, skipping.", soname) + continue + if any(fnmatch(str(realpath), e) for e in exclude): log.info("Excluding %s", realpath) _excluded_libs.add(soname) - continue - _all_libs[soname] = DynamicLibrary(soname, fullpath, realpath) - if realpath is None or fullpath is None: + _all_libs.pop(soname) continue dependency = ldd(realpath, root, prefix, ldpaths, fullpath, exclude, _all_libs) _all_libs[soname] = DynamicLibrary( diff --git a/tests/integration/test_manylinux.py b/tests/integration/test_manylinux.py index 527c89a7..fe8ceef7 100644 --- a/tests/integration/test_manylinux.py +++ b/tests/integration/test_manylinux.py @@ -161,13 +161,17 @@ def repair( strip: bool = False, library_paths: list[str] | None = None, excludes: list[str] | None = None, + verbose: int = 0, ) -> str: plat = plat or self._policy args = [] if library_paths: ld_library_path = ":".join([*library_paths, "$LD_LIBRARY_PATH"]) args.append(f"LD_LIBRARY_PATH={ld_library_path}") - args.extend(["auditwheel", "repair", "-w", "/io", "--plat", plat]) + args.append("auditwheel") + if verbose: + args.append(f"-{'v' * verbose}") + args.extend(["repair", "-w", "/io", "--plat", plat]) if only_plat: args.append("--only-plat") if not isa_ext_check: @@ -597,6 +601,7 @@ def test_rpath( # - check if RUNPATH is replaced by RPATH # - check if RPATH location is correct, i.e. it is inside .libs directory # where all gathered libraries are put + # - check if the order of dependencies affects if library is found policy = anylinux.policy @@ -610,19 +615,27 @@ def test_rpath( assert f"DT_{dtag.upper()}" in tags # Repair the wheel using the appropriate manylinux container - anylinux.repair(orig_wheel, library_paths=[f"{test_path}/a"]) + repair_output = anylinux.repair( + orig_wheel, library_paths=[f"{test_path}/a"], verbose=3 + ) + assert "lddtree:Could not locate libd.so, skipping" in repair_output, ( + repair_output + ) repaired_wheel = anylinux.check_wheel("testrpath") assert_show_output(anylinux, repaired_wheel, policy, False) python.install_wheel(repaired_wheel) output = python.run("from testrpath import testrpath; print(testrpath.func())") - assert output.strip() == "11" + assert output.strip() == "33" with zipfile.ZipFile(anylinux.io_folder / repaired_wheel) as w: libraries = tuple( name for name in w.namelist() if "testrpath.libs/lib" in name ) - assert len(libraries) == 2 - assert any(".libs/liba" in name for name in libraries) + assert len(libraries) == 3 + assert all( + (any(f".libs/lib{lib}" in name for name in libraries)) + for lib in ["a", "b", "d"] + ) for name in libraries: with w.open(name) as f: elf = ELFFile(io.BytesIO(f.read())) diff --git a/tests/integration/testrpath/a/a.c b/tests/integration/testrpath/a/a.c index 0a4ec831..2dd8e414 100644 --- a/tests/integration/testrpath/a/a.c +++ b/tests/integration/testrpath/a/a.c @@ -1,6 +1,6 @@ #include "b.h" - +#include "d.h" int fa(void) { - return 1 + fb(); + return 1 + fb() + fd(); } diff --git a/tests/integration/testrpath/b/b.c b/tests/integration/testrpath/b/b.c index d1b58fac..15202ee3 100644 --- a/tests/integration/testrpath/b/b.c +++ b/tests/integration/testrpath/b/b.c @@ -1,3 +1,5 @@ +#include "d.h" + int fb(void) { - return 10; + return 10 + fd(); } diff --git a/tests/integration/testrpath/d/d.c b/tests/integration/testrpath/d/d.c new file mode 100644 index 00000000..2647917e --- /dev/null +++ b/tests/integration/testrpath/d/d.c @@ -0,0 +1,3 @@ +int fd(void) { + return 11; +} diff --git a/tests/integration/testrpath/d/d.h b/tests/integration/testrpath/d/d.h new file mode 100644 index 00000000..15aace72 --- /dev/null +++ b/tests/integration/testrpath/d/d.h @@ -0,0 +1 @@ +int fd(void); diff --git a/tests/integration/testrpath/setup.py b/tests/integration/testrpath/setup.py index 75b92674..9ebe7ec9 100644 --- a/tests/integration/testrpath/setup.py +++ b/tests/integration/testrpath/setup.py @@ -9,12 +9,16 @@ class BuildExt(build_ext): def run(self) -> None: - cmd = "gcc -fPIC -shared -o b/libb.so b/b.c" + cmd = "gcc -fPIC -shared -o d/libd.so d/d.c" + subprocess.check_call(cmd.split()) + cmd = "gcc -fPIC -shared -o b/libb.so b/b.c -Id" + subprocess.check_call(cmd.split()) + cmd = "patchelf --add-needed libd.so b/libb.so" subprocess.check_call(cmd.split()) cmd = ( - "gcc -fPIC -shared -o a/liba.so " - "-Wl,{dtags_flag} -Wl,-rpath=$ORIGIN/../b " - "-Ib a/a.c -Lb -lb" + "gcc -fPIC -shared -o a/liba.so a/a.c " + "-Wl,{dtags_flag} -Wl,-rpath=$ORIGIN/../b -Wl,-rpath=$ORIGIN/../d " + "-Ib -Lb -lb -Id -Ld -ld" ).format( dtags_flag=( "--enable-new-dtags"