From c20f6395bbadef014f78e774e1526fecf2c12bfc Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Thu, 31 Oct 2013 01:20:28 -0700 Subject: [PATCH] bottle: improve relocatable debugging. * When Homebrew developer mode is enabled, if a bottle is not found to be relocatable attempt to explain why * Print out paths of each file that still contains the string search for * If the string searched for was found in an executable, check to see if `otool` can explain the string's appearance * If otool can't explain, see if `strings` can explain Closes Homebrew/homebrew#23824. Signed-off-by: Mike McQuaid --- Library/Homebrew/cmd/bottle.rb | 43 +++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/cmd/bottle.rb b/Library/Homebrew/cmd/bottle.rb index 0fe7fb8367..04f2fb3efd 100644 --- a/Library/Homebrew/cmd/bottle.rb +++ b/Library/Homebrew/cmd/bottle.rb @@ -5,6 +5,8 @@ require 'keg' require 'cmd/versions' require 'utils/inreplace' require 'erb' +require 'open3' +require 'extend/pathname' class BottleMerger < Formula # This provides a URL and Version which are the only needed properties of @@ -42,7 +44,46 @@ module Homebrew extend self end def keg_contains string, keg - quiet_system 'fgrep', '--recursive', '--quiet', '--max-count=1', string, keg + if not ARGV.homebrew_developer? + return quiet_system 'fgrep', '--recursive', '--quiet', '--max-count=1', string, keg + end + + # Find all files that still reference the keg via a string search + keg_ref_files = `/usr/bin/fgrep --files-with-matches --recursive "#{string}" "#{keg}" 2>/dev/null` + keg_ref_files = (keg_ref_files.map{ |file| Pathname.new(file.strip) }).reject(&:symlink?) + + # If there are no files with that string found, return immediately + return false if keg_ref_files.empty? + + # Start printing out each file and any extra information we can find + opoo "String '#{string}' still exists in these files:" + keg_ref_files.each do |file| + puts "#{Tty.red}#{file}#{Tty.reset}" + + # If we can't use otool on this file, just skip to the next file + next if not file.mach_o_executable? and not file.mach_o_bundle? and not file.dylib? and not file.extname == '.a' + + # Get all libraries this file links to, then display only links to libraries that contain string in the path + linked_libraries = `otool -L "#{file}"`.split("\n").drop(1) + linked_libraries.map!{ |lib| lib.strip.split()[0] } + linked_libraries = linked_libraries.select{ |lib| lib.include? string } + + linked_libraries.each do |lib| + puts " #{Tty.gray}-->#{Tty.reset} links to #{lib}" + end + + # Use strings to search through the file for each string + strings = `strings -t x - "#{file}"`.select{ |str| str.include? string }.map{ |s| s.strip } + + # Don't bother reporting a string if it was found by otool + strings.reject!{ |str| linked_libraries.include? str.split[1] } + strings.each do |str| + offset, match = str.split + puts " #{Tty.gray}-->#{Tty.reset} match '#{match}' at offset #{Tty.em}0x#{offset}#{Tty.reset}" + end + end + puts + true end def bottle_output bottle