brew/Library/Homebrew/keg_fix_install_names.rb
Max Howell f02d81ecbf Create active symlinks for installed formula
Similar to the LinkedKegs record, we write a symlink for installed kegs to PREFIX/opt.

Unlike the linked-keg record, unlinking doesn't remove the link, only uninstalling, and keg-only formula have a record too.

The reason for this addition is so that formula that depend on keg-only formula can build against the opt directory and not the cellar keg. Thus surviving upgrades.

To enforce this fix_install_names and built were adapted to use the opt path.

Standard kegs also create an opt symlink so that caveats can now refer to the opt directory and thus provide steps that survive upgrades too.

Thus the choice of /opt. It is short, neat and the right choice: POSIX dictates that opt is for stand-alone prefixes of software.
2012-08-29 12:41:33 -04:00

81 lines
2.7 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class Keg
def fix_install_names
mach_o_files.each do |file|
bad_install_names_for file do |id, bad_names|
file.ensure_writable do
system MacOS.locate("install_name_tool"), "-id", id, file if file.dylib?
bad_names.each do |bad_name|
new_name = bad_name
new_name = Pathname.new(bad_name).basename unless (file.parent + new_name).exist?
# First check to see if the dylib is present in the current
# directory, so we can skip the more expensive search.
if (file.parent + new_name).exist?
system MacOS.locate("install_name_tool"), "-change", bad_name, "@loader_path/#{new_name}", file
else
# Otherwise, try and locate the appropriate dylib by walking
# the entire 'lib' tree recursively.
abs_name = (self+'lib').find do |pn|
break pn if pn.basename == Pathname.new(new_name)
end
if abs_name and abs_name.exist?
system MacOS.locate("install_name_tool"), "-change", bad_name, abs_name, file
else
opoo "Could not fix install names for #{file}"
end
end
end
end
end
end
end
private
OTOOL_RX = /\t(.*) \(compatibility version (\d+\.)*\d+, current version (\d+\.)*\d+\)/
def bad_install_names_for file
ENV['HOMEBREW_MACH_O_FILE'] = file.to_s # solves all shell escaping problems
install_names = `#{MacOS.locate("otool")} -L "$HOMEBREW_MACH_O_FILE"`.split "\n"
install_names.shift # first line is fluff
install_names.map!{ |s| OTOOL_RX =~ s && $1 }
# Bundles don't have an ID
id = install_names.shift unless file.mach_o_bundle?
install_names.compact!
install_names.reject!{ |fn| fn =~ /^@(loader|executable)_path/ }
# Don't fix absolute paths unless they are rooted in the build directory
install_names.reject! do |fn|
tmp = ENV['HOMEBREW_TEMP'] ? Regexp.escape(ENV['HOMEBREW_TEMP']) : '/tmp'
fn[0,1] == '/' and not %r[^#{tmp}] === fn
end
# the shortpath ensures that library upgrades dont break installed tools
relative_path = Pathname.new(file).relative_path_from(self)
shortpath = HOMEBREW_PREFIX.join(relative_path)
id = if shortpath.exist?
shortpath
else
"#{HOMEBREW_PREFIX}/opt/#{fname}/#{relative_path}"
end
yield id, install_names
end
def mach_o_files
mach_o_files = []
if (lib = join 'lib').directory?
lib.find do |pn|
next if pn.symlink? or pn.directory?
mach_o_files << pn if pn.dylib? or pn.mach_o_bundle?
end
end
mach_o_files
end
end