fix: stop Homebrew rewriting bundled dylib IDs on macOS - #335
Merged
cloudsmith-iduffy merged 1 commit intoJul 31, 2026
Merged
Conversation
Since 1.20.1 the Homebrew formula ships the PyInstaller onedir bundle, so the keg
contains 65 prebuilt Mach-O files where the zipapp had none. Homebrew rewrites the
dylib ID of every one of them to an absolute Cellar path, and that name does not
fit in the header padding of pydantic_core's prebuilt wheel:
Failed changing dylib ID of .../_pydantic_core.cpython-312-darwin.so
from @rpath/pydantic_core._pydantic_core.cpython-312-darwin.so
to /opt/homebrew/opt/cloudsmith-cli/libexec/_internal/...
Error: Failed to fix install linkage
The install still links and the CLI runs, but brew exits non-zero, which breaks
`brew upgrade` and the automation around it. Both macOS architectures are
affected; the Intel bundle has less padding to spare (32 bytes against the 56 the
new name needs, versus 48 on arm64).
Rewriting these IDs achieves nothing: every non-system linkage in the bundle is
@rpath-relative and private to it, and nothing outside links against them.
Homebrew already skips @rpath install names and rpaths; the dylib ID is the one
path lacking that exemption, and preserve_rpath supplies it.
The tap carries this fix already (cloudsmith-io/homebrew-cloudsmith-cli#28), but
publish-homebrew copies the rendered template over Formula/cloudsmith-cli.rb
wholesale, so without the same change here the next release would silently revert
it. Rendered with 1.20.2's values this template now produces a formula
byte-identical to the tap's, and brew style and brew audit both pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟢 Ready to approve
The change is narrowly scoped to the Homebrew formula template and aligns with the stated install failure mode without introducing additional logic or surface area.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
Updates the Homebrew formula template used by the release workflow so macOS Homebrew installs of the PyInstaller onedir bundle don’t fail due to Homebrew rewriting Mach-O linkage metadata.
Changes:
- Adds the
preserve_rpathdirective to the Homebrew formula template to prevent rewriting@rpath-based linkage. - Documents (in-formula) the rationale tied to Mach-O header padding constraints in prebuilt wheels (e.g.,
pydantic_core).
File summaries
| File | Description |
|---|---|
| packaging/homebrew/cloudsmith-cli.rb.tmpl | Adds preserve_rpath (with explanatory comment) to avoid Homebrew rewriting @rpath-based dylib IDs during macOS installs. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 0
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
BartoszBlizniak
approved these changes
Jul 31, 2026
cloudsmith-iduffy
deleted the
fix/eng-13692-preserve-rpath-in-homebrew-template
branch
July 31, 2026 15:02
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
preserve_rpathto the Homebrew formula template so macOS installs stop failing.Companion to cloudsmith-io/homebrew-cloudsmith-cli#28, which fixed the tap. This change is what stops the next release reverting that fix, because
publish-homebrewcopies the rendered template overFormula/cloudsmith-cli.rbwholesale.The bug
Since 1.20.1 the Homebrew formula ships the PyInstaller onedir bundle, so the keg contains 65 prebuilt Mach-O files where the zipapp had none. Homebrew rewrites the dylib ID of every one to an absolute Cellar path, and that name does not fit the header padding of
pydantic_core's prebuilt wheel:Measured against the published 1.20.2 archives — the new ID needs 56 more bytes than are available:
_pydantic_core.so_pydantic_core.sorpds.soBoth macOS architectures are affected, and the margin elsewhere is thin. The install does link and the CLI runs, but
brewexits non-zero, which breaksbrew upgradeand any automation around it. Reported by a customer upgrading 1.19.0 → 1.20.1.Why
preserve_rpathrather than a build change_pydantic_core.sois a prebuilt maturin wheel from PyPI that PyInstaller copies verbatim, so linking it with-headerpad_max_install_nameswould mean building pydantic-core from source.The rewrite is also pointless. Every non-system linkage in the bundle is
@rpath-relative and private to it, and nothing outside links against them. Homebrew already skips@rpathinstall names and rpaths viagrep_v(VARIABLE_REFERENCE_RX); the dylib ID is the one path lacking that exemption, andpreserve_rpathsupplies it. All six dylibs in the bundle use@rpathIDs, so it covers every one.Verification
Rendered with 1.20.2's version and checksums, this template produces a formula byte-identical to the one merged in the tap, and:
brew style— no offensesbrew audit— cleanBefore the fix the install reproduced the error above and exited 1; after it, exit 0 with all six dylib IDs left as
@rpath.🤖 Generated with Claude Code