Skip to content

fix: always set RPATH or clear RUNPATH/RPATH for grafted libraries#693

Open
mayeut wants to merge 5 commits intopypa:mainfrom
mayeut:fixup-rpath
Open

fix: always set RPATH or clear RUNPATH/RPATH for grafted libraries#693
mayeut wants to merge 5 commits intopypa:mainfrom
mayeut:fixup-rpath

Conversation

@mayeut
Copy link
Copy Markdown
Member

@mayeut mayeut commented Apr 18, 2026

follow-up on #643 (comment)

The rationale for not setting RPATH unconditionally is that every patchelf modification comes with a risk and that it's mostly not needed for runtime.
There are a number of issues requesting that it'd be set anyway.

The proposed solution here is to set RPATH when grafted dependency has itself other grafted dependencies and to clear RUNPATH/RPATH when it's not the case. The 2nd operation should mostly be no-op patchelf-wise thus reducing the risk at least for "leaf" dependencies.

fix #671
fix #617
fix #459
fix #451
fix #344

close #672

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts how auditwheel handles RUNPATH/RPATH for grafted libraries to improve runtime reliability for transitive bundled dependencies while minimizing unnecessary patchelf mutations.

Changes:

  • Set $ORIGIN RPATH on grafted libraries that depend on other grafted libraries; clear RUNPATH/RPATH for grafted “leaf” libraries.
  • Introduce ElfPatcher.clear_rpath() and remove the now-unused elf_read_rpaths() helper.
  • Remove unit tests that targeted the deleted elf_read_rpaths() function.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/auditwheel/repair.py Updates grafted-lib postprocessing to set $ORIGIN RPATH when internal grafted dependencies exist; otherwise clears RUNPATH/RPATH.
src/auditwheel/patcher.py Adds clear_rpath() API and implements it via patchelf --remove-rpath.
src/auditwheel/elfutils.py Removes elf_read_rpaths() implementation and related import usage.
tests/unit/test_elfutils.py Removes tests for the deleted elf_read_rpaths() function and its import.
Comments suppressed due to low confidence (1)

src/auditwheel/repair.py:166

  • The inline comment about clearing RUNPATH/RPATH and setting RPATH is now stale: copylib() no longer reads or updates RPATH/RUNPATH, but the comment still claims it does. Please update/remove this comment so it matches the current behavior.
    # Copy the a shared library from the system (src_path) into the wheel
    # if the library has a RUNPATH/RPATH we clear it and set RPATH to point to
    # its new location.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/auditwheel/repair.py
Comment thread src/auditwheel/repair.py
Comment thread src/auditwheel/patcher.py
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.31%. Comparing base (e21df8b) to head (b7e8e79).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #693      +/-   ##
==========================================
- Coverage   95.34%   95.31%   -0.04%     
==========================================
  Files          22       22              
  Lines        1870     1858      -12     
  Branches      355      350       -5     
==========================================
- Hits         1783     1771      -12     
  Misses         48       48              
  Partials       39       39              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/auditwheel/repair.py:166

  • The comment above copylib() still says the function clears RUNPATH/RPATH and sets a new RPATH, but copylib() no longer touches RPATH (it’s now handled later in repair_wheel() when iterating soname_map). Please update/remove this comment so it matches the current behavior and doesn’t mislead future changes.
    # Copy the a shared library from the system (src_path) into the wheel
    # if the library has a RUNPATH/RPATH we clear it and set RPATH to point to
    # its new location.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/integration/test_manylinux.py Outdated
mayeut and others added 2 commits April 19, 2026 07:45
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@mayeut mayeut marked this pull request as ready for review April 19, 2026 05:48
@mayeut mayeut requested a review from lkollar April 19, 2026 05:48
Copy link
Copy Markdown
Contributor

@oraluben oraluben left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment thread src/auditwheel/repair.py
patcher.set_rpath(path, "$ORIGIN")
patcher.replace_needed(path, *replacements)
else:
patcher.clear_rpath(path)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it happen that we clear the RPATH for entries which are internal to the wheel? I don't think those will show up in soname_map and this can cause a regression where we clear a RUNPATH which is required to pick up .so's internal to the wheel.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only applies to external grafted libraries so we can't be modifying for entries which are internal to the wheel.

Comment thread src/auditwheel/repair.py
# we need to update those records so each now knows about the new
# name of the other.
# we also clear or set RPATH depending on the presence of internal dependencies
for _, path in soname_map.values():
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there can be a logic issue here if the same library is stored under multiple SONAME entries in soname_map:

  soname_map["libfoo.so"] = ("libfoo-abc.so", libfoo-abc.so)
  soname_map["libfoo.so.1"] = ("libfoo-abc.so", libfoo-abc.so)

The first loop iteration will call set_rpath(path, "$ORIGIN") and rewrite internal DT_NEEDED entries. Processing the second SONAME entry pointing to the same library elf_read_dt_needed will see the already-rewritten name and find no matching replacements, and invoke clear_rpath(path).

One way to solve this would be to perform this in two passes: first record what needs changes and in a second pass, perform the actual changes to RPATH.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any given path can only have a single soname so this can't happen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants