aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike McQuaid2013-03-11 18:56:26 +0000
committerMike McQuaid2013-03-11 18:58:37 +0000
commit0f9910d352e460fe7d93544d91cdc1eb53a9631c (patch)
treebd424a5196ae9896a632a1686fdb9debffef4442
parent258d70028f359e88b3300fdd1b8442428ef75826 (diff)
downloadbrew-0f9910d352e460fe7d93544d91cdc1eb53a9631c.tar.bz2
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.
-rw-r--r--Library/Homebrew/cmd/bottle.rb48
-rw-r--r--Library/Homebrew/formula_installer.rb15
-rw-r--r--Library/Homebrew/formula_support.rb5
-rw-r--r--Library/Homebrew/keg_fix_install_names.rb48
-rw-r--r--Library/Homebrew/test/testball.rb1
5 files changed, 98 insertions, 19 deletions
diff --git a/Library/Homebrew/cmd/bottle.rb b/Library/Homebrew/cmd/bottle.rb
index cda1d776d..6f703d4b3 100644
--- a/Library/Homebrew/cmd/bottle.rb
+++ b/Library/Homebrew/cmd/bottle.rb
@@ -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}"
diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb
index 9251fe487..767db6e63 100644
--- a/Library/Homebrew/formula_installer.rb
+++ b/Library/Homebrew/formula_installer.rb
@@ -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"
diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb
index 4fa06c0e7..23472547f 100644
--- a/Library/Homebrew/formula_support.rb
+++ b/Library/Homebrew/formula_support.rb
@@ -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
diff --git a/Library/Homebrew/keg_fix_install_names.rb b/Library/Homebrew/keg_fix_install_names.rb
index dd647660a..bdb98286f 100644
--- a/Library/Homebrew/keg_fix_install_names.rb
+++ b/Library/Homebrew/keg_fix_install_names.rb
@@ -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)
diff --git a/Library/Homebrew/test/testball.rb b/Library/Homebrew/test/testball.rb
index d3054810a..f685f5e2c 100644
--- a/Library/Homebrew/test/testball.rb
+++ b/Library/Homebrew/test/testball.rb
@@ -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