MacOS: refactor sdk_path lookup

* Pull SDK lookup code into a new `locator` class, which caches its
  results
* SDKLocator only queries one SDK location, not all SDK locations
* Build a map of all installed SDKs inside that location, instead of
  just the requested SDK
* Ask xcrun for --show-sdk-platform-path first so that all SDKs can be
  found, instead of asking xcodebuild for a specific SDK
* Add a new `SDK` class, which tracks the version and the prefix; add a
  new `MacOS.sdk` method which returns an `SDK` instance instead of a
  bare path; MacOS.sdk_path still returns a bare path
This commit is contained in:
Misty De Meo 2015-12-04 13:58:22 -08:00
parent 7b26c585c2
commit 3a1d7e7259
2 changed files with 75 additions and 10 deletions

View File

@ -3,6 +3,7 @@ require "os/mac/version"
require "os/mac/xcode"
require "os/mac/xquartz"
require "os/mac/pathname"
require "os/mac/sdk"
module OS
module Mac
@ -79,19 +80,24 @@ module OS
@active_developer_dir ||= Utils.popen_read("/usr/bin/xcode-select", "-print-path").strip
end
def sdk_path(v = version)
(@sdk_path ||= {}).fetch(v.to_s) do |key|
opts = []
# First query Xcode itself
opts << Utils.popen_read(locate("xcodebuild"), "-version", "-sdk", "macosx#{v}", "Path").chomp
# Xcode.prefix is pretty smart, so lets look inside to find the sdk
opts << "#{Xcode.prefix}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX#{v}.sdk"
# Xcode < 4.3 style
opts << "/Developer/SDKs/MacOSX#{v}.sdk"
@sdk_path[key] = opts.map { |a| Pathname.new(a) }.detect(&:directory?)
# Returns the requested SDK, if installed.
# If the requested SDK is not installed returns either:
# a) The newest SDK (if any SDKs are available), or
# b) nil
def sdk(v = version)
@locator ||= SDKLocator.new
begin
@locator.sdk_for v
rescue SDKLocator::NoSDKError
end
end
# Returns the path to an SDK or nil, following the rules set by #sdk.
def sdk_path(v = version)
s = sdk(v)
s.path unless s.nil?
end
def default_cc
cc = locate "cc"
cc.realpath.basename.to_s rescue nil

View File

@ -0,0 +1,59 @@
require "os/mac/version"
module OS
module Mac
class SDK
attr_reader :version, :path
def initialize(version, path)
@version = OS::Mac::Version.new version
@path = Pathname.new(path)
end
end
class SDKLocator
class NoSDKError < StandardError; end
def sdk_for(v)
path = sdk_paths[v]
raise NoSDKError if path.nil?
SDK.new v, path
end
def latest_sdk
return if sdk_paths.empty?
v, path = sdk_paths.max {|a, b| OS::Mac::Version.new(a[0]) <=> OS::Mac::Version.new(b[0])}
SDK.new v, path
end
private
def sdk_paths
@sdk_paths ||= begin
# Xcode.prefix is pretty smart, so let's look inside to find the sdk
sdk_prefix = "#{Xcode.prefix}/Platforms/MacOSX.platform/Developer/SDKs"
# Xcode < 4.3 style
sdk_prefix = "/Developer/SDKs" unless File.directory? sdk_prefix
# Finally query Xcode itself (this is slow, so check it last)
sdk_prefix = File.join(Utils.popen_read(OS::Mac.locate("xcrun"), "--show-sdk-platform-path").chomp, "Developer", "SDKs") unless File.directory? sdk_prefix
# Bail out if there is no SDK prefix at all
if !File.directory? sdk_prefix
{}
else
paths = {}
Dir[File.join(sdk_prefix, "MacOSX*.sdk")].each do |sdk_path|
version = sdk_path[/MacOSX(\d+\.\d+)u?.sdk$/, 1]
paths[version] = sdk_path unless version.nil?
end
paths
end
end
end
end
end
end