From 75c84f51a5394c6026f2084a56a10f545013886e Mon Sep 17 00:00:00 2001 From: Yichen Yan Date: Thu, 15 Jan 2026 12:19:53 +0800 Subject: [PATCH 1/5] Set rpath when a lib has invalid ones --- src/auditwheel/elfutils.py | 4 ++-- src/auditwheel/lddtree.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/auditwheel/elfutils.py b/src/auditwheel/elfutils.py index f375a20c..a6be6f8c 100644 --- a/src/auditwheel/elfutils.py +++ b/src/auditwheel/elfutils.py @@ -117,9 +117,9 @@ def elf_read_rpaths(fn: Path) -> dict[str, list[str]]: for t in section.iter_tags(): if t.entry.d_tag == "DT_RPATH": - result["rpaths"] = parse_ld_paths(t.rpath, root="/", path=str(fn)) + result["rpaths"] = parse_ld_paths(t.rpath, root="/", path=str(fn), keep_non_exist=True) elif t.entry.d_tag == "DT_RUNPATH": - result["runpaths"] = parse_ld_paths(t.runpath, root="/", path=str(fn)) + result["runpaths"] = parse_ld_paths(t.runpath, root="/", path=str(fn), keep_non_exist=True) return result diff --git a/src/auditwheel/lddtree.py b/src/auditwheel/lddtree.py index 76fe6836..9c925d66 100644 --- a/src/auditwheel/lddtree.py +++ b/src/auditwheel/lddtree.py @@ -213,7 +213,7 @@ def dedupe(items: list[str]) -> list[str]: return [seen.setdefault(x, x) for x in items if x not in seen] -def parse_ld_paths(str_ldpaths: str, path: str, root: str = "") -> list[str]: +def parse_ld_paths(str_ldpaths: str, path: str, root: str = "", keep_non_exist=False) -> list[str]: """Parse the colon-delimited list of paths and apply ldso rules to each Note the special handling as dictated by the ldso: @@ -245,7 +245,7 @@ def parse_ld_paths(str_ldpaths: str, path: str, root: str = "") -> list[str]: else: ldpath_ = root + ldpath ldpaths.append(normpath(ldpath_)) - return [p for p in dedupe(ldpaths) if os.path.isdir(p)] + return [p for p in dedupe(ldpaths) if keep_non_exist or os.path.isdir(p)] @functools.lru_cache From 0cbf7e243a21448f69c6bbfafd53a905842652ed Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 04:20:50 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/auditwheel/elfutils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/auditwheel/elfutils.py b/src/auditwheel/elfutils.py index a6be6f8c..2f585a9f 100644 --- a/src/auditwheel/elfutils.py +++ b/src/auditwheel/elfutils.py @@ -117,9 +117,13 @@ def elf_read_rpaths(fn: Path) -> dict[str, list[str]]: for t in section.iter_tags(): if t.entry.d_tag == "DT_RPATH": - result["rpaths"] = parse_ld_paths(t.rpath, root="/", path=str(fn), keep_non_exist=True) + result["rpaths"] = parse_ld_paths( + t.rpath, root="/", path=str(fn), keep_non_exist=True + ) elif t.entry.d_tag == "DT_RUNPATH": - result["runpaths"] = parse_ld_paths(t.runpath, root="/", path=str(fn), keep_non_exist=True) + result["runpaths"] = parse_ld_paths( + t.runpath, root="/", path=str(fn), keep_non_exist=True + ) return result From f16df89bd1df559f479fa81abf437b98260dfcab Mon Sep 17 00:00:00 2001 From: Yichen Yan Date: Thu, 15 Jan 2026 14:38:40 +0800 Subject: [PATCH 3/5] fmt --- src/auditwheel/elfutils.py | 10 ++++++++-- src/auditwheel/lddtree.py | 9 ++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/auditwheel/elfutils.py b/src/auditwheel/elfutils.py index 2f585a9f..677fe169 100644 --- a/src/auditwheel/elfutils.py +++ b/src/auditwheel/elfutils.py @@ -118,11 +118,17 @@ def elf_read_rpaths(fn: Path) -> dict[str, list[str]]: for t in section.iter_tags(): if t.entry.d_tag == "DT_RPATH": result["rpaths"] = parse_ld_paths( - t.rpath, root="/", path=str(fn), keep_non_exist=True + t.rpath, + root="/", + path=str(fn), + keep_non_exist=True, ) elif t.entry.d_tag == "DT_RUNPATH": result["runpaths"] = parse_ld_paths( - t.runpath, root="/", path=str(fn), keep_non_exist=True + t.runpath, + root="/", + path=str(fn), + keep_non_exist=True, ) return result diff --git a/src/auditwheel/lddtree.py b/src/auditwheel/lddtree.py index 9c925d66..275cef9d 100644 --- a/src/auditwheel/lddtree.py +++ b/src/auditwheel/lddtree.py @@ -213,7 +213,12 @@ def dedupe(items: list[str]) -> list[str]: return [seen.setdefault(x, x) for x in items if x not in seen] -def parse_ld_paths(str_ldpaths: str, path: str, root: str = "", keep_non_exist=False) -> list[str]: +def parse_ld_paths( + str_ldpaths: str, + path: str, + root: str = "", + keep_non_exist: bool = False, # noqa: FBT001, FBT002 +) -> list[str]: """Parse the colon-delimited list of paths and apply ldso rules to each Note the special handling as dictated by the ldso: @@ -229,6 +234,8 @@ def parse_ld_paths(str_ldpaths: str, path: str, root: str = "", keep_non_exist=F The path to prepend to all paths found path The object actively being parsed (used for $ORIGIN) + keep_non_exist + If to eliminate non-exist rpath from result Returns ------- From ef6e14652598b69e97b71e05f86e5bb38909fb43 Mon Sep 17 00:00:00 2001 From: Yichen Yan Date: Thu, 15 Jan 2026 15:03:41 +0800 Subject: [PATCH 4/5] upd doc --- src/auditwheel/lddtree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auditwheel/lddtree.py b/src/auditwheel/lddtree.py index 275cef9d..421bd35b 100644 --- a/src/auditwheel/lddtree.py +++ b/src/auditwheel/lddtree.py @@ -235,7 +235,7 @@ def parse_ld_paths( path The object actively being parsed (used for $ORIGIN) keep_non_exist - If to eliminate non-exist rpath from result + Do not eliminate non-exist rpath from result Returns ------- From ea446417a9da5b53cc14c909af4ebe0b22e79a87 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 10:51:40 +0800 Subject: [PATCH 5/5] Add tests Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: oraluben <5031346+oraluben@users.noreply.github.com> --- tests/unit/test_repair.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_repair.py b/tests/unit/test_repair.py index 2a0df9d4..bfef1112 100644 --- a/tests/unit/test_repair.py +++ b/tests/unit/test_repair.py @@ -4,7 +4,7 @@ from unittest.mock import call, patch from auditwheel.patcher import Patchelf -from auditwheel.repair import append_rpath_within_wheel +from auditwheel.repair import append_rpath_within_wheel, copylib @patch("auditwheel.patcher._verify_patchelf") @@ -115,3 +115,27 @@ def test_append_rpath_ignore_relative(self, check_call, check_output, _): # noq assert check_output.call_args_list == check_output_expected_args assert check_call.call_args_list == check_call_expected_args + + +@patch("auditwheel.patcher._verify_patchelf") +@patch("auditwheel.patcher.check_output") +@patch("auditwheel.patcher.check_call") +class TestCopylib: + @patch("auditwheel.repair.elf_read_rpaths") + def test_nonexistent_rpath(self, elf_read_rpaths, check_call, _0, _1, tmp_path): # noqa: PT019 + # When a library has a non-existent runpath, copylib should still + # call set_rpath to replace it with $ORIGIN + patcher = Patchelf() + src_path = tmp_path / "b.so" + src_path.write_bytes(b"\x00") + dest_dir = tmp_path / "dest" + dest_dir.mkdir() + elf_read_rpaths.return_value = {"rpaths": [], "runpaths": ["/nonexistent/path"]} + + copylib(src_path, dest_dir, patcher) + + elf_read_rpaths.assert_called_once_with(src_path) + dest_path = next(dest_dir.iterdir()) + check_call.assert_any_call( + ["patchelf", "--force-rpath", "--set-rpath", "$ORIGIN", dest_path], + )