aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
authorMisty De Meo2013-10-06 01:51:31 -0700
committerMisty De Meo2013-10-06 19:26:06 -0700
commit74ab0234223332585f9d249c8d55a33de60a9b4c (patch)
tree871fb635b1edf016b0f3e2d4c618feda5ab9b788 /Library
parent9c53a1b8b760614fc076afe0d94ff68ac30cd385 (diff)
downloadbrew-74ab0234223332585f9d249c8d55a33de60a9b4c.tar.bz2
Only track C++ stdlibs for C++ code
After a formula is built, scan all mach-o files for dynamic links to see if any of them point to a C++ stdlib (libc++ or libstdc++). If one of them is linked, record that information in the formula's tab. This replaces the old behaviour where all files were assumed to be C++ code, and stdlibs were always tracked regardless of whether they were actually linked against. This also modifies the way that tabs are written - now tabs are written with the stdlib field null, and values are only written if an stdlib is detected.
Diffstat (limited to 'Library')
-rwxr-xr-xLibrary/Homebrew/build.rb2
-rw-r--r--Library/Homebrew/extend/pathname.rb11
-rw-r--r--Library/Homebrew/formula_installer.rb14
-rw-r--r--Library/Homebrew/keg_fix_install_names.rb15
-rw-r--r--Library/Homebrew/tab.rb5
5 files changed, 43 insertions, 4 deletions
diff --git a/Library/Homebrew/build.rb b/Library/Homebrew/build.rb
index de9d503f3..6cb903efd 100755
--- a/Library/Homebrew/build.rb
+++ b/Library/Homebrew/build.rb
@@ -171,7 +171,7 @@ class Build
begin
f.install
- Tab.create(f, :libstdcxx, ENV.compiler,
+ Tab.create(f, ENV.compiler,
Options.coerce(ARGV.options_only)).write
rescue Exception => e
if ARGV.debug?
diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb
index 8ca86d39a..d54e7d72f 100644
--- a/Library/Homebrew/extend/pathname.rb
+++ b/Library/Homebrew/extend/pathname.rb
@@ -390,6 +390,17 @@ class Pathname
end
end
+ # Returns an array containing all dynamically-linked libraries, based on the
+ # output of otool. This returns the install names, so these are not guaranteed
+ # to be absolute paths.
+ # Returns an empty array both for software that links against no libraries,
+ # and for non-mach objects.
+ def dynamically_linked_libraries
+ `otool -L "#{expand_path}"`.chomp.split("\n")[1..-1].map do |line|
+ line[/\t(.+) \([^(]+\)/, 1]
+ end
+ end
+
# We redefine these private methods in order to add the /o modifier to
# the Regexp literals, which forces string interpolation to happen only
# once instead of each time the method is called. This is fixed in 1.9+.
diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb
index f2f739c53..8bc09475c 100644
--- a/Library/Homebrew/formula_installer.rb
+++ b/Library/Homebrew/formula_installer.rb
@@ -349,6 +349,8 @@ class FormulaInstaller
fix_install_names
+ record_cxx_stdlib
+
ohai "Summary" if ARGV.verbose? or show_summary_heading
unless ENV['HOMEBREW_NO_EMOJI']
print "\xf0\x9f\x8d\xba " if MacOS.version >= :lion
@@ -490,6 +492,18 @@ class FormulaInstaller
@show_summary_heading = true
end
+ def record_cxx_stdlib
+ stdlibs = Keg.new(f.prefix).detect_cxx_stdlibs
+ return if stdlibs.empty?
+
+ tab = Tab.for_formula(f)
+ tab.tabfile.unlink
+ # It's technically possible for the same lib to link to multiple C++ stdlibs,
+ # but very bad news. Right now we don't track this woeful scenario.
+ tab.stdlib = stdlibs.first
+ tab.write
+ end
+
def clean
ohai "Cleaning" if ARGV.verbose?
if f.class.skip_clean_all?
diff --git a/Library/Homebrew/keg_fix_install_names.rb b/Library/Homebrew/keg_fix_install_names.rb
index fdb348608..3b37ccf26 100644
--- a/Library/Homebrew/keg_fix_install_names.rb
+++ b/Library/Homebrew/keg_fix_install_names.rb
@@ -42,6 +42,21 @@ class Keg
end
end
+ # Detects the C++ dynamic libraries in place, scanning the dynamic links
+ # of the files within the keg.
+ # 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
OTOOL_RX = /\t(.*) \(compatibility version (\d+\.)*\d+, current version (\d+\.)*\d+\)/
diff --git a/Library/Homebrew/tab.rb b/Library/Homebrew/tab.rb
index 9b19e9510..4b8eb3581 100644
--- a/Library/Homebrew/tab.rb
+++ b/Library/Homebrew/tab.rb
@@ -10,7 +10,7 @@ require 'utils/json'
class Tab < OpenStruct
FILENAME = 'INSTALL_RECEIPT.json'
- def self.create f, stdlib, compiler, args
+ def self.create f, compiler, args
f.build.args = args
sha = HOMEBREW_REPOSITORY.cd do
@@ -25,8 +25,7 @@ class Tab < OpenStruct
:tapped_from => f.tap,
:time => Time.now.to_i, # to_s would be better but Ruby has no from_s function :P
:HEAD => sha,
- :compiler => compiler,
- :stdlib => stdlib
+ :compiler => compiler
end
def self.from_file path