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,
 | 
			
		||||
      }
 | 
			
		||||
    end
 | 
			
		||||
    alias generic_build_system_info build_system_info
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
require "os/linux/glibc"
 | 
			
		||||
 | 
			
		||||
class DependencyCollector
 | 
			
		||||
  undef gcc_dep_if_needed
 | 
			
		||||
  undef glibc_dep_if_needed
 | 
			
		||||
  undef init_global_dep_tree_if_needed!
 | 
			
		||||
module OS
 | 
			
		||||
  module Linux
 | 
			
		||||
    module DependencyCollector
 | 
			
		||||
      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)) }
 | 
			
		||||
  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)
 | 
			
		||||
        Dependency.new(GCC, [:implicit])
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    Dependency.new(GCC, [:implicit])
 | 
			
		||||
  end
 | 
			
		||||
      sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
 | 
			
		||||
      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)) }
 | 
			
		||||
  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)
 | 
			
		||||
        Dependency.new(GLIBC, [:implicit])
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    Dependency.new(GLIBC, [:implicit])
 | 
			
		||||
  end
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
      GLIBC = "glibc"
 | 
			
		||||
      GCC = OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA
 | 
			
		||||
 | 
			
		||||
  GLIBC = "glibc"
 | 
			
		||||
  GCC = OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA
 | 
			
		||||
      sig { void }
 | 
			
		||||
      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 }
 | 
			
		||||
  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?
 | 
			
		||||
        building_global_dep_tree!
 | 
			
		||||
        global_dep_tree[GLIBC] = Set.new(global_deps_for(GLIBC))
 | 
			
		||||
        # gcc depends on glibc
 | 
			
		||||
        global_dep_tree[GCC] = Set.new([*global_deps_for(GCC), GLIBC, *@@global_dep_tree[GLIBC]])
 | 
			
		||||
        built_global_dep_tree!
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    building_global_dep_tree!
 | 
			
		||||
    global_dep_tree[GLIBC] = Set.new(global_deps_for(GLIBC))
 | 
			
		||||
    # gcc depends on glibc
 | 
			
		||||
    global_dep_tree[GCC] = Set.new([*global_deps_for(GCC), GLIBC, *@@global_dep_tree[GLIBC]])
 | 
			
		||||
    built_global_dep_tree!
 | 
			
		||||
  end
 | 
			
		||||
      sig { params(name: String).returns(T.nilable(Formula)) }
 | 
			
		||||
      def formula_for(name)
 | 
			
		||||
        @formula_for ||= T.let({}, T.nilable(T::Hash[String, Formula]))
 | 
			
		||||
        @formula_for[name] ||= ::Formula[name]
 | 
			
		||||
      rescue FormulaUnavailableError
 | 
			
		||||
        nil
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
  sig { params(name: String).returns(T.nilable(Formula)) }
 | 
			
		||||
  def formula_for(name)
 | 
			
		||||
    @formula_for ||= {}
 | 
			
		||||
    @formula_for[name] ||= Formula[name]
 | 
			
		||||
  rescue FormulaUnavailableError
 | 
			
		||||
    nil
 | 
			
		||||
  end
 | 
			
		||||
      sig { params(name: String).returns(T::Array[String]) }
 | 
			
		||||
      def global_deps_for(name)
 | 
			
		||||
        @global_deps_for ||= T.let({}, T.nilable(T::Hash[String, T::Array[String]]))
 | 
			
		||||
        # Always strip out glibc and gcc from all parts of dependency tree when
 | 
			
		||||
        # we're calculating their dependency trees. Other parts of Homebrew will
 | 
			
		||||
        # catch any circular dependencies.
 | 
			
		||||
        @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]) }
 | 
			
		||||
  def global_deps_for(name)
 | 
			
		||||
    @global_deps_for ||= {}
 | 
			
		||||
    # Always strip out glibc and gcc from all parts of dependency tree when
 | 
			
		||||
    # we're calculating their dependency trees. Other parts of Homebrew will
 | 
			
		||||
    # catch any circular dependencies.
 | 
			
		||||
    @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
 | 
			
		||||
      []
 | 
			
		||||
      # Use class variables to avoid this expensive logic needing to be done more
 | 
			
		||||
      # than once.
 | 
			
		||||
      # rubocop:disable Style/ClassVars
 | 
			
		||||
      @@global_dep_tree = T.let({}, T::Hash[String, T::Set[String]])
 | 
			
		||||
      @@building_global_dep_tree = T.let(false, T::Boolean)
 | 
			
		||||
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
  # 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
 | 
			
		||||
 | 
			
		||||
DependencyCollector.prepend(OS::Linux::DependencyCollector)
 | 
			
		||||
 | 
			
		||||
@ -1,54 +1,64 @@
 | 
			
		||||
# typed: true # rubocop:todo Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class DevelopmentTools
 | 
			
		||||
  class << self
 | 
			
		||||
    sig { params(tool: T.any(String, Symbol)).returns(T.nilable(Pathname)) }
 | 
			
		||||
    def locate(tool)
 | 
			
		||||
      (@locate ||= {}).fetch(tool) do |key|
 | 
			
		||||
        @locate[key] = if needs_build_formulae? &&
 | 
			
		||||
                          (binutils_path = HOMEBREW_PREFIX/"opt/binutils/bin/#{tool}").executable?
 | 
			
		||||
          binutils_path
 | 
			
		||||
        elsif 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
 | 
			
		||||
