2012-05-28 20:39:05 -05:00
|
|
|
module ArchitectureListExtension
|
2013-08-11 19:11:58 -07:00
|
|
|
def fat?
|
|
|
|
length > 1
|
|
|
|
end
|
|
|
|
|
|
|
|
def intel_universal?
|
|
|
|
intersects_all?(Hardware::CPU::INTEL_32BIT_ARCHS, Hardware::CPU::INTEL_64BIT_ARCHS)
|
|
|
|
end
|
|
|
|
|
|
|
|
def ppc_universal?
|
|
|
|
intersects_all?(Hardware::CPU::PPC_32BIT_ARCHS, Hardware::CPU::PPC_64BIT_ARCHS)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Old-style 32-bit PPC/Intel universal, e.g. ppc7400 and i386
|
|
|
|
def cross_universal?
|
|
|
|
intersects_all?(Hardware::CPU::PPC_32BIT_ARCHS, Hardware::CPU::INTEL_32BIT_ARCHS)
|
|
|
|
end
|
|
|
|
|
2012-05-28 20:39:05 -05:00
|
|
|
def universal?
|
2013-08-11 19:11:58 -07:00
|
|
|
intel_universal? || ppc_universal? || cross_universal?
|
2012-05-28 20:39:05 -05:00
|
|
|
end
|
|
|
|
|
2013-02-03 21:06:51 -08:00
|
|
|
def ppc?
|
2015-08-03 13:09:07 +01:00
|
|
|
(Hardware::CPU::PPC_32BIT_ARCHS+Hardware::CPU::PPC_64BIT_ARCHS).any? { |a| self.include? a }
|
2013-02-03 21:06:51 -08:00
|
|
|
end
|
|
|
|
|
2012-05-28 20:39:05 -05:00
|
|
|
def remove_ppc!
|
2015-08-03 13:09:07 +01:00
|
|
|
(Hardware::CPU::PPC_32BIT_ARCHS+Hardware::CPU::PPC_64BIT_ARCHS).each { |a| delete a }
|
2012-05-28 20:39:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def as_arch_flags
|
2015-08-03 13:09:07 +01:00
|
|
|
collect { |a| "-arch #{a}" }.join(" ")
|
2012-05-28 20:39:05 -05:00
|
|
|
end
|
2013-08-11 19:11:58 -07:00
|
|
|
|
2013-08-11 19:13:16 -07:00
|
|
|
def as_cmake_arch_flags
|
2015-08-03 13:09:07 +01:00
|
|
|
join(";")
|
2013-08-11 19:13:16 -07:00
|
|
|
end
|
|
|
|
|
2013-08-11 19:11:58 -07:00
|
|
|
protected
|
|
|
|
|
|
|
|
def intersects_all?(*set)
|
|
|
|
set.all? do |archset|
|
2015-08-03 13:09:07 +01:00
|
|
|
archset.any? { |a| self.include? a }
|
2013-08-11 19:11:58 -07:00
|
|
|
end
|
|
|
|
end
|
2012-05-28 20:39:05 -05:00
|
|
|
end
|
|
|
|
|
2012-05-25 23:44:11 -05:00
|
|
|
module MachO
|
2013-12-14 09:35:58 -06:00
|
|
|
OTOOL_RX = /\t(.*) \(compatibility version (?:\d+\.)*\d+, current version (?:\d+\.)*\d+\)/
|
2013-12-14 09:35:58 -06:00
|
|
|
|
2012-05-25 23:44:11 -05:00
|
|
|
# Mach-O binary methods, see:
|
|
|
|
# /usr/include/mach-o/loader.h
|
|
|
|
# /usr/include/mach-o/fat.h
|
|
|
|
|
|
|
|
def mach_data
|
2014-10-11 01:45:41 -05:00
|
|
|
@mach_data ||= begin
|
|
|
|
offsets = []
|
|
|
|
mach_data = []
|
|
|
|
|
|
|
|
header = read(8).unpack("N2")
|
|
|
|
case header[0]
|
|
|
|
when 0xcafebabe # universal
|
|
|
|
header[1].times do |i|
|
|
|
|
# header[1] is the number of struct fat_arch in the file.
|
|
|
|
# Each struct fat_arch is 20 bytes, and the 'offset' member
|
|
|
|
# begins 8 bytes into the struct, with an additional 8 byte
|
|
|
|
# offset due to the struct fat_header at the beginning of
|
|
|
|
# the file.
|
|
|
|
offsets << read(4, 20*i + 16).unpack("N")[0]
|
|
|
|
end
|
|
|
|
when 0xcefaedfe, 0xcffaedfe, 0xfeedface, 0xfeedfacf # Single arch
|
|
|
|
offsets << 0
|
|
|
|
when 0x7f454c46 # ELF
|
|
|
|
mach_data << { :arch => :x86_64, :type => :executable }
|
|
|
|
else
|
|
|
|
raise "Not a Mach-O binary."
|
2012-05-25 23:44:11 -05:00
|
|
|
end
|
|
|
|
|
2014-10-11 01:45:41 -05:00
|
|
|
offsets.each do |offset|
|
|
|
|
arch = case read(8, offset).unpack("N2")
|
|
|
|
when [0xcefaedfe, 0x07000000] then :i386
|
|
|
|
when [0xcffaedfe, 0x07000001] then :x86_64
|
|
|
|
when [0xfeedface, 0x00000012] then :ppc7400
|
|
|
|
when [0xfeedfacf, 0x01000012] then :ppc64
|
|
|
|
else :dunno
|
|
|
|
end
|
|
|
|
|
|
|
|
type = case read(4, offset + 12).unpack("N")[0]
|
|
|
|
when 0x00000002, 0x02000000 then :executable
|
|
|
|
when 0x00000006, 0x06000000 then :dylib
|
|
|
|
when 0x00000008, 0x08000000 then :bundle
|
|
|
|
else :dunno
|
|
|
|
end
|
|
|
|
|
|
|
|
mach_data << { :arch => arch, :type => type }
|
|
|
|
end
|
|
|
|
mach_data
|
|
|
|
rescue
|
|
|
|
[]
|
2012-05-25 23:44:11 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def archs
|
2015-08-03 13:09:07 +01:00
|
|
|
mach_data.map { |m| m.fetch :arch }.extend(ArchitectureListExtension)
|
2012-05-25 23:44:11 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def arch
|
|
|
|
case archs.length
|
|
|
|
when 0 then :dunno
|
|
|
|
when 1 then archs.first
|
|
|
|
else :universal
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def universal?
|
|
|
|
arch == :universal
|
|
|
|
end
|
|
|
|
|
|
|
|
def i386?
|
|
|
|
arch == :i386
|
|
|
|
end
|
|
|
|
|
|
|
|
def x86_64?
|
|
|
|
arch == :x86_64
|
|
|
|
end
|
|
|
|
|
|
|
|
def ppc7400?
|
|
|
|
arch == :ppc7400
|
|
|
|
end
|
|
|
|
|
|
|
|
def ppc64?
|
|
|
|
arch == :ppc64
|
|
|
|
end
|
|
|
|
|
|
|
|
def dylib?
|
2012-08-21 13:45:35 -05:00
|
|
|
mach_data.any? { |m| m.fetch(:type) == :dylib }
|
2012-05-25 23:44:11 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def mach_o_executable?
|
2012-08-21 13:45:35 -05:00
|
|
|
mach_data.any? { |m| m.fetch(:type) == :executable }
|
2012-05-25 23:44:11 -05:00
|
|
|
end
|
2012-06-16 11:35:02 -05:00
|
|
|
|
|
|
|
def mach_o_bundle?
|
2012-08-21 13:45:35 -05:00
|
|
|
mach_data.any? { |m| m.fetch(:type) == :bundle }
|
2012-06-16 11:35:02 -05:00
|
|
|
end
|
2013-12-14 09:35:58 -06:00
|
|
|
|
2014-04-13 13:53:46 -05:00
|
|
|
class Metadata
|
|
|
|
attr_reader :path, :dylib_id, :dylibs
|
|
|
|
|
|
|
|
def initialize(path)
|
|
|
|
@path = path
|
|
|
|
@dylib_id, @dylibs = parse_otool_L_output
|
|
|
|
end
|
|
|
|
|
|
|
|
def parse_otool_L_output
|
|
|
|
ENV["HOMEBREW_MACH_O_FILE"] = path.expand_path.to_s
|
2015-06-13 20:32:04 -04:00
|
|
|
libs = `#{MacOS.otool} -L "$HOMEBREW_MACH_O_FILE"`.split("\n")
|
2014-12-11 13:59:12 +00:00
|
|
|
unless $?.success?
|
2015-06-13 20:32:04 -04:00
|
|
|
raise ErrorDuringExecution.new(MacOS.otool,
|
2014-12-11 13:59:12 +00:00
|
|
|
["-L", ENV["HOMEBREW_MACH_O_FILE"]])
|
|
|
|
end
|
2014-04-13 13:53:46 -05:00
|
|
|
|
|
|
|
libs.shift # first line is the filename
|
|
|
|
|
|
|
|
id = libs.shift[OTOOL_RX, 1] if path.dylib?
|
|
|
|
libs.map! { |lib| lib[OTOOL_RX, 1] }.compact!
|
|
|
|
|
|
|
|
return id, libs
|
|
|
|
ensure
|
|
|
|
ENV.delete "HOMEBREW_MACH_O_FILE"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def mach_metadata
|
|
|
|
@mach_metadata ||= Metadata.new(self)
|
|
|
|
end
|
|
|
|
|
2013-12-14 09:35:58 -06:00
|
|
|
# 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
|
2014-04-13 13:53:46 -05:00
|
|
|
mach_metadata.dylibs
|
|
|
|
end
|
2013-12-14 09:35:58 -06:00
|
|
|
|
2014-04-13 13:53:46 -05:00
|
|
|
def dylib_id
|
|
|
|
mach_metadata.dylib_id
|
2013-12-14 09:35:58 -06:00
|
|
|
end
|
2012-05-25 23:44:11 -05:00
|
|
|
end
|