
Fixes Homebrew/homebrew#2709. By forcing dylibs to have an install_name id that is the HOMEBREW_PREFIX path, ie. the symlink’s path. Stuff that links to these dylibs will use this id and thus by immune to upgrades of underlying libraries. Thus whatever keg is "current" ie. linked, will be the library that is used by the tool. This fix is not retroactive. So there will still be breakage for existing installations of stuff. The fix_install step in install is moved after the link step as the symlinking is required to determine the eventual ids for each dylib.
51 lines
1.6 KiB
Ruby
51 lines
1.6 KiB
Ruby
class Keg
|
||
def fix_install_names
|
||
dylibs.each do |dylib|
|
||
bad_install_names_for dylib do |id, bad_names|
|
||
# avoid the chmod change if unecessary—I'm not convinced it reverses right
|
||
next if bad_names.empty? and id.to_s == dylib.to_s
|
||
|
||
dylib.ensure_writable do
|
||
system "install_name_tool", "-id", id, dylib
|
||
bad_names.each do |bad_name|
|
||
# we should be more careful here, check the path we point to exists etc.
|
||
system "install_name_tool", "-change", bad_name, "@loader_path/#{bad_name}", dylib
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
private
|
||
|
||
OTOOL_RX = /\t(.*) \(compatibility version (\d+\.)*\d+, current version (\d+\.)*\d+\)/
|
||
|
||
def bad_install_names_for dylib
|
||
dylib = dylib.to_s
|
||
|
||
ENV['HOMEBREW_DYLIB'] = dylib # solves all shell escaping problems
|
||
install_names = `otool -L "$HOMEBREW_DYLIB"`.split "\n"
|
||
|
||
install_names.shift # first line is fluff
|
||
install_names.map!{ |s| OTOOL_RX =~ s && $1 }
|
||
id = install_names.shift
|
||
install_names.compact!
|
||
install_names.reject!{ |fn| fn =~ /^@(loader|executable)_path/ }
|
||
install_names.reject!{ |fn| fn[0,1] == '/' }
|
||
|
||
# the shortpath ensures that library upgrades don’t break installed tools
|
||
shortpath = HOMEBREW_PREFIX + Pathname.new(dylib).relative_path_from(self)
|
||
id = if shortpath.exist? then shortpath else dylib end
|
||
|
||
yield id, install_names
|
||
end
|
||
|
||
def dylibs
|
||
if (lib = join 'lib').directory?
|
||
lib.children.select{ |pn| pn.extname == '.dylib' and not pn.symlink? }
|
||
else
|
||
[]
|
||
end
|
||
end
|
||
end
|