Skip to content

Commit b5225c1

Browse files
authored
Merge pull request #20801 from Homebrew/copilot/fix-fab7d5fc-dabe-4a66-8fc4-ed32200d3d65
Add formula DSL support for omitting install name rewriting for `@rpath/*` install names
2 parents d4815b2 + 2bd0b81 commit b5225c1

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

Library/Homebrew/extend/os/mac/keg_relocate.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,23 @@ def dylib_id_for(file)
151151
# Swift dylib IDs should be /usr/lib/swift
152152
return file.dylib_id if file.dylib_id.start_with?("/usr/lib/swift/libswift")
153153

154+
# Preserve @rpath install names if the formula has specified preserve_rpath
155+
return file.dylib_id if file.dylib_id.start_with?("@rpath") && formula_preserve_rpath?
156+
154157
# The new dylib ID should have the same basename as the old dylib ID, not
155158
# the basename of the file itself.
156159
basename = File.basename(file.dylib_id)
157160
relative_dirname = file.dirname.relative_path_from(path)
158161
(opt_record/relative_dirname/basename).to_s
159162
end
160163

164+
sig { returns(T::Boolean) }
165+
def formula_preserve_rpath?
166+
::Formula[name].preserve_rpath?
167+
rescue FormulaUnavailableError
168+
false
169+
end
170+
161171
sig { params(old_name: String, relocation: ::Keg::Relocation).returns(T.nilable(String)) }
162172
def relocated_name_for(old_name, relocation)
163173
old_prefix, new_prefix = relocation.replacement_pair_for(:prefix)

Library/Homebrew/formula.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,9 @@ def ensure_installed!(reason: "", latest: false, output_to_stderr: true, quiet:
347347
self
348348
end
349349

350+
sig { returns(T::Boolean) }
351+
def preserve_rpath? = self.class.preserve_rpath?
352+
350353
private
351354

352355
# Allow full name logic to be re-used between names, aliases and installed aliases.
@@ -3406,6 +3409,7 @@ def inherited(child)
34063409
@network_access_allowed = T.let(SUPPORTED_NETWORK_ACCESS_PHASES.to_h do |phase|
34073410
[phase, DEFAULT_NETWORK_ACCESS_ALLOWED]
34083411
end, T.nilable(T::Hash[Symbol, T::Boolean]))
3412+
@preserve_rpath = T.let(false, T.nilable(T::Boolean))
34093413
end
34103414
end
34113415

@@ -3416,6 +3420,7 @@ def freeze
34163420
@conflicts.freeze
34173421
@skip_clean_paths.freeze
34183422
@link_overwrite_paths.freeze
3423+
@preserve_rpath&.freeze
34193424
super
34203425
end
34213426

@@ -4130,6 +4135,34 @@ def skip_clean(*paths)
41304135
T.must(skip_clean_paths).merge(paths)
41314136
end
41324137

4138+
# Preserve `@rpath` install names when fixing dynamic linkage on macOS.
4139+
#
4140+
# By default, Homebrew rewrites library install names (including those starting
4141+
# with `@rpath`) to use absolute paths. This can break tools like `macdeployqt`
4142+
# that expect `@rpath`-based install names to remain unchanged.
4143+
#
4144+
# Call this method to skip rewriting install names that start with `@rpath`.
4145+
#
4146+
# ### Example
4147+
#
4148+
# ```ruby
4149+
# preserve_rpath
4150+
# ```
4151+
#
4152+
# @api public
4153+
sig { params(value: T::Boolean).returns(T::Boolean) }
4154+
def preserve_rpath(value: true)
4155+
@preserve_rpath = value
4156+
end
4157+
4158+
# Check if `@rpath` install names should be preserved.
4159+
#
4160+
# @api internal
4161+
sig { returns(T::Boolean) }
4162+
def preserve_rpath?
4163+
@preserve_rpath == true
4164+
end
4165+
41334166
# Software that will not be symlinked into the `brew --prefix` and will
41344167
# only live in its Cellar. Other formulae can depend on it and Homebrew
41354168
# will add the necessary includes, libraries and other paths while

Library/Homebrew/test/formula_spec.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,4 +2005,32 @@ def install
20052005
end
20062006
end
20072007
end
2008+
2009+
describe "#preserve_rpath" do
2010+
it "defaults to false" do
2011+
f = formula do
2012+
url "foo-1.0"
2013+
end
2014+
2015+
expect(f.class.preserve_rpath?).to be(false)
2016+
end
2017+
2018+
it "can be enabled" do
2019+
f = formula do
2020+
url "foo-1.0"
2021+
preserve_rpath
2022+
end
2023+
2024+
expect(f.class.preserve_rpath?).to be(true)
2025+
end
2026+
2027+
it "can be explicitly disabled" do
2028+
f = formula do
2029+
url "foo-1.0"
2030+
preserve_rpath value: false
2031+
end
2032+
2033+
expect(f.class.preserve_rpath?).to be(false)
2034+
end
2035+
end
20082036
end

0 commit comments

Comments
 (0)