keg_relocate: retain framework info in relocatable install names

`dyld` uses the target library's install name to work out whether this
is a Framework or a dylib, which affects how `dyld` searches for the
desired library.

We should therefore avoid confusing `dyld` by including the
`*.framework` part of the install name in the target dylib, which is
what this change does.

Here's a concrete example of what this changes. Before:

    ❯ otool -L /usr/local/bin/python3
    /usr/local/bin/python3:
            @loader_path/../Python (compatibility version 3.11.0, current version 3.11.0)
            /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.100.3)

After:

    ❯ otool -L /usr/local/bin/python3
    /usr/local/bin/python3:
            @loader_path/../../../../Python.framework/Versions/3.11/Python (compatibility version 3.11.0, current version 3.11.0)
            /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.100.3)

By retaining the `Python.framework` part of the install name, we make
sure that `dyld` knows that it should be looking for a framework rather
than a dylib.
This commit is contained in:
Carlo Cabrera 2023-08-07 14:43:56 +08:00
parent 98f1be77f9
commit dbeac59584
No known key found for this signature in database
GPG Key ID: C74D447FC549A1D0

View File

@ -80,7 +80,10 @@ class Keg
def loader_name_for(file, target) def loader_name_for(file, target)
# Use @loader_path-relative install names for other Homebrew-installed binaries. # Use @loader_path-relative install names for other Homebrew-installed binaries.
if ENV["HOMEBREW_RELOCATABLE_INSTALL_NAMES"] && target.start_with?(HOMEBREW_PREFIX) if ENV["HOMEBREW_RELOCATABLE_INSTALL_NAMES"] && target.start_with?(HOMEBREW_PREFIX)
"@loader_path/#{Pathname(target).relative_path_from(file.dirname)}" dylib_suffix = find_dylib_suffix_from(target)
target_dir = Pathname.new(target.delete_suffix(dylib_suffix)).cleanpath
"@loader_path/#{target_dir.relative_path_from(file.dirname)/dylib_suffix}"
else else
target target
end end