brew/Library/Homebrew/keg_fix_install_names.rb
2013-12-14 09:35:58 -06:00

178 lines
5.3 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
PREFIX_PLACEHOLDER = "@@HOMEBREW_PREFIX@@".freeze
CELLAR_PLACEHOLDER = "@@HOMEBREW_CELLAR@@".freeze
def fix_install_names options={}
mach_o_files.each do |file|
file.ensure_writable do
change_dylib_id(dylib_id_for(file, options), file) if file.dylib?
each_install_name_for(file) do |bad_name|
# Don't fix absolute paths unless they are rooted in the build directory
next if bad_name.start_with? '/' and not bad_name.start_with? HOMEBREW_TEMP.to_s
new_name = fixed_name(file, bad_name)
change_install_name(bad_name, new_name, file) unless new_name == bad_name
end
end
end
end
def relocate_install_names old_prefix, new_prefix, old_cellar, new_cellar, options={}
mach_o_files.each do |file|
file.ensure_writable do
if file.dylib?
id = dylib_id_for(file, options).sub(old_prefix, new_prefix)
change_dylib_id(id, file)
end
each_install_name_for(file) do |old_name|
if old_name.start_with? old_cellar
new_name = old_name.sub(old_cellar, new_cellar)
elsif old_name.start_with? old_prefix
new_name = old_name.sub(old_prefix, new_prefix)
end
change_install_name(old_name, new_name, file) if new_name
end
end
end
(pkgconfig_files | libtool_files).each do |file|
file.ensure_writable do
file.open('rb') do |f|
s = f.read
s.gsub!(old_cellar, new_cellar)
s.gsub!(old_prefix, new_prefix)
f.reopen(file, 'wb')
f.write(s)
end
end
end
end
def change_dylib_id(id, file)
puts "Changing dylib ID in #{file} to #{id}" if ARGV.debug?
install_name_tool("-id", id, file)
end
def change_install_name(old, new, file)
puts "Changing install name in #{file} from #{old} to #{new}" if ARGV.debug?
install_name_tool("-change", old, new, file)
end
# Detects the C++ dynamic libraries in place, scanning the dynamic links
# of the files within the keg. This searches only libs contained within
# lib/, and ignores binaries and other mach-o objects
# Note that this doesn't attempt to distinguish between libstdc++ versions,
# for instance between Apple libstdc++ and GNU libstdc++
def detect_cxx_stdlibs
results = Set.new
mach_o_files.each do |file|
dylibs = file.dynamically_linked_libraries
results << :libcxx unless dylibs.grep(/libc\+\+.+\.dylib/).empty?
results << :libstdcxx unless dylibs.grep(/libstdc\+\+.+\.dylib/).empty?
end
results.to_a
end
private
def install_name_tool(*args)
system(MacOS.locate("install_name_tool"), *args)
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.
def fixed_name(file, bad_name)
if bad_name.start_with? PREFIX_PLACEHOLDER
bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s)
elsif bad_name.start_with? CELLAR_PLACEHOLDER
bad_name.sub(CELLAR_PLACEHOLDER, HOMEBREW_CELLAR.to_s)
elsif (file.dylib? || file.mach_o_bundle?) && (file.parent + bad_name).exist?
"@loader_path/#{bad_name}"
elsif file.mach_o_executable? && (lib + bad_name).exist?
"#{lib}/#{bad_name}"
elsif (abs_name = find_dylib(Pathname.new(bad_name).basename)) && abs_name.exist?
abs_name.to_s
else
opoo "Could not fix #{bad_name} in #{file}"
bad_name
end
end
def lib; join 'lib' end
def each_install_name_for file, &block
dylibs = file.dynamically_linked_libraries
dylibs.reject! { |fn| fn =~ /^@(loader_|executable_|r)path/ }
dylibs.each(&block)
end
def dylib_id_for file, options={}
# 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)
if shortpath.exist? and not options[:keg_only]
shortpath
else
"#{HOMEBREW_PREFIX}/opt/#{fname}/#{relative_path}"
end
end
def find_dylib name
lib.find { |pn| break pn if pn.basename == name }
end
def mach_o_files
mach_o_files = []
dirs = %w{bin lib Frameworks}
dirs.map! { |dir| join(dir) }
dirs.reject! { |dir| not dir.directory? }
dirs.each do |dir|
dir.find do |pn|
next if pn.symlink? or pn.directory?
mach_o_files << pn if pn.dylib? or pn.mach_o_bundle? or pn.mach_o_executable?
end
end
mach_o_files
end
def pkgconfig_files
pkgconfig_files = []
# find .pc files, which are stored in lib/pkgconfig
pc_dir = self/'lib/pkgconfig'
if pc_dir.directory?
pc_dir.find do |pn|
next if pn.symlink? or pn.directory? or pn.extname != '.pc'
pkgconfig_files << pn
end
end
# find name-config scripts, which can be all over the keg
Pathname.new(self).find do |pn|
next if pn.symlink? or pn.directory?
pkgconfig_files << pn if pn.basename.to_s.end_with? '-config' and pn.text_executable?
end
pkgconfig_files
end
def libtool_files
libtool_files = []
# find .la files, which are stored in lib/
lib.find do |pn|
next if pn.symlink? or pn.directory? or pn.extname != '.la'
libtool_files << pn
end
libtool_files
end
end