os/mac/mach: resolve rpaths too

We can add a small amount of logic to `#resolve_variable_name` that will
allow us to perform (limited) resolution of rpath references. This is
for informational purposes only: failing to resolve an `@rpath`
reference will not (and should not) result in `brew linkage` failures.

`dyld` will typically have more information than we do to resolve these
references, so not failing `brew linkage` when we fail to resolve an
`@rpath` reference is the right behaviour here.

As an example, before:

    ❯ brew linkage jpeg-turbo
    System libraries:
      /usr/lib/libSystem.B.dylib
    @rpath-referenced libraries:
      @rpath/libjpeg.8.dylib
      @rpath/libturbojpeg.0.dylib

After:

    ❯ brew linkage jpeg-turbo
    System libraries:
      /usr/lib/libSystem.B.dylib
    Homebrew libraries:
      /usr/local/Cellar/jpeg-turbo/3.0.0/lib/libjpeg.8.dylib (jpeg-turbo)
      /usr/local/Cellar/jpeg-turbo/3.0.0/lib/libturbojpeg.0.dylib (jpeg-turbo)
This commit is contained in:
Carlo Cabrera 2023-07-27 11:53:46 +08:00
parent a0457c3695
commit acae97e70f
No known key found for this signature in database
GPG Key ID: C74D447FC549A1D0

View File

@ -110,11 +110,22 @@ module MachOShim
Pathname(name.sub("@loader_path", dirname)).cleanpath.to_s
elsif name.start_with?("@executable_path") && binary_executable?
Pathname(name.sub("@executable_path", dirname)).cleanpath.to_s
elsif name.start_with?("@rpath") && (target = resolve_rpath(name)).present?
target
else
name
end
end
def resolve_rpath(name)
target = T.let(nil, T.nilable(String))
return unless rpaths(resolve_variable_references: true).find do |rpath|
File.exist?(target = File.join(rpath, name.delete_prefix("@rpath")))
end
target
end
def archs
mach_data.map { |m| m.fetch :arch }
end