2010-05-10 00:19:14 +01:00
|
|
|
|
class Keg
|
2013-10-02 22:12:13 -07:00
|
|
|
|
def fix_install_names options={}
|
2012-06-16 16:14:47 -05:00
|
|
|
|
mach_o_files.each do |file|
|
2013-10-02 22:12:13 -07:00
|
|
|
|
install_names_for(file, options) do |id, bad_names|
|
2012-06-16 16:14:47 -05:00
|
|
|
|
file.ensure_writable do
|
2013-12-04 22:37:57 -06:00
|
|
|
|
change_dylib_id(id, file) if file.dylib?
|
2012-06-16 16:14:47 -05:00
|
|
|
|
|
2010-05-10 00:19:14 +01:00
|
|
|
|
bad_names.each do |bad_name|
|
2013-10-06 11:55:05 -07:00
|
|
|
|
new_name = fixed_name(file, bad_name)
|
2013-05-22 19:42:43 -05:00
|
|
|
|
unless new_name == bad_name
|
2013-12-04 22:37:57 -06:00
|
|
|
|
change_install_name(bad_name, new_name, file)
|
2012-02-17 19:19:08 -06:00
|
|
|
|
end
|
2010-05-10 00:19:14 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2013-10-02 22:12:13 -07:00
|
|
|
|
def relocate_install_names old_prefix, new_prefix, old_cellar, new_cellar, options={}
|
2013-03-11 18:56:26 +00:00
|
|
|
|
mach_o_files.each do |file|
|
2013-12-04 22:37:57 -06:00
|
|
|
|
install_names_for(file, options, 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
|
|
|
|
|
change_install_name(old_cellar_name, new_cellar_name, file)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2013-10-02 22:12:13 -07:00
|
|
|
|
install_names_for(file, options, relocate_reject_proc(old_prefix)) do |id, old_prefix_names|
|
2013-03-11 18:56:26 +00:00
|
|
|
|
file.ensure_writable do
|
|
|
|
|
new_prefix_id = id.to_s.gsub old_prefix, new_prefix
|
2013-12-04 22:37:57 -06:00
|
|
|
|
change_dylib_id(new_prefix_id, file) if file.dylib?
|
2013-03-11 18:56:26 +00:00
|
|
|
|
|
|
|
|
|
old_prefix_names.each do |old_prefix_name|
|
|
|
|
|
new_prefix_name = old_prefix_name.to_s.gsub old_prefix, new_prefix
|
2013-12-04 22:37:57 -06:00
|
|
|
|
change_install_name(old_prefix_name, new_prefix_name, file)
|
2013-03-11 18:56:26 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2013-10-31 01:08:57 -07:00
|
|
|
|
|
|
|
|
|
# Search for pkgconfig .pc files and relocate references to the cellar
|
2013-11-30 19:38:49 -06:00
|
|
|
|
old_cellar = "#{old_prefix}/Cellar" if old_cellar == :any
|
2013-10-31 01:08:57 -07:00
|
|
|
|
|
|
|
|
|
pkgconfig_files.each do |pcfile|
|
|
|
|
|
pcfile.ensure_writable do
|
|
|
|
|
pcfile.open('rb') do |f|
|
|
|
|
|
s = f.read
|
2013-11-30 19:38:48 -06:00
|
|
|
|
replace_pkgconfig_file_path(s, old_cellar, new_cellar)
|
|
|
|
|
replace_pkgconfig_file_path(s, old_prefix, new_prefix)
|
2013-10-31 01:08:57 -07:00
|
|
|
|
f.reopen(pcfile, 'wb')
|
|
|
|
|
f.write(s)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2013-03-11 18:56:26 +00:00
|
|
|
|
end
|
|
|
|
|
|
2013-12-04 22:37:57 -06:00
|
|
|
|
def change_dylib_id(id, file)
|
|
|
|
|
install_name_tool("-id", id, file)
|
|
|
|
|
end
|
|
|
|
|
|
2013-12-04 22:37:57 -06:00
|
|
|
|
def change_install_name(old, new, file)
|
|
|
|
|
install_name_tool("-change", old, new, file)
|
|
|
|
|
end
|
|
|
|
|
|
2013-11-30 19:38:48 -06:00
|
|
|
|
# Given old == "/usr/local/Cellar" and new == "/opt/homebrew/Cellar",
|
|
|
|
|
# then update lines of the form
|
|
|
|
|
# some_variable=/usr/local/Cellar/foo/1.0/lib
|
|
|
|
|
# to
|
|
|
|
|
# some_variable="/opt/homebrew/Cellar/foo/1.0/lib"
|
|
|
|
|
# and add quotes to protect against paths containing spaces.
|
|
|
|
|
def replace_pkgconfig_file_path(s, old, new)
|
2013-11-30 19:38:48 -06:00
|
|
|
|
return if old == new
|
2013-11-30 19:38:48 -06:00
|
|
|
|
s.gsub!(%r[([\S]+)="?#{Regexp.escape(old)}(.*?)"?$], "\\1=\"#{new}\\2\"")
|
|
|
|
|
end
|
|
|
|
|
|
2013-10-06 01:51:31 -07:00
|
|
|
|
# Detects the C++ dynamic libraries in place, scanning the dynamic links
|
2013-10-08 09:03:17 -07:00
|
|
|
|
# of the files within the keg. This searches only libs contained within
|
|
|
|
|
# lib/, and ignores binaries and other mach-o objects
|
2013-10-06 01:51:31 -07:00
|
|
|
|
# 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
|
2013-10-08 09:03:17 -07:00
|
|
|
|
|
2013-10-24 20:29:14 -07:00
|
|
|
|
mach_o_files.each do |file|
|
2013-10-06 01:51:31 -07:00
|
|
|
|
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
|
|
|
|
|
|
2010-05-10 00:19:14 +01:00
|
|
|
|
private
|
|
|
|
|
|
|
|
|
|
OTOOL_RX = /\t(.*) \(compatibility version (\d+\.)*\d+, current version (\d+\.)*\d+\)/
|
|
|
|
|
|
2013-05-22 11:11:21 -05:00
|
|
|
|
def install_name_tool(*args)
|
|
|
|
|
system(MacOS.locate("install_name_tool"), *args)
|
|
|
|
|
end
|
|
|
|
|
|
2013-05-22 11:40:57 -05:00
|
|
|
|
# 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 (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
|
2013-05-22 19:42:43 -05:00
|
|
|
|
opoo "Could not fix #{bad_name} in #{file}"
|
|
|
|
|
bad_name
|
2013-05-22 11:40:57 -05:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2012-09-04 10:49:14 -05:00
|
|
|
|
def lib; join 'lib' end
|
|
|
|
|
|
2013-03-11 18:56:26 +00:00
|
|
|
|
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
|
|
|
|
|
|
2013-10-02 22:12:13 -07:00
|
|
|
|
def install_names_for file, options, reject_proc=default_reject_proc
|
2012-06-16 16:14:47 -05:00
|
|
|
|
ENV['HOMEBREW_MACH_O_FILE'] = file.to_s # solves all shell escaping problems
|
Core change: XCode only install, with CLT or both
Allow XCode without the Command Line Tools to
work with homebrew, so it's not necessary
to register an Apple Dev ID and/or go to the
XCode prefs and download the CLT. Yay!
Further, this commit allows to use the CLT
solely (without the need for XCode).
Saves quite some megs.
(Some furmulae require xcodebuild)
Of course XCode together with the CLT is still
fine and has been tested on 10.7 and 10.6
with Xcode 4 and Xcode 3.
Only on Lion or above, tell the user about the options,
which are
- Xcode without CLT
- CLT without Xcode
- both (ok, it's not directly stated, but implicit)
So if no Xcode is found and we are on Lion or above,
we don't fail but check for the CLTs now.
For older Macs, the old message that Xcode is needed
and the installer should be run is still displayed.
If the CLT are not found but Xcode is, then we
print out about the experimental status of this setup.
Closes Homebrew/homebrew#10510.
Signed-off-by: Adam Vandenberg <flangy@gmail.com>
2012-02-26 21:04:15 +01:00
|
|
|
|
install_names = `#{MacOS.locate("otool")} -L "$HOMEBREW_MACH_O_FILE"`.split "\n"
|
2010-05-10 00:19:14 +01:00
|
|
|
|
|
|
|
|
|
install_names.shift # first line is fluff
|
|
|
|
|
install_names.map!{ |s| OTOOL_RX =~ s && $1 }
|
2012-06-16 16:14:47 -05:00
|
|
|
|
|
2012-09-04 10:49:14 -05:00
|
|
|
|
# Bundles and executables do not have an ID
|
|
|
|
|
id = install_names.shift if file.dylib?
|
2012-06-16 16:14:47 -05:00
|
|
|
|
|
2010-05-10 00:19:14 +01:00
|
|
|
|
install_names.compact!
|
2012-09-18 13:07:00 -05:00
|
|
|
|
install_names.reject!{ |fn| fn =~ /^@(loader_|executable_|r)path/ }
|
2013-03-11 18:56:26 +00:00
|
|
|
|
install_names.reject!{ |fn| reject_proc.call(fn) }
|
2010-05-10 00:19:14 +01:00
|
|
|
|
|
2011-06-16 15:11:41 +01:00
|
|
|
|
# the shortpath ensures that library upgrades don’t break installed tools
|
2012-08-10 16:33:22 -04:00
|
|
|
|
relative_path = Pathname.new(file).relative_path_from(self)
|
|
|
|
|
shortpath = HOMEBREW_PREFIX.join(relative_path)
|
2013-10-02 22:12:13 -07:00
|
|
|
|
id = if shortpath.exist? and not options[:keg_only]
|
2012-08-10 16:33:22 -04:00
|
|
|
|
shortpath
|
|
|
|
|
else
|
|
|
|
|
"#{HOMEBREW_PREFIX}/opt/#{fname}/#{relative_path}"
|
|
|
|
|
end
|
2011-06-16 15:11:41 +01:00
|
|
|
|
|
|
|
|
|
yield id, install_names
|
2010-05-10 00:19:14 +01:00
|
|
|
|
end
|
|
|
|
|
|
2012-09-04 10:49:14 -05:00
|
|
|
|
def find_dylib name
|
|
|
|
|
(join 'lib').find do |pn|
|
|
|
|
|
break pn if pn.basename == Pathname.new(name)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2012-06-16 16:14:47 -05:00
|
|
|
|
def mach_o_files
|
|
|
|
|
mach_o_files = []
|
2012-11-06 13:04:40 -06:00
|
|
|
|
dirs = %w{bin lib Frameworks}
|
|
|
|
|
dirs.map! { |dir| join(dir) }
|
|
|
|
|
dirs.reject! { |dir| not dir.directory? }
|
2012-09-04 10:49:14 -05:00
|
|
|
|
|
2012-11-06 13:04:40 -06:00
|
|
|
|
dirs.each do |dir|
|
|
|
|
|
dir.find do |pn|
|
2012-09-04 10:49:14 -05:00
|
|
|
|
next if pn.symlink? or pn.directory?
|
2012-11-06 13:04:40 -06:00
|
|
|
|
mach_o_files << pn if pn.dylib? or pn.mach_o_bundle? or pn.mach_o_executable?
|
2012-09-04 10:49:14 -05:00
|
|
|
|
end
|
|
|
|
|
end
|
2012-11-06 13:04:40 -06:00
|
|
|
|
|
2012-06-16 16:14:47 -05:00
|
|
|
|
mach_o_files
|
2010-05-10 00:19:14 +01:00
|
|
|
|
end
|
2013-10-31 01:08:57 -07:00
|
|
|
|
|
|
|
|
|
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.to_s != '.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.text_executable? and pn.basename.to_s.end_with? '-config'
|
|
|
|
|
end
|
|
|
|
|
pkgconfig_files
|
|
|
|
|
end
|
2010-05-10 00:19:14 +01:00
|
|
|
|
end
|