Relocate bottles using install_name_tool.
This has two parts: 1. Bottles are temporarily relocated on bottling and tested if that is sufficient for them to contain no longer reference the prefix or cellar. If so, they are marked as relocatable. 2. On installation if bottles are marked as relocatable they will be relocated using install_name_tool to the current prefix and cellar. Closes Homebrew/homebrew#18374.
This commit is contained in:
parent
258d70028f
commit
0f9910d352
@ -1,8 +1,13 @@
|
||||
require 'formula'
|
||||
require 'bottles'
|
||||
require 'tab'
|
||||
require 'keg'
|
||||
|
||||
module Homebrew extend self
|
||||
def keg_contains string, keg
|
||||
quiet_system 'fgrep', '--recursive', '--quiet', '--max-count=1', string, keg
|
||||
end
|
||||
|
||||
def bottle_formula f
|
||||
unless f.installed?
|
||||
return ofail "Formula not installed: #{f.name}"
|
||||
@ -18,23 +23,48 @@ module Homebrew extend self
|
||||
bottle_path = Pathname.pwd/filename
|
||||
sha1 = nil
|
||||
|
||||
prefix = HOMEBREW_PREFIX.to_s
|
||||
tmp_prefix = '/tmp'
|
||||
cellar = HOMEBREW_CELLAR.to_s
|
||||
tmp_cellar = '/tmp/Cellar'
|
||||
|
||||
HOMEBREW_CELLAR.cd do
|
||||
ohai "Bottling #{f.name} #{f.version}..."
|
||||
bottle_relocatable = !quiet_system(
|
||||
'grep', '--recursive', '--quiet', '--max-count=1',
|
||||
HOMEBREW_CELLAR, "#{f.name}/#{f.version}")
|
||||
cellar = nil
|
||||
if bottle_relocatable
|
||||
cellar = ':any'
|
||||
elsif HOMEBREW_CELLAR.to_s != '/usr/local/Cellar'
|
||||
cellar = "'#{HOMEBREW_CELLAR}'"
|
||||
end
|
||||
# Use gzip, faster to compress than bzip2, faster to uncompress than bzip2
|
||||
# or an uncompressed tarball (and more bandwidth friendly).
|
||||
safe_system 'tar', 'czf', bottle_path, "#{f.name}/#{f.version}"
|
||||
sha1 = bottle_path.sha1
|
||||
relocatable = false
|
||||
|
||||
keg = Keg.new f.prefix
|
||||
keg.lock do
|
||||
# Relocate bottle library references before testing for built-in
|
||||
# references to the Cellar e.g. Qt's QMake annoyingly does this.
|
||||
keg.relocate_install_names prefix, tmp_prefix, cellar, tmp_cellar
|
||||
|
||||
relocatable = !keg_contains(HOMEBREW_PREFIX, keg)
|
||||
relocatable = !keg_contains(HOMEBREW_CELLAR, keg) if relocatable
|
||||
|
||||
# And do the same thing in reverse to change the library references
|
||||
# back to how they were.
|
||||
keg.relocate_install_names tmp_prefix, prefix, tmp_cellar, cellar
|
||||
end
|
||||
|
||||
prefix = cellar = nil
|
||||
if relocatable
|
||||
cellar = ':any'
|
||||
else
|
||||
if HOMEBREW_PREFIX.to_s != '/usr/local'
|
||||
prefix = "'#{HOMEBREW_PREFIX}"
|
||||
end
|
||||
if HOMEBREW_CELLAR.to_s != '/usr/local/Cellar'
|
||||
cellar = "'#{HOMEBREW_CELLAR}'"
|
||||
end
|
||||
end
|
||||
|
||||
puts "./#{filename}"
|
||||
puts "bottle do"
|
||||
puts " prefix #{prefix}" if prefix
|
||||
puts " cellar #{cellar}" if cellar
|
||||
puts " revision #{bottle_revision}" if bottle_revision > 0
|
||||
puts " sha1 '#{sha1}' => :#{MacOS.cat}"
|
||||
|
@ -96,13 +96,13 @@ class FormulaInstaller
|
||||
begin
|
||||
if pour_bottle?
|
||||
pour
|
||||
poured_bottle = true
|
||||
@poured_bottle = true
|
||||
end
|
||||
rescue
|
||||
opoo "Bottle installation failed: building from source."
|
||||
end
|
||||
|
||||
unless poured_bottle
|
||||
unless @poured_bottle
|
||||
build
|
||||
clean
|
||||
end
|
||||
@ -353,6 +353,17 @@ class FormulaInstaller
|
||||
|
||||
def fix_install_names
|
||||
Keg.new(f.prefix).fix_install_names
|
||||
if @poured_bottle
|
||||
old_prefix = f.bottle.prefix
|
||||
new_prefix = HOMEBREW_PREFIX.to_s
|
||||
old_cellar = f.bottle.cellar
|
||||
new_cellar = HOMEBREW_CELLAR.to_s
|
||||
|
||||
if old_prefix != new_prefix or old_cellar != new_cellar
|
||||
Keg.new(f.prefix).relocate_install_names \
|
||||
old_prefix, new_prefix, old_cellar, new_cellar
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
onoe "Failed to fix install names"
|
||||
puts "The formula built, but you may encounter issues using it or linking other"
|
||||
|
@ -85,6 +85,7 @@ class Bottle < SoftwareSpec
|
||||
def initialize
|
||||
super
|
||||
@revision = 0
|
||||
@prefix = '/usr/local'
|
||||
@cellar = '/usr/local/Cellar'
|
||||
@cat_without_underscores = false
|
||||
end
|
||||
@ -117,6 +118,10 @@ class Bottle < SoftwareSpec
|
||||
val.nil? ? @root_url : @root_url = val
|
||||
end
|
||||
|
||||
def prefix val=nil
|
||||
val.nil? ? @prefix : @prefix = val
|
||||
end
|
||||
|
||||
def cellar val=nil
|
||||
val.nil? ? @cellar : @cellar = val
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ class Keg
|
||||
def fix_install_names
|
||||
return unless MACOS
|
||||
mach_o_files.each do |file|
|
||||
bad_install_names_for file do |id, bad_names|
|
||||
install_names_for file do |id, bad_names|
|
||||
file.ensure_writable do
|
||||
system MacOS.locate("install_name_tool"), "-id", id, file if file.dylib?
|
||||
|
||||
@ -31,13 +31,50 @@ class Keg
|
||||
end
|
||||
end
|
||||
|
||||
def relocate_install_names old_prefix, new_prefix, old_cellar, new_cellar
|
||||
mach_o_files.each do |file|
|
||||
install_names_for(file, relocate_reject_proc(old_prefix)) do |id, old_prefix_names|
|
||||
file.ensure_writable do
|
||||
new_prefix_id = id.to_s.gsub old_prefix, new_prefix
|
||||
system MacOS.locate("install_name_tool"), "-id", new_prefix_id, file if file.dylib?
|
||||
|
||||
old_prefix_names.each do |old_prefix_name|
|
||||
new_prefix_name = old_prefix_name.to_s.gsub old_prefix, new_prefix
|
||||
system MacOS.locate("install_name_tool"), "-change", old_prefix_name, new_prefix_name, file
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
install_names_for(file, relocate_reject_proc(old_cellar)) do |id, old_cellar_names|
|
||||
file.ensure_writable do
|
||||
old_cellar_names.each do |old_cellar_name|
|
||||
new_cellar_name = old_cellar_name.to_s.gsub old_cellar, new_cellar
|
||||
system MacOS.locate("install_name_tool"), "-change", old_cellar_name, new_cellar_name, file
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
OTOOL_RX = /\t(.*) \(compatibility version (\d+\.)*\d+, current version (\d+\.)*\d+\)/
|
||||
|
||||
def lib; join 'lib' end
|
||||
|
||||
def bad_install_names_for file
|
||||
def default_reject_proc
|
||||
Proc.new do |fn|
|
||||
# Don't fix absolute paths unless they are rooted in the build directory
|
||||
tmp = ENV['HOMEBREW_TEMP'] ? Regexp.escape(ENV['HOMEBREW_TEMP']) : '/tmp'
|
||||
fn[0,1] == '/' and not %r[^#{tmp}] === fn
|
||||
end
|
||||
end
|
||||
|
||||
def relocate_reject_proc(path)
|
||||
Proc.new { |fn| not fn.start_with?(path) }
|
||||
end
|
||||
|
||||
def install_names_for file, reject_proc=default_reject_proc
|
||||
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"
|
||||
|
||||
@ -49,12 +86,7 @@ class Keg
|
||||
|
||||
install_names.compact!
|
||||
install_names.reject!{ |fn| fn =~ /^@(loader_|executable_|r)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
|
||||
install_names.reject!{ |fn| reject_proc.call(fn) }
|
||||
|
||||
# the shortpath ensures that library upgrades don’t break installed tools
|
||||
relative_path = Pathname.new(file).relative_path_from(self)
|
||||
|
@ -221,6 +221,7 @@ class AllCatsBottleSpecTestBall < Formula
|
||||
sha1 '482e737739d946b7c8cbaf127d9ee9c148b999f5'
|
||||
|
||||
bottle do
|
||||
prefix '/private/tmp/testbrew/prefix'
|
||||
cellar '/private/tmp/testbrew/cellar'
|
||||
sha1 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' => :snow_leopard_32
|
||||
sha1 'faceb00cfaceb00cfaceb00cfaceb00cfaceb00c' => :snow_leopard
|
||||
|
Loading…
x
Reference in New Issue
Block a user