diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index c4916a9556..893eb6ddfb 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -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 diff --git a/Library/Homebrew/os/mac/sdk.rb b/Library/Homebrew/os/mac/sdk.rb new file mode 100644 index 0000000000..8ba5f43294 --- /dev/null +++ b/Library/Homebrew/os/mac/sdk.rb @@ -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