Merge pull request #15571 from gerlero/relocate-relative-names

mac/keg_relocate: use relative install names
This commit is contained in:
Carlo Cabrera 2023-07-11 04:38:26 +08:00 committed by GitHub
commit cff8d8c155
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 17 deletions

View File

@ -45,20 +45,24 @@ class Keg
change_dylib_id(dylib_id_for(file), file) if file.dylib?
each_linkage_for(file, :dynamically_linked_libraries) do |bad_name|
# Don't fix absolute paths unless they are rooted in the build directory
next if bad_name.start_with?("/") &&
!rooted_in_build_directory?(bad_name)
new_name = fixed_name(file, bad_name)
change_install_name(bad_name, new_name, file) if new_name != bad_name
# Don't fix absolute paths unless they are rooted in the build directory.
new_name = if bad_name.start_with?("/") && !rooted_in_build_directory?(bad_name)
bad_name
else
fixed_name(file, bad_name)
end
loader_name = loader_name_for(file, new_name)
change_install_name(bad_name, loader_name, file) if loader_name != bad_name
end
each_linkage_for(file, :rpaths) do |bad_name|
# Strip duplicate rpaths and rpaths rooted in the build directory.
next if !rooted_in_build_directory?(bad_name) &&
(file.rpaths.count(bad_name) == 1)
delete_rpath(bad_name, file)
if rooted_in_build_directory?(bad_name) || (file.rpaths.count(bad_name) > 1)
delete_rpath(bad_name, file)
else
loader_name = loader_name_for(file, bad_name)
change_rpath(bad_name, loader_name, file) if loader_name != bad_name
end
end
end
end
@ -66,6 +70,15 @@ class Keg
generic_fix_dynamic_linkage
end
def loader_name_for(file, target)
# Use @loader_path-relative install names for other Homebrew-installed binaries.
if ENV["HOMEBREW_RELOCATABLE_INSTALL_NAMES"] && target.start_with?(HOMEBREW_PREFIX)
"@loader_path/#{Pathname(target).relative_path_from(file.dirname)}"
else
target
end
end
# If file is a dylib or bundle itself, look for the dylib named by
# bad_name relative to the lib directory, so that we can skip the more
# expensive recursive search if possible.
@ -90,7 +103,7 @@ class Keg
def each_linkage_for(file, linkage_type, &block)
links = file.method(linkage_type)
.call
.call(resolve_variable_references: false)
.grep_v(/^@(loader_|executable_|r)path/)
links.each(&block)
end

View File

@ -31,6 +31,7 @@ class LinkageChecker
@unwanted_system_dylibs = []
@version_conflict_deps = []
@files_missing_rpaths = []
@executable_path_dylibs = []
check_dylibs(rebuild_cache: rebuild_cache)
end
@ -39,13 +40,14 @@ class LinkageChecker
display_items "System libraries", @system_dylibs
display_items "Homebrew libraries", @brewed_dylibs
display_items "Indirect dependencies with linkage", @indirect_deps
display_items "Variable-referenced libraries", @variable_dylibs
display_items "@rpath-referenced libraries", @variable_dylibs
display_items "Missing libraries", @broken_dylibs
display_items "Broken dependencies", @broken_deps
display_items "Undeclared dependencies with linkage", @undeclared_deps
display_items "Dependencies with no linkage", @unnecessary_deps
display_items "Unwanted system libraries", @unwanted_system_dylibs
display_items "Files with missing rpath", @files_missing_rpaths
display_items "@executable_path references in libraries", @executable_path_dylibs
end
def display_reverse_output
@ -72,6 +74,7 @@ class LinkageChecker
display_items "Undeclared dependencies with linkage", @undeclared_deps, puts_output: puts_output
display_items "Files with missing rpath", @files_missing_rpaths, puts_output: puts_output
display_items "@executable_path references in libraries", @executable_path_dylibs, puts_output: puts_output
end
sig { params(test: T::Boolean, strict: T::Boolean).returns(T::Boolean) }
@ -81,7 +84,7 @@ class LinkageChecker
issues = [@broken_deps, unexpected_broken_dylibs]
if test
issues += [@unwanted_system_dylibs, @version_conflict_deps, unexpected_present_dylibs]
issues += [@undeclared_deps, @files_missing_rpaths] if strict
issues += [@undeclared_deps, @files_missing_rpaths, @executable_path_dylibs] if strict
end
issues.any?(&:present?)
end
@ -176,9 +179,12 @@ class LinkageChecker
checked_dylibs << dylib
if dylib.start_with? "@"
if dylib.start_with? "@rpath"
@variable_dylibs << dylib
next
elsif dylib.start_with?("@executable_path") && !Pathname(file).binary_executable?
@executable_path_dylibs << dylib
next
end
begin

View File

@ -9,7 +9,7 @@ require "macho"
module MachOShim
extend Forwardable
delegate [:dylib_id, :rpaths] => :macho
delegate [:dylib_id] => :macho
def macho
@macho ||= MachO.open(to_s)
@ -79,10 +79,32 @@ module MachOShim
macho.write!
end
def dynamically_linked_libraries(except: :none)
def dynamically_linked_libraries(except: :none, resolve_variable_references: true)
lcs = macho.dylib_load_commands.reject { |lc| lc.type == except }
lcs.map(&:name).map(&:to_s).uniq
names = lcs.map(&:name).map(&:to_s).uniq
names.map! { |name| resolve_variable_name(name) } if resolve_variable_references
names
end
def rpaths(resolve_variable_references: true)
names = macho.rpaths.uniq
names.map! { |name| resolve_variable_name(name) } if resolve_variable_references
names
end
def resolve_variable_name(name)
if name.start_with? "@loader_path"
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
else
name
end
end
def archs