From eed8f252df735702cd7219fdc8e092eb28c22fc6 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Thu, 21 Mar 2024 15:42:03 -0500 Subject: [PATCH] Fix deleting duplicated rpaths (#208) * Fix deleting duplicated rpaths * review suggestions * change to delete_rpaths * Add to changelog and remove redundant replace_signature * commit replace_signature removal and update changelog --- Changelog.md | 5 +++++ delocate/tools.py | 50 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/Changelog.md b/Changelog.md index 2e27f0dd..9aea39fc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -23,6 +23,11 @@ rules on making a good Changelog. - `delocate-wheel` is now more strict with platform tags and will no longer allow a wheel to be incompatible with its own tags. #198 +### Fixed + +- `--sanitize-rpaths` was failing with duplicate rpaths. + [#208](https://github.com/matthew-brett/delocate/pull/208) + ## [0.10.7] - 2023-12-12 ### Changed diff --git a/delocate/tools.py b/delocate/tools.py index d20a0dd8..bbc4424c 100644 --- a/delocate/tools.py +++ b/delocate/tools.py @@ -18,6 +18,7 @@ Any, Dict, FrozenSet, + Iterable, List, Optional, Sequence, @@ -750,6 +751,8 @@ def get_rpaths(filename: str) -> Tuple[str, ...]: """Return a tuple of rpaths from the library `filename`. If `filename` is not a library then the returned tuple will be empty. + Duplicate rpaths will be returned if there are duplicate rpaths in the + Mach-O binary. Parameters ---------- @@ -818,6 +821,34 @@ def add_rpath(filename: str, newpath: str, ad_hoc_sign: bool = True) -> None: replace_signature(filename, "-") +@ensure_writable +def _delete_rpaths( + filename: str, rpaths: Iterable[str], ad_hoc_sign: bool = True +) -> None: + """Remove rpath `newpath` from library `filename`. + + Parameters + ---------- + filename : str + filename of library + rpaths : Iterable[str] + rpaths to delete + ad_hoc_sign : {True, False}, optional + If True, sign file with ad-hoc signature + """ + for rpath in rpaths: + logger.info("Sanitize: Deleting rpath %r from %r", rpath, filename) + # We can run these as one command to install_name_tool if there are + # no duplicates. When there are duplicates, we need to delete them + # separately. + _run( + ["install_name_tool", "-delete_rpath", rpath, filename], + check=True, + ) + if ad_hoc_sign: + replace_signature(filename, "-") + + _SANITARY_RPATH = re.compile(r"^@loader_path/|^@executable_path/") """Matches rpaths which are considered sanitary.""" @@ -858,16 +889,15 @@ def _remove_absolute_rpaths(filename: str, ad_hoc_sign: bool = True) -> None: ad_hoc_sign : {True, False}, optional If True, sign file with ad-hoc signature """ - commands = [] # install_name_tool commands - for rpath in get_rpaths(filename): - if not _is_rpath_sanitary(rpath): - commands += ["-delete_rpath", rpath] - logger.info("Sanitize: Deleting rpath %r from %r", rpath, filename) - if not commands: - return - _run(["install_name_tool", filename, *commands], check=True) - if ad_hoc_sign: - replace_signature(filename, "-") + _delete_rpaths( + filename, + ( + rpath + for rpath in get_rpaths(filename) + if not _is_rpath_sanitary(rpath) + ), + ad_hoc_sign, + ) def zip2dir(