module OS
 | 
			
		||||
  module Linux
 | 
			
		||||
    module DevelopmentTools
 | 
			
		||||
      extend T::Helpers
 | 
			
		||||
 | 
			
		||||
      requires_ancestor { ::DevelopmentTools }
 | 
			
		||||
 | 
			
		||||
      sig { params(tool: T.any(String, Symbol)).returns(T.nilable(Pathname)) }
 | 
			
		||||
      def locate(tool)
 | 
			
		||||
        @locate ||= T.let({}, T.nilable(T::Hash[T.any(String, Symbol), Pathname]))
 | 
			
		||||
        @locate.fetch(tool) do |key|
 | 
			
		||||
          @locate[key] = if ::DevelopmentTools.needs_build_formulae? &&
 | 
			
		||||
                            (binutils_path = HOMEBREW_PREFIX/"opt/binutils/bin/#{tool}").executable?
 | 
			
		||||
            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
 | 
			
		||||
 | 
			
		||||
    sig { returns(Symbol) }
 | 
			
		||||
    def default_compiler
 | 
			
		||||
      :gcc
 | 
			
		||||
    end
 | 
			
		||||
      sig { returns(Symbol) }
 | 
			
		||||
      def default_compiler = :gcc
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def needs_libc_formula?
 | 
			
		||||
      return @needs_libc_formula if defined? @needs_libc_formula
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def needs_libc_formula?
 | 
			
		||||
        return @needs_libc_formula unless @needs_libc_formula.nil?
 | 
			
		||||
 | 
			
		||||
      @needs_libc_formula = OS::Linux::Glibc.below_ci_version?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
        @needs_libc_formula = T.let(OS::Linux::Glibc.below_ci_version?, T.nilable(T::Boolean))
 | 
			
		||||
        @needs_libc_formula = !!@needs_libc_formula
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Hash[String, T.nilable(String)]) }
 | 
			
		||||
    def build_system_info
 | 
			
		||||
      generic_build_system_info.merge({
 | 
			
		||||
        "glibc_version"     => OS::Linux::Glibc.version.to_s.presence,
 | 
			
		||||
        "oldest_cpu_family" => Hardware.oldest_cpu.to_s,
 | 
			
		||||
      })
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def needs_compiler_formula?
 | 
			
		||||
        return @needs_compiler_formula unless @needs_compiler_formula.nil?
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
DevelopmentTools.singleton_class.prepend(OS::Linux::DevelopmentTools)
 | 
			
		||||
 | 
			
		||||
@ -7,168 +7,174 @@ require "hardware"
 | 
			
		||||
require "os/linux/glibc"
 | 
			
		||||
require "os/linux/kernel"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module Diagnostic
 | 
			
		||||
    class Checks
 | 
			
		||||
      undef fatal_preinstall_checks, supported_configuration_checks
 | 
			
		||||
module OS
 | 
			
		||||
  module Linux
 | 
			
		||||
    module Diagnostic
 | 
			
		||||
      module Checks
 | 
			
		||||
        extend T::Helpers
 | 
			
		||||
 | 
			
		||||
      def fatal_preinstall_checks
 | 
			
		||||
        %w[
 | 
			
		||||
          check_access_directories
 | 
			
		||||
          check_linuxbrew_core
 | 
			
		||||
          check_linuxbrew_bottle_domain
 | 
			
		||||
        ].freeze
 | 
			
		||||
      end
 | 
			
		||||
        requires_ancestor { Homebrew::Diagnostic::Checks }
 | 
			
		||||
 | 
			
		||||
      def supported_configuration_checks
 | 
			
		||||
        %w[
 | 
			
		||||
          check_glibc_minimum_version
 | 
			
		||||
          check_kernel_minimum_version
 | 
			
		||||
          check_supported_architecture
 | 
			
		||||
        ].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
 | 
			
		||||
        def fatal_preinstall_checks
 | 
			
		||||
          %w[
 | 
			
		||||
            check_access_directories
 | 
			
		||||
            check_linuxbrew_core
 | 
			
		||||
            check_linuxbrew_bottle_domain
 | 
			
		||||
          ].freeze
 | 
			
		||||
        end
 | 
			
		||||
        return if gcc_dependents.empty?
 | 
			
		||||
 | 
			
		||||
        badly_linked = gcc_dependents.select do |dependent|
 | 
			
		||||
          keg = Keg.new(dependent.prefix)
 | 
			
		||||
          keg.binary_executable_or_library_files.any? do |binary|
 | 
			
		||||
            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$}) }
 | 
			
		||||
        def supported_configuration_checks
 | 
			
		||||
          %w[
 | 
			
		||||
            check_glibc_minimum_version
 | 
			
		||||
            check_kernel_minimum_version
 | 
			
		||||
            check_supported_architecture
 | 
			
		||||
          ].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
 | 
			
		||||
        return if badly_linked.empty?
 | 
			
		||||
          return if gcc_dependents.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
 | 
			
		||||
          badly_linked = gcc_dependents.select do |dependent|
 | 
			
		||||
            keg = Keg.new(dependent.prefix)
 | 
			
		||||
            keg.binary_executable_or_library_files.any? do |binary|
 | 
			
		||||
              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
 | 
			
		||||
 | 
			
		||||
Homebrew::Diagnostic::Checks.prepend(OS::Linux::Diagnostic::Checks)
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ module OS
 | 
			
		||||
 | 
			
		||||
      sig { params(spec: SoftwareSpec).void }
 | 
			
		||||
      def add_global_deps_to_spec(spec)
 | 
			
		||||
        return unless DevelopmentTools.needs_build_formulae?
 | 
			
		||||
        return unless ::DevelopmentTools.needs_build_formulae?
 | 
			
		||||
 | 
			
		||||
        @global_deps ||= begin
 | 
			
		||||
          dependency_collector = spec.dependency_collector
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,12 @@
 | 
			
		||||
# typed: true # rubocop:disable Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  class SimulateSystem
 | 
			
		||||
    class << self
 | 
			
		||||
      undef os
 | 
			
		||||
      undef simulating_or_running_on_linux?
 | 
			
		||||
      undef current_os
 | 
			
		||||
 | 
			
		||||
module OS
 | 
			
		||||
  module Linux
 | 
			
		||||
    module SimulateSystem
 | 
			
		||||
      sig { returns(T.nilable(Symbol)) }
 | 
			
		||||
      def os
 | 
			
		||||
        @os ||= T.let(nil, T.nilable(Symbol))
 | 
			
		||||
        return :macos if @os.blank? && Homebrew::EnvConfig.simulate_macos_on_linux?
 | 
			
		||||
 | 
			
		||||
        @os
 | 
			
		||||
@ -27,3 +24,5 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
Homebrew::SimulateSystem.singleton_class.prepend(OS::Linux::SimulateSystem)
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ module OS
 | 
			
		||||
      def use_system_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
 | 
			
		||||
 | 
			
		||||
@ -1,23 +1,26 @@
 | 
			
		||||
# typed: true # rubocop:disable Sorbet/StrictSigil
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class DependencyCollector
 | 
			
		||||
  undef git_dep_if_needed, subversion_dep_if_needed, cvs_dep_if_needed,
 | 
			
		||||
        xz_dep_if_needed, unzip_dep_if_needed, bzip2_dep_if_needed
 | 
			
		||||
module OS
 | 
			
		||||
  module Mac
 | 
			
		||||
    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)
 | 
			
		||||
    Dependency.new("subversion", [*tags, :implicit])
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
DependencyCollector.prepend(OS::Mac::DependencyCollector)
 | 
			
		||||
 | 
			
		||||
@ -1,86 +1,91 @@
 | 
			
		||||
# typed: true # rubocop:disable Sorbet/StrictSigil
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "os/mac/xcode"
 | 
			
		||||
 | 
			
		||||
class DevelopmentTools
 | 
			
		||||
  class << self
 | 
			
		||||
    alias generic_locate locate
 | 
			
		||||
    undef installed?, default_compiler, curl_handles_most_https_certificates?,
 | 
			
		||||
          subversion_handles_most_https_certificates?
 | 
			
		||||
module OS
 | 
			
		||||
  module Mac
 | 
			
		||||
    module DevelopmentTools
 | 
			
		||||
      extend T::Helpers
 | 
			
		||||
 | 
			
		||||
    sig { params(tool: T.any(String, Symbol)).returns(T.nilable(Pathname)) }
 | 
			
		||||
    def locate(tool)
 | 
			
		||||
      (@locate ||= {}).fetch(tool) do |key|
 | 
			
		||||
        @locate[key] = if (located_tool = generic_locate(tool))
 | 
			
		||||
          located_tool
 | 
			
		||||
        else
 | 
			
		||||
          path = Utils.popen_read("/usr/bin/xcrun", "-no-cache", "-find", tool, err: :close).chomp
 | 
			
		||||
          Pathname.new(path) if File.executable?(path)
 | 
			
		||||
      requires_ancestor { ::DevelopmentTools }
 | 
			
		||||
 | 
			
		||||
      sig { params(tool: T.any(String, Symbol)).returns(T.nilable(Pathname)) }
 | 
			
		||||
      def locate(tool)
 | 
			
		||||
        @locate ||= T.let({}, T.nilable(T::Hash[T.any(String, Symbol), Pathname]))
 | 
			
		||||
        @locate.fetch(tool) do |key|
 | 
			
		||||
          @locate[key] = if (located_tool = super(tool))
 | 
			
		||||
            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
 | 
			
		||||
 | 
			
		||||
    # Checks if the user has any developer tools installed, either via Xcode
 | 
			
		||||
    # or the CLT. Convenient for guarding against formula builds when building
 | 
			
		||||
    # is impossible.
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def 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
 | 
			
		||||
      # Checks if the user has any developer tools installed, either via Xcode
 | 
			
		||||
      # or the CLT. Convenient for guarding against formula builds when building
 | 
			
		||||
      # is impossible.
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def installed?
 | 
			
		||||
        MacOS::Xcode.installed? || MacOS::CLT.installed?
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def curl_handles_most_https_certificates?
 | 
			
		||||
      # The system Curl is too old for some modern HTTPS certificates on
 | 
			
		||||
      # older macOS versions.
 | 
			
		||||
      ENV["HOMEBREW_SYSTEM_CURL_TOO_OLD"].nil?
 | 
			
		||||
    end
 | 
			
		||||
      sig { returns(Symbol) }
 | 
			
		||||
      def default_compiler
 | 
			
		||||
        :clang
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def subversion_handles_most_https_certificates?
 | 
			
		||||
      # The system Subversion is too old for some HTTPS certificates on
 | 
			
		||||
      # older macOS versions.
 | 
			
		||||
      MacOS.version >= :sierra
 | 
			
		||||
    end
 | 
			
		||||
      sig { returns(Version) }
 | 
			
		||||
      def self.ld64_version
 | 
			
		||||
        @ld64_version ||= T.let(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, T.nilable(Version))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    sig { returns(String) }
 | 
			
		||||
    def installation_instructions
 | 
			
		||||
      MacOS::CLT.installation_instructions
 | 
			
		||||
    end
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def curl_handles_most_https_certificates?
 | 
			
		||||
        # The system Curl is too old for some modern HTTPS certificates on
 | 
			
		||||
        # older macOS versions.
 | 
			
		||||
        ENV["HOMEBREW_SYSTEM_CURL_TOO_OLD"].nil?
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    sig { returns(String) }
 | 
			
		||||
    def custom_installation_instructions
 | 
			
		||||
      <<~EOS
 | 
			
		||||
        Install GNU's GCC:
 | 
			
		||||
          brew install gcc
 | 
			
		||||
      EOS
 | 
			
		||||
    end
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def subversion_handles_most_https_certificates?
 | 
			
		||||
        # The system Subversion is too old for some HTTPS certificates on
 | 
			
		||||
        # older macOS versions.
 | 
			
		||||
        MacOS.version >= :sierra
 | 
			
		||||
      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,
 | 
			
		||||
      }
 | 
			
		||||
      generic_build_system_info.merge build_info
 | 
			
		||||
      sig { returns(String) }
 | 
			
		||||
      def installation_instructions
 | 
			
		||||
        MacOS::CLT.installation_instructions
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(String) }
 | 
			
		||||
      def custom_installation_instructions
 | 
			
		||||
        <<~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
 | 
			
		||||
 | 
			
		||||
DevelopmentTools.singleton_class.prepend(OS::Mac::DevelopmentTools)
 | 
			
		||||
 | 
			
		||||
@ -1,467 +1,471 @@
 | 
			
		||||
# typed: true # rubocop:disable Sorbet/StrictSigil
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module Diagnostic
 | 
			
		||||
    class Volumes
 | 
			
		||||
      def initialize
 | 
			
		||||
        @volumes = get_mounts
 | 
			
		||||
      end
 | 
			
		||||
module OS
 | 
			
		||||
  module Mac
 | 
			
		||||
    module Diagnostic
 | 
			
		||||
      class Volumes
 | 
			
		||||
        def initialize
 | 
			
		||||
          @volumes = get_mounts
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      def which(path)
 | 
			
		||||
        vols = get_mounts path
 | 
			
		||||
        def which(path)
 | 
			
		||||
          vols = get_mounts path
 | 
			
		||||
 | 
			
		||||
        # no volume found
 | 
			
		||||
        return -1 if vols.empty?
 | 
			
		||||
          # no volume found
 | 
			
		||||
          return -1 if vols.empty?
 | 
			
		||||
 | 
			
		||||
        vol_index = @volumes.index(vols[0])
 | 
			
		||||
        # volume not found in volume list
 | 
			
		||||
        return -1 if vol_index.nil?
 | 
			
		||||
          vol_index = @volumes.index(vols[0])
 | 
			
		||||
          # volume not found in volume list
 | 
			
		||||
          return -1 if vol_index.nil?
 | 
			
		||||
 | 
			
		||||
        vol_index
 | 
			
		||||
      end
 | 
			
		||||
          vol_index
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      def get_mounts(path = nil)
 | 
			
		||||
        vols = []
 | 
			
		||||
        # get the volume of path, if path is nil returns all volumes
 | 
			
		||||
        def get_mounts(path = nil)
 | 
			
		||||
          vols = []
 | 
			
		||||
          # get the volume of path, if path is nil returns all volumes
 | 
			
		||||
 | 
			
		||||
        args = %w[/bin/df -P]
 | 
			
		||||
        args << path if path
 | 
			
		||||
          args = %w[/bin/df -P]
 | 
			
		||||
          args << path if path
 | 
			
		||||
 | 
			
		||||
        Utils.popen_read(*args) do |io|
 | 
			
		||||
          io.each_line do |line|
 | 
			
		||||
            case line.chomp
 | 
			
		||||
              # regex matches: /dev/disk0s2   489562928 440803616  48247312    91%    /
 | 
			
		||||
            when /^.+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+[0-9]{1,3}%\s+(.+)/
 | 
			
		||||
              vols << Regexp.last_match(1)
 | 
			
		||||
          Utils.popen_read(*args) do |io|
 | 
			
		||||
            io.each_line do |line|
 | 
			
		||||
              case line.chomp
 | 
			
		||||
                # regex matches: /dev/disk0s2   489562928 440803616  48247312    91%    /
 | 
			
		||||
              when /^.+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+[0-9]{1,3}%\s+(.+)/
 | 
			
		||||
                vols << Regexp.last_match(1)
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
          vols
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
      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
 | 
			
		||||
      module Checks
 | 
			
		||||
        extend T::Helpers
 | 
			
		||||
 | 
			
		||||
      def fatal_setup_build_environment_checks
 | 
			
		||||
        %w[
 | 
			
		||||
          check_xcode_minimum_version
 | 
			
		||||
          check_clt_minimum_version
 | 
			
		||||
          check_if_supported_sdk_available
 | 
			
		||||
        ].freeze
 | 
			
		||||
      end
 | 
			
		||||
        requires_ancestor { Homebrew::Diagnostic::Checks }
 | 
			
		||||
 | 
			
		||||
      def supported_configuration_checks
 | 
			
		||||
        %w[
 | 
			
		||||
          check_for_unsupported_macos
 | 
			
		||||
        ].freeze
 | 
			
		||||
      end
 | 
			
		||||
        def fatal_preinstall_checks
 | 
			
		||||
          checks = %w[
 | 
			
		||||
            check_access_directories
 | 
			
		||||
          ]
 | 
			
		||||
 | 
			
		||||
      def build_from_source_checks
 | 
			
		||||
        %w[
 | 
			
		||||
          check_for_installed_developer_tools
 | 
			
		||||
          check_xcode_up_to_date
 | 
			
		||||
          check_clt_up_to_date
 | 
			
		||||
        ].freeze
 | 
			
		||||
      end
 | 
			
		||||
          # We need the developer tools for `codesign`.
 | 
			
		||||
          checks << "check_for_installed_developer_tools" if ::Hardware::CPU.arm?
 | 
			
		||||
 | 
			
		||||
      def check_for_non_prefixed_findutils
 | 
			
		||||
        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"
 | 
			
		||||
          checks.freeze
 | 
			
		||||
        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
 | 
			
		||||
          You are using macOS #{MacOS.version}.
 | 
			
		||||
          #{who} do not provide support for this #{what}.
 | 
			
		||||
          #{please_create_pull_requests(what)}
 | 
			
		||||
        EOS
 | 
			
		||||
      end
 | 
			
		||||
        def fatal_setup_build_environment_checks
 | 
			
		||||
          %w[
 | 
			
		||||
            check_xcode_minimum_version
 | 
			
		||||
            check_clt_minimum_version
 | 
			
		||||
            check_if_supported_sdk_available
 | 
			
		||||
          ].freeze
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      def check_xcode_up_to_date
 | 
			
		||||
        return unless MacOS::Xcode.outdated?
 | 
			
		||||
        def supported_configuration_checks
 | 
			
		||||
          %w[
 | 
			
		||||
            check_for_unsupported_macos
 | 
			
		||||
          ].freeze
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # avoid duplicate very similar messages
 | 
			
		||||
        return if MacOS::Xcode.below_minimum_version?
 | 
			
		||||
        def build_from_source_checks
 | 
			
		||||
          %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
 | 
			
		||||
        # `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?
 | 
			
		||||
        def check_for_non_prefixed_findutils
 | 
			
		||||
          findutils = ::Formula["findutils"]
 | 
			
		||||
          return unless findutils.any_version_installed?
 | 
			
		||||
 | 
			
		||||
        # With fake El Capitan for Portable Ruby, we are intentionally not using Xcode 8.
 | 
			
		||||
        # This is because we are not using the CLT and Xcode 8 has the 10.12 SDK.
 | 
			
		||||
        return if ENV["HOMEBREW_FAKE_MACOS"]
 | 
			
		||||
          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)
 | 
			
		||||
 | 
			
		||||
        message = <<~EOS
 | 
			
		||||
          Your Xcode (#{MacOS::Xcode.version}) is outdated.
 | 
			
		||||
          Please update to Xcode #{MacOS::Xcode.latest_version} (or delete it).
 | 
			
		||||
          #{MacOS::Xcode.update_instructions}
 | 
			
		||||
        EOS
 | 
			
		||||
          <<~EOS
 | 
			
		||||
            Putting non-prefixed findutils in your path can cause python builds to fail.
 | 
			
		||||
          EOS
 | 
			
		||||
        rescue FormulaUnavailableError
 | 
			
		||||
          nil
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if OS::Mac.version.prerelease?
 | 
			
		||||
          current_path = Utils.popen_read("/usr/bin/xcode-select", "-p")
 | 
			
		||||
          message += <<~EOS
 | 
			
		||||
            If #{MacOS::Xcode.latest_version} is installed, you may need to:
 | 
			
		||||
              sudo xcode-select --switch /Applications/Xcode.app
 | 
			
		||||
            Current developer directory is:
 | 
			
		||||
              #{current_path}
 | 
			
		||||
        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
 | 
			
		||||
          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
 | 
			
		||||
        end
 | 
			
		||||
        message
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def check_clt_up_to_date
 | 
			
		||||
        return unless MacOS::CLT.outdated?
 | 
			
		||||
        def check_xcode_up_to_date
 | 
			
		||||
          return unless MacOS::Xcode.outdated?
 | 
			
		||||
 | 
			
		||||
        # avoid duplicate very similar messages
 | 
			
		||||
        return if MacOS::CLT.below_minimum_version?
 | 
			
		||||
          # avoid duplicate very similar messages
 | 
			
		||||
          return if MacOS::Xcode.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?
 | 
			
		||||
          # 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
 | 
			
		||||
      end
 | 
			
		||||
          # With fake El Capitan for Portable Ruby, we are intentionally not using Xcode 8.
 | 
			
		||||
          # This is because we are not using the CLT and Xcode 8 has the 10.12 SDK.
 | 
			
		||||
          return if ENV["HOMEBREW_FAKE_MACOS"]
 | 
			
		||||
 | 
			
		||||
      def check_xcode_minimum_version
 | 
			
		||||
        return unless MacOS::Xcode.below_minimum_version?
 | 
			
		||||
          message = <<~EOS
 | 
			
		||||
            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
 | 
			
		||||
        xcode += " => #{MacOS::Xcode.prefix}" unless MacOS::Xcode.default_prefix?
 | 
			
		||||
 | 
			
		||||
        <<~EOS
 | 
			
		||||
          Your Xcode (#{xcode}) at #{MacOS::Xcode.bundle_path} is too outdated.
 | 
			
		||||
          Please update to Xcode #{MacOS::Xcode.latest_version} (or delete it).
 | 
			
		||||
          #{MacOS::Xcode.update_instructions}
 | 
			
		||||
        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.
 | 
			
		||||
          if OS::Mac.version.prerelease?
 | 
			
		||||
            current_path = Utils.popen_read("/usr/bin/xcode-select", "-p")
 | 
			
		||||
            message += <<~EOS
 | 
			
		||||
              If #{MacOS::Xcode.latest_version} is installed, you may need to:
 | 
			
		||||
                sudo xcode-select --switch /Applications/Xcode.app
 | 
			
		||||
              Current developer directory is:
 | 
			
		||||
                #{current_path}
 | 
			
		||||
            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.
 | 
			
		||||
          message
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
            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
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def check_for_multiple_volumes
 | 
			
		||||
        return unless HOMEBREW_CELLAR.exist?
 | 
			
		||||
        def check_xcode_minimum_version
 | 
			
		||||
          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
 | 
			
		||||
        real_cellar = HOMEBREW_CELLAR.realpath
 | 
			
		||||
        where_cellar = volumes.which real_cellar
 | 
			
		||||
          <<~EOS
 | 
			
		||||
            Your Xcode (#{xcode}) at #{MacOS::Xcode.bundle_path} is too outdated.
 | 
			
		||||
            Please update to Xcode #{MacOS::Xcode.latest_version} (or delete it).
 | 
			
		||||
            #{MacOS::Xcode.update_instructions}
 | 
			
		||||
          EOS
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
        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
 | 
			
		||||
        rescue
 | 
			
		||||
          return
 | 
			
		||||
          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
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
          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.
 | 
			
		||||
          # Our gettext formula will be caught by check_linked_keg_only_brews
 | 
			
		||||
          gettext = begin
 | 
			
		||||
            Formulary.factory("gettext")
 | 
			
		||||
          rescue
 | 
			
		||||
            nil
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          You should set the "HOMEBREW_TEMP" environment variable to a suitable
 | 
			
		||||
          directory on the same volume as your Cellar.
 | 
			
		||||
        EOS
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
      def check_deprecated_caskroom_taps
 | 
			
		||||
        tapped_caskroom_taps = Tap.select { |t| t.user == "caskroom" || t.name == "phinze/cask" }
 | 
			
		||||
                                  .map(&:name)
 | 
			
		||||
        return if tapped_caskroom_taps.empty?
 | 
			
		||||
            return if @found.all? do |path|
 | 
			
		||||
              realpath = Pathname.new(path).realpath.to_s
 | 
			
		||||
              allowlist.any? { |rack| realpath.start_with?(rack) }
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        <<~EOS
 | 
			
		||||
          You have the following deprecated, cask taps tapped:
 | 
			
		||||
            #{tapped_caskroom_taps.join("\n  ")}
 | 
			
		||||
          Untap them with `brew untap`.
 | 
			
		||||
        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"
 | 
			
		||||
          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
 | 
			
		||||
 | 
			
		||||
        <<~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
 | 
			
		||||
        def check_for_iconv
 | 
			
		||||
          find_relative_paths("lib/libiconv.dylib", "include/iconv.h")
 | 
			
		||||
          return if @found.empty?
 | 
			
		||||
 | 
			
		||||
      # 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
 | 
			
		||||
          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
 | 
			
		||||
            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|
 | 
			
		||||
          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
 | 
			
		||||
              tl;dr: delete these files:
 | 
			
		||||
            EOS
 | 
			
		||||
          end
 | 
			
		||||
        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
 | 
			
		||||
        def check_for_multiple_volumes
 | 
			
		||||
          return unless HOMEBREW_CELLAR.exist?
 | 
			
		||||
 | 
			
		||||
          volumes = Volumes.new
 | 
			
		||||
 | 
			
		||||
          # Find the volumes for the TMP folder & HOMEBREW_CELLAR
 | 
			
		||||
          real_cellar = HOMEBREW_CELLAR.realpath
 | 
			
		||||
          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
 | 
			
		||||
 | 
			
		||||
        <<~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.
 | 
			
		||||
        def check_deprecated_caskroom_taps
 | 
			
		||||
          tapped_caskroom_taps = Tap.select { |t| t.user == "caskroom" || t.name == "phinze/cask" }
 | 
			
		||||
                                    .map(&:name)
 | 
			
		||||
          return if tapped_caskroom_taps.empty?
 | 
			
		||||
 | 
			
		||||
          Remove the broken installation before reinstalling:
 | 
			
		||||
            sudo rm -rf #{path_to_remove}
 | 
			
		||||
          <<~EOS
 | 
			
		||||
            You have the following deprecated, cask taps tapped:
 | 
			
		||||
              #{tapped_caskroom_taps.join("\n  ")}
 | 
			
		||||
            Untap them with `brew untap`.
 | 
			
		||||
          EOS
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
          #{installation_instructions}
 | 
			
		||||
        EOS
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
          <<~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
 | 
			
		||||
 | 
			
		||||
Homebrew::Diagnostic::Checks.prepend(OS::Mac::Diagnostic::Checks)
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,6 @@ module SharedEnvExtension
 | 
			
		||||
    # This is supported starting Xcode 13, which ships ld64-711.
 | 
			
		||||
    # 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
 | 
			
		||||
    DevelopmentTools.ld64_version >= 711
 | 
			
		||||
    OS::Mac::DevelopmentTools.ld64_version >= 711
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -1,117 +1,125 @@
 | 
			
		||||
# typed: true # rubocop:disable Sorbet/StrictSigil
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Stdenv
 | 
			
		||||
  undef homebrew_extra_pkg_config_paths
 | 
			
		||||
module OS
 | 
			
		||||
  module Mac
 | 
			
		||||
    module Stdenv
 | 
			
		||||
      extend T::Helpers
 | 
			
		||||
 | 
			
		||||
  sig { returns(T::Array[Pathname]) }
 | 
			
		||||
  def homebrew_extra_pkg_config_paths
 | 
			
		||||
    [Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")]
 | 
			
		||||
  end
 | 
			
		||||
  private :homebrew_extra_pkg_config_paths
 | 
			
		||||
      requires_ancestor { ::Stdenv }
 | 
			
		||||
 | 
			
		||||
  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:)
 | 
			
		||||
      sig { returns(T::Array[Pathname]) }
 | 
			
		||||
      def homebrew_extra_pkg_config_paths
 | 
			
		||||
        [Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")]
 | 
			
		||||
      end
 | 
			
		||||
      private :homebrew_extra_pkg_config_paths
 | 
			
		||||
 | 
			
		||||
    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.
 | 
			
		||||
    delete("LC_ALL")
 | 
			
		||||
    self["LC_CTYPE"] = "C"
 | 
			
		||||
        append "LDFLAGS", "-Wl,-headerpad_max_install_names"
 | 
			
		||||
 | 
			
		||||
    # Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags:
 | 
			
		||||
    macosxsdk(formula: @formula, testing_formula:)
 | 
			
		||||
        # `sed` is strict and errors out when it encounters files with mixed character sets.
 | 
			
		||||
        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"
 | 
			
		||||
    append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin"
 | 
			
		||||
  end
 | 
			
		||||
        return unless MacOS::Xcode.without_clt?
 | 
			
		||||
 | 
			
		||||
  def remove_macosxsdk(version = nil)
 | 
			
		||||
    # 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"
 | 
			
		||||
        append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin"
 | 
			
		||||
        append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed(version)
 | 
			
		||||
    return unless sdk
 | 
			
		||||
      def remove_macosxsdk(version = nil)
 | 
			
		||||
        # 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")
 | 
			
		||||
    remove_from_cflags "-isysroot#{sdk}"
 | 
			
		||||
    remove "CPPFLAGS", "-isysroot#{sdk}"
 | 
			
		||||
    remove "LDFLAGS", "-isysroot#{sdk}"
 | 
			
		||||
    if HOMEBREW_PREFIX.to_s == "/usr/local"
 | 
			
		||||
      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
 | 
			
		||||
        sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed(version)
 | 
			
		||||
        return unless sdk
 | 
			
		||||
 | 
			
		||||
        delete("SDKROOT")
 | 
			
		||||
        remove_from_cflags "-isysroot#{sdk}"
 | 
			
		||||
        remove "CPPFLAGS", "-isysroot#{sdk}"
 | 
			
		||||
        remove "LDFLAGS", "-isysroot#{sdk}"
 | 
			
		||||
        if HOMEBREW_PREFIX.to_s == "/usr/local"
 | 
			
		||||
          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
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
Stdenv.prepend(OS::Mac::Stdenv)
 | 
			
		||||
 | 
			
		||||
@ -1,169 +1,175 @@
 | 
			
		||||
# typed: true # rubocop:disable Sorbet/StrictSigil
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Superenv
 | 
			
		||||
  class << self
 | 
			
		||||
    # The location of Homebrew's shims on macOS.
 | 
			
		||||
    def shims_path
 | 
			
		||||
      HOMEBREW_SHIMS_PATH/"mac/super"
 | 
			
		||||
    end
 | 
			
		||||
module OS
 | 
			
		||||
  module Mac
 | 
			
		||||
    module Superenv
 | 
			
		||||
      extend T::Helpers
 | 
			
		||||
 | 
			
		||||
    undef bin
 | 
			
		||||
      requires_ancestor { ::Superenv }
 | 
			
		||||
 | 
			
		||||
    def bin
 | 
			
		||||
      return unless DevelopmentTools.installed?
 | 
			
		||||
      module ClassMethods
 | 
			
		||||
        # The location of Homebrew's shims on macOS.
 | 
			
		||||
        def shims_path
 | 
			
		||||
          HOMEBREW_SHIMS_PATH/"mac/super"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      shims_path.realpath
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
        def bin
 | 
			
		||||
          return unless ::DevelopmentTools.installed?
 | 
			
		||||
 | 
			
		||||
  undef homebrew_extra_pkg_config_paths,
 | 
			
		||||
        homebrew_extra_isystem_paths, homebrew_extra_library_paths,
 | 
			
		||||
        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"
 | 
			
		||||
          shims_path.realpath
 | 
			
		||||
        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
 | 
			
		||||
      ENV["ac_have_clock_syscall"] = "no"
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
          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
 | 
			
		||||
 | 
			
		||||
    # 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
 | 
			
		||||
 | 
			
		||||
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 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|
 | 
			
		||||
      next true unless file.dylib?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ module OS
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: Formula).returns(T.nilable(T::Boolean)) }
 | 
			
		||||
      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?)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -3,175 +3,179 @@
 | 
			
		||||
 | 
			
		||||
require "macho"
 | 
			
		||||
 | 
			
		||||
module Hardware
 | 
			
		||||
  class CPU
 | 
			
		||||
    class << self
 | 
			
		||||
      undef type, family, features, sse4?
 | 
			
		||||
module OS
 | 
			
		||||
  module Mac
 | 
			
		||||
    module Hardware
 | 
			
		||||
      module CPU
 | 
			
		||||
        extend T::Helpers
 | 
			
		||||
 | 
			
		||||
      # These methods use info spewed out by sysctl.
 | 
			
		||||
      # Look in <mach/machine.h> for decoding info.
 | 
			
		||||
      def type
 | 
			
		||||
        case sysctl_int("hw.cputype")
 | 
			
		||||
        when MachO::Headers::CPU_TYPE_I386
 | 
			
		||||
          :intel
 | 
			
		||||
        when MachO::Headers::CPU_TYPE_ARM64
 | 
			
		||||
          :arm
 | 
			
		||||
        else
 | 
			
		||||
          :dunno
 | 
			
		||||
        # These methods use info spewed out by sysctl.
 | 
			
		||||
        # Look in <mach/machine.h> for decoding info.
 | 
			
		||||
        def type
 | 
			
		||||
          case sysctl_int("hw.cputype")
 | 
			
		||||
          when MachO::Headers::CPU_TYPE_I386
 | 
			
		||||
            :intel
 | 
			
		||||
          when MachO::Headers::CPU_TYPE_ARM64
 | 
			
		||||
            :arm
 | 
			
		||||
          else
 | 
			
		||||
            :dunno
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def family
 | 
			
		||||
        if arm?
 | 
			
		||||
          arm_family
 | 
			
		||||
        elsif intel?
 | 
			
		||||
          intel_family
 | 
			
		||||
        else
 | 
			
		||||
          :dunno
 | 
			
		||||
        def family
 | 
			
		||||
          if ::Hardware::CPU.arm?
 | 
			
		||||
            arm_family
 | 
			
		||||
          elsif ::Hardware::CPU.intel?
 | 
			
		||||
            intel_family
 | 
			
		||||
          else
 | 
			
		||||
            :dunno
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # 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
 | 
			
		||||
      # conflict between what `uname` reports and the underlying `sysctl` flags,
 | 
			
		||||
      # since the `sysctl` flags don't change behaviour under Rosetta 2.
 | 
			
		||||
      def in_rosetta2?
 | 
			
		||||
        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
 | 
			
		||||
        # 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
 | 
			
		||||
        # conflict between what `uname` reports and the underlying `sysctl` flags,
 | 
			
		||||
        # since the `sysctl` flags don't change behaviour under Rosetta 2.
 | 
			
		||||
        def in_rosetta2?
 | 
			
		||||
          sysctl_bool("sysctl.proc_translated")
 | 
			
		||||
        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
 | 
			
		||||
        def features
 | 
			
		||||
          @features ||= sysctl_n(
 | 
			
		||||
            "machdep.cpu.features",
 | 
			
		||||
            "machdep.cpu.extfeatures",
 | 
			
		||||
            "machdep.cpu.leaf7_features",
 | 
			
		||||
          ).split.map { |s| s.downcase.to_sym }
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def sysctl_bool(key)
 | 
			
		||||
        sysctl_int(key) == 1
 | 
			
		||||
      end
 | 
			
		||||
        def sse4?
 | 
			
		||||
          sysctl_bool("hw.optional.sse4_1")
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      def sysctl_int(key)
 | 
			
		||||
        sysctl_n(key).to_i & 0xffffffff
 | 
			
		||||
      end
 | 
			
		||||
        def extmodel
 | 
			
		||||
          sysctl_int("machdep.cpu.extmodel")
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      def sysctl_n(*keys)
 | 
			
		||||
        (@properties ||= {}).fetch(keys) do
 | 
			
		||||
          @properties[keys] = Utils.popen_read("/usr/sbin/sysctl", "-n", *keys)
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
Hardware::CPU.singleton_class.prepend(OS::Mac::Hardware::CPU)
 | 
			
		||||
 | 
			
		||||
@ -23,101 +23,101 @@ class Keg
 | 
			
		||||
    GENERIC_MUST_BE_WRITABLE_DIRECTORIES +
 | 
			
		||||
    [HOMEBREW_PREFIX/"Frameworks"]
 | 
			
		||||
  ).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
 | 
			
		||||
    mach_o_files
 | 
			
		||||
  end
 | 
			
		||||
      def codesign_patched_binary(file)
 | 
			
		||||
        return if MacOS.version < :big_sur
 | 
			
		||||
 | 
			
		||||
  def codesign_patched_binary(file)
 | 
			
		||||
    return if MacOS.version < :big_sur
 | 
			
		||||
        unless ::Hardware::CPU.arm?
 | 
			
		||||
          result = system_command("codesign", args: ["--verify", file], print_stderr: false)
 | 
			
		||||
          return unless result.stderr.match?(/invalid signature/i)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
    unless Hardware::CPU.arm?
 | 
			
		||||
      result = system_command("codesign", args: ["--verify", file], print_stderr: false)
 | 
			
		||||
      return unless result.stderr.match?(/invalid signature/i)
 | 
			
		||||
    end
 | 
			
		||||
        odebug "Codesigning #{file}"
 | 
			
		||||
        prepare_codesign_writable_files(file) do
 | 
			
		||||
          # Use quiet_system to squash notifications about resigning binaries
 | 
			
		||||
          # which already have valid signatures.
 | 
			
		||||
          return if quiet_system("codesign", "--sign", "-", "--force",
 | 
			
		||||
                                 "--preserve-metadata=entitlements,requirements,flags,runtime",
 | 
			
		||||
                                 file)
 | 
			
		||||
 | 
			
		||||
    odebug "Codesigning #{file}"
 | 
			
		||||
    prepare_codesign_writable_files(file) do
 | 
			
		||||
      # Use quiet_system to squash notifications about resigning binaries
 | 
			
		||||
      # which already have valid signatures.
 | 
			
		||||
      return if quiet_system("codesign", "--sign", "-", "--force",
 | 
			
		||||
                             "--preserve-metadata=entitlements,requirements,flags,runtime",
 | 
			
		||||
                             file)
 | 
			
		||||
          # If the codesigning fails, it may be a bug in Apple's codesign utility
 | 
			
		||||
          # A known workaround is to copy the file to another inode, then move it back
 | 
			
		||||
          # erasing the previous file. Then sign again.
 | 
			
		||||
          #
 | 
			
		||||
          # TODO: remove this once the bug in Apple's codesign utility is fixed
 | 
			
		||||
          Dir::Tmpname.create("workaround") do |tmppath|
 | 
			
		||||
            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
 | 
			
		||||
      # A known workaround is to copy the file to another inode, then move it back
 | 
			
		||||
      # erasing the previous file. Then sign again.
 | 
			
		||||
      #
 | 
			
		||||
      # TODO: remove this once the bug in Apple's codesign utility is fixed
 | 
			
		||||
      Dir::Tmpname.create("workaround") do |tmppath|
 | 
			
		||||
        FileUtils.cp file, tmppath
 | 
			
		||||
        FileUtils.mv tmppath, file, force: true
 | 
			
		||||
          # Try signing again
 | 
			
		||||
          odebug "Codesigning (2nd try) #{file}"
 | 
			
		||||
          result = system_command("codesign", args: [
 | 
			
		||||
            "--sign", "-", "--force",
 | 
			
		||||
            "--preserve-metadata=entitlements,requirements,flags,runtime",
 | 
			
		||||
            file
 | 
			
		||||
          ], print_stderr: false)
 | 
			
		||||
          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
 | 
			
		||||
 | 
			
		||||
      # Try signing again
 | 
			
		||||
      odebug "Codesigning (2nd try) #{file}"
 | 
			
		||||
      result = system_command("codesign", args: [
 | 
			
		||||
        "--sign", "-", "--force",
 | 
			
		||||
        "--preserve-metadata=entitlements,requirements,flags,runtime",
 | 
			
		||||
        file
 | 
			
		||||
      ], print_stderr: false)
 | 
			
		||||
      return if result.success?
 | 
			
		||||
      def prepare_codesign_writable_files(file)
 | 
			
		||||
        result = system_command("codesign", args: [
 | 
			
		||||
          "--display", "--file-list", "-", file
 | 
			
		||||
        ], print_stderr: false)
 | 
			
		||||
        return unless result.success?
 | 
			
		||||
 | 
			
		||||
      # If it fails again, error out
 | 
			
		||||
      onoe <<~EOS
 | 
			
		||||
        Failed applying an ad-hoc signature to #{file}:
 | 
			
		||||
        #{result.stderr}
 | 
			
		||||
      EOS
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def prepare_codesign_writable_files(file)
 | 
			
		||||
    result = system_command("codesign", args: [
 | 
			
		||||
      "--display", "--file-list", "-", file
 | 
			
		||||
    ], print_stderr: false)
 | 
			
		||||
    return unless result.success?
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
        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
 | 
			
		||||
        yield
 | 
			
		||||
      ensure
 | 
			
		||||
        saved_perms&.each do |f, p|
 | 
			
		||||
          f.chmod p if p
 | 
			
		||||
        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
 | 
			
		||||
    binary_executable_or_library_files.each do |file|
 | 
			
		||||
      odebug "Extracting symbols #{file}"
 | 
			
		||||
          result = system_command("dsymutil", args: [file], print_stderr: false)
 | 
			
		||||
          next if result.success?
 | 
			
		||||
 | 
			
		||||
      result = system_command("dsymutil", args: [file], print_stderr: false)
 | 
			
		||||
      next if result.success?
 | 
			
		||||
          # If it fails again, error out
 | 
			
		||||
          ofail <<~EOS
 | 
			
		||||
            Failed to extract symbols from #{file}:
 | 
			
		||||
            #{result.stderr}
 | 
			
		||||
          EOS
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # If it fails again, error out
 | 
			
		||||
      ofail <<~EOS
 | 
			
		||||
        Failed to extract symbols from #{file}:
 | 
			
		||||
        #{result.stderr}
 | 
			
		||||
      EOS
 | 
			
		||||
    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?
 | 
			
		||||
      # 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
 | 
			
		||||
 | 
			
		||||
Keg.prepend(OS::Mac::Keg)
 | 
			
		||||
 | 
			
		||||
@ -1,255 +1,262 @@
 | 
			
		||||
# typed: true # rubocop:disable Sorbet/StrictSigil
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Keg
 | 
			
		||||
  class << self
 | 
			
		||||
    undef file_linked_libraries
 | 
			
		||||
module OS
 | 
			
		||||
  module Mac
 | 
			
		||||
    module Keg
 | 
			
		||||
      extend T::Helpers
 | 
			
		||||
 | 
			
		||||
    def file_linked_libraries(file, string)
 | 
			
		||||
      # 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
 | 
			
		||||
      requires_ancestor { ::Keg }
 | 
			
		||||
 | 
			
		||||
  undef relocate_dynamic_linkage
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
      module ClassMethods
 | 
			
		||||
        def file_linked_libraries(file, string)
 | 
			
		||||
          # 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
 | 
			
		||||
            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
 | 
			
		||||
          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
 | 
			
		||||
        generic_fix_dynamic_linkage
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
          modified = change_rpath(bad_name, loader_name, file)
 | 
			
		||||
          needs_codesigning ||= modified
 | 
			
		||||
      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? ::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
 | 
			
		||||
 | 
			
		||||
        # 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
 | 
			
		||||
        mach_o_files
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
          modified = delete_rpath(bad_name, file)
 | 
			
		||||
          needs_codesigning ||= modified
 | 
			
		||||
      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, ::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
 | 
			
		||||
 | 
			
		||||
        # codesign the file if needed
 | 
			
		||||
        codesign_patched_binary(file) if needs_codesigning
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
Keg.singleton_class.prepend(OS::Mac::Keg::ClassMethods)
 | 
			
		||||
Keg.prepend(OS::Mac::Keg)
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ module OS
 | 
			
		||||
      requires_ancestor { Kernel }
 | 
			
		||||
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
        current_macos_version = if os_name.is_a?(Symbol)
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ module OS
 | 
			
		||||
 | 
			
		||||
      sig { returns(Symbol) }
 | 
			
		||||
      def current_os
 | 
			
		||||
        Homebrew::SimulateSystem.os || MacOS.version.to_sym
 | 
			
		||||
        ::Homebrew::SimulateSystem.os || MacOS.version.to_sym
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -3,20 +3,26 @@
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
  class << self
 | 
			
		||||
    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
 | 
			
		||||
      @xcode ||= if MacOS::Xcode.installed?
 | 
			
		||||
        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
 | 
			
		||||
    "-lr"
 | 
			
		||||
  end
 | 
			
		||||
  alias generic_recursive_fgrep_args recursive_fgrep_args
 | 
			
		||||
 | 
			
		||||
  def egrep_args
 | 
			
		||||
    grep_bin = "grep"
 | 
			
		||||
 | 
			
		||||
@ -151,7 +151,7 @@ module OS
 | 
			
		||||
          # Xcode.prefix is pretty smart, so let's look inside to find the sdk
 | 
			
		||||
          sdk_prefix = "#{Xcode.prefix}/Platforms/MacOSX.platform/Developer/SDKs"
 | 
			
		||||
          # Finally query Xcode itself (this is slow, so check it last)
 | 
			
		||||
          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
 | 
			
		||||
 | 
			
		||||
@ -227,7 +227,7 @@ module OS
 | 
			
		||||
 | 
			
		||||
      sig { returns(String) }
 | 
			
		||||
      def self.detect_version_from_clang_version
 | 
			
		||||
        version = DevelopmentTools.clang_version
 | 
			
		||||
        version = ::DevelopmentTools.clang_version
 | 
			
		||||
 | 
			
		||||
        return "dunno" if version.null?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -87,7 +87,7 @@ class AbstractTab
 | 
			
		||||
        "tap"          => nil,
 | 
			
		||||
        "tap_git_head" => nil,
 | 
			
		||||
      },
 | 
			
		||||
      "built_on"                => DevelopmentTools.generic_build_system_info,
 | 
			
		||||
      "built_on"                => DevelopmentTools.build_system_info,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    new(attributes)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user