203 lines
5.5 KiB
Ruby
Raw Normal View History

2020-10-10 14:16:11 +02:00
# typed: true
# frozen_string_literal: true
require "os/mac/version"
module OS
module Mac
2020-08-25 00:33:34 +02:00
# Class representing a macOS SDK.
#
# @api private
class SDK
2021-09-29 15:12:53 -07:00
extend T::Sig
2021-03-03 04:00:58 +00:00
# 11.x SDKs are explicitly excluded - we want the MacOSX11.sdk symlink instead.
VERSIONED_SDK_REGEX = /MacOSX(10\.\d+|\d+)\.sdk$/.freeze
2021-09-29 15:12:53 -07:00
sig { returns(OS::Mac::Version) }
attr_reader :version
2021-09-29 15:12:53 -07:00
sig { returns(Pathname) }
attr_reader :path
sig { returns(Symbol) }
attr_reader :source
sig { params(version: OS::Mac::Version, path: T.any(String, Pathname), source: Symbol).void }
2020-04-07 16:43:32 +01:00
def initialize(version, path, source)
2020-10-05 14:46:43 +02:00
@version = version
@path = Pathname.new(path)
2020-04-07 16:43:32 +01:00
@source = source
end
end
2020-08-25 00:33:34 +02:00
# Base class for SDK locators.
#
# @api private
2018-06-12 14:55:31 -07:00
class BaseSDKLocator
2021-09-29 15:12:53 -07:00
extend T::Sig
extend T::Helpers
abstract!
class NoSDKError < StandardError; end
2021-09-29 15:12:53 -07:00
sig { params(v: OS::Mac::Version).returns(SDK) }
def sdk_for(v)
sdk = all_sdks.find { |s| s.version == v }
raise NoSDKError if sdk.nil?
sdk
end
2021-09-29 15:12:53 -07:00
sig { returns(T::Array[SDK]) }
2020-07-01 16:02:29 +01:00
def all_sdks
return @all_sdks if @all_sdks
@all_sdks = []
# Bail out if there is no SDK prefix at all
return @all_sdks unless File.directory? sdk_prefix
found_versions = Set.new
Dir["#{sdk_prefix}/MacOSX*.sdk"].each do |sdk_path|
next unless sdk_path.match?(SDK::VERSIONED_SDK_REGEX)
version = read_sdk_version(Pathname.new(sdk_path))
2021-03-03 04:00:58 +00:00
next if version.nil?
@all_sdks << SDK.new(version, sdk_path, source)
found_versions << version
end
# Use unversioned SDK only if we don't have one matching that version.
sdk_path = Pathname.new("#{sdk_prefix}/MacOSX.sdk")
if (version = read_sdk_version(sdk_path)) && found_versions.exclude?(version)
@all_sdks << SDK.new(version, sdk_path, source)
2021-03-03 04:00:58 +00:00
end
@all_sdks
2020-07-01 16:02:29 +01:00
end
2021-09-29 15:12:53 -07:00
sig { params(v: T.nilable(OS::Mac::Version)).returns(T.nilable(SDK)) }
def sdk_if_applicable(v = nil)
2018-07-27 15:44:22 -07:00
sdk = begin
if v.blank?
2020-12-26 01:06:12 +00:00
sdk_for OS::Mac.version
else
sdk_for v
end
2020-08-25 00:33:34 +02:00
rescue NoSDKError
2018-07-27 15:44:22 -07:00
latest_sdk
end
2020-11-30 12:58:38 +00:00
return if sdk.blank?
2020-12-26 01:06:12 +00:00
# On OSs lower than 11, whenever the major versions don't match,
# only return an SDK older than the OS version if it was specifically requested
2020-11-30 12:58:38 +00:00
return if v.blank? && sdk.version < OS::Mac.version
2018-09-17 02:45:00 +02:00
2018-07-27 15:44:22 -07:00
sdk
end
2021-09-29 15:12:53 -07:00
sig { abstract.returns(Symbol) }
def source; end
2020-04-07 16:43:32 +01:00
2020-07-01 16:02:29 +01:00
private
2021-09-29 15:12:53 -07:00
sig { abstract.returns(String) }
def sdk_prefix; end
2018-06-12 14:55:31 -07:00
2021-09-29 15:12:53 -07:00
sig { returns(T.nilable(SDK)) }
def latest_sdk
all_sdks.max_by(&:version)
end
2020-12-26 01:06:12 +00:00
2021-09-29 15:12:53 -07:00
sig { params(sdk_path: Pathname).returns(T.nilable(OS::Mac::Version)) }
def read_sdk_version(sdk_path)
sdk_settings = sdk_path/"SDKSettings.json"
sdk_settings_string = sdk_settings.read if sdk_settings.exist?
2020-12-26 01:06:12 +00:00
# Pre-10.14 SDKs
sdk_settings = sdk_path/"SDKSettings.plist"
if sdk_settings_string.blank? && sdk_settings.exist?
result = system_command("plutil", args: ["-convert", "json", "-o", "-", sdk_settings])
sdk_settings_string = result.stdout if result.success?
end
return if sdk_settings_string.blank?
sdk_settings_json = JSON.parse(sdk_settings_string)
return if sdk_settings_json.blank?
version_string = sdk_settings_json.fetch("Version", nil)
return if version_string.blank?
begin
OS::Mac::Version.new(version_string).strip_patch
rescue MacOSVersionError
nil
end
2020-12-26 01:06:12 +00:00
end
end
2020-08-25 00:33:34 +02:00
private_constant :BaseSDKLocator
2018-06-12 14:55:31 -07:00
2020-08-25 00:33:34 +02:00
# Helper class for locating the Xcode SDK.
#
# @api private
2018-06-12 14:55:31 -07:00
class XcodeSDKLocator < BaseSDKLocator
2020-10-20 12:03:48 +02:00
extend T::Sig
2021-09-29 15:12:53 -07:00
sig { override.returns(Symbol) }
2020-04-07 16:43:32 +01:00
def source
:xcode
end
2020-07-01 16:02:29 +01:00
private
2021-09-29 15:12:53 -07:00
sig { override.returns(String) }
2018-06-12 14:55:31 -07:00
def sdk_prefix
@sdk_prefix ||= begin
# Xcode.prefix is pretty smart, so let's look inside to find the sdk
sdk_prefix = "#{Xcode.prefix}/Platforms/MacOSX.platform/Developer/SDKs"
# Finally query Xcode itself (this is slow, so check it last)
2018-07-27 15:44:22 -07:00
sdk_platform_path = Utils.popen_read(DevelopmentTools.locate("xcrun"), "--show-sdk-platform-path").chomp
sdk_prefix = File.join(sdk_platform_path, "Developer", "SDKs") unless File.directory? sdk_prefix
2018-06-12 14:55:31 -07:00
sdk_prefix
end
end
end
2020-08-25 00:33:34 +02:00
# Helper class for locating the macOS Command Line Tools SDK.
#
# @api private
2018-06-12 14:55:31 -07:00
class CLTSDKLocator < BaseSDKLocator
2020-10-20 12:03:48 +02:00
extend T::Sig
2021-09-29 15:12:53 -07:00
sig { override.returns(Symbol) }
2020-04-07 16:43:32 +01:00
def source
:clt
end
2020-07-01 16:02:29 +01:00
private
2018-06-12 14:55:31 -07:00
# While CLT SDKs existed prior to Xcode 10, those packages also
# installed a traditional Unix-style header layout and we prefer
# using that.
2018-06-12 14:55:31 -07:00
# As of Xcode 10, the Unix-style headers are installed via a
# separate package, so we can't rely on their being present.
# This will only look up SDKs on Xcode 10 or newer, and still
# return nil SDKs for Xcode 9 and older.
2021-09-29 15:12:53 -07:00
sig { override.returns(String) }
2018-06-12 14:55:31 -07:00
def sdk_prefix
2021-03-26 14:11:03 +00:00
@sdk_prefix ||= if CLT.provides_sdk?
"#{CLT::PKG_PATH}/SDKs"
else
""
2018-06-12 14:55:31 -07:00
end
end
end
end
end