Move remaining OS extensions to prepend
This commit is contained in:
parent
7c4f2c19fe
commit
eed660e784
@ -177,7 +177,6 @@ class DevelopmentTools
|
|||||||
"cpu_family" => Hardware::CPU.family.to_s,
|
"cpu_family" => Hardware::CPU.family.to_s,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
alias generic_build_system_info build_system_info
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
5
Library/Homebrew/extend/os/linux/cleanup.rbi
Normal file
5
Library/Homebrew/extend/os/linux/cleanup.rbi
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# typed: strict
|
||||||
|
|
||||||
|
# module OS::Linux::Cleanup
|
||||||
|
# include Kernel
|
||||||
|
# end
|
@ -1,101 +1,103 @@
|
|||||||
# typed: true # rubocop:disable Sorbet/StrictSigil
|
# typed: strict
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "os/linux/glibc"
|
require "os/linux/glibc"
|
||||||
|
|
||||||
class DependencyCollector
|
module OS
|
||||||
undef gcc_dep_if_needed
|
module Linux
|
||||||
undef glibc_dep_if_needed
|
module DependencyCollector
|
||||||
undef init_global_dep_tree_if_needed!
|
sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
|
||||||
|
def gcc_dep_if_needed(related_formula_names)
|
||||||
|
# gcc is required for libgcc_s.so.1 if glibc or gcc are too old
|
||||||
|
return unless ::DevelopmentTools.needs_build_formulae?
|
||||||
|
return if building_global_dep_tree?
|
||||||
|
return if related_formula_names.include?(GCC)
|
||||||
|
return if global_dep_tree[GCC]&.intersect?(related_formula_names)
|
||||||
|
return unless formula_for(GCC)
|
||||||
|
|
||||||
sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
|
Dependency.new(GCC, [:implicit])
|
||||||
def gcc_dep_if_needed(related_formula_names)
|
end
|
||||||
# gcc is required for libgcc_s.so.1 if glibc or gcc are too old
|
|
||||||
return unless DevelopmentTools.needs_build_formulae?
|
|
||||||
return if building_global_dep_tree?
|
|
||||||
return if related_formula_names.include?(GCC)
|
|
||||||
return if global_dep_tree[GCC]&.intersect?(related_formula_names)
|
|
||||||
return unless formula_for(GCC)
|
|
||||||
|
|
||||||
Dependency.new(GCC, [:implicit])
|
sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
|
||||||
end
|
def glibc_dep_if_needed(related_formula_names)
|
||||||
|
return unless ::DevelopmentTools.needs_libc_formula?
|
||||||
|
return if building_global_dep_tree?
|
||||||
|
return if related_formula_names.include?(GLIBC)
|
||||||
|
return if global_dep_tree[GLIBC]&.intersect?(related_formula_names)
|
||||||
|
return unless formula_for(GLIBC)
|
||||||
|
|
||||||
sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
|
Dependency.new(GLIBC, [:implicit])
|
||||||
def glibc_dep_if_needed(related_formula_names)
|
end
|
||||||
return unless DevelopmentTools.needs_libc_formula?
|
|
||||||
return if building_global_dep_tree?
|
|
||||||
return if related_formula_names.include?(GLIBC)
|
|
||||||
return if global_dep_tree[GLIBC]&.intersect?(related_formula_names)
|
|
||||||
return unless formula_for(GLIBC)
|
|
||||||
|
|
||||||
Dependency.new(GLIBC, [:implicit])
|
private
|
||||||
end
|
|
||||||
|
|
||||||
private
|
GLIBC = "glibc"
|
||||||
|
GCC = OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA
|
||||||
|
|
||||||
GLIBC = "glibc"
|
sig { void }
|
||||||
GCC = OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA
|
def init_global_dep_tree_if_needed!
|
||||||
|
return unless ::DevelopmentTools.needs_build_formulae?
|
||||||
|
return if building_global_dep_tree?
|
||||||
|
return unless global_dep_tree.empty?
|
||||||
|
|
||||||
sig { void }
|
building_global_dep_tree!
|
||||||
def init_global_dep_tree_if_needed!
|
global_dep_tree[GLIBC] = Set.new(global_deps_for(GLIBC))
|
||||||
return unless DevelopmentTools.needs_build_formulae?
|
# gcc depends on glibc
|
||||||
return if building_global_dep_tree?
|
global_dep_tree[GCC] = Set.new([*global_deps_for(GCC), GLIBC, *@@global_dep_tree[GLIBC]])
|
||||||
return unless global_dep_tree.empty?
|
built_global_dep_tree!
|
||||||
|
end
|
||||||
|
|
||||||
building_global_dep_tree!
|
sig { params(name: String).returns(T.nilable(Formula)) }
|
||||||
global_dep_tree[GLIBC] = Set.new(global_deps_for(GLIBC))
|
def formula_for(name)
|
||||||
# gcc depends on glibc
|
@formula_for ||= T.let({}, T.nilable(T::Hash[String, Formula]))
|
||||||
global_dep_tree[GCC] = Set.new([*global_deps_for(GCC), GLIBC, *@@global_dep_tree[GLIBC]])
|
@formula_for[name] ||= ::Formula[name]
|
||||||
built_global_dep_tree!
|
rescue FormulaUnavailableError
|
||||||
end
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
sig { params(name: String).returns(T.nilable(Formula)) }
|
sig { params(name: String).returns(T::Array[String]) }
|
||||||
def formula_for(name)
|
def global_deps_for(name)
|
||||||
@formula_for ||= {}
|
@global_deps_for ||= T.let({}, T.nilable(T::Hash[String, T::Array[String]]))
|
||||||
@formula_for[name] ||= Formula[name]
|
# Always strip out glibc and gcc from all parts of dependency tree when
|
||||||
rescue FormulaUnavailableError
|
# we're calculating their dependency trees. Other parts of Homebrew will
|
||||||
nil
|
# catch any circular dependencies.
|
||||||
end
|
@global_deps_for[name] ||= if (formula = formula_for(name))
|
||||||
|
formula.deps.map(&:name).flat_map do |dep|
|
||||||
|
[dep, *global_deps_for(dep)].compact
|
||||||
|
end.uniq
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
sig { params(name: String).returns(T::Array[String]) }
|
# Use class variables to avoid this expensive logic needing to be done more
|
||||||
def global_deps_for(name)
|
# than once.
|
||||||
@global_deps_for ||= {}
|
# rubocop:disable Style/ClassVars
|
||||||
# Always strip out glibc and gcc from all parts of dependency tree when
|
@@global_dep_tree = T.let({}, T::Hash[String, T::Set[String]])
|
||||||
# we're calculating their dependency trees. Other parts of Homebrew will
|
@@building_global_dep_tree = T.let(false, T::Boolean)
|
||||||
# catch any circular dependencies.
|
|
||||||
@global_deps_for[name] ||= if (formula = formula_for(name))
|
sig { returns(T::Hash[String, T::Set[String]]) }
|
||||||
formula.deps.map(&:name).flat_map do |dep|
|
def global_dep_tree
|
||||||
[dep, *global_deps_for(dep)].compact
|
@@global_dep_tree
|
||||||
end.uniq
|
end
|
||||||
else
|
|
||||||
[]
|
sig { void }
|
||||||
|
def building_global_dep_tree!
|
||||||
|
@@building_global_dep_tree = true
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { void }
|
||||||
|
def built_global_dep_tree!
|
||||||
|
@@building_global_dep_tree = false
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
|
def building_global_dep_tree?
|
||||||
|
@@building_global_dep_tree.present?
|
||||||
|
end
|
||||||
|
# rubocop:enable Style/ClassVars
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Use class variables to avoid this expensive logic needing to be done more
|
|
||||||
# than once.
|
|
||||||
# rubocop:disable Style/ClassVars
|
|
||||||
@@global_dep_tree = {}
|
|
||||||
@@building_global_dep_tree = false
|
|
||||||
|
|
||||||
sig { returns(T::Hash[String, T::Set[String]]) }
|
|
||||||
def global_dep_tree
|
|
||||||
@@global_dep_tree
|
|
||||||
end
|
|
||||||
|
|
||||||
sig { void }
|
|
||||||
def building_global_dep_tree!
|
|
||||||
@@building_global_dep_tree = true
|
|
||||||
end
|
|
||||||
|
|
||||||
sig { void }
|
|
||||||
def built_global_dep_tree!
|
|
||||||
@@building_global_dep_tree = false
|
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
|
||||||
def building_global_dep_tree?
|
|
||||||
@@building_global_dep_tree.present?
|
|
||||||
end
|
|
||||||
# rubocop:enable Style/ClassVars
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
DependencyCollector.prepend(OS::Linux::DependencyCollector)
|
||||||
|
@ -1,54 +1,64 @@
|
|||||||
# typed: true # rubocop:todo Sorbet/StrictSigil
|
# typed: strict
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class DevelopmentTools
|
module OS
|
||||||
class << self
|
module Linux
|
||||||
sig { params(tool: T.any(String, Symbol)).returns(T.nilable(Pathname)) }
|
module DevelopmentTools
|
||||||
def locate(tool)
|
extend T::Helpers
|
||||||
(@locate ||= {}).fetch(tool) do |key|
|
|
||||||
@locate[key] = if needs_build_formulae? &&
|
requires_ancestor { ::DevelopmentTools }
|
||||||
(binutils_path = HOMEBREW_PREFIX/"opt/binutils/bin/#{tool}").executable?
|
|
||||||
binutils_path
|
sig { params(tool: T.any(String, Symbol)).returns(T.nilable(Pathname)) }
|
||||||
elsif needs_build_formulae? && (glibc_path = HOMEBREW_PREFIX/"opt/glibc/bin/#{tool}").executable?
|
def locate(tool)
|
||||||
glibc_path
|
@locate ||= T.let({}, T.nilable(T::Hash[T.any(String, Symbol), Pathname]))
|
||||||
elsif (homebrew_path = HOMEBREW_PREFIX/"bin/#{tool}").executable?
|
@locate.fetch(tool) do |key|
|
||||||
homebrew_path
|
@locate[key] = if ::DevelopmentTools.needs_build_formulae? &&
|
||||||
elsif File.executable?((system_path = "/usr/bin/#{tool}"))
|
(binutils_path = HOMEBREW_PREFIX/"opt/binutils/bin/#{tool}").executable?
|
||||||
Pathname.new system_path
|
binutils_path
|
||||||
|
elsif ::DevelopmentTools.needs_build_formulae? &&
|
||||||
|
(glibc_path = HOMEBREW_PREFIX/"opt/glibc/bin/#{tool}").executable?
|
||||||
|
glibc_path
|
||||||
|
elsif (homebrew_path = HOMEBREW_PREFIX/"bin/#{tool}").executable?
|
||||||
|
homebrew_path
|
||||||
|
elsif File.executable?((system_path = "/usr/bin/#{tool}"))
|
||||||
|
Pathname.new system_path
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(Symbol) }
|
sig { returns(Symbol) }
|
||||||
def default_compiler
|
def default_compiler = :gcc
|
||||||
:gcc
|
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def needs_libc_formula?
|
def needs_libc_formula?
|
||||||
return @needs_libc_formula if defined? @needs_libc_formula
|
return @needs_libc_formula unless @needs_libc_formula.nil?
|
||||||
|
|
||||||
@needs_libc_formula = OS::Linux::Glibc.below_ci_version?
|
@needs_libc_formula = T.let(OS::Linux::Glibc.below_ci_version?, T.nilable(T::Boolean))
|
||||||
end
|
@needs_libc_formula = !!@needs_libc_formula
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
|
||||||
def needs_compiler_formula?
|
|
||||||
return @needs_compiler_formula if defined? @needs_compiler_formula
|
|
||||||
|
|
||||||
gcc = "/usr/bin/gcc"
|
|
||||||
@needs_compiler_formula = if File.exist?(gcc)
|
|
||||||
gcc_version(gcc) < OS::LINUX_GCC_CI_VERSION
|
|
||||||
else
|
|
||||||
true
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(T::Hash[String, T.nilable(String)]) }
|
sig { returns(T::Boolean) }
|
||||||
def build_system_info
|
def needs_compiler_formula?
|
||||||
generic_build_system_info.merge({
|
return @needs_compiler_formula unless @needs_compiler_formula.nil?
|
||||||
"glibc_version" => OS::Linux::Glibc.version.to_s.presence,
|
|
||||||
"oldest_cpu_family" => Hardware.oldest_cpu.to_s,
|
gcc = "/usr/bin/gcc"
|
||||||
})
|
@needs_compiler_formula = T.let(if File.exist?(gcc)
|
||||||
|
::DevelopmentTools.gcc_version(gcc) < OS::LINUX_GCC_CI_VERSION
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end, T.nilable(T::Boolean))
|
||||||
|
!!@needs_compiler_formula
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Hash[String, T.nilable(String)]) }
|
||||||
|
def build_system_info
|
||||||
|
super.merge({
|
||||||
|
"glibc_version" => OS::Linux::Glibc.version.to_s.presence,
|
||||||
|
"oldest_cpu_family" => Hardware.oldest_cpu.to_s,
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
DevelopmentTools.singleton_class.prepend(OS::Linux::DevelopmentTools)
|
||||||
|
@ -7,168 +7,174 @@ require "hardware"
|
|||||||
require "os/linux/glibc"
|
require "os/linux/glibc"
|
||||||
require "os/linux/kernel"
|
require "os/linux/kernel"
|
||||||
|
|
||||||
module Homebrew
|
module OS
|
||||||
module Diagnostic
|
module Linux
|
||||||
class Checks
|
module Diagnostic
|
||||||
undef fatal_preinstall_checks, supported_configuration_checks
|
module Checks
|
||||||
|
extend T::Helpers
|
||||||
|
|
||||||
def fatal_preinstall_checks
|
requires_ancestor { Homebrew::Diagnostic::Checks }
|
||||||
%w[
|
|
||||||
check_access_directories
|
|
||||||
check_linuxbrew_core
|
|
||||||
check_linuxbrew_bottle_domain
|
|
||||||
].freeze
|
|
||||||
end
|
|
||||||
|
|
||||||
def supported_configuration_checks
|
def fatal_preinstall_checks
|
||||||
%w[
|
%w[
|
||||||
check_glibc_minimum_version
|
check_access_directories
|
||||||
check_kernel_minimum_version
|
check_linuxbrew_core
|
||||||
check_supported_architecture
|
check_linuxbrew_bottle_domain
|
||||||
].freeze
|
].freeze
|
||||||
end
|
|
||||||
|
|
||||||
def check_tmpdir_sticky_bit
|
|
||||||
message = generic_check_tmpdir_sticky_bit
|
|
||||||
return if message.nil?
|
|
||||||
|
|
||||||
message + <<~EOS
|
|
||||||
If you don't have administrative privileges on this machine,
|
|
||||||
create a directory and set the HOMEBREW_TEMP environment variable,
|
|
||||||
for example:
|
|
||||||
install -d -m 1755 ~/tmp
|
|
||||||
#{Utils::Shell.set_variable_in_profile("HOMEBREW_TEMP", "~/tmp")}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_tmpdir_executable
|
|
||||||
f = Tempfile.new(%w[homebrew_check_tmpdir_executable .sh], HOMEBREW_TEMP)
|
|
||||||
f.write "#!/bin/sh\n"
|
|
||||||
f.chmod 0700
|
|
||||||
f.close
|
|
||||||
return if system T.must(f.path)
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
The directory #{HOMEBREW_TEMP} does not permit executing
|
|
||||||
programs. It is likely mounted as "noexec". Please set HOMEBREW_TEMP
|
|
||||||
in your #{Utils::Shell.profile} to a different directory, for example:
|
|
||||||
export HOMEBREW_TEMP=~/tmp
|
|
||||||
echo 'export HOMEBREW_TEMP=~/tmp' >> #{Utils::Shell.profile}
|
|
||||||
EOS
|
|
||||||
ensure
|
|
||||||
f&.unlink
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_xdg_data_dirs
|
|
||||||
xdg_data_dirs = ENV.fetch("HOMEBREW_XDG_DATA_DIRS", nil)
|
|
||||||
return if xdg_data_dirs.blank?
|
|
||||||
return if xdg_data_dirs.split(":").include?("#{HOMEBREW_PREFIX}/share")
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Homebrew's share was not found in your XDG_DATA_DIRS but you have
|
|
||||||
this variable set to include other locations.
|
|
||||||
Some programs like `vapigen` may not work correctly.
|
|
||||||
Consider adding Homebrew's share directory to XDG_DATA_DIRS like so:
|
|
||||||
echo 'export XDG_DATA_DIRS="#{HOMEBREW_PREFIX}/share:$XDG_DATA_DIRS"' >> #{Utils::Shell.profile}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_umask_not_zero
|
|
||||||
return unless File.umask.zero?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
umask is currently set to 000. Directories created by Homebrew cannot
|
|
||||||
be world-writable. This issue can be resolved by adding "umask 002" to
|
|
||||||
your #{Utils::Shell.profile}:
|
|
||||||
echo 'umask 002' >> #{Utils::Shell.profile}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_supported_architecture
|
|
||||||
return if Hardware::CPU.arch == :x86_64
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Your CPU architecture (#{Hardware::CPU.arch}) is not supported. We only support
|
|
||||||
x86_64 CPU architectures. You will be unable to use binary packages (bottles).
|
|
||||||
#{please_create_pull_requests}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_glibc_minimum_version
|
|
||||||
return unless OS::Linux::Glibc.below_minimum_version?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Your system glibc #{OS::Linux::Glibc.system_version} is too old.
|
|
||||||
We only support glibc #{OS::Linux::Glibc.minimum_version} or later.
|
|
||||||
#{please_create_pull_requests}
|
|
||||||
We recommend updating to a newer version via your distribution's
|
|
||||||
package manager, upgrading your distribution to the latest version,
|
|
||||||
or changing distributions.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_kernel_minimum_version
|
|
||||||
return unless OS::Linux::Kernel.below_minimum_version?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Your Linux kernel #{OS.kernel_version} is too old.
|
|
||||||
We only support kernel #{OS::Linux::Kernel.minimum_version} or later.
|
|
||||||
You will be unable to use binary packages (bottles).
|
|
||||||
#{please_create_pull_requests}
|
|
||||||
We recommend updating to a newer version via your distribution's
|
|
||||||
package manager, upgrading your distribution to the latest version,
|
|
||||||
or changing distributions.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_linuxbrew_core
|
|
||||||
return unless Homebrew::EnvConfig.no_install_from_api?
|
|
||||||
return unless CoreTap.instance.linuxbrew_core?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Your Linux core repository is still linuxbrew-core.
|
|
||||||
You must `brew update` to update to homebrew-core.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_linuxbrew_bottle_domain
|
|
||||||
return unless Homebrew::EnvConfig.bottle_domain.include?("linuxbrew")
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Your HOMEBREW_BOTTLE_DOMAIN still contains "linuxbrew".
|
|
||||||
You must unset it (or adjust it to not contain linuxbrew
|
|
||||||
e.g. by using homebrew instead).
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_gcc_dependent_linkage
|
|
||||||
gcc_dependents = Formula.installed.select do |formula|
|
|
||||||
next false unless formula.tap&.core_tap?
|
|
||||||
|
|
||||||
# FIXME: This includes formulae that have no runtime dependency on GCC.
|
|
||||||
formula.recursive_dependencies.map(&:name).include? "gcc"
|
|
||||||
rescue TapFormulaUnavailableError
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
return if gcc_dependents.empty?
|
|
||||||
|
|
||||||
badly_linked = gcc_dependents.select do |dependent|
|
def supported_configuration_checks
|
||||||
keg = Keg.new(dependent.prefix)
|
%w[
|
||||||
keg.binary_executable_or_library_files.any? do |binary|
|
check_glibc_minimum_version
|
||||||
paths = binary.rpaths
|
check_kernel_minimum_version
|
||||||
versioned_linkage = paths.any? { |path| path.match?(%r{lib/gcc/\d+$}) }
|
check_supported_architecture
|
||||||
unversioned_linkage = paths.any? { |path| path.match?(%r{lib/gcc/current$}) }
|
].freeze
|
||||||
|
end
|
||||||
|
|
||||||
versioned_linkage && !unversioned_linkage
|
def check_tmpdir_sticky_bit
|
||||||
|
message = generic_check_tmpdir_sticky_bit
|
||||||
|
return if message.nil?
|
||||||
|
|
||||||
|
message + <<~EOS
|
||||||
|
If you don't have administrative privileges on this machine,
|
||||||
|
create a directory and set the HOMEBREW_TEMP environment variable,
|
||||||
|
for example:
|
||||||
|
install -d -m 1755 ~/tmp
|
||||||
|
#{Utils::Shell.set_variable_in_profile("HOMEBREW_TEMP", "~/tmp")}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_tmpdir_executable
|
||||||
|
f = Tempfile.new(%w[homebrew_check_tmpdir_executable .sh], HOMEBREW_TEMP)
|
||||||
|
f.write "#!/bin/sh\n"
|
||||||
|
f.chmod 0700
|
||||||
|
f.close
|
||||||
|
return if system T.must(f.path)
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
The directory #{HOMEBREW_TEMP} does not permit executing
|
||||||
|
programs. It is likely mounted as "noexec". Please set HOMEBREW_TEMP
|
||||||
|
in your #{Utils::Shell.profile} to a different directory, for example:
|
||||||
|
export HOMEBREW_TEMP=~/tmp
|
||||||
|
echo 'export HOMEBREW_TEMP=~/tmp' >> #{Utils::Shell.profile}
|
||||||
|
EOS
|
||||||
|
ensure
|
||||||
|
f&.unlink
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_xdg_data_dirs
|
||||||
|
xdg_data_dirs = ENV.fetch("HOMEBREW_XDG_DATA_DIRS", nil)
|
||||||
|
return if xdg_data_dirs.blank?
|
||||||
|
return if xdg_data_dirs.split(":").include?("#{HOMEBREW_PREFIX}/share")
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Homebrew's share was not found in your XDG_DATA_DIRS but you have
|
||||||
|
this variable set to include other locations.
|
||||||
|
Some programs like `vapigen` may not work correctly.
|
||||||
|
Consider adding Homebrew's share directory to XDG_DATA_DIRS like so:
|
||||||
|
echo 'export XDG_DATA_DIRS="#{HOMEBREW_PREFIX}/share:$XDG_DATA_DIRS"' >> #{Utils::Shell.profile}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_umask_not_zero
|
||||||
|
return unless File.umask.zero?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
umask is currently set to 000. Directories created by Homebrew cannot
|
||||||
|
be world-writable. This issue can be resolved by adding "umask 002" to
|
||||||
|
your #{Utils::Shell.profile}:
|
||||||
|
echo 'umask 002' >> #{Utils::Shell.profile}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_supported_architecture
|
||||||
|
return if Hardware::CPU.arch == :x86_64
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Your CPU architecture (#{Hardware::CPU.arch}) is not supported. We only support
|
||||||
|
x86_64 CPU architectures. You will be unable to use binary packages (bottles).
|
||||||
|
#{please_create_pull_requests}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_glibc_minimum_version
|
||||||
|
return unless OS::Linux::Glibc.below_minimum_version?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Your system glibc #{OS::Linux::Glibc.system_version} is too old.
|
||||||
|
We only support glibc #{OS::Linux::Glibc.minimum_version} or later.
|
||||||
|
#{please_create_pull_requests}
|
||||||
|
We recommend updating to a newer version via your distribution's
|
||||||
|
package manager, upgrading your distribution to the latest version,
|
||||||
|
or changing distributions.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_kernel_minimum_version
|
||||||
|
return unless OS::Linux::Kernel.below_minimum_version?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Your Linux kernel #{OS.kernel_version} is too old.
|
||||||
|
We only support kernel #{OS::Linux::Kernel.minimum_version} or later.
|
||||||
|
You will be unable to use binary packages (bottles).
|
||||||
|
#{please_create_pull_requests}
|
||||||
|
We recommend updating to a newer version via your distribution's
|
||||||
|
package manager, upgrading your distribution to the latest version,
|
||||||
|
or changing distributions.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_linuxbrew_core
|
||||||
|
return unless Homebrew::EnvConfig.no_install_from_api?
|
||||||
|
return unless CoreTap.instance.linuxbrew_core?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Your Linux core repository is still linuxbrew-core.
|
||||||
|
You must `brew update` to update to homebrew-core.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_linuxbrew_bottle_domain
|
||||||
|
return unless Homebrew::EnvConfig.bottle_domain.include?("linuxbrew")
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Your HOMEBREW_BOTTLE_DOMAIN still contains "linuxbrew".
|
||||||
|
You must unset it (or adjust it to not contain linuxbrew
|
||||||
|
e.g. by using homebrew instead).
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_gcc_dependent_linkage
|
||||||
|
gcc_dependents = ::Formula.installed.select do |formula|
|
||||||
|
next false unless formula.tap&.core_tap?
|
||||||
|
|
||||||
|
# FIXME: This includes formulae that have no runtime dependency on GCC.
|
||||||
|
formula.recursive_dependencies.map(&:name).include? "gcc"
|
||||||
|
rescue TapFormulaUnavailableError
|
||||||
|
false
|
||||||
end
|
end
|
||||||
end
|
return if gcc_dependents.empty?
|
||||||
return if badly_linked.empty?
|
|
||||||
|
|
||||||
inject_file_list badly_linked, <<~EOS
|
badly_linked = gcc_dependents.select do |dependent|
|
||||||
Formulae which link to GCC through a versioned path were found. These formulae
|
keg = Keg.new(dependent.prefix)
|
||||||
are prone to breaking when GCC is updated. You should `brew reinstall` these formulae:
|
keg.binary_executable_or_library_files.any? do |binary|
|
||||||
EOS
|
paths = binary.rpaths
|
||||||
|
versioned_linkage = paths.any? { |path| path.match?(%r{lib/gcc/\d+$}) }
|
||||||
|
unversioned_linkage = paths.any? { |path| path.match?(%r{lib/gcc/current$}) }
|
||||||
|
|
||||||
|
versioned_linkage && !unversioned_linkage
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return if badly_linked.empty?
|
||||||
|
|
||||||
|
inject_file_list badly_linked, <<~EOS
|
||||||
|
Formulae which link to GCC through a versioned path were found. These formulae
|
||||||
|
are prone to breaking when GCC is updated. You should `brew reinstall` these formulae:
|
||||||
|
EOS
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Homebrew::Diagnostic::Checks.prepend(OS::Linux::Diagnostic::Checks)
|
||||||
|
@ -28,7 +28,7 @@ module OS
|
|||||||
|
|
||||||
sig { params(spec: SoftwareSpec).void }
|
sig { params(spec: SoftwareSpec).void }
|
||||||
def add_global_deps_to_spec(spec)
|
def add_global_deps_to_spec(spec)
|
||||||
return unless DevelopmentTools.needs_build_formulae?
|
return unless ::DevelopmentTools.needs_build_formulae?
|
||||||
|
|
||||||
@global_deps ||= begin
|
@global_deps ||= begin
|
||||||
dependency_collector = spec.dependency_collector
|
dependency_collector = spec.dependency_collector
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
# typed: true # rubocop:disable Sorbet/StrictSigil
|
# typed: strict
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Homebrew
|
module OS
|
||||||
class SimulateSystem
|
module Linux
|
||||||
class << self
|
module SimulateSystem
|
||||||
undef os
|
|
||||||
undef simulating_or_running_on_linux?
|
|
||||||
undef current_os
|
|
||||||
|
|
||||||
sig { returns(T.nilable(Symbol)) }
|
sig { returns(T.nilable(Symbol)) }
|
||||||
def os
|
def os
|
||||||
|
@os ||= T.let(nil, T.nilable(Symbol))
|
||||||
return :macos if @os.blank? && Homebrew::EnvConfig.simulate_macos_on_linux?
|
return :macos if @os.blank? && Homebrew::EnvConfig.simulate_macos_on_linux?
|
||||||
|
|
||||||
@os
|
@os
|
||||||
@ -27,3 +24,5 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Homebrew::SimulateSystem.singleton_class.prepend(OS::Linux::SimulateSystem)
|
||||||
|
@ -8,7 +8,7 @@ module OS
|
|||||||
def use_system_ruby?
|
def use_system_ruby?
|
||||||
return false if Homebrew::EnvConfig.force_vendor_ruby?
|
return false if Homebrew::EnvConfig.force_vendor_ruby?
|
||||||
|
|
||||||
Homebrew::EnvConfig.developer? && ENV["HOMEBREW_USE_RUBY_FROM_PATH"].present?
|
::Homebrew::EnvConfig.developer? && ENV["HOMEBREW_USE_RUBY_FROM_PATH"].present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
# typed: true # rubocop:disable Sorbet/StrictSigil
|
# typed: true # rubocop:disable Sorbet/StrictSigil
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class DependencyCollector
|
module OS
|
||||||
undef git_dep_if_needed, subversion_dep_if_needed, cvs_dep_if_needed,
|
module Mac
|
||||||
xz_dep_if_needed, unzip_dep_if_needed, bzip2_dep_if_needed
|
module DependencyCollector
|
||||||
|
def git_dep_if_needed(tags); end
|
||||||
|
|
||||||
def git_dep_if_needed(tags); end
|
def subversion_dep_if_needed(tags)
|
||||||
|
Dependency.new("subversion", [*tags, :implicit])
|
||||||
|
end
|
||||||
|
|
||||||
def subversion_dep_if_needed(tags)
|
def cvs_dep_if_needed(tags)
|
||||||
Dependency.new("subversion", [*tags, :implicit])
|
Dependency.new("cvs", [*tags, :implicit])
|
||||||
|
end
|
||||||
|
|
||||||
|
def xz_dep_if_needed(tags); end
|
||||||
|
|
||||||
|
def unzip_dep_if_needed(tags); end
|
||||||
|
|
||||||
|
def bzip2_dep_if_needed(tags); end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def cvs_dep_if_needed(tags)
|
|
||||||
Dependency.new("cvs", [*tags, :implicit])
|
|
||||||
end
|
|
||||||
|
|
||||||
def xz_dep_if_needed(tags); end
|
|
||||||
|
|
||||||
def unzip_dep_if_needed(tags); end
|
|
||||||
|
|
||||||
def bzip2_dep_if_needed(tags); end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
DependencyCollector.prepend(OS::Mac::DependencyCollector)
|
||||||
|
@ -1,86 +1,91 @@
|
|||||||
# typed: true # rubocop:disable Sorbet/StrictSigil
|
# typed: strict
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "os/mac/xcode"
|
require "os/mac/xcode"
|
||||||
|
|
||||||
class DevelopmentTools
|
module OS
|
||||||
class << self
|
module Mac
|
||||||
alias generic_locate locate
|
module DevelopmentTools
|
||||||
undef installed?, default_compiler, curl_handles_most_https_certificates?,
|
extend T::Helpers
|
||||||
subversion_handles_most_https_certificates?
|
|
||||||
|
|
||||||
sig { params(tool: T.any(String, Symbol)).returns(T.nilable(Pathname)) }
|
requires_ancestor { ::DevelopmentTools }
|
||||||
def locate(tool)
|
|
||||||
(@locate ||= {}).fetch(tool) do |key|
|
sig { params(tool: T.any(String, Symbol)).returns(T.nilable(Pathname)) }
|
||||||
@locate[key] = if (located_tool = generic_locate(tool))
|
def locate(tool)
|
||||||
located_tool
|
@locate ||= T.let({}, T.nilable(T::Hash[T.any(String, Symbol), Pathname]))
|
||||||
else
|
@locate.fetch(tool) do |key|
|
||||||
path = Utils.popen_read("/usr/bin/xcrun", "-no-cache", "-find", tool, err: :close).chomp
|
@locate[key] = if (located_tool = super(tool))
|
||||||
Pathname.new(path) if File.executable?(path)
|
located_tool
|
||||||
|
else
|
||||||
|
path = Utils.popen_read("/usr/bin/xcrun", "-no-cache", "-find", tool, err: :close).chomp
|
||||||
|
Pathname.new(path) if File.executable?(path)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# Checks if the user has any developer tools installed, either via Xcode
|
# Checks if the user has any developer tools installed, either via Xcode
|
||||||
# or the CLT. Convenient for guarding against formula builds when building
|
# or the CLT. Convenient for guarding against formula builds when building
|
||||||
# is impossible.
|
# is impossible.
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def installed?
|
def installed?
|
||||||
MacOS::Xcode.installed? || MacOS::CLT.installed?
|
MacOS::Xcode.installed? || MacOS::CLT.installed?
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(Symbol) }
|
|
||||||
def default_compiler
|
|
||||||
:clang
|
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(Version) }
|
|
||||||
def ld64_version
|
|
||||||
@ld64_version ||= begin
|
|
||||||
json = Utils.popen_read("/usr/bin/ld", "-version_details")
|
|
||||||
if $CHILD_STATUS.success?
|
|
||||||
Version.parse(JSON.parse(json)["version"])
|
|
||||||
else
|
|
||||||
Version::NULL
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(Symbol) }
|
||||||
def curl_handles_most_https_certificates?
|
def default_compiler
|
||||||
# The system Curl is too old for some modern HTTPS certificates on
|
:clang
|
||||||
# older macOS versions.
|
end
|
||||||
ENV["HOMEBREW_SYSTEM_CURL_TOO_OLD"].nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(Version) }
|
||||||
def subversion_handles_most_https_certificates?
|
def self.ld64_version
|
||||||
# The system Subversion is too old for some HTTPS certificates on
|
@ld64_version ||= T.let(begin
|
||||||
# older macOS versions.
|
json = Utils.popen_read("/usr/bin/ld", "-version_details")
|
||||||
MacOS.version >= :sierra
|
if $CHILD_STATUS.success?
|
||||||
end
|
Version.parse(JSON.parse(json)["version"])
|
||||||
|
else
|
||||||
|
Version::NULL
|
||||||
|
end
|
||||||
|
end, T.nilable(Version))
|
||||||
|
end
|
||||||
|
|
||||||
sig { returns(String) }
|
sig { returns(T::Boolean) }
|
||||||
def installation_instructions
|
def curl_handles_most_https_certificates?
|
||||||
MacOS::CLT.installation_instructions
|
# The system Curl is too old for some modern HTTPS certificates on
|
||||||
end
|
# older macOS versions.
|
||||||
|
ENV["HOMEBREW_SYSTEM_CURL_TOO_OLD"].nil?
|
||||||
|
end
|
||||||
|
|
||||||
sig { returns(String) }
|
sig { returns(T::Boolean) }
|
||||||
def custom_installation_instructions
|
def subversion_handles_most_https_certificates?
|
||||||
<<~EOS
|
# The system Subversion is too old for some HTTPS certificates on
|
||||||
Install GNU's GCC:
|
# older macOS versions.
|
||||||
brew install gcc
|
MacOS.version >= :sierra
|
||||||
EOS
|
end
|
||||||
end
|
|
||||||
|
|
||||||
sig { returns(T::Hash[String, T.nilable(String)]) }
|
sig { returns(String) }
|
||||||
def build_system_info
|
def installation_instructions
|
||||||
build_info = {
|
MacOS::CLT.installation_instructions
|
||||||
"xcode" => MacOS::Xcode.version.to_s.presence,
|
end
|
||||||
"clt" => MacOS::CLT.version.to_s.presence,
|
|
||||||
"preferred_perl" => MacOS.preferred_perl_version,
|
sig { returns(String) }
|
||||||
}
|
def custom_installation_instructions
|
||||||
generic_build_system_info.merge build_info
|
<<~EOS
|
||||||
|
Install GNU's GCC:
|
||||||
|
brew install gcc
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Hash[String, T.nilable(String)]) }
|
||||||
|
def build_system_info
|
||||||
|
build_info = {
|
||||||
|
"xcode" => MacOS::Xcode.version.to_s.presence,
|
||||||
|
"clt" => MacOS::CLT.version.to_s.presence,
|
||||||
|
"preferred_perl" => MacOS.preferred_perl_version,
|
||||||
|
}
|
||||||
|
super.merge build_info
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
DevelopmentTools.singleton_class.prepend(OS::Mac::DevelopmentTools)
|
||||||
|
@ -1,467 +1,471 @@
|
|||||||
# typed: true # rubocop:disable Sorbet/StrictSigil
|
# typed: true # rubocop:disable Sorbet/StrictSigil
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Homebrew
|
module OS
|
||||||
module Diagnostic
|
module Mac
|
||||||
class Volumes
|
module Diagnostic
|
||||||
def initialize
|
class Volumes
|
||||||
@volumes = get_mounts
|
def initialize
|
||||||
end
|
@volumes = get_mounts
|
||||||
|
end
|
||||||
|
|
||||||
def which(path)
|
def which(path)
|
||||||
vols = get_mounts path
|
vols = get_mounts path
|
||||||
|
|
||||||
# no volume found
|
# no volume found
|
||||||
return -1 if vols.empty?
|
return -1 if vols.empty?
|
||||||
|
|
||||||
vol_index = @volumes.index(vols[0])
|
vol_index = @volumes.index(vols[0])
|
||||||
# volume not found in volume list
|
# volume not found in volume list
|
||||||
return -1 if vol_index.nil?
|
return -1 if vol_index.nil?
|
||||||
|
|
||||||
vol_index
|
vol_index
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_mounts(path = nil)
|
def get_mounts(path = nil)
|
||||||
vols = []
|
vols = []
|
||||||
# get the volume of path, if path is nil returns all volumes
|
# get the volume of path, if path is nil returns all volumes
|
||||||
|
|
||||||
args = %w[/bin/df -P]
|
args = %w[/bin/df -P]
|
||||||
args << path if path
|
args << path if path
|
||||||
|
|
||||||
Utils.popen_read(*args) do |io|
|
Utils.popen_read(*args) do |io|
|
||||||
io.each_line do |line|
|
io.each_line do |line|
|
||||||
case line.chomp
|
case line.chomp
|
||||||
# regex matches: /dev/disk0s2 489562928 440803616 48247312 91% /
|
# regex matches: /dev/disk0s2 489562928 440803616 48247312 91% /
|
||||||
when /^.+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+[0-9]{1,3}%\s+(.+)/
|
when /^.+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+[0-9]{1,3}%\s+(.+)/
|
||||||
vols << Regexp.last_match(1)
|
vols << Regexp.last_match(1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
vols
|
||||||
end
|
end
|
||||||
vols
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Checks
|
|
||||||
undef fatal_preinstall_checks, fatal_build_from_source_checks,
|
|
||||||
fatal_setup_build_environment_checks, supported_configuration_checks,
|
|
||||||
build_from_source_checks
|
|
||||||
|
|
||||||
def fatal_preinstall_checks
|
|
||||||
checks = %w[
|
|
||||||
check_access_directories
|
|
||||||
]
|
|
||||||
|
|
||||||
# We need the developer tools for `codesign`.
|
|
||||||
checks << "check_for_installed_developer_tools" if Hardware::CPU.arm?
|
|
||||||
|
|
||||||
checks.freeze
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fatal_build_from_source_checks
|
module Checks
|
||||||
%w[
|
extend T::Helpers
|
||||||
check_xcode_license_approved
|
|
||||||
check_xcode_minimum_version
|
|
||||||
check_clt_minimum_version
|
|
||||||
check_if_xcode_needs_clt_installed
|
|
||||||
check_if_supported_sdk_available
|
|
||||||
check_broken_sdks
|
|
||||||
].freeze
|
|
||||||
end
|
|
||||||
|
|
||||||
def fatal_setup_build_environment_checks
|
requires_ancestor { Homebrew::Diagnostic::Checks }
|
||||||
%w[
|
|
||||||
check_xcode_minimum_version
|
|
||||||
check_clt_minimum_version
|
|
||||||
check_if_supported_sdk_available
|
|
||||||
].freeze
|
|
||||||
end
|
|
||||||
|
|
||||||
def supported_configuration_checks
|
def fatal_preinstall_checks
|
||||||
%w[
|
checks = %w[
|
||||||
check_for_unsupported_macos
|
check_access_directories
|
||||||
].freeze
|
]
|
||||||
end
|
|
||||||
|
|
||||||
def build_from_source_checks
|
# We need the developer tools for `codesign`.
|
||||||
%w[
|
checks << "check_for_installed_developer_tools" if ::Hardware::CPU.arm?
|
||||||
check_for_installed_developer_tools
|
|
||||||
check_xcode_up_to_date
|
|
||||||
check_clt_up_to_date
|
|
||||||
].freeze
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_non_prefixed_findutils
|
checks.freeze
|
||||||
findutils = Formula["findutils"]
|
|
||||||
return unless findutils.any_version_installed?
|
|
||||||
|
|
||||||
gnubin = %W[#{findutils.opt_libexec}/gnubin #{findutils.libexec}/gnubin]
|
|
||||||
default_names = Tab.for_name("findutils").with? "default-names"
|
|
||||||
return if !default_names && !paths.intersect?(gnubin)
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Putting non-prefixed findutils in your path can cause python builds to fail.
|
|
||||||
EOS
|
|
||||||
rescue FormulaUnavailableError
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_unsupported_macos
|
|
||||||
return if Homebrew::EnvConfig.developer?
|
|
||||||
return if ENV["HOMEBREW_INTEGRATION_TEST"]
|
|
||||||
|
|
||||||
who = +"We"
|
|
||||||
what = if OS::Mac.version.prerelease?
|
|
||||||
"pre-release version"
|
|
||||||
elsif OS::Mac.version.outdated_release?
|
|
||||||
who << " (and Apple)"
|
|
||||||
"old version"
|
|
||||||
end
|
end
|
||||||
return if what.blank?
|
|
||||||
|
|
||||||
who.freeze
|
def fatal_build_from_source_checks
|
||||||
|
%w[
|
||||||
|
check_xcode_license_approved
|
||||||
|
check_xcode_minimum_version
|
||||||
|
check_clt_minimum_version
|
||||||
|
check_if_xcode_needs_clt_installed
|
||||||
|
check_if_supported_sdk_available
|
||||||
|
check_broken_sdks
|
||||||
|
].freeze
|
||||||
|
end
|
||||||
|
|
||||||
<<~EOS
|
def fatal_setup_build_environment_checks
|
||||||
You are using macOS #{MacOS.version}.
|
%w[
|
||||||
#{who} do not provide support for this #{what}.
|
check_xcode_minimum_version
|
||||||
#{please_create_pull_requests(what)}
|
check_clt_minimum_version
|
||||||
EOS
|
check_if_supported_sdk_available
|
||||||
end
|
].freeze
|
||||||
|
end
|
||||||
|
|
||||||
def check_xcode_up_to_date
|
def supported_configuration_checks
|
||||||
return unless MacOS::Xcode.outdated?
|
%w[
|
||||||
|
check_for_unsupported_macos
|
||||||
|
].freeze
|
||||||
|
end
|
||||||
|
|
||||||
# avoid duplicate very similar messages
|
def build_from_source_checks
|
||||||
return if MacOS::Xcode.below_minimum_version?
|
%w[
|
||||||
|
check_for_installed_developer_tools
|
||||||
|
check_xcode_up_to_date
|
||||||
|
check_clt_up_to_date
|
||||||
|
].freeze
|
||||||
|
end
|
||||||
|
|
||||||
# CI images are going to end up outdated so don't complain when
|
def check_for_non_prefixed_findutils
|
||||||
# `brew test-bot` runs `brew doctor` in the CI for the Homebrew/brew
|
findutils = ::Formula["findutils"]
|
||||||
# repository. This only needs to support whatever CI providers
|
return unless findutils.any_version_installed?
|
||||||
# Homebrew/brew is currently using.
|
|
||||||
return if GitHub::Actions.env_set?
|
|
||||||
|
|
||||||
# With fake El Capitan for Portable Ruby, we are intentionally not using Xcode 8.
|
gnubin = %W[#{findutils.opt_libexec}/gnubin #{findutils.libexec}/gnubin]
|
||||||
# This is because we are not using the CLT and Xcode 8 has the 10.12 SDK.
|
default_names = Tab.for_name("findutils").with? "default-names"
|
||||||
return if ENV["HOMEBREW_FAKE_MACOS"]
|
return if !default_names && !paths.intersect?(gnubin)
|
||||||
|
|
||||||
message = <<~EOS
|
<<~EOS
|
||||||
Your Xcode (#{MacOS::Xcode.version}) is outdated.
|
Putting non-prefixed findutils in your path can cause python builds to fail.
|
||||||
Please update to Xcode #{MacOS::Xcode.latest_version} (or delete it).
|
EOS
|
||||||
#{MacOS::Xcode.update_instructions}
|
rescue FormulaUnavailableError
|
||||||
EOS
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
if OS::Mac.version.prerelease?
|
def check_for_unsupported_macos
|
||||||
current_path = Utils.popen_read("/usr/bin/xcode-select", "-p")
|
return if Homebrew::EnvConfig.developer?
|
||||||
message += <<~EOS
|
return if ENV["HOMEBREW_INTEGRATION_TEST"]
|
||||||
If #{MacOS::Xcode.latest_version} is installed, you may need to:
|
|
||||||
sudo xcode-select --switch /Applications/Xcode.app
|
who = +"We"
|
||||||
Current developer directory is:
|
what = if OS::Mac.version.prerelease?
|
||||||
#{current_path}
|
"pre-release version"
|
||||||
|
elsif OS::Mac.version.outdated_release?
|
||||||
|
who << " (and Apple)"
|
||||||
|
"old version"
|
||||||
|
end
|
||||||
|
return if what.blank?
|
||||||
|
|
||||||
|
who.freeze
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
You are using macOS #{MacOS.version}.
|
||||||
|
#{who} do not provide support for this #{what}.
|
||||||
|
#{please_create_pull_requests(what)}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
message
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_clt_up_to_date
|
def check_xcode_up_to_date
|
||||||
return unless MacOS::CLT.outdated?
|
return unless MacOS::Xcode.outdated?
|
||||||
|
|
||||||
# avoid duplicate very similar messages
|
# avoid duplicate very similar messages
|
||||||
return if MacOS::CLT.below_minimum_version?
|
return if MacOS::Xcode.below_minimum_version?
|
||||||
|
|
||||||
# CI images are going to end up outdated so don't complain when
|
# CI images are going to end up outdated so don't complain when
|
||||||
# `brew test-bot` runs `brew doctor` in the CI for the Homebrew/brew
|
# `brew test-bot` runs `brew doctor` in the CI for the Homebrew/brew
|
||||||
# repository. This only needs to support whatever CI providers
|
# repository. This only needs to support whatever CI providers
|
||||||
# Homebrew/brew is currently using.
|
# Homebrew/brew is currently using.
|
||||||
return if GitHub::Actions.env_set?
|
return if GitHub::Actions.env_set?
|
||||||
|
|
||||||
<<~EOS
|
# With fake El Capitan for Portable Ruby, we are intentionally not using Xcode 8.
|
||||||
A newer Command Line Tools release is available.
|
# This is because we are not using the CLT and Xcode 8 has the 10.12 SDK.
|
||||||
#{MacOS::CLT.update_instructions}
|
return if ENV["HOMEBREW_FAKE_MACOS"]
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_xcode_minimum_version
|
message = <<~EOS
|
||||||
return unless MacOS::Xcode.below_minimum_version?
|
Your Xcode (#{MacOS::Xcode.version}) is outdated.
|
||||||
|
Please update to Xcode #{MacOS::Xcode.latest_version} (or delete it).
|
||||||
|
#{MacOS::Xcode.update_instructions}
|
||||||
|
EOS
|
||||||
|
|
||||||
xcode = MacOS::Xcode.version.to_s
|
if OS::Mac.version.prerelease?
|
||||||
xcode += " => #{MacOS::Xcode.prefix}" unless MacOS::Xcode.default_prefix?
|
current_path = Utils.popen_read("/usr/bin/xcode-select", "-p")
|
||||||
|
message += <<~EOS
|
||||||
<<~EOS
|
If #{MacOS::Xcode.latest_version} is installed, you may need to:
|
||||||
Your Xcode (#{xcode}) at #{MacOS::Xcode.bundle_path} is too outdated.
|
sudo xcode-select --switch /Applications/Xcode.app
|
||||||
Please update to Xcode #{MacOS::Xcode.latest_version} (or delete it).
|
Current developer directory is:
|
||||||
#{MacOS::Xcode.update_instructions}
|
#{current_path}
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_clt_minimum_version
|
|
||||||
return unless MacOS::CLT.below_minimum_version?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Your Command Line Tools are too outdated.
|
|
||||||
#{MacOS::CLT.update_instructions}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_if_xcode_needs_clt_installed
|
|
||||||
return unless MacOS::Xcode.needs_clt_installed?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Xcode alone is not sufficient on #{MacOS.version.pretty_name}.
|
|
||||||
#{DevelopmentTools.installation_instructions}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_xcode_prefix
|
|
||||||
prefix = MacOS::Xcode.prefix
|
|
||||||
return if prefix.nil?
|
|
||||||
return unless prefix.to_s.include?(" ")
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Xcode is installed to a directory with a space in the name.
|
|
||||||
This will cause some formulae to fail to build.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_xcode_prefix_exists
|
|
||||||
prefix = MacOS::Xcode.prefix
|
|
||||||
return if prefix.nil? || prefix.exist?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
The directory Xcode is reportedly installed to doesn't exist:
|
|
||||||
#{prefix}
|
|
||||||
You may need to `xcode-select` the proper path if you have moved Xcode.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_xcode_select_path
|
|
||||||
return if MacOS::CLT.installed?
|
|
||||||
return unless MacOS::Xcode.installed?
|
|
||||||
return if File.file?("#{MacOS.active_developer_dir}/usr/bin/xcodebuild")
|
|
||||||
|
|
||||||
path = MacOS::Xcode.bundle_path
|
|
||||||
path = "/Developer" if path.nil? || !path.directory?
|
|
||||||
<<~EOS
|
|
||||||
Your Xcode is configured with an invalid path.
|
|
||||||
You should change it to the correct path:
|
|
||||||
sudo xcode-select --switch #{path}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_xcode_license_approved
|
|
||||||
# If the user installs Xcode-only, they have to approve the
|
|
||||||
# license or no "xc*" tool will work.
|
|
||||||
return unless `/usr/bin/xcrun clang 2>&1`.include?("license")
|
|
||||||
return if $CHILD_STATUS.success?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
You have not agreed to the Xcode license.
|
|
||||||
Agree to the license by opening Xcode.app or running:
|
|
||||||
sudo xcodebuild -license
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_filesystem_case_sensitive
|
|
||||||
dirs_to_check = [
|
|
||||||
HOMEBREW_PREFIX,
|
|
||||||
HOMEBREW_REPOSITORY,
|
|
||||||
HOMEBREW_CELLAR,
|
|
||||||
HOMEBREW_TEMP,
|
|
||||||
]
|
|
||||||
case_sensitive_dirs = dirs_to_check.select do |dir|
|
|
||||||
# We select the dir as being case-sensitive if either the UPCASED or the
|
|
||||||
# downcased variant is missing.
|
|
||||||
# Of course, on a case-insensitive fs, both exist because the os reports so.
|
|
||||||
# In the rare situation when the user has indeed a downcased and an upcased
|
|
||||||
# dir (e.g. /TMP and /tmp) this check falsely thinks it is case-insensitive
|
|
||||||
# but we don't care because: 1. there is more than one dir checked, 2. the
|
|
||||||
# check is not vital and 3. we would have to touch files otherwise.
|
|
||||||
upcased = Pathname.new(dir.to_s.upcase)
|
|
||||||
downcased = Pathname.new(dir.to_s.downcase)
|
|
||||||
dir.exist? && !(upcased.exist? && downcased.exist?)
|
|
||||||
end
|
|
||||||
return if case_sensitive_dirs.empty?
|
|
||||||
|
|
||||||
volumes = Volumes.new
|
|
||||||
case_sensitive_vols = case_sensitive_dirs.map do |case_sensitive_dir|
|
|
||||||
volumes.get_mounts(case_sensitive_dir)
|
|
||||||
end
|
|
||||||
case_sensitive_vols.uniq!
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
The filesystem on #{case_sensitive_vols.join(",")} appears to be case-sensitive.
|
|
||||||
The default macOS filesystem is case-insensitive. Please report any apparent problems.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_gettext
|
|
||||||
find_relative_paths("lib/libgettextlib.dylib",
|
|
||||||
"lib/libintl.dylib",
|
|
||||||
"include/libintl.h")
|
|
||||||
return if @found.empty?
|
|
||||||
|
|
||||||
# Our gettext formula will be caught by check_linked_keg_only_brews
|
|
||||||
gettext = begin
|
|
||||||
Formulary.factory("gettext")
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if gettext&.linked_keg&.directory?
|
|
||||||
allowlist = ["#{HOMEBREW_CELLAR}/gettext"]
|
|
||||||
if Hardware::CPU.physical_cpu_arm64?
|
|
||||||
allowlist += %W[
|
|
||||||
#{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX}/Cellar/gettext
|
|
||||||
#{HOMEBREW_DEFAULT_PREFIX}/Cellar/gettext
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
return if @found.all? do |path|
|
|
||||||
realpath = Pathname.new(path).realpath.to_s
|
|
||||||
allowlist.any? { |rack| realpath.start_with?(rack) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
inject_file_list @found, <<~EOS
|
|
||||||
gettext files detected at a system prefix.
|
|
||||||
These files can cause compilation and link failures, especially if they
|
|
||||||
are compiled with improper architectures. Consider removing these files:
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_iconv
|
|
||||||
find_relative_paths("lib/libiconv.dylib", "include/iconv.h")
|
|
||||||
return if @found.empty?
|
|
||||||
|
|
||||||
libiconv = begin
|
|
||||||
Formulary.factory("libiconv")
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
if libiconv&.linked_keg&.directory?
|
|
||||||
unless libiconv&.keg_only?
|
|
||||||
<<~EOS
|
|
||||||
A libiconv formula is installed and linked.
|
|
||||||
This will break stuff. For serious. Unlink it.
|
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
else
|
message
|
||||||
inject_file_list @found, <<~EOS
|
end
|
||||||
libiconv files detected at a system prefix other than /usr.
|
|
||||||
Homebrew doesn't provide a libiconv formula and expects to link against
|
|
||||||
the system version in /usr. libiconv in other prefixes can cause
|
|
||||||
compile or link failure, especially if compiled with improper
|
|
||||||
architectures. macOS itself never installs anything to /usr/local so
|
|
||||||
it was either installed by a user or some other third party software.
|
|
||||||
|
|
||||||
tl;dr: delete these files:
|
def check_clt_up_to_date
|
||||||
|
return unless MacOS::CLT.outdated?
|
||||||
|
|
||||||
|
# avoid duplicate very similar messages
|
||||||
|
return if MacOS::CLT.below_minimum_version?
|
||||||
|
|
||||||
|
# CI images are going to end up outdated so don't complain when
|
||||||
|
# `brew test-bot` runs `brew doctor` in the CI for the Homebrew/brew
|
||||||
|
# repository. This only needs to support whatever CI providers
|
||||||
|
# Homebrew/brew is currently using.
|
||||||
|
return if GitHub::Actions.env_set?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
A newer Command Line Tools release is available.
|
||||||
|
#{MacOS::CLT.update_instructions}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_multiple_volumes
|
def check_xcode_minimum_version
|
||||||
return unless HOMEBREW_CELLAR.exist?
|
return unless MacOS::Xcode.below_minimum_version?
|
||||||
|
|
||||||
volumes = Volumes.new
|
xcode = MacOS::Xcode.version.to_s
|
||||||
|
xcode += " => #{MacOS::Xcode.prefix}" unless MacOS::Xcode.default_prefix?
|
||||||
|
|
||||||
# Find the volumes for the TMP folder & HOMEBREW_CELLAR
|
<<~EOS
|
||||||
real_cellar = HOMEBREW_CELLAR.realpath
|
Your Xcode (#{xcode}) at #{MacOS::Xcode.bundle_path} is too outdated.
|
||||||
where_cellar = volumes.which real_cellar
|
Please update to Xcode #{MacOS::Xcode.latest_version} (or delete it).
|
||||||
|
#{MacOS::Xcode.update_instructions}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
def check_clt_minimum_version
|
||||||
tmp = Pathname.new(Dir.mktmpdir("doctor", HOMEBREW_TEMP))
|
return unless MacOS::CLT.below_minimum_version?
|
||||||
begin
|
|
||||||
real_tmp = tmp.realpath.parent
|
<<~EOS
|
||||||
where_tmp = volumes.which real_tmp
|
Your Command Line Tools are too outdated.
|
||||||
ensure
|
#{MacOS::CLT.update_instructions}
|
||||||
Dir.delete tmp.to_s
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_if_xcode_needs_clt_installed
|
||||||
|
return unless MacOS::Xcode.needs_clt_installed?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Xcode alone is not sufficient on #{MacOS.version.pretty_name}.
|
||||||
|
#{::DevelopmentTools.installation_instructions}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_xcode_prefix
|
||||||
|
prefix = MacOS::Xcode.prefix
|
||||||
|
return if prefix.nil?
|
||||||
|
return unless prefix.to_s.include?(" ")
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Xcode is installed to a directory with a space in the name.
|
||||||
|
This will cause some formulae to fail to build.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_xcode_prefix_exists
|
||||||
|
prefix = MacOS::Xcode.prefix
|
||||||
|
return if prefix.nil? || prefix.exist?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
The directory Xcode is reportedly installed to doesn't exist:
|
||||||
|
#{prefix}
|
||||||
|
You may need to `xcode-select` the proper path if you have moved Xcode.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_xcode_select_path
|
||||||
|
return if MacOS::CLT.installed?
|
||||||
|
return unless MacOS::Xcode.installed?
|
||||||
|
return if File.file?("#{MacOS.active_developer_dir}/usr/bin/xcodebuild")
|
||||||
|
|
||||||
|
path = MacOS::Xcode.bundle_path
|
||||||
|
path = "/Developer" if path.nil? || !path.directory?
|
||||||
|
<<~EOS
|
||||||
|
Your Xcode is configured with an invalid path.
|
||||||
|
You should change it to the correct path:
|
||||||
|
sudo xcode-select --switch #{path}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_xcode_license_approved
|
||||||
|
# If the user installs Xcode-only, they have to approve the
|
||||||
|
# license or no "xc*" tool will work.
|
||||||
|
return unless `/usr/bin/xcrun clang 2>&1`.include?("license")
|
||||||
|
return if $CHILD_STATUS.success?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
You have not agreed to the Xcode license.
|
||||||
|
Agree to the license by opening Xcode.app or running:
|
||||||
|
sudo xcodebuild -license
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_filesystem_case_sensitive
|
||||||
|
dirs_to_check = [
|
||||||
|
HOMEBREW_PREFIX,
|
||||||
|
HOMEBREW_REPOSITORY,
|
||||||
|
HOMEBREW_CELLAR,
|
||||||
|
HOMEBREW_TEMP,
|
||||||
|
]
|
||||||
|
case_sensitive_dirs = dirs_to_check.select do |dir|
|
||||||
|
# We select the dir as being case-sensitive if either the UPCASED or the
|
||||||
|
# downcased variant is missing.
|
||||||
|
# Of course, on a case-insensitive fs, both exist because the os reports so.
|
||||||
|
# In the rare situation when the user has indeed a downcased and an upcased
|
||||||
|
# dir (e.g. /TMP and /tmp) this check falsely thinks it is case-insensitive
|
||||||
|
# but we don't care because: 1. there is more than one dir checked, 2. the
|
||||||
|
# check is not vital and 3. we would have to touch files otherwise.
|
||||||
|
upcased = Pathname.new(dir.to_s.upcase)
|
||||||
|
downcased = Pathname.new(dir.to_s.downcase)
|
||||||
|
dir.exist? && !(upcased.exist? && downcased.exist?)
|
||||||
end
|
end
|
||||||
rescue
|
return if case_sensitive_dirs.empty?
|
||||||
return
|
|
||||||
|
volumes = Volumes.new
|
||||||
|
case_sensitive_vols = case_sensitive_dirs.map do |case_sensitive_dir|
|
||||||
|
volumes.get_mounts(case_sensitive_dir)
|
||||||
|
end
|
||||||
|
case_sensitive_vols.uniq!
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
The filesystem on #{case_sensitive_vols.join(",")} appears to be case-sensitive.
|
||||||
|
The default macOS filesystem is case-insensitive. Please report any apparent problems.
|
||||||
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
return if where_cellar == where_tmp
|
def check_for_gettext
|
||||||
|
find_relative_paths("lib/libgettextlib.dylib",
|
||||||
|
"lib/libintl.dylib",
|
||||||
|
"include/libintl.h")
|
||||||
|
return if @found.empty?
|
||||||
|
|
||||||
<<~EOS
|
# Our gettext formula will be caught by check_linked_keg_only_brews
|
||||||
Your Cellar and TEMP directories are on different volumes.
|
gettext = begin
|
||||||
macOS won't move relative symlinks across volumes unless the target file already
|
Formulary.factory("gettext")
|
||||||
exists. Brews known to be affected by this are Git and Narwhal.
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
You should set the "HOMEBREW_TEMP" environment variable to a suitable
|
if gettext&.linked_keg&.directory?
|
||||||
directory on the same volume as your Cellar.
|
allowlist = ["#{HOMEBREW_CELLAR}/gettext"]
|
||||||
EOS
|
if ::Hardware::CPU.physical_cpu_arm64?
|
||||||
end
|
allowlist += %W[
|
||||||
|
#{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX}/Cellar/gettext
|
||||||
|
#{HOMEBREW_DEFAULT_PREFIX}/Cellar/gettext
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
def check_deprecated_caskroom_taps
|
return if @found.all? do |path|
|
||||||
tapped_caskroom_taps = Tap.select { |t| t.user == "caskroom" || t.name == "phinze/cask" }
|
realpath = Pathname.new(path).realpath.to_s
|
||||||
.map(&:name)
|
allowlist.any? { |rack| realpath.start_with?(rack) }
|
||||||
return if tapped_caskroom_taps.empty?
|
end
|
||||||
|
end
|
||||||
|
|
||||||
<<~EOS
|
inject_file_list @found, <<~EOS
|
||||||
You have the following deprecated, cask taps tapped:
|
gettext files detected at a system prefix.
|
||||||
#{tapped_caskroom_taps.join("\n ")}
|
These files can cause compilation and link failures, especially if they
|
||||||
Untap them with `brew untap`.
|
are compiled with improper architectures. Consider removing these files:
|
||||||
EOS
|
EOS
|
||||||
end
|
|
||||||
|
|
||||||
def check_if_supported_sdk_available
|
|
||||||
return unless DevelopmentTools.installed?
|
|
||||||
return unless MacOS.sdk_root_needed?
|
|
||||||
return if MacOS.sdk
|
|
||||||
|
|
||||||
locator = MacOS.sdk_locator
|
|
||||||
|
|
||||||
source = if locator.source == :clt
|
|
||||||
return if MacOS::CLT.below_minimum_version? # Handled by other diagnostics.
|
|
||||||
|
|
||||||
update_instructions = MacOS::CLT.update_instructions
|
|
||||||
"Command Line Tools (CLT)"
|
|
||||||
else
|
|
||||||
return if MacOS::Xcode.below_minimum_version? # Handled by other diagnostics.
|
|
||||||
|
|
||||||
update_instructions = MacOS::Xcode.update_instructions
|
|
||||||
"Xcode"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
<<~EOS
|
def check_for_iconv
|
||||||
Your #{source} does not support macOS #{MacOS.version}.
|
find_relative_paths("lib/libiconv.dylib", "include/iconv.h")
|
||||||
It is either outdated or was modified.
|
return if @found.empty?
|
||||||
Please update your #{source} or delete it if no updates are available.
|
|
||||||
#{update_instructions}
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
# The CLT 10.x -> 11.x upgrade process on 10.14 contained a bug which broke the SDKs.
|
libiconv = begin
|
||||||
# Notably, MacOSX10.14.sdk would indirectly symlink to MacOSX10.15.sdk.
|
Formulary.factory("libiconv")
|
||||||
# This diagnostic was introduced to check for this and recommend a full reinstall.
|
rescue
|
||||||
def check_broken_sdks
|
nil
|
||||||
locator = MacOS.sdk_locator
|
end
|
||||||
|
if libiconv&.linked_keg&.directory?
|
||||||
|
unless libiconv&.keg_only?
|
||||||
|
<<~EOS
|
||||||
|
A libiconv formula is installed and linked.
|
||||||
|
This will break stuff. For serious. Unlink it.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inject_file_list @found, <<~EOS
|
||||||
|
libiconv files detected at a system prefix other than /usr.
|
||||||
|
Homebrew doesn't provide a libiconv formula and expects to link against
|
||||||
|
the system version in /usr. libiconv in other prefixes can cause
|
||||||
|
compile or link failure, especially if compiled with improper
|
||||||
|
architectures. macOS itself never installs anything to /usr/local so
|
||||||
|
it was either installed by a user or some other third party software.
|
||||||
|
|
||||||
return if locator.all_sdks.all? do |sdk|
|
tl;dr: delete these files:
|
||||||
path_version = sdk.path.basename.to_s[MacOS::SDK::VERSIONED_SDK_REGEX, 1]
|
EOS
|
||||||
next true if path_version.blank?
|
end
|
||||||
|
|
||||||
sdk.version == MacOSVersion.new(path_version).strip_patch
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if locator.source == :clt
|
def check_for_multiple_volumes
|
||||||
source = "Command Line Tools (CLT)"
|
return unless HOMEBREW_CELLAR.exist?
|
||||||
path_to_remove = MacOS::CLT::PKG_PATH
|
|
||||||
installation_instructions = MacOS::CLT.installation_instructions
|
volumes = Volumes.new
|
||||||
else
|
|
||||||
source = "Xcode"
|
# Find the volumes for the TMP folder & HOMEBREW_CELLAR
|
||||||
path_to_remove = MacOS::Xcode.bundle_path
|
real_cellar = HOMEBREW_CELLAR.realpath
|
||||||
installation_instructions = MacOS::Xcode.installation_instructions
|
where_cellar = volumes.which real_cellar
|
||||||
|
|
||||||
|
begin
|
||||||
|
tmp = Pathname.new(Dir.mktmpdir("doctor", HOMEBREW_TEMP))
|
||||||
|
begin
|
||||||
|
real_tmp = tmp.realpath.parent
|
||||||
|
where_tmp = volumes.which real_tmp
|
||||||
|
ensure
|
||||||
|
Dir.delete tmp.to_s
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return if where_cellar == where_tmp
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Your Cellar and TEMP directories are on different volumes.
|
||||||
|
macOS won't move relative symlinks across volumes unless the target file already
|
||||||
|
exists. Brews known to be affected by this are Git and Narwhal.
|
||||||
|
|
||||||
|
You should set the "HOMEBREW_TEMP" environment variable to a suitable
|
||||||
|
directory on the same volume as your Cellar.
|
||||||
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
<<~EOS
|
def check_deprecated_caskroom_taps
|
||||||
The contents of the SDKs in your #{source} installation do not match the SDK folder names.
|
tapped_caskroom_taps = Tap.select { |t| t.user == "caskroom" || t.name == "phinze/cask" }
|
||||||
A clean reinstall of #{source} should fix this.
|
.map(&:name)
|
||||||
|
return if tapped_caskroom_taps.empty?
|
||||||
|
|
||||||
Remove the broken installation before reinstalling:
|
<<~EOS
|
||||||
sudo rm -rf #{path_to_remove}
|
You have the following deprecated, cask taps tapped:
|
||||||
|
#{tapped_caskroom_taps.join("\n ")}
|
||||||
|
Untap them with `brew untap`.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
#{installation_instructions}
|
def check_if_supported_sdk_available
|
||||||
EOS
|
return unless ::DevelopmentTools.installed?
|
||||||
|
return unless MacOS.sdk_root_needed?
|
||||||
|
return if MacOS.sdk
|
||||||
|
|
||||||
|
locator = MacOS.sdk_locator
|
||||||
|
|
||||||
|
source = if locator.source == :clt
|
||||||
|
return if MacOS::CLT.below_minimum_version? # Handled by other diagnostics.
|
||||||
|
|
||||||
|
update_instructions = MacOS::CLT.update_instructions
|
||||||
|
"Command Line Tools (CLT)"
|
||||||
|
else
|
||||||
|
return if MacOS::Xcode.below_minimum_version? # Handled by other diagnostics.
|
||||||
|
|
||||||
|
update_instructions = MacOS::Xcode.update_instructions
|
||||||
|
"Xcode"
|
||||||
|
end
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Your #{source} does not support macOS #{MacOS.version}.
|
||||||
|
It is either outdated or was modified.
|
||||||
|
Please update your #{source} or delete it if no updates are available.
|
||||||
|
#{update_instructions}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
# The CLT 10.x -> 11.x upgrade process on 10.14 contained a bug which broke the SDKs.
|
||||||
|
# Notably, MacOSX10.14.sdk would indirectly symlink to MacOSX10.15.sdk.
|
||||||
|
# This diagnostic was introduced to check for this and recommend a full reinstall.
|
||||||
|
def check_broken_sdks
|
||||||
|
locator = MacOS.sdk_locator
|
||||||
|
|
||||||
|
return if locator.all_sdks.all? do |sdk|
|
||||||
|
path_version = sdk.path.basename.to_s[MacOS::SDK::VERSIONED_SDK_REGEX, 1]
|
||||||
|
next true if path_version.blank?
|
||||||
|
|
||||||
|
sdk.version == MacOSVersion.new(path_version).strip_patch
|
||||||
|
end
|
||||||
|
|
||||||
|
if locator.source == :clt
|
||||||
|
source = "Command Line Tools (CLT)"
|
||||||
|
path_to_remove = MacOS::CLT::PKG_PATH
|
||||||
|
installation_instructions = MacOS::CLT.installation_instructions
|
||||||
|
else
|
||||||
|
source = "Xcode"
|
||||||
|
path_to_remove = MacOS::Xcode.bundle_path
|
||||||
|
installation_instructions = MacOS::Xcode.installation_instructions
|
||||||
|
end
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
The contents of the SDKs in your #{source} installation do not match the SDK folder names.
|
||||||
|
A clean reinstall of #{source} should fix this.
|
||||||
|
|
||||||
|
Remove the broken installation before reinstalling:
|
||||||
|
sudo rm -rf #{path_to_remove}
|
||||||
|
|
||||||
|
#{installation_instructions}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Homebrew::Diagnostic::Checks.prepend(OS::Mac::Diagnostic::Checks)
|
||||||
|
@ -37,6 +37,6 @@ module SharedEnvExtension
|
|||||||
# This is supported starting Xcode 13, which ships ld64-711.
|
# This is supported starting Xcode 13, which ships ld64-711.
|
||||||
# https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes
|
# https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes
|
||||||
# https://en.wikipedia.org/wiki/Xcode#Xcode_11.0_-_14.x_(since_SwiftUI_framework)_2
|
# https://en.wikipedia.org/wiki/Xcode#Xcode_11.0_-_14.x_(since_SwiftUI_framework)_2
|
||||||
DevelopmentTools.ld64_version >= 711
|
OS::Mac::DevelopmentTools.ld64_version >= 711
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,117 +1,125 @@
|
|||||||
# typed: true # rubocop:disable Sorbet/StrictSigil
|
# typed: true # rubocop:disable Sorbet/StrictSigil
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Stdenv
|
module OS
|
||||||
undef homebrew_extra_pkg_config_paths
|
module Mac
|
||||||
|
module Stdenv
|
||||||
|
extend T::Helpers
|
||||||
|
|
||||||
sig { returns(T::Array[Pathname]) }
|
requires_ancestor { ::Stdenv }
|
||||||
def homebrew_extra_pkg_config_paths
|
|
||||||
[Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")]
|
|
||||||
end
|
|
||||||
private :homebrew_extra_pkg_config_paths
|
|
||||||
|
|
||||||
sig {
|
sig { returns(T::Array[Pathname]) }
|
||||||
params(
|
def homebrew_extra_pkg_config_paths
|
||||||
formula: T.nilable(Formula),
|
[Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")]
|
||||||
cc: T.nilable(String),
|
end
|
||||||
build_bottle: T.nilable(T::Boolean),
|
private :homebrew_extra_pkg_config_paths
|
||||||
bottle_arch: T.nilable(String),
|
|
||||||
testing_formula: T::Boolean,
|
|
||||||
debug_symbols: T.nilable(T::Boolean),
|
|
||||||
).void
|
|
||||||
}
|
|
||||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
|
|
||||||
debug_symbols: false)
|
|
||||||
generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:,
|
|
||||||
testing_formula:, debug_symbols:)
|
|
||||||
|
|
||||||
append "LDFLAGS", "-Wl,-headerpad_max_install_names"
|
sig {
|
||||||
|
params(
|
||||||
|
formula: T.nilable(::Formula),
|
||||||
|
cc: T.nilable(String),
|
||||||
|
build_bottle: T.nilable(T::Boolean),
|
||||||
|
bottle_arch: T.nilable(String),
|
||||||
|
testing_formula: T::Boolean,
|
||||||
|
debug_symbols: T.nilable(T::Boolean),
|
||||||
|
).void
|
||||||
|
}
|
||||||
|
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil,
|
||||||
|
testing_formula: false, debug_symbols: false)
|
||||||
|
generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:,
|
||||||
|
testing_formula:, debug_symbols:)
|
||||||
|
|
||||||
# `sed` is strict and errors out when it encounters files with mixed character sets.
|
append "LDFLAGS", "-Wl,-headerpad_max_install_names"
|
||||||
delete("LC_ALL")
|
|
||||||
self["LC_CTYPE"] = "C"
|
|
||||||
|
|
||||||
# Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags:
|
# `sed` is strict and errors out when it encounters files with mixed character sets.
|
||||||
macosxsdk(formula: @formula, testing_formula:)
|
delete("LC_ALL")
|
||||||
|
self["LC_CTYPE"] = "C"
|
||||||
|
|
||||||
return unless MacOS::Xcode.without_clt?
|
# Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags:
|
||||||
|
macosxsdk(formula: @formula, testing_formula:)
|
||||||
|
|
||||||
append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin"
|
return unless MacOS::Xcode.without_clt?
|
||||||
append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin"
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_macosxsdk(version = nil)
|
append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin"
|
||||||
# Clear all `lib` and `include` dirs from `CFLAGS`, `CPPFLAGS`, `LDFLAGS` that were
|
append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin"
|
||||||
# previously added by `macosxsdk`.
|
end
|
||||||
remove_from_cflags(/ ?-mmacosx-version-min=\d+\.\d+/)
|
|
||||||
delete("CPATH")
|
|
||||||
remove "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib"
|
|
||||||
|
|
||||||
sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed(version)
|
def remove_macosxsdk(version = nil)
|
||||||
return unless sdk
|
# Clear all `lib` and `include` dirs from `CFLAGS`, `CPPFLAGS`, `LDFLAGS` that were
|
||||||
|
# previously added by `macosxsdk`.
|
||||||
|
remove_from_cflags(/ ?-mmacosx-version-min=\d+\.\d+/)
|
||||||
|
delete("CPATH")
|
||||||
|
remove "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib"
|
||||||
|
|
||||||
delete("SDKROOT")
|
sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed(version)
|
||||||
remove_from_cflags "-isysroot#{sdk}"
|
return unless sdk
|
||||||
remove "CPPFLAGS", "-isysroot#{sdk}"
|
|
||||||
remove "LDFLAGS", "-isysroot#{sdk}"
|
delete("SDKROOT")
|
||||||
if HOMEBREW_PREFIX.to_s == "/usr/local"
|
remove_from_cflags "-isysroot#{sdk}"
|
||||||
delete("CMAKE_PREFIX_PATH")
|
remove "CPPFLAGS", "-isysroot#{sdk}"
|
||||||
else
|
remove "LDFLAGS", "-isysroot#{sdk}"
|
||||||
# It was set in `setup_build_environment`, so we have to restore it here.
|
if HOMEBREW_PREFIX.to_s == "/usr/local"
|
||||||
self["CMAKE_PREFIX_PATH"] = HOMEBREW_PREFIX.to_s
|
delete("CMAKE_PREFIX_PATH")
|
||||||
|
else
|
||||||
|
# It was set in `setup_build_environment`, so we have to restore it here.
|
||||||
|
self["CMAKE_PREFIX_PATH"] = HOMEBREW_PREFIX.to_s
|
||||||
|
end
|
||||||
|
remove "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks"
|
||||||
|
end
|
||||||
|
|
||||||
|
def macosxsdk(version = nil, formula: nil, testing_formula: false)
|
||||||
|
# Sets all needed `lib` and `include` dirs to `CFLAGS`, `CPPFLAGS`, `LDFLAGS`.
|
||||||
|
remove_macosxsdk
|
||||||
|
min_version = version || MacOS.version
|
||||||
|
append_to_cflags("-mmacosx-version-min=#{min_version}")
|
||||||
|
self["CPATH"] = "#{HOMEBREW_PREFIX}/include"
|
||||||
|
prepend "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib"
|
||||||
|
|
||||||
|
sdk = if formula
|
||||||
|
MacOS.sdk_for_formula(formula, version, check_only_runtime_requirements: testing_formula)
|
||||||
|
else
|
||||||
|
MacOS.sdk(version)
|
||||||
|
end
|
||||||
|
return if !MacOS.sdk_root_needed? && sdk&.source != :xcode
|
||||||
|
|
||||||
|
Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks)
|
||||||
|
sdk = sdk.path
|
||||||
|
|
||||||
|
# Extra setup to support Xcode 4.3+ without CLT.
|
||||||
|
self["SDKROOT"] = sdk
|
||||||
|
# Tell clang/gcc where system include's are:
|
||||||
|
append_path "CPATH", "#{sdk}/usr/include"
|
||||||
|
# The -isysroot is needed, too, because of the Frameworks
|
||||||
|
append_to_cflags "-isysroot#{sdk}"
|
||||||
|
append "CPPFLAGS", "-isysroot#{sdk}"
|
||||||
|
# And the linker needs to find sdk/usr/lib
|
||||||
|
append "LDFLAGS", "-isysroot#{sdk}"
|
||||||
|
# Needed to build cmake itself and perhaps some cmake projects:
|
||||||
|
append_path "CMAKE_PREFIX_PATH", "#{sdk}/usr"
|
||||||
|
append_path "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Some configure scripts won't find libxml2 without help.
|
||||||
|
# This is a no-op with macOS SDK 10.15.4 and later.
|
||||||
|
def libxml2
|
||||||
|
sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed
|
||||||
|
if !sdk
|
||||||
|
append "CPPFLAGS", "-I/usr/include/libxml2"
|
||||||
|
elsif !Pathname("#{sdk}/usr/include/libxml").directory?
|
||||||
|
# Use the includes form the sdk
|
||||||
|
append "CPPFLAGS", "-I#{sdk}/usr/include/libxml2"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_weak_imports
|
||||||
|
append "LDFLAGS", "-Wl,-no_weak_imports" if no_weak_imports_support?
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_fixup_chains
|
||||||
|
append "LDFLAGS", "-Wl,-no_fixup_chains" if no_fixup_chains_support?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
remove "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks"
|
|
||||||
end
|
|
||||||
|
|
||||||
def macosxsdk(version = nil, formula: nil, testing_formula: false)
|
|
||||||
# Sets all needed `lib` and `include` dirs to `CFLAGS`, `CPPFLAGS`, `LDFLAGS`.
|
|
||||||
remove_macosxsdk
|
|
||||||
min_version = version || MacOS.version
|
|
||||||
append_to_cflags("-mmacosx-version-min=#{min_version}")
|
|
||||||
self["CPATH"] = "#{HOMEBREW_PREFIX}/include"
|
|
||||||
prepend "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib"
|
|
||||||
|
|
||||||
sdk = if formula
|
|
||||||
MacOS.sdk_for_formula(formula, version, check_only_runtime_requirements: testing_formula)
|
|
||||||
else
|
|
||||||
MacOS.sdk(version)
|
|
||||||
end
|
|
||||||
return if !MacOS.sdk_root_needed? && sdk&.source != :xcode
|
|
||||||
|
|
||||||
Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks)
|
|
||||||
sdk = sdk.path
|
|
||||||
|
|
||||||
# Extra setup to support Xcode 4.3+ without CLT.
|
|
||||||
self["SDKROOT"] = sdk
|
|
||||||
# Tell clang/gcc where system include's are:
|
|
||||||
append_path "CPATH", "#{sdk}/usr/include"
|
|
||||||
# The -isysroot is needed, too, because of the Frameworks
|
|
||||||
append_to_cflags "-isysroot#{sdk}"
|
|
||||||
append "CPPFLAGS", "-isysroot#{sdk}"
|
|
||||||
# And the linker needs to find sdk/usr/lib
|
|
||||||
append "LDFLAGS", "-isysroot#{sdk}"
|
|
||||||
# Needed to build cmake itself and perhaps some cmake projects:
|
|
||||||
append_path "CMAKE_PREFIX_PATH", "#{sdk}/usr"
|
|
||||||
append_path "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Some configure scripts won't find libxml2 without help.
|
|
||||||
# This is a no-op with macOS SDK 10.15.4 and later.
|
|
||||||
def libxml2
|
|
||||||
sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed
|
|
||||||
if !sdk
|
|
||||||
append "CPPFLAGS", "-I/usr/include/libxml2"
|
|
||||||
elsif !Pathname("#{sdk}/usr/include/libxml").directory?
|
|
||||||
# Use the includes form the sdk
|
|
||||||
append "CPPFLAGS", "-I#{sdk}/usr/include/libxml2"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def no_weak_imports
|
|
||||||
append "LDFLAGS", "-Wl,-no_weak_imports" if no_weak_imports_support?
|
|
||||||
end
|
|
||||||
|
|
||||||
def no_fixup_chains
|
|
||||||
append "LDFLAGS", "-Wl,-no_fixup_chains" if no_fixup_chains_support?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Stdenv.prepend(OS::Mac::Stdenv)
|
||||||
|
@ -1,169 +1,175 @@
|
|||||||
# typed: true # rubocop:disable Sorbet/StrictSigil
|
# typed: true # rubocop:disable Sorbet/StrictSigil
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Superenv
|
module OS
|
||||||
class << self
|
module Mac
|
||||||
# The location of Homebrew's shims on macOS.
|
module Superenv
|
||||||
def shims_path
|
extend T::Helpers
|
||||||
HOMEBREW_SHIMS_PATH/"mac/super"
|
|
||||||
end
|
|
||||||
|
|
||||||
undef bin
|
requires_ancestor { ::Superenv }
|
||||||
|
|
||||||
def bin
|
module ClassMethods
|
||||||
return unless DevelopmentTools.installed?
|
# The location of Homebrew's shims on macOS.
|
||||||
|
def shims_path
|
||||||
|
HOMEBREW_SHIMS_PATH/"mac/super"
|
||||||
|
end
|
||||||
|
|
||||||
shims_path.realpath
|
def bin
|
||||||
end
|
return unless ::DevelopmentTools.installed?
|
||||||
end
|
|
||||||
|
|
||||||
undef homebrew_extra_pkg_config_paths,
|
shims_path.realpath
|
||||||
homebrew_extra_isystem_paths, homebrew_extra_library_paths,
|
end
|
||||||
homebrew_extra_cmake_include_paths,
|
|
||||||
homebrew_extra_cmake_library_paths,
|
|
||||||
homebrew_extra_cmake_frameworks_paths,
|
|
||||||
determine_cccfg
|
|
||||||
|
|
||||||
sig { returns(T::Array[Pathname]) }
|
|
||||||
def homebrew_extra_pkg_config_paths
|
|
||||||
[Pathname("/usr/lib/pkgconfig"), Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")]
|
|
||||||
end
|
|
||||||
private :homebrew_extra_pkg_config_paths
|
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
|
||||||
def libxml2_include_needed?
|
|
||||||
return false if deps.any? { |d| d.name == "libxml2" }
|
|
||||||
return false if Pathname("#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml").directory?
|
|
||||||
|
|
||||||
true
|
|
||||||
end
|
|
||||||
private :libxml2_include_needed?
|
|
||||||
|
|
||||||
def homebrew_extra_isystem_paths
|
|
||||||
paths = []
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml2" if libxml2_include_needed?
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/apache2" if MacOS::Xcode.without_clt?
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers"
|
|
||||||
paths
|
|
||||||
end
|
|
||||||
|
|
||||||
def homebrew_extra_library_paths
|
|
||||||
paths = []
|
|
||||||
if compiler == :llvm_clang
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/lib"
|
|
||||||
paths << Formula["llvm"].opt_lib.to_s
|
|
||||||
end
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries"
|
|
||||||
paths
|
|
||||||
end
|
|
||||||
|
|
||||||
def homebrew_extra_cmake_include_paths
|
|
||||||
paths = []
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml2" if libxml2_include_needed?
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/apache2" if MacOS::Xcode.without_clt?
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers"
|
|
||||||
paths
|
|
||||||
end
|
|
||||||
|
|
||||||
def homebrew_extra_cmake_library_paths
|
|
||||||
[Pathname("#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries")]
|
|
||||||
end
|
|
||||||
|
|
||||||
def homebrew_extra_cmake_frameworks_paths
|
|
||||||
paths = []
|
|
||||||
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks" if MacOS::Xcode.without_clt?
|
|
||||||
paths
|
|
||||||
end
|
|
||||||
|
|
||||||
def determine_cccfg
|
|
||||||
s = +""
|
|
||||||
# Fix issue with >= Mountain Lion apr-1-config having broken paths
|
|
||||||
s << "a"
|
|
||||||
s.freeze
|
|
||||||
end
|
|
||||||
|
|
||||||
# @private
|
|
||||||
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
|
|
||||||
debug_symbols: false)
|
|
||||||
sdk = formula ? MacOS.sdk_for_formula(formula) : MacOS.sdk
|
|
||||||
is_xcode_sdk = sdk&.source == :xcode
|
|
||||||
|
|
||||||
if is_xcode_sdk || MacOS.sdk_root_needed?
|
|
||||||
Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks)
|
|
||||||
self["HOMEBREW_SDKROOT"] = sdk.path if sdk
|
|
||||||
end
|
|
||||||
|
|
||||||
self["HOMEBREW_DEVELOPER_DIR"] = if is_xcode_sdk
|
|
||||||
MacOS::Xcode.prefix.to_s
|
|
||||||
else
|
|
||||||
MacOS::CLT::PKG_PATH
|
|
||||||
end
|
|
||||||
|
|
||||||
# This is a workaround for the missing `m4` in Xcode CLT 15.3, which was
|
|
||||||
# reported in FB13679972. Apple has fixed this in Xcode CLT 16.0.
|
|
||||||
# See https://github.com/Homebrew/homebrew-core/issues/165388
|
|
||||||
if deps.none? { |d| d.name == "m4" } &&
|
|
||||||
MacOS.active_developer_dir == MacOS::CLT::PKG_PATH &&
|
|
||||||
!File.exist?("#{MacOS::CLT::PKG_PATH}/usr/bin/m4") &&
|
|
||||||
(gm4 = DevelopmentTools.locate("gm4").to_s).present?
|
|
||||||
self["M4"] = gm4
|
|
||||||
end
|
|
||||||
|
|
||||||
generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:,
|
|
||||||
testing_formula:, debug_symbols:)
|
|
||||||
|
|
||||||
# Filter out symbols known not to be defined since GNU Autotools can't
|
|
||||||
# reliably figure this out with Xcode 8 and above.
|
|
||||||
if MacOS.version == "10.12" && MacOS::Xcode.version >= "9.0"
|
|
||||||
%w[fmemopen futimens open_memstream utimensat].each do |s|
|
|
||||||
ENV["ac_cv_func_#{s}"] = "no"
|
|
||||||
end
|
|
||||||
elsif MacOS.version == "10.11" && MacOS::Xcode.version >= "8.0"
|
|
||||||
%w[basename_r clock_getres clock_gettime clock_settime dirname_r
|
|
||||||
getentropy mkostemp mkostemps timingsafe_bcmp].each do |s|
|
|
||||||
ENV["ac_cv_func_#{s}"] = "no"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
ENV["ac_cv_search_clock_gettime"] = "no"
|
sig { returns(T::Array[Pathname]) }
|
||||||
|
def homebrew_extra_pkg_config_paths
|
||||||
|
[Pathname("/usr/lib/pkgconfig"), Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")]
|
||||||
|
end
|
||||||
|
private :homebrew_extra_pkg_config_paths
|
||||||
|
|
||||||
# works around libev.m4 unsetting ac_cv_func_clock_gettime
|
sig { returns(T::Boolean) }
|
||||||
ENV["ac_have_clock_syscall"] = "no"
|
def libxml2_include_needed?
|
||||||
|
return false if deps.any? { |d| d.name == "libxml2" }
|
||||||
|
return false if Pathname("#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml").directory?
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
private :libxml2_include_needed?
|
||||||
|
|
||||||
|
def homebrew_extra_isystem_paths
|
||||||
|
paths = []
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml2" if libxml2_include_needed?
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/apache2" if MacOS::Xcode.without_clt?
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers"
|
||||||
|
paths
|
||||||
|
end
|
||||||
|
|
||||||
|
def homebrew_extra_library_paths
|
||||||
|
paths = []
|
||||||
|
if compiler == :llvm_clang
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/lib"
|
||||||
|
paths << ::Formula["llvm"].opt_lib.to_s
|
||||||
|
end
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries"
|
||||||
|
paths
|
||||||
|
end
|
||||||
|
|
||||||
|
def homebrew_extra_cmake_include_paths
|
||||||
|
paths = []
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml2" if libxml2_include_needed?
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/apache2" if MacOS::Xcode.without_clt?
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers"
|
||||||
|
paths
|
||||||
|
end
|
||||||
|
|
||||||
|
def homebrew_extra_cmake_library_paths
|
||||||
|
[Pathname(
|
||||||
|
"#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries",
|
||||||
|
)]
|
||||||
|
end
|
||||||
|
|
||||||
|
def homebrew_extra_cmake_frameworks_paths
|
||||||
|
paths = []
|
||||||
|
paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks" if MacOS::Xcode.without_clt?
|
||||||
|
paths
|
||||||
|
end
|
||||||
|
|
||||||
|
def determine_cccfg
|
||||||
|
s = +""
|
||||||
|
# Fix issue with >= Mountain Lion apr-1-config having broken paths
|
||||||
|
s << "a"
|
||||||
|
s.freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
# @private
|
||||||
|
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil,
|
||||||
|
testing_formula: false, debug_symbols: false)
|
||||||
|
sdk = formula ? MacOS.sdk_for_formula(formula) : MacOS.sdk
|
||||||
|
is_xcode_sdk = sdk&.source == :xcode
|
||||||
|
|
||||||
|
if is_xcode_sdk || MacOS.sdk_root_needed?
|
||||||
|
Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks)
|
||||||
|
self["HOMEBREW_SDKROOT"] = sdk.path if sdk
|
||||||
|
end
|
||||||
|
|
||||||
|
self["HOMEBREW_DEVELOPER_DIR"] = if is_xcode_sdk
|
||||||
|
MacOS::Xcode.prefix.to_s
|
||||||
|
else
|
||||||
|
MacOS::CLT::PKG_PATH
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is a workaround for the missing `m4` in Xcode CLT 15.3, which was
|
||||||
|
# reported in FB13679972. Apple has fixed this in Xcode CLT 16.0.
|
||||||
|
# See https://github.com/Homebrew/homebrew-core/issues/165388
|
||||||
|
if deps.none? { |d| d.name == "m4" } &&
|
||||||
|
MacOS.active_developer_dir == MacOS::CLT::PKG_PATH &&
|
||||||
|
!File.exist?("#{MacOS::CLT::PKG_PATH}/usr/bin/m4") &&
|
||||||
|
(gm4 = ::DevelopmentTools.locate("gm4").to_s).present?
|
||||||
|
self["M4"] = gm4
|
||||||
|
end
|
||||||
|
|
||||||
|
generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:,
|
||||||
|
testing_formula:, debug_symbols:)
|
||||||
|
|
||||||
|
# Filter out symbols known not to be defined since GNU Autotools can't
|
||||||
|
# reliably figure this out with Xcode 8 and above.
|
||||||
|
if MacOS.version == "10.12" && MacOS::Xcode.version >= "9.0"
|
||||||
|
%w[fmemopen futimens open_memstream utimensat].each do |s|
|
||||||
|
ENV["ac_cv_func_#{s}"] = "no"
|
||||||
|
end
|
||||||
|
elsif MacOS.version == "10.11" && MacOS::Xcode.version >= "8.0"
|
||||||
|
%w[basename_r clock_getres clock_gettime clock_settime dirname_r
|
||||||
|
getentropy mkostemp mkostemps timingsafe_bcmp].each do |s|
|
||||||
|
ENV["ac_cv_func_#{s}"] = "no"
|
||||||
|
end
|
||||||
|
|
||||||
|
ENV["ac_cv_search_clock_gettime"] = "no"
|
||||||
|
|
||||||
|
# works around libev.m4 unsetting ac_cv_func_clock_gettime
|
||||||
|
ENV["ac_have_clock_syscall"] = "no"
|
||||||
|
end
|
||||||
|
|
||||||
|
# On macOS Sonoma (at least release candidate), iconv() is generally
|
||||||
|
# present and working, but has a minor regression that defeats the
|
||||||
|
# test implemented in gettext's configure script (and used by many
|
||||||
|
# gettext dependents).
|
||||||
|
ENV["am_cv_func_iconv_works"] = "yes" if MacOS.version == "14"
|
||||||
|
|
||||||
|
# The tools in /usr/bin proxy to the active developer directory.
|
||||||
|
# This means we can use them for any combination of CLT and Xcode.
|
||||||
|
self["HOMEBREW_PREFER_CLT_PROXIES"] = "1"
|
||||||
|
|
||||||
|
# Deterministic timestamping.
|
||||||
|
# This can work on older Xcode versions, but they contain some bugs.
|
||||||
|
# Notably, Xcode 10.2 fixes issues where ZERO_AR_DATE affected file mtimes.
|
||||||
|
# Xcode 11.0 contains fixes for lldb reading things built with ZERO_AR_DATE.
|
||||||
|
self["ZERO_AR_DATE"] = "1" if MacOS::Xcode.version >= "11.0" || MacOS::CLT.version >= "11.0"
|
||||||
|
|
||||||
|
# Pass `-no_fixup_chains` whenever the linker is invoked with `-undefined dynamic_lookup`.
|
||||||
|
# See: https://github.com/python/cpython/issues/97524
|
||||||
|
# https://github.com/pybind/pybind11/pull/4301
|
||||||
|
no_fixup_chains
|
||||||
|
|
||||||
|
# Strip build prefixes from linker where supported, for deterministic builds.
|
||||||
|
append_to_cccfg "o" if OS::Mac::DevelopmentTools.ld64_version >= 512
|
||||||
|
|
||||||
|
# Pass `-ld_classic` whenever the linker is invoked with `-dead_strip_dylibs`
|
||||||
|
# on `ld` versions that don't properly handle that option.
|
||||||
|
if OS::Mac::DevelopmentTools.ld64_version >= "1015.7" && OS::Mac::DevelopmentTools.ld64_version <= "1022.1"
|
||||||
|
append_to_cccfg "c"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_weak_imports
|
||||||
|
append_to_cccfg "w" if no_weak_imports_support?
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_fixup_chains
|
||||||
|
append_to_cccfg "f" if no_fixup_chains_support?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# On macOS Sonoma (at least release candidate), iconv() is generally
|
|
||||||
# present and working, but has a minor regression that defeats the
|
|
||||||
# test implemented in gettext's configure script (and used by many
|
|
||||||
# gettext dependents).
|
|
||||||
ENV["am_cv_func_iconv_works"] = "yes" if MacOS.version == "14"
|
|
||||||
|
|
||||||
# The tools in /usr/bin proxy to the active developer directory.
|
|
||||||
# This means we can use them for any combination of CLT and Xcode.
|
|
||||||
self["HOMEBREW_PREFER_CLT_PROXIES"] = "1"
|
|
||||||
|
|
||||||
# Deterministic timestamping.
|
|
||||||
# This can work on older Xcode versions, but they contain some bugs.
|
|
||||||
# Notably, Xcode 10.2 fixes issues where ZERO_AR_DATE affected file mtimes.
|
|
||||||
# Xcode 11.0 contains fixes for lldb reading things built with ZERO_AR_DATE.
|
|
||||||
self["ZERO_AR_DATE"] = "1" if MacOS::Xcode.version >= "11.0" || MacOS::CLT.version >= "11.0"
|
|
||||||
|
|
||||||
# Pass `-no_fixup_chains` whenever the linker is invoked with `-undefined dynamic_lookup`.
|
|
||||||
# See: https://github.com/python/cpython/issues/97524
|
|
||||||
# https://github.com/pybind/pybind11/pull/4301
|
|
||||||
no_fixup_chains
|
|
||||||
|
|
||||||
# Strip build prefixes from linker where supported, for deterministic builds.
|
|
||||||
append_to_cccfg "o" if DevelopmentTools.ld64_version >= 512
|
|
||||||
|
|
||||||
# Pass `-ld_classic` whenever the linker is invoked with `-dead_strip_dylibs`
|
|
||||||
# on `ld` versions that don't properly handle that option.
|
|
||||||
append_to_cccfg "c" if DevelopmentTools.ld64_version >= "1015.7" && DevelopmentTools.ld64_version <= "1022.1"
|
|
||||||
end
|
|
||||||
|
|
||||||
def no_weak_imports
|
|
||||||
append_to_cccfg "w" if no_weak_imports_support?
|
|
||||||
end
|
|
||||||
|
|
||||||
def no_fixup_chains
|
|
||||||
append_to_cccfg "f" if no_fixup_chains_support?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Superenv.singleton_class.prepend(OS::Mac::Superenv::ClassMethods)
|
||||||
|
Superenv.prepend(OS::Mac::Superenv)
|
||||||
|
@ -97,7 +97,7 @@ module FormulaCellarChecks
|
|||||||
return unless formula.prefix.directory?
|
return unless formula.prefix.directory?
|
||||||
return if formula.tap&.audit_exception(:flat_namespace_allowlist, formula.name)
|
return if formula.tap&.audit_exception(:flat_namespace_allowlist, formula.name)
|
||||||
|
|
||||||
keg = Keg.new(formula.prefix)
|
keg = ::Keg.new(formula.prefix)
|
||||||
flat_namespace_files = keg.mach_o_files.reject do |file|
|
flat_namespace_files = keg.mach_o_files.reject do |file|
|
||||||
next true unless file.dylib?
|
next true unless file.dylib?
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ module OS
|
|||||||
|
|
||||||
sig { params(formula: Formula).returns(T.nilable(T::Boolean)) }
|
sig { params(formula: Formula).returns(T.nilable(T::Boolean)) }
|
||||||
def fresh_install?(formula)
|
def fresh_install?(formula)
|
||||||
!Homebrew::EnvConfig.developer? && !OS::Mac.version.outdated_release? &&
|
!::Homebrew::EnvConfig.developer? && !OS::Mac.version.outdated_release? &&
|
||||||
(!installed_as_dependency? || !formula.any_version_installed?)
|
(!installed_as_dependency? || !formula.any_version_installed?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,175 +3,179 @@
|
|||||||
|
|
||||||
require "macho"
|
require "macho"
|
||||||
|
|
||||||
module Hardware
|
module OS
|
||||||
class CPU
|
module Mac
|
||||||
class << self
|
module Hardware
|
||||||
undef type, family, features, sse4?
|
module CPU
|
||||||
|
extend T::Helpers
|
||||||
|
|
||||||
# These methods use info spewed out by sysctl.
|
# These methods use info spewed out by sysctl.
|
||||||
# Look in <mach/machine.h> for decoding info.
|
# Look in <mach/machine.h> for decoding info.
|
||||||
def type
|
def type
|
||||||
case sysctl_int("hw.cputype")
|
case sysctl_int("hw.cputype")
|
||||||
when MachO::Headers::CPU_TYPE_I386
|
when MachO::Headers::CPU_TYPE_I386
|
||||||
:intel
|
:intel
|
||||||
when MachO::Headers::CPU_TYPE_ARM64
|
when MachO::Headers::CPU_TYPE_ARM64
|
||||||
:arm
|
:arm
|
||||||
else
|
else
|
||||||
:dunno
|
:dunno
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def family
|
def family
|
||||||
if arm?
|
if ::Hardware::CPU.arm?
|
||||||
arm_family
|
arm_family
|
||||||
elsif intel?
|
elsif ::Hardware::CPU.intel?
|
||||||
intel_family
|
intel_family
|
||||||
else
|
else
|
||||||
:dunno
|
:dunno
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# True when running under an Intel-based shell via Rosetta 2 on an
|
# True when running under an Intel-based shell via Rosetta 2 on an
|
||||||
# Apple Silicon Mac. This can be detected via seeing if there's a
|
# Apple Silicon Mac. This can be detected via seeing if there's a
|
||||||
# conflict between what `uname` reports and the underlying `sysctl` flags,
|
# conflict between what `uname` reports and the underlying `sysctl` flags,
|
||||||
# since the `sysctl` flags don't change behaviour under Rosetta 2.
|
# since the `sysctl` flags don't change behaviour under Rosetta 2.
|
||||||
def in_rosetta2?
|
def in_rosetta2?
|
||||||
sysctl_bool("sysctl.proc_translated")
|
sysctl_bool("sysctl.proc_translated")
|
||||||
end
|
|
||||||
|
|
||||||
def features
|
|
||||||
@features ||= sysctl_n(
|
|
||||||
"machdep.cpu.features",
|
|
||||||
"machdep.cpu.extfeatures",
|
|
||||||
"machdep.cpu.leaf7_features",
|
|
||||||
).split.map { |s| s.downcase.to_sym }
|
|
||||||
end
|
|
||||||
|
|
||||||
def sse4?
|
|
||||||
sysctl_bool("hw.optional.sse4_1")
|
|
||||||
end
|
|
||||||
|
|
||||||
def extmodel
|
|
||||||
sysctl_int("machdep.cpu.extmodel")
|
|
||||||
end
|
|
||||||
|
|
||||||
def aes?
|
|
||||||
sysctl_bool("hw.optional.aes")
|
|
||||||
end
|
|
||||||
|
|
||||||
def altivec?
|
|
||||||
sysctl_bool("hw.optional.altivec")
|
|
||||||
end
|
|
||||||
|
|
||||||
def avx?
|
|
||||||
sysctl_bool("hw.optional.avx1_0")
|
|
||||||
end
|
|
||||||
|
|
||||||
def avx2?
|
|
||||||
sysctl_bool("hw.optional.avx2_0")
|
|
||||||
end
|
|
||||||
|
|
||||||
def sse3?
|
|
||||||
sysctl_bool("hw.optional.sse3")
|
|
||||||
end
|
|
||||||
|
|
||||||
def ssse3?
|
|
||||||
sysctl_bool("hw.optional.supplementalsse3")
|
|
||||||
end
|
|
||||||
|
|
||||||
def sse4_2?
|
|
||||||
sysctl_bool("hw.optional.sse4_2")
|
|
||||||
end
|
|
||||||
|
|
||||||
# NOTE: This is more reliable than checking `uname`. `sysctl` returns
|
|
||||||
# the right answer even when running in Rosetta 2.
|
|
||||||
def physical_cpu_arm64?
|
|
||||||
sysctl_bool("hw.optional.arm64")
|
|
||||||
end
|
|
||||||
|
|
||||||
def virtualized?
|
|
||||||
sysctl_bool("kern.hv_vmm_present")
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def arm_family
|
|
||||||
case sysctl_int("hw.cpufamily")
|
|
||||||
when 0x2c91a47e # ARMv8.0-A (Typhoon)
|
|
||||||
:arm_typhoon
|
|
||||||
when 0x92fb37c8 # ARMv8.0-A (Twister)
|
|
||||||
:arm_twister
|
|
||||||
when 0x67ceee93 # ARMv8.1-A (Hurricane, Zephyr)
|
|
||||||
:arm_hurricane_zephyr
|
|
||||||
when 0xe81e7ef6 # ARMv8.2-A (Monsoon, Mistral)
|
|
||||||
:arm_monsoon_mistral
|
|
||||||
when 0x07d34b9f # ARMv8.3-A (Vortex, Tempest)
|
|
||||||
:arm_vortex_tempest
|
|
||||||
when 0x462504d2 # ARMv8.4-A (Lightning, Thunder)
|
|
||||||
:arm_lightning_thunder
|
|
||||||
when 0x573b5eec, 0x1b588bb3 # ARMv8.4-A (Firestorm, Icestorm)
|
|
||||||
:arm_firestorm_icestorm
|
|
||||||
when 0xda33d83d # ARMv8.5-A (Blizzard, Avalanche)
|
|
||||||
:arm_blizzard_avalanche
|
|
||||||
when 0xfa33415e # ARMv8.6-A (M3, Ibiza)
|
|
||||||
:arm_ibiza
|
|
||||||
when 0x5f4dea93 # ARMv8.6-A (M3 Pro, Lobos)
|
|
||||||
:arm_lobos
|
|
||||||
when 0x72015832 # ARMv8.6-A (M3 Max, Palma)
|
|
||||||
:arm_palma
|
|
||||||
else
|
|
||||||
# When adding new ARM CPU families, please also update
|
|
||||||
# test/hardware/cpu_spec.rb to include the new families.
|
|
||||||
:dunno
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def intel_family(_family = nil, _cpu_model = nil)
|
def features
|
||||||
case sysctl_int("hw.cpufamily")
|
@features ||= sysctl_n(
|
||||||
when 0x73d67300 # Yonah: Core Solo/Duo
|
"machdep.cpu.features",
|
||||||
:core
|
"machdep.cpu.extfeatures",
|
||||||
when 0x426f69ef # Merom: Core 2 Duo
|
"machdep.cpu.leaf7_features",
|
||||||
:core2
|
).split.map { |s| s.downcase.to_sym }
|
||||||
when 0x78ea4fbc # Penryn
|
|
||||||
:penryn
|
|
||||||
when 0x6b5a4cd2 # Nehalem
|
|
||||||
:nehalem
|
|
||||||
when 0x573b5eec # Westmere
|
|
||||||
:westmere
|
|
||||||
when 0x5490b78c # Sandy Bridge
|
|
||||||
:sandybridge
|
|
||||||
when 0x1f65e835 # Ivy Bridge
|
|
||||||
:ivybridge
|
|
||||||
when 0x10b282dc # Haswell
|
|
||||||
:haswell
|
|
||||||
when 0x582ed09c # Broadwell
|
|
||||||
:broadwell
|
|
||||||
when 0x37fc219f # Skylake
|
|
||||||
:skylake
|
|
||||||
when 0x0f817246 # Kaby Lake
|
|
||||||
:kabylake
|
|
||||||
when 0x38435547 # Ice Lake
|
|
||||||
:icelake
|
|
||||||
when 0x1cf8a03e # Comet Lake
|
|
||||||
:cometlake
|
|
||||||
else
|
|
||||||
:dunno
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def sysctl_bool(key)
|
def sse4?
|
||||||
sysctl_int(key) == 1
|
sysctl_bool("hw.optional.sse4_1")
|
||||||
end
|
end
|
||||||
|
|
||||||
def sysctl_int(key)
|
def extmodel
|
||||||
sysctl_n(key).to_i & 0xffffffff
|
sysctl_int("machdep.cpu.extmodel")
|
||||||
end
|
end
|
||||||
|
|
||||||
def sysctl_n(*keys)
|
def aes?
|
||||||
(@properties ||= {}).fetch(keys) do
|
sysctl_bool("hw.optional.aes")
|
||||||
@properties[keys] = Utils.popen_read("/usr/sbin/sysctl", "-n", *keys)
|
end
|
||||||
|
|
||||||
|
def altivec?
|
||||||
|
sysctl_bool("hw.optional.altivec")
|
||||||
|
end
|
||||||
|
|
||||||
|
def avx?
|
||||||
|
sysctl_bool("hw.optional.avx1_0")
|
||||||
|
end
|
||||||
|
|
||||||
|
def avx2?
|
||||||
|
sysctl_bool("hw.optional.avx2_0")
|
||||||
|
end
|
||||||
|
|
||||||
|
def sse3?
|
||||||
|
sysctl_bool("hw.optional.sse3")
|
||||||
|
end
|
||||||
|
|
||||||
|
def ssse3?
|
||||||
|
sysctl_bool("hw.optional.supplementalsse3")
|
||||||
|
end
|
||||||
|
|
||||||
|
def sse4_2?
|
||||||
|
sysctl_bool("hw.optional.sse4_2")
|
||||||
|
end
|
||||||
|
|
||||||
|
# NOTE: This is more reliable than checking `uname`. `sysctl` returns
|
||||||
|
# the right answer even when running in Rosetta 2.
|
||||||
|
def physical_cpu_arm64?
|
||||||
|
sysctl_bool("hw.optional.arm64")
|
||||||
|
end
|
||||||
|
|
||||||
|
def virtualized?
|
||||||
|
sysctl_bool("kern.hv_vmm_present")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def arm_family
|
||||||
|
case sysctl_int("hw.cpufamily")
|
||||||
|
when 0x2c91a47e # ARMv8.0-A (Typhoon)
|
||||||
|
:arm_typhoon
|
||||||
|
when 0x92fb37c8 # ARMv8.0-A (Twister)
|
||||||
|
:arm_twister
|
||||||
|
when 0x67ceee93 # ARMv8.1-A (Hurricane, Zephyr)
|
||||||
|
:arm_hurricane_zephyr
|
||||||
|
when 0xe81e7ef6 # ARMv8.2-A (Monsoon, Mistral)
|
||||||
|
:arm_monsoon_mistral
|
||||||
|
when 0x07d34b9f # ARMv8.3-A (Vortex, Tempest)
|
||||||
|
:arm_vortex_tempest
|
||||||
|
when 0x462504d2 # ARMv8.4-A (Lightning, Thunder)
|
||||||
|
:arm_lightning_thunder
|
||||||
|
when 0x573b5eec, 0x1b588bb3 # ARMv8.4-A (Firestorm, Icestorm)
|
||||||
|
:arm_firestorm_icestorm
|
||||||
|
when 0xda33d83d # ARMv8.5-A (Blizzard, Avalanche)
|
||||||
|
:arm_blizzard_avalanche
|
||||||
|
when 0xfa33415e # ARMv8.6-A (M3, Ibiza)
|
||||||
|
:arm_ibiza
|
||||||
|
when 0x5f4dea93 # ARMv8.6-A (M3 Pro, Lobos)
|
||||||
|
:arm_lobos
|
||||||
|
when 0x72015832 # ARMv8.6-A (M3 Max, Palma)
|
||||||
|
:arm_palma
|
||||||
|
else
|
||||||
|
# When adding new ARM CPU families, please also update
|
||||||
|
# test/hardware/cpu_spec.rb to include the new families.
|
||||||
|
:dunno
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def intel_family(_family = nil, _cpu_model = nil)
|
||||||
|
case sysctl_int("hw.cpufamily")
|
||||||
|
when 0x73d67300 # Yonah: Core Solo/Duo
|
||||||
|
:core
|
||||||
|
when 0x426f69ef # Merom: Core 2 Duo
|
||||||
|
:core2
|
||||||
|
when 0x78ea4fbc # Penryn
|
||||||
|
:penryn
|
||||||
|
when 0x6b5a4cd2 # Nehalem
|
||||||
|
:nehalem
|
||||||
|
when 0x573b5eec # Westmere
|
||||||
|
:westmere
|
||||||
|
when 0x5490b78c # Sandy Bridge
|
||||||
|
:sandybridge
|
||||||
|
when 0x1f65e835 # Ivy Bridge
|
||||||
|
:ivybridge
|
||||||
|
when 0x10b282dc # Haswell
|
||||||
|
:haswell
|
||||||
|
when 0x582ed09c # Broadwell
|
||||||
|
:broadwell
|
||||||
|
when 0x37fc219f # Skylake
|
||||||
|
:skylake
|
||||||
|
when 0x0f817246 # Kaby Lake
|
||||||
|
:kabylake
|
||||||
|
when 0x38435547 # Ice Lake
|
||||||
|
:icelake
|
||||||
|
when 0x1cf8a03e # Comet Lake
|
||||||
|
:cometlake
|
||||||
|
else
|
||||||
|
:dunno
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def sysctl_bool(key)
|
||||||
|
sysctl_int(key) == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def sysctl_int(key)
|
||||||
|
sysctl_n(key).to_i & 0xffffffff
|
||||||
|
end
|
||||||
|
|
||||||
|
def sysctl_n(*keys)
|
||||||
|
(@properties ||= {}).fetch(keys) do
|
||||||
|
@properties[keys] = Utils.popen_read("/usr/sbin/sysctl", "-n", *keys)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Hardware::CPU.singleton_class.prepend(OS::Mac::Hardware::CPU)
|
||||||
|
@ -23,101 +23,101 @@ class Keg
|
|||||||
GENERIC_MUST_BE_WRITABLE_DIRECTORIES +
|
GENERIC_MUST_BE_WRITABLE_DIRECTORIES +
|
||||||
[HOMEBREW_PREFIX/"Frameworks"]
|
[HOMEBREW_PREFIX/"Frameworks"]
|
||||||
).sort.uniq.freeze
|
).sort.uniq.freeze
|
||||||
|
end
|
||||||
|
|
||||||
undef binary_executable_or_library_files
|
module OS
|
||||||
|
module Mac
|
||||||
|
module Keg
|
||||||
|
def binary_executable_or_library_files = mach_o_files
|
||||||
|
|
||||||
def binary_executable_or_library_files
|
def codesign_patched_binary(file)
|
||||||
mach_o_files
|
return if MacOS.version < :big_sur
|
||||||
end
|
|
||||||
|
|
||||||
def codesign_patched_binary(file)
|
unless ::Hardware::CPU.arm?
|
||||||
return if MacOS.version < :big_sur
|
result = system_command("codesign", args: ["--verify", file], print_stderr: false)
|
||||||
|
return unless result.stderr.match?(/invalid signature/i)
|
||||||
|
end
|
||||||
|
|
||||||
unless Hardware::CPU.arm?
|
odebug "Codesigning #{file}"
|
||||||
result = system_command("codesign", args: ["--verify", file], print_stderr: false)
|
prepare_codesign_writable_files(file) do
|
||||||
return unless result.stderr.match?(/invalid signature/i)
|
# Use quiet_system to squash notifications about resigning binaries
|
||||||
end
|
# which already have valid signatures.
|
||||||
|
return if quiet_system("codesign", "--sign", "-", "--force",
|
||||||
|
"--preserve-metadata=entitlements,requirements,flags,runtime",
|
||||||
|
file)
|
||||||
|
|
||||||
odebug "Codesigning #{file}"
|
# If the codesigning fails, it may be a bug in Apple's codesign utility
|
||||||
prepare_codesign_writable_files(file) do
|
# A known workaround is to copy the file to another inode, then move it back
|
||||||
# Use quiet_system to squash notifications about resigning binaries
|
# erasing the previous file. Then sign again.
|
||||||
# which already have valid signatures.
|
#
|
||||||
return if quiet_system("codesign", "--sign", "-", "--force",
|
# TODO: remove this once the bug in Apple's codesign utility is fixed
|
||||||
"--preserve-metadata=entitlements,requirements,flags,runtime",
|
Dir::Tmpname.create("workaround") do |tmppath|
|
||||||
file)
|
FileUtils.cp file, tmppath
|
||||||
|
FileUtils.mv tmppath, file, force: true
|
||||||
|
end
|
||||||
|
|
||||||
# If the codesigning fails, it may be a bug in Apple's codesign utility
|
# Try signing again
|
||||||
# A known workaround is to copy the file to another inode, then move it back
|
odebug "Codesigning (2nd try) #{file}"
|
||||||
# erasing the previous file. Then sign again.
|
result = system_command("codesign", args: [
|
||||||
#
|
"--sign", "-", "--force",
|
||||||
# TODO: remove this once the bug in Apple's codesign utility is fixed
|
"--preserve-metadata=entitlements,requirements,flags,runtime",
|
||||||
Dir::Tmpname.create("workaround") do |tmppath|
|
file
|
||||||
FileUtils.cp file, tmppath
|
], print_stderr: false)
|
||||||
FileUtils.mv tmppath, file, force: true
|
return if result.success?
|
||||||
|
|
||||||
|
# If it fails again, error out
|
||||||
|
onoe <<~EOS
|
||||||
|
Failed applying an ad-hoc signature to #{file}:
|
||||||
|
#{result.stderr}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Try signing again
|
def prepare_codesign_writable_files(file)
|
||||||
odebug "Codesigning (2nd try) #{file}"
|
result = system_command("codesign", args: [
|
||||||
result = system_command("codesign", args: [
|
"--display", "--file-list", "-", file
|
||||||
"--sign", "-", "--force",
|
], print_stderr: false)
|
||||||
"--preserve-metadata=entitlements,requirements,flags,runtime",
|
return unless result.success?
|
||||||
file
|
|
||||||
], print_stderr: false)
|
|
||||||
return if result.success?
|
|
||||||
|
|
||||||
# If it fails again, error out
|
files = result.stdout.lines.map { |f| Pathname(f.chomp) }
|
||||||
onoe <<~EOS
|
saved_perms = {}
|
||||||
Failed applying an ad-hoc signature to #{file}:
|
files.each do |f|
|
||||||
#{result.stderr}
|
unless f.writable?
|
||||||
EOS
|
saved_perms[f] = f.stat.mode
|
||||||
end
|
FileUtils.chmod "u+rw", f.to_path
|
||||||
end
|
end
|
||||||
|
end
|
||||||
def prepare_codesign_writable_files(file)
|
yield
|
||||||
result = system_command("codesign", args: [
|
ensure
|
||||||
"--display", "--file-list", "-", file
|
saved_perms&.each do |f, p|
|
||||||
], print_stderr: false)
|
f.chmod p if p
|
||||||
return unless result.success?
|
end
|
||||||
|
|
||||||
files = result.stdout.lines.map { |f| Pathname(f.chomp) }
|
|
||||||
saved_perms = {}
|
|
||||||
files.each do |f|
|
|
||||||
unless f.writable?
|
|
||||||
saved_perms[f] = f.stat.mode
|
|
||||||
FileUtils.chmod "u+rw", f.to_path
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
saved_perms&.each do |f, p|
|
|
||||||
f.chmod p if p
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
undef prepare_debug_symbols
|
def prepare_debug_symbols
|
||||||
|
binary_executable_or_library_files.each do |file|
|
||||||
|
odebug "Extracting symbols #{file}"
|
||||||
|
|
||||||
def prepare_debug_symbols
|
result = system_command("dsymutil", args: [file], print_stderr: false)
|
||||||
binary_executable_or_library_files.each do |file|
|
next if result.success?
|
||||||
odebug "Extracting symbols #{file}"
|
|
||||||
|
|
||||||
result = system_command("dsymutil", args: [file], print_stderr: false)
|
# If it fails again, error out
|
||||||
next if result.success?
|
ofail <<~EOS
|
||||||
|
Failed to extract symbols from #{file}:
|
||||||
|
#{result.stderr}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# If it fails again, error out
|
# Needed to make symlink permissions consistent on macOS and Linux for
|
||||||
ofail <<~EOS
|
# reproducible bottles.
|
||||||
Failed to extract symbols from #{file}:
|
def consistent_reproducible_symlink_permissions!
|
||||||
#{result.stderr}
|
path.find do |file|
|
||||||
EOS
|
File.lchmod 0777, file if file.symlink?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
undef consistent_reproducible_symlink_permissions!
|
|
||||||
|
|
||||||
# Needed to make symlink permissions consistent on macOS and Linux for
|
|
||||||
# reproducible bottles.
|
|
||||||
def consistent_reproducible_symlink_permissions!
|
|
||||||
path.find do |file|
|
|
||||||
File.lchmod 0777, file if file.symlink?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Keg.prepend(OS::Mac::Keg)
|
||||||
|
@ -1,255 +1,262 @@
|
|||||||
# typed: true # rubocop:disable Sorbet/StrictSigil
|
# typed: true # rubocop:disable Sorbet/StrictSigil
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Keg
|
module OS
|
||||||
class << self
|
module Mac
|
||||||
undef file_linked_libraries
|
module Keg
|
||||||
|
extend T::Helpers
|
||||||
|
|
||||||
def file_linked_libraries(file, string)
|
requires_ancestor { ::Keg }
|
||||||
# Check dynamic library linkage. Importantly, do not perform for static
|
|
||||||
# libraries, which will falsely report "linkage" to themselves.
|
|
||||||
if file.mach_o_executable? || file.dylib? || file.mach_o_bundle?
|
|
||||||
file.dynamically_linked_libraries.select { |lib| lib.include? string }
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
undef relocate_dynamic_linkage
|
module ClassMethods
|
||||||
|
def file_linked_libraries(file, string)
|
||||||
def relocate_dynamic_linkage(relocation)
|
# Check dynamic library linkage. Importantly, do not perform for static
|
||||||
mach_o_files.each do |file|
|
# libraries, which will falsely report "linkage" to themselves.
|
||||||
file.ensure_writable do
|
if file.mach_o_executable? || file.dylib? || file.mach_o_bundle?
|
||||||
modified = T.let(false, T::Boolean)
|
file.dynamically_linked_libraries.select { |lib| lib.include? string }
|
||||||
needs_codesigning = T.let(false, T::Boolean)
|
|
||||||
|
|
||||||
if file.dylib?
|
|
||||||
id = relocated_name_for(file.dylib_id, relocation)
|
|
||||||
modified = change_dylib_id(id, file)
|
|
||||||
needs_codesigning ||= modified
|
|
||||||
end
|
|
||||||
|
|
||||||
each_linkage_for(file, :dynamically_linked_libraries) do |old_name|
|
|
||||||
new_name = relocated_name_for(old_name, relocation)
|
|
||||||
modified = change_install_name(old_name, new_name, file) if new_name
|
|
||||||
needs_codesigning ||= modified
|
|
||||||
end
|
|
||||||
|
|
||||||
each_linkage_for(file, :rpaths) do |old_name|
|
|
||||||
new_name = relocated_name_for(old_name, relocation)
|
|
||||||
modified = change_rpath(old_name, new_name, file) if new_name
|
|
||||||
needs_codesigning ||= modified
|
|
||||||
end
|
|
||||||
|
|
||||||
# codesign the file if needed
|
|
||||||
codesign_patched_binary(file) if needs_codesigning
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def fix_dynamic_linkage
|
|
||||||
mach_o_files.each do |file|
|
|
||||||
file.ensure_writable do
|
|
||||||
modified = T.let(false, T::Boolean)
|
|
||||||
needs_codesigning = T.let(false, T::Boolean)
|
|
||||||
|
|
||||||
modified = change_dylib_id(dylib_id_for(file), file) if file.dylib?
|
|
||||||
needs_codesigning ||= modified
|
|
||||||
|
|
||||||
each_linkage_for(file, :dynamically_linked_libraries) do |bad_name|
|
|
||||||
# Don't fix absolute paths unless they are rooted in the build directory.
|
|
||||||
new_name = if bad_name.start_with?("/") && !rooted_in_build_directory?(bad_name)
|
|
||||||
bad_name
|
|
||||||
else
|
else
|
||||||
fixed_name(file, bad_name)
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def relocate_dynamic_linkage(relocation)
|
||||||
|
mach_o_files.each do |file|
|
||||||
|
file.ensure_writable do
|
||||||
|
modified = T.let(false, T::Boolean)
|
||||||
|
needs_codesigning = T.let(false, T::Boolean)
|
||||||
|
|
||||||
|
if file.dylib?
|
||||||
|
id = relocated_name_for(file.dylib_id, relocation)
|
||||||
|
modified = change_dylib_id(id, file)
|
||||||
|
needs_codesigning ||= modified
|
||||||
|
end
|
||||||
|
|
||||||
|
each_linkage_for(file, :dynamically_linked_libraries) do |old_name|
|
||||||
|
new_name = relocated_name_for(old_name, relocation)
|
||||||
|
modified = change_install_name(old_name, new_name, file) if new_name
|
||||||
|
needs_codesigning ||= modified
|
||||||
|
end
|
||||||
|
|
||||||
|
each_linkage_for(file, :rpaths) do |old_name|
|
||||||
|
new_name = relocated_name_for(old_name, relocation)
|
||||||
|
modified = change_rpath(old_name, new_name, file) if new_name
|
||||||
|
needs_codesigning ||= modified
|
||||||
|
end
|
||||||
|
|
||||||
|
# codesign the file if needed
|
||||||
|
codesign_patched_binary(file) if needs_codesigning
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_dynamic_linkage
|
||||||
|
mach_o_files.each do |file|
|
||||||
|
file.ensure_writable do
|
||||||
|
modified = T.let(false, T::Boolean)
|
||||||
|
needs_codesigning = T.let(false, T::Boolean)
|
||||||
|
|
||||||
|
modified = change_dylib_id(dylib_id_for(file), file) if file.dylib?
|
||||||
|
needs_codesigning ||= modified
|
||||||
|
|
||||||
|
each_linkage_for(file, :dynamically_linked_libraries) do |bad_name|
|
||||||
|
# Don't fix absolute paths unless they are rooted in the build directory.
|
||||||
|
new_name = if bad_name.start_with?("/") && !rooted_in_build_directory?(bad_name)
|
||||||
|
bad_name
|
||||||
|
else
|
||||||
|
fixed_name(file, bad_name)
|
||||||
|
end
|
||||||
|
loader_name = loader_name_for(file, new_name)
|
||||||
|
modified = change_install_name(bad_name, loader_name, file) if loader_name != bad_name
|
||||||
|
needs_codesigning ||= modified
|
||||||
|
end
|
||||||
|
|
||||||
|
each_linkage_for(file, :rpaths) do |bad_name|
|
||||||
|
new_name = opt_name_for(bad_name)
|
||||||
|
loader_name = loader_name_for(file, new_name)
|
||||||
|
next if loader_name == bad_name
|
||||||
|
|
||||||
|
modified = change_rpath(bad_name, loader_name, file)
|
||||||
|
needs_codesigning ||= modified
|
||||||
|
end
|
||||||
|
|
||||||
|
# Strip duplicate rpaths and rpaths rooted in the build directory.
|
||||||
|
# We do this separately from the rpath relocation above to avoid
|
||||||
|
# failing to relocate an rpath whose variable duplicate we deleted.
|
||||||
|
each_linkage_for(file, :rpaths, resolve_variable_references: true) do |bad_name|
|
||||||
|
next if !rooted_in_build_directory?(bad_name) && file.rpaths.count(bad_name) == 1
|
||||||
|
|
||||||
|
modified = delete_rpath(bad_name, file)
|
||||||
|
needs_codesigning ||= modified
|
||||||
|
end
|
||||||
|
|
||||||
|
# codesign the file if needed
|
||||||
|
codesign_patched_binary(file) if needs_codesigning
|
||||||
end
|
end
|
||||||
loader_name = loader_name_for(file, new_name)
|
|
||||||
modified = change_install_name(bad_name, loader_name, file) if loader_name != bad_name
|
|
||||||
needs_codesigning ||= modified
|
|
||||||
end
|
end
|
||||||
|
|
||||||
each_linkage_for(file, :rpaths) do |bad_name|
|
generic_fix_dynamic_linkage
|
||||||
new_name = opt_name_for(bad_name)
|
end
|
||||||
loader_name = loader_name_for(file, new_name)
|
|
||||||
next if loader_name == bad_name
|
|
||||||
|
|
||||||
modified = change_rpath(bad_name, loader_name, file)
|
def loader_name_for(file, target)
|
||||||
needs_codesigning ||= modified
|
# Use @loader_path-relative install names for other Homebrew-installed binaries.
|
||||||
|
if ENV["HOMEBREW_RELOCATABLE_INSTALL_NAMES"] && target.start_with?(HOMEBREW_PREFIX)
|
||||||
|
dylib_suffix = find_dylib_suffix_from(target)
|
||||||
|
target_dir = Pathname.new(target.delete_suffix(dylib_suffix)).cleanpath
|
||||||
|
|
||||||
|
"@loader_path/#{target_dir.relative_path_from(file.dirname)/dylib_suffix}"
|
||||||
|
else
|
||||||
|
target
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If file is a dylib or bundle itself, look for the dylib named by
|
||||||
|
# bad_name relative to the lib directory, so that we can skip the more
|
||||||
|
# expensive recursive search if possible.
|
||||||
|
def fixed_name(file, bad_name)
|
||||||
|
if bad_name.start_with? ::Keg::PREFIX_PLACEHOLDER
|
||||||
|
bad_name.sub(::Keg::PREFIX_PLACEHOLDER, HOMEBREW_PREFIX)
|
||||||
|
elsif bad_name.start_with? ::Keg::CELLAR_PLACEHOLDER
|
||||||
|
bad_name.sub(::Keg::CELLAR_PLACEHOLDER, HOMEBREW_CELLAR)
|
||||||
|
elsif (file.dylib? || file.mach_o_bundle?) && (file.dirname/bad_name).exist?
|
||||||
|
"@loader_path/#{bad_name}"
|
||||||
|
elsif file.mach_o_executable? && (lib/bad_name).exist?
|
||||||
|
"#{lib}/#{bad_name}"
|
||||||
|
elsif file.mach_o_executable? && (libexec/"lib"/bad_name).exist?
|
||||||
|
"#{libexec}/lib/#{bad_name}"
|
||||||
|
elsif (abs_name = find_dylib(bad_name)) && abs_name.exist?
|
||||||
|
abs_name.to_s
|
||||||
|
else
|
||||||
|
opoo "Could not fix #{bad_name} in #{file}"
|
||||||
|
bad_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
VARIABLE_REFERENCE_RX = /^@(loader_|executable_|r)path/
|
||||||
|
|
||||||
|
def each_linkage_for(file, linkage_type, resolve_variable_references: false, &block)
|
||||||
|
file.public_send(linkage_type, resolve_variable_references:)
|
||||||
|
.grep_v(VARIABLE_REFERENCE_RX)
|
||||||
|
.each(&block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def dylib_id_for(file)
|
||||||
|
# The new dylib ID should have the same basename as the old dylib ID, not
|
||||||
|
# the basename of the file itself.
|
||||||
|
basename = File.basename(file.dylib_id)
|
||||||
|
relative_dirname = file.dirname.relative_path_from(path)
|
||||||
|
(opt_record/relative_dirname/basename).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def relocated_name_for(old_name, relocation)
|
||||||
|
old_prefix, new_prefix = relocation.replacement_pair_for(:prefix)
|
||||||
|
old_cellar, new_cellar = relocation.replacement_pair_for(:cellar)
|
||||||
|
|
||||||
|
if old_name.start_with? old_cellar
|
||||||
|
old_name.sub(old_cellar, new_cellar)
|
||||||
|
elsif old_name.start_with? old_prefix
|
||||||
|
old_name.sub(old_prefix, new_prefix)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Matches framework references like `XXX.framework/Versions/YYY/XXX` and
|
||||||
|
# `XXX.framework/XXX`, both with or without a slash-delimited prefix.
|
||||||
|
FRAMEWORK_RX = %r{(?:^|/)(([^/]+)\.framework/(?:Versions/[^/]+/)?\2)$}
|
||||||
|
|
||||||
|
def find_dylib_suffix_from(bad_name)
|
||||||
|
if (framework = bad_name.match(FRAMEWORK_RX))
|
||||||
|
framework[1]
|
||||||
|
else
|
||||||
|
File.basename(bad_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_dylib(bad_name)
|
||||||
|
return unless lib.directory?
|
||||||
|
|
||||||
|
suffix = "/#{find_dylib_suffix_from(bad_name)}"
|
||||||
|
lib.find { |pn| break pn if pn.to_s.end_with?(suffix) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def mach_o_files
|
||||||
|
hardlinks = Set.new
|
||||||
|
mach_o_files = []
|
||||||
|
path.find do |pn|
|
||||||
|
next if pn.symlink? || pn.directory?
|
||||||
|
next if !pn.dylib? && !pn.mach_o_bundle? && !pn.mach_o_executable?
|
||||||
|
# if we've already processed a file, ignore its hardlinks (which have the same dev ID and inode)
|
||||||
|
# this prevents relocations from being performed on a binary more than once
|
||||||
|
next unless hardlinks.add? [pn.stat.dev, pn.stat.ino]
|
||||||
|
|
||||||
|
mach_o_files << pn
|
||||||
end
|
end
|
||||||
|
|
||||||
# Strip duplicate rpaths and rpaths rooted in the build directory.
|
mach_o_files
|
||||||
# We do this separately from the rpath relocation above to avoid
|
end
|
||||||
# failing to relocate an rpath whose variable duplicate we deleted.
|
|
||||||
each_linkage_for(file, :rpaths, resolve_variable_references: true) do |bad_name|
|
|
||||||
next if !rooted_in_build_directory?(bad_name) && file.rpaths.count(bad_name) == 1
|
|
||||||
|
|
||||||
modified = delete_rpath(bad_name, file)
|
def prepare_relocation_to_locations
|
||||||
needs_codesigning ||= modified
|
relocation = generic_prepare_relocation_to_locations
|
||||||
|
|
||||||
|
brewed_perl = runtime_dependencies&.any? { |dep| dep["full_name"] == "perl" && dep["declared_directly"] }
|
||||||
|
perl_path = if brewed_perl || name == "perl"
|
||||||
|
"#{HOMEBREW_PREFIX}/opt/perl/bin/perl"
|
||||||
|
elsif tab.built_on.present?
|
||||||
|
perl_path = "/usr/bin/perl#{tab.built_on["preferred_perl"]}"
|
||||||
|
|
||||||
|
# For `:all` bottles, we could have built this bottle with a Perl we don't have.
|
||||||
|
# Such bottles typically don't have strict version requirements.
|
||||||
|
perl_path = "/usr/bin/perl#{MacOS.preferred_perl_version}" unless File.exist?(perl_path)
|
||||||
|
|
||||||
|
perl_path
|
||||||
|
else
|
||||||
|
"/usr/bin/perl#{MacOS.preferred_perl_version}"
|
||||||
|
end
|
||||||
|
relocation.add_replacement_pair(:perl, ::Keg::PERL_PLACEHOLDER, perl_path)
|
||||||
|
|
||||||
|
if (openjdk = openjdk_dep_name_if_applicable)
|
||||||
|
openjdk_path = HOMEBREW_PREFIX/"opt"/openjdk/"libexec/openjdk.jdk/Contents/Home"
|
||||||
|
relocation.add_replacement_pair(:java, ::Keg::JAVA_PLACEHOLDER, openjdk_path.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
# codesign the file if needed
|
relocation
|
||||||
codesign_patched_binary(file) if needs_codesigning
|
end
|
||||||
|
|
||||||
|
def recursive_fgrep_args
|
||||||
|
# Don't recurse into symlinks; the man page says this is the default, but
|
||||||
|
# it's wrong. -O is a BSD-grep-only option.
|
||||||
|
"-lrO"
|
||||||
|
end
|
||||||
|
|
||||||
|
def egrep_args
|
||||||
|
grep_bin = "egrep"
|
||||||
|
grep_args = "--files-with-matches"
|
||||||
|
[grep_bin, grep_args]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
CELLAR_RX = %r{\A#{HOMEBREW_CELLAR}/(?<formula_name>[^/]+)/[^/]+}
|
||||||
|
|
||||||
|
# Replace HOMEBREW_CELLAR references with HOMEBREW_PREFIX/opt references
|
||||||
|
# if the Cellar reference is to a different keg.
|
||||||
|
def opt_name_for(filename)
|
||||||
|
return filename unless filename.start_with?(HOMEBREW_PREFIX.to_s)
|
||||||
|
return filename if filename.start_with?(path.to_s)
|
||||||
|
return filename if (matches = CELLAR_RX.match(filename)).blank?
|
||||||
|
|
||||||
|
filename.sub(CELLAR_RX, "#{HOMEBREW_PREFIX}/opt/#{matches[:formula_name]}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def rooted_in_build_directory?(filename)
|
||||||
|
# CMake normalises `/private/tmp` to `/tmp`.
|
||||||
|
# https://gitlab.kitware.com/cmake/cmake/-/issues/23251
|
||||||
|
return true if HOMEBREW_TEMP.to_s == "/private/tmp" && filename.start_with?("/tmp/")
|
||||||
|
|
||||||
|
filename.start_with?(HOMEBREW_TEMP.to_s) || filename.start_with?(HOMEBREW_TEMP.realpath.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
generic_fix_dynamic_linkage
|
|
||||||
end
|
|
||||||
|
|
||||||
def loader_name_for(file, target)
|
|
||||||
# Use @loader_path-relative install names for other Homebrew-installed binaries.
|
|
||||||
if ENV["HOMEBREW_RELOCATABLE_INSTALL_NAMES"] && target.start_with?(HOMEBREW_PREFIX)
|
|
||||||
dylib_suffix = find_dylib_suffix_from(target)
|
|
||||||
target_dir = Pathname.new(target.delete_suffix(dylib_suffix)).cleanpath
|
|
||||||
|
|
||||||
"@loader_path/#{target_dir.relative_path_from(file.dirname)/dylib_suffix}"
|
|
||||||
else
|
|
||||||
target
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# If file is a dylib or bundle itself, look for the dylib named by
|
|
||||||
# bad_name relative to the lib directory, so that we can skip the more
|
|
||||||
# expensive recursive search if possible.
|
|
||||||
def fixed_name(file, bad_name)
|
|
||||||
if bad_name.start_with? PREFIX_PLACEHOLDER
|
|
||||||
bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX)
|
|
||||||
elsif bad_name.start_with? CELLAR_PLACEHOLDER
|
|
||||||
bad_name.sub(CELLAR_PLACEHOLDER, HOMEBREW_CELLAR)
|
|
||||||
elsif (file.dylib? || file.mach_o_bundle?) && (file.dirname/bad_name).exist?
|
|
||||||
"@loader_path/#{bad_name}"
|
|
||||||
elsif file.mach_o_executable? && (lib/bad_name).exist?
|
|
||||||
"#{lib}/#{bad_name}"
|
|
||||||
elsif file.mach_o_executable? && (libexec/"lib"/bad_name).exist?
|
|
||||||
"#{libexec}/lib/#{bad_name}"
|
|
||||||
elsif (abs_name = find_dylib(bad_name)) && abs_name.exist?
|
|
||||||
abs_name.to_s
|
|
||||||
else
|
|
||||||
opoo "Could not fix #{bad_name} in #{file}"
|
|
||||||
bad_name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
VARIABLE_REFERENCE_RX = /^@(loader_|executable_|r)path/
|
|
||||||
|
|
||||||
def each_linkage_for(file, linkage_type, resolve_variable_references: false, &block)
|
|
||||||
file.public_send(linkage_type, resolve_variable_references:)
|
|
||||||
.grep_v(VARIABLE_REFERENCE_RX)
|
|
||||||
.each(&block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def dylib_id_for(file)
|
|
||||||
# The new dylib ID should have the same basename as the old dylib ID, not
|
|
||||||
# the basename of the file itself.
|
|
||||||
basename = File.basename(file.dylib_id)
|
|
||||||
relative_dirname = file.dirname.relative_path_from(path)
|
|
||||||
(opt_record/relative_dirname/basename).to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def relocated_name_for(old_name, relocation)
|
|
||||||
old_prefix, new_prefix = relocation.replacement_pair_for(:prefix)
|
|
||||||
old_cellar, new_cellar = relocation.replacement_pair_for(:cellar)
|
|
||||||
|
|
||||||
if old_name.start_with? old_cellar
|
|
||||||
old_name.sub(old_cellar, new_cellar)
|
|
||||||
elsif old_name.start_with? old_prefix
|
|
||||||
old_name.sub(old_prefix, new_prefix)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Matches framework references like `XXX.framework/Versions/YYY/XXX` and
|
|
||||||
# `XXX.framework/XXX`, both with or without a slash-delimited prefix.
|
|
||||||
FRAMEWORK_RX = %r{(?:^|/)(([^/]+)\.framework/(?:Versions/[^/]+/)?\2)$}
|
|
||||||
|
|
||||||
def find_dylib_suffix_from(bad_name)
|
|
||||||
if (framework = bad_name.match(FRAMEWORK_RX))
|
|
||||||
framework[1]
|
|
||||||
else
|
|
||||||
File.basename(bad_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_dylib(bad_name)
|
|
||||||
return unless lib.directory?
|
|
||||||
|
|
||||||
suffix = "/#{find_dylib_suffix_from(bad_name)}"
|
|
||||||
lib.find { |pn| break pn if pn.to_s.end_with?(suffix) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def mach_o_files
|
|
||||||
hardlinks = Set.new
|
|
||||||
mach_o_files = []
|
|
||||||
path.find do |pn|
|
|
||||||
next if pn.symlink? || pn.directory?
|
|
||||||
next if !pn.dylib? && !pn.mach_o_bundle? && !pn.mach_o_executable?
|
|
||||||
# if we've already processed a file, ignore its hardlinks (which have the same dev ID and inode)
|
|
||||||
# this prevents relocations from being performed on a binary more than once
|
|
||||||
next unless hardlinks.add? [pn.stat.dev, pn.stat.ino]
|
|
||||||
|
|
||||||
mach_o_files << pn
|
|
||||||
end
|
|
||||||
|
|
||||||
mach_o_files
|
|
||||||
end
|
|
||||||
|
|
||||||
def prepare_relocation_to_locations
|
|
||||||
relocation = generic_prepare_relocation_to_locations
|
|
||||||
|
|
||||||
brewed_perl = runtime_dependencies&.any? { |dep| dep["full_name"] == "perl" && dep["declared_directly"] }
|
|
||||||
perl_path = if brewed_perl || name == "perl"
|
|
||||||
"#{HOMEBREW_PREFIX}/opt/perl/bin/perl"
|
|
||||||
elsif tab.built_on.present?
|
|
||||||
perl_path = "/usr/bin/perl#{tab.built_on["preferred_perl"]}"
|
|
||||||
|
|
||||||
# For `:all` bottles, we could have built this bottle with a Perl we don't have.
|
|
||||||
# Such bottles typically don't have strict version requirements.
|
|
||||||
perl_path = "/usr/bin/perl#{MacOS.preferred_perl_version}" unless File.exist?(perl_path)
|
|
||||||
|
|
||||||
perl_path
|
|
||||||
else
|
|
||||||
"/usr/bin/perl#{MacOS.preferred_perl_version}"
|
|
||||||
end
|
|
||||||
relocation.add_replacement_pair(:perl, PERL_PLACEHOLDER, perl_path)
|
|
||||||
|
|
||||||
if (openjdk = openjdk_dep_name_if_applicable)
|
|
||||||
openjdk_path = HOMEBREW_PREFIX/"opt"/openjdk/"libexec/openjdk.jdk/Contents/Home"
|
|
||||||
relocation.add_replacement_pair(:java, JAVA_PLACEHOLDER, openjdk_path.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
relocation
|
|
||||||
end
|
|
||||||
|
|
||||||
def recursive_fgrep_args
|
|
||||||
# Don't recurse into symlinks; the man page says this is the default, but
|
|
||||||
# it's wrong. -O is a BSD-grep-only option.
|
|
||||||
"-lrO"
|
|
||||||
end
|
|
||||||
|
|
||||||
def egrep_args
|
|
||||||
grep_bin = "egrep"
|
|
||||||
grep_args = "--files-with-matches"
|
|
||||||
[grep_bin, grep_args]
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
CELLAR_RX = %r{\A#{HOMEBREW_CELLAR}/(?<formula_name>[^/]+)/[^/]+}
|
|
||||||
|
|
||||||
# Replace HOMEBREW_CELLAR references with HOMEBREW_PREFIX/opt references
|
|
||||||
# if the Cellar reference is to a different keg.
|
|
||||||
def opt_name_for(filename)
|
|
||||||
return filename unless filename.start_with?(HOMEBREW_PREFIX.to_s)
|
|
||||||
return filename if filename.start_with?(path.to_s)
|
|
||||||
return filename if (matches = CELLAR_RX.match(filename)).blank?
|
|
||||||
|
|
||||||
filename.sub(CELLAR_RX, "#{HOMEBREW_PREFIX}/opt/#{matches[:formula_name]}")
|
|
||||||
end
|
|
||||||
|
|
||||||
def rooted_in_build_directory?(filename)
|
|
||||||
# CMake normalises `/private/tmp` to `/tmp`.
|
|
||||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/23251
|
|
||||||
return true if HOMEBREW_TEMP.to_s == "/private/tmp" && filename.start_with?("/tmp/")
|
|
||||||
|
|
||||||
filename.start_with?(HOMEBREW_TEMP.to_s) || filename.start_with?(HOMEBREW_TEMP.realpath.to_s)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Keg.singleton_class.prepend(OS::Mac::Keg::ClassMethods)
|
||||||
|
Keg.prepend(OS::Mac::Keg)
|
||||||
|
@ -9,7 +9,7 @@ module OS
|
|||||||
requires_ancestor { Kernel }
|
requires_ancestor { Kernel }
|
||||||
|
|
||||||
sig { params(tap: Tap, os_name: T.nilable(Symbol), arch: T.nilable(Symbol)).returns(T::Boolean) }
|
sig { params(tap: Tap, os_name: T.nilable(Symbol), arch: T.nilable(Symbol)).returns(T::Boolean) }
|
||||||
def valid_casks?(tap, os_name: nil, arch: Hardware::CPU.type)
|
def valid_casks?(tap, os_name: nil, arch: ::Hardware::CPU.type)
|
||||||
return true if os_name == :linux
|
return true if os_name == :linux
|
||||||
|
|
||||||
current_macos_version = if os_name.is_a?(Symbol)
|
current_macos_version = if os_name.is_a?(Symbol)
|
||||||
|
@ -13,7 +13,7 @@ module OS
|
|||||||
|
|
||||||
sig { returns(Symbol) }
|
sig { returns(Symbol) }
|
||||||
def current_os
|
def current_os
|
||||||
Homebrew::SimulateSystem.os || MacOS.version.to_sym
|
::Homebrew::SimulateSystem.os || MacOS.version.to_sym
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,20 +3,26 @@
|
|||||||
|
|
||||||
require "system_command"
|
require "system_command"
|
||||||
|
|
||||||
|
module OS
|
||||||
|
module Mac
|
||||||
|
module SystemConfig
|
||||||
|
sig { returns(String) }
|
||||||
|
def describe_clang
|
||||||
|
return "N/A" if ::SystemConfig.clang.null?
|
||||||
|
|
||||||
|
clang_build_info = ::SystemConfig.clang_build.null? ? "(parse error)" : ::SystemConfig.clang_build
|
||||||
|
"#{::SystemConfig.clang} build #{clang_build_info}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
SystemConfig.prepend(OS::Mac::SystemConfig)
|
||||||
|
|
||||||
module SystemConfig
|
module SystemConfig
|
||||||
class << self
|
class << self
|
||||||
include SystemCommand::Mixin
|
include SystemCommand::Mixin
|
||||||
|
|
||||||
undef describe_clang
|
|
||||||
|
|
||||||
sig { returns(String) }
|
|
||||||
def describe_clang
|
|
||||||
return "N/A" if clang.null?
|
|
||||||
|
|
||||||
clang_build_info = clang_build.null? ? "(parse error)" : clang_build
|
|
||||||
"#{clang} build #{clang_build_info}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def xcode
|
def xcode
|
||||||
@xcode ||= if MacOS::Xcode.installed?
|
@xcode ||= if MacOS::Xcode.installed?
|
||||||
xcode = MacOS::Xcode.version.to_s
|
xcode = MacOS::Xcode.version.to_s
|
||||||
|
9
Library/Homebrew/hardware.rbi
Normal file
9
Library/Homebrew/hardware.rbi
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# typed: strict
|
||||||
|
|
||||||
|
module Hardware
|
||||||
|
class CPU
|
||||||
|
class << self
|
||||||
|
include OS::Mac::Hardware::CPU
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
5
Library/Homebrew/keg.rbi
Normal file
5
Library/Homebrew/keg.rbi
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# typed: strict
|
||||||
|
|
||||||
|
class Keg
|
||||||
|
include OS::Mac::Keg
|
||||||
|
end
|
@ -210,7 +210,6 @@ class Keg
|
|||||||
# for GNU grep; overridden for BSD grep on OS X
|
# for GNU grep; overridden for BSD grep on OS X
|
||||||
"-lr"
|
"-lr"
|
||||||
end
|
end
|
||||||
alias generic_recursive_fgrep_args recursive_fgrep_args
|
|
||||||
|
|
||||||
def egrep_args
|
def egrep_args
|
||||||
grep_bin = "grep"
|
grep_bin = "grep"
|
||||||
|
@ -151,7 +151,7 @@ module OS
|
|||||||
# Xcode.prefix is pretty smart, so let's look inside to find the sdk
|
# Xcode.prefix is pretty smart, so let's look inside to find the sdk
|
||||||
sdk_prefix = "#{Xcode.prefix}/Platforms/MacOSX.platform/Developer/SDKs"
|
sdk_prefix = "#{Xcode.prefix}/Platforms/MacOSX.platform/Developer/SDKs"
|
||||||
# Finally query Xcode itself (this is slow, so check it last)
|
# Finally query Xcode itself (this is slow, so check it last)
|
||||||
sdk_platform_path = Utils.popen_read(DevelopmentTools.locate("xcrun"), "--show-sdk-platform-path").chomp
|
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
|
sdk_prefix = File.join(sdk_platform_path, "Developer", "SDKs") unless File.directory? sdk_prefix
|
||||||
|
|
||||||
sdk_prefix
|
sdk_prefix
|
||||||
|
@ -227,7 +227,7 @@ module OS
|
|||||||
|
|
||||||
sig { returns(String) }
|
sig { returns(String) }
|
||||||
def self.detect_version_from_clang_version
|
def self.detect_version_from_clang_version
|
||||||
version = DevelopmentTools.clang_version
|
version = ::DevelopmentTools.clang_version
|
||||||
|
|
||||||
return "dunno" if version.null?
|
return "dunno" if version.null?
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class AbstractTab
|
|||||||
"tap" => nil,
|
"tap" => nil,
|
||||||
"tap_git_head" => nil,
|
"tap_git_head" => nil,
|
||||||
},
|
},
|
||||||
"built_on" => DevelopmentTools.generic_build_system_info,
|
"built_on" => DevelopmentTools.build_system_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
new(attributes)
|
new(attributes)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user