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.
This commit is contained in:
parent
9c53a1b8b7
commit
74ab023422
@ -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?
|
||||
|
||||
@ -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+.
|
||||
|
||||
@ -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?
|
||||
|
||||
@ -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+\)/
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user