From eed660e7844e666165976c10d71fafbe1325f958 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Sat, 21 Sep 2024 12:24:21 -0700 Subject: [PATCH 1/4] Move remaining OS extensions to prepend --- Library/Homebrew/development_tools.rb | 1 - Library/Homebrew/extend/os/linux/cleanup.rbi | 5 + .../extend/os/linux/dependency_collector.rb | 190 ++--- .../extend/os/linux/development_tools.rb | 90 ++- .../Homebrew/extend/os/linux/diagnostic.rb | 288 +++---- Library/Homebrew/extend/os/linux/formula.rb | 2 +- .../extend/os/linux/simulate_system.rb | 15 +- Library/Homebrew/extend/os/mac/cleanup.rb | 2 +- .../extend/os/mac/dependency_collector.rb | 31 +- .../extend/os/mac/development_tools.rb | 139 ++-- Library/Homebrew/extend/os/mac/diagnostic.rb | 744 +++++++++--------- .../extend/os/mac/extend/ENV/shared.rb | 2 +- .../Homebrew/extend/os/mac/extend/ENV/std.rb | 230 +++--- .../extend/os/mac/extend/ENV/super.rb | 300 +++---- .../extend/os/mac/formula_cellar_checks.rb | 2 +- .../extend/os/mac/formula_installer.rb | 2 +- .../Homebrew/extend/os/mac/hardware/cpu.rb | 292 +++---- Library/Homebrew/extend/os/mac/keg.rb | 174 ++-- .../Homebrew/extend/os/mac/keg_relocate.rb | 431 +++++----- Library/Homebrew/extend/os/mac/readall.rb | 2 +- .../Homebrew/extend/os/mac/simulate_system.rb | 2 +- .../Homebrew/extend/os/mac/system_config.rb | 26 +- Library/Homebrew/hardware.rbi | 9 + Library/Homebrew/keg.rbi | 5 + Library/Homebrew/keg_relocate.rb | 1 - Library/Homebrew/os/mac/sdk.rb | 2 +- Library/Homebrew/os/mac/xcode.rb | 2 +- Library/Homebrew/tab.rb | 2 +- 28 files changed, 1534 insertions(+), 1457 deletions(-) create mode 100644 Library/Homebrew/extend/os/linux/cleanup.rbi create mode 100644 Library/Homebrew/hardware.rbi create mode 100644 Library/Homebrew/keg.rbi diff --git a/Library/Homebrew/development_tools.rb b/Library/Homebrew/development_tools.rb index 5a379a04f12de..84f743954a0dc 100644 --- a/Library/Homebrew/development_tools.rb +++ b/Library/Homebrew/development_tools.rb @@ -177,7 +177,6 @@ def build_system_info "cpu_family" => Hardware::CPU.family.to_s, } end - alias generic_build_system_info build_system_info end end diff --git a/Library/Homebrew/extend/os/linux/cleanup.rbi b/Library/Homebrew/extend/os/linux/cleanup.rbi new file mode 100644 index 0000000000000..bc5db498cff3d --- /dev/null +++ b/Library/Homebrew/extend/os/linux/cleanup.rbi @@ -0,0 +1,5 @@ +# typed: strict + +# module OS::Linux::Cleanup +# include Kernel +# end diff --git a/Library/Homebrew/extend/os/linux/dependency_collector.rb b/Library/Homebrew/extend/os/linux/dependency_collector.rb index 80362457b2cfb..2f7485eef2f0e 100644 --- a/Library/Homebrew/extend/os/linux/dependency_collector.rb +++ b/Library/Homebrew/extend/os/linux/dependency_collector.rb @@ -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! - - 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 - - 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 - - private - - 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? - - 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 ||= {} - @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 ||= {} - # 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 - [] +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) + + 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) + + Dependency.new(GLIBC, [:implicit]) + end + + private + + 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? + + 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::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 + + # 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) diff --git a/Library/Homebrew/extend/os/linux/development_tools.rb b/Library/Homebrew/extend/os/linux/development_tools.rb index 5766df623e22a..bd07e5d03ac45 100644 --- a/Library/Homebrew/extend/os/linux/development_tools.rb +++ b/Library/Homebrew/extend/os/linux/development_tools.rb @@ -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 + @needs_libc_formula = T.let(OS::Linux::Glibc.below_ci_version?, T.nilable(T::Boolean)) + @needs_libc_formula = !!@needs_libc_formula + end - sig { returns(T::Boolean) } - def needs_compiler_formula? - return @needs_compiler_formula if defined? @needs_compiler_formula + sig { returns(T::Boolean) } + def needs_compiler_formula? + return @needs_compiler_formula unless @needs_compiler_formula.nil? - gcc = "/usr/bin/gcc" - @needs_compiler_formula = if File.exist?(gcc) - gcc_version(gcc) < OS::LINUX_GCC_CI_VERSION - else - true + 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 - 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::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) diff --git a/Library/Homebrew/extend/os/linux/diagnostic.rb b/Library/Homebrew/extend/os/linux/diagnostic.rb index c3c665cb20a8c..28322c0afd6c7 100644 --- a/Library/Homebrew/extend/os/linux/diagnostic.rb +++ b/Library/Homebrew/extend/os/linux/diagnostic.rb @@ -7,168 +7,174 @@ require "os/linux/glibc" require "os/linux/kernel" -module Homebrew - module Diagnostic - class Checks - undef fatal_preinstall_checks, supported_configuration_checks - - def fatal_preinstall_checks - %w[ - check_access_directories - check_linuxbrew_core - check_linuxbrew_bottle_domain - ].freeze - end +module OS + module Linux + module Diagnostic + module Checks + extend T::Helpers + + requires_ancestor { Homebrew::Diagnostic::Checks } + + def fatal_preinstall_checks + %w[ + check_access_directories + check_linuxbrew_core + check_linuxbrew_bottle_domain + ].freeze + end - def supported_configuration_checks - %w[ - check_glibc_minimum_version - check_kernel_minimum_version - check_supported_architecture - ].freeze - end + 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_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_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_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? + 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 + <<~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 + 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 + <<~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_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_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? + 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 + <<~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") + 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 + <<~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? + 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 - return if gcc_dependents.empty? + # FIXME: This includes formulae that have no runtime dependency on GCC. + formula.recursive_dependencies.map(&:name).include? "gcc" + rescue TapFormulaUnavailableError + false + 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$}) } + 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 + versioned_linkage && !unversioned_linkage + end end - end - return if badly_linked.empty? + 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 + 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) diff --git a/Library/Homebrew/extend/os/linux/formula.rb b/Library/Homebrew/extend/os/linux/formula.rb index 4af57d02c9eef..46489c1c0d862 100644 --- a/Library/Homebrew/extend/os/linux/formula.rb +++ b/Library/Homebrew/extend/os/linux/formula.rb @@ -28,7 +28,7 @@ def deuniversalize_machos(*targets); end 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 diff --git a/Library/Homebrew/extend/os/linux/simulate_system.rb b/Library/Homebrew/extend/os/linux/simulate_system.rb index 106cbc0eb5af8..248ee7e2a56d1 100644 --- a/Library/Homebrew/extend/os/linux/simulate_system.rb +++ b/Library/Homebrew/extend/os/linux/simulate_system.rb @@ -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 @@ def current_os end end end + +Homebrew::SimulateSystem.singleton_class.prepend(OS::Linux::SimulateSystem) diff --git a/Library/Homebrew/extend/os/mac/cleanup.rb b/Library/Homebrew/extend/os/mac/cleanup.rb index 08b4ec01454d2..8779780d36dd6 100644 --- a/Library/Homebrew/extend/os/mac/cleanup.rb +++ b/Library/Homebrew/extend/os/mac/cleanup.rb @@ -8,7 +8,7 @@ module Cleanup 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 diff --git a/Library/Homebrew/extend/os/mac/dependency_collector.rb b/Library/Homebrew/extend/os/mac/dependency_collector.rb index 5483178f5694a..da245f7e0f4d4 100644 --- a/Library/Homebrew/extend/os/mac/dependency_collector.rb +++ b/Library/Homebrew/extend/os/mac/dependency_collector.rb @@ -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]) - end - - def cvs_dep_if_needed(tags) - Dependency.new("cvs", [*tags, :implicit]) - end + def cvs_dep_if_needed(tags) + Dependency.new("cvs", [*tags, :implicit]) + end - def xz_dep_if_needed(tags); end + def xz_dep_if_needed(tags); end - def unzip_dep_if_needed(tags); end + def unzip_dep_if_needed(tags); end - def bzip2_dep_if_needed(tags); end + def bzip2_dep_if_needed(tags); end + end + end end + +DependencyCollector.prepend(OS::Mac::DependencyCollector) diff --git a/Library/Homebrew/extend/os/mac/development_tools.rb b/Library/Homebrew/extend/os/mac/development_tools.rb index 7f3f111a718b4..0ee2c31c957a9 100644 --- a/Library/Homebrew/extend/os/mac/development_tools.rb +++ b/Library/Homebrew/extend/os/mac/development_tools.rb @@ -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 + # 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(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 + 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 - 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(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(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::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(String) } - def installation_instructions - MacOS::CLT.installation_instructions - end + 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(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, - } - generic_build_system_info.merge build_info + 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) diff --git a/Library/Homebrew/extend/os/mac/diagnostic.rb b/Library/Homebrew/extend/os/mac/diagnostic.rb index fa714f68ec56e..0b993813a8ca3 100644 --- a/Library/Homebrew/extend/os/mac/diagnostic.rb +++ b/Library/Homebrew/extend/os/mac/diagnostic.rb @@ -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 - ] + module Checks + extend T::Helpers - # We need the developer tools for `codesign`. - checks << "check_for_installed_developer_tools" if Hardware::CPU.arm? + requires_ancestor { Homebrew::Diagnostic::Checks } - checks.freeze - end + def fatal_preinstall_checks + checks = %w[ + check_access_directories + ] - 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 + # We need the developer tools for `codesign`. + checks << "check_for_installed_developer_tools" if ::Hardware::CPU.arm? - def fatal_setup_build_environment_checks - %w[ - check_xcode_minimum_version - check_clt_minimum_version - check_if_supported_sdk_available - ].freeze - end + checks.freeze + end - def supported_configuration_checks - %w[ - check_for_unsupported_macos - ].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 - def build_from_source_checks - %w[ - check_for_installed_developer_tools - check_xcode_up_to_date - check_clt_up_to_date - ].freeze - 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_for_non_prefixed_findutils - findutils = Formula["findutils"] - return unless findutils.any_version_installed? + def supported_configuration_checks + %w[ + check_for_unsupported_macos + ].freeze + end - 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) + def build_from_source_checks + %w[ + check_for_installed_developer_tools + check_xcode_up_to_date + check_clt_up_to_date + ].freeze + end - <<~EOS - Putting non-prefixed findutils in your path can cause python builds to fail. - EOS - rescue FormulaUnavailableError - nil - end + def check_for_non_prefixed_findutils + findutils = ::Formula["findutils"] + return unless findutils.any_version_installed? - def check_for_unsupported_macos - return if Homebrew::EnvConfig.developer? - return if ENV["HOMEBREW_INTEGRATION_TEST"] + 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) - who = +"We" - what = if OS::Mac.version.prerelease? - "pre-release version" - elsif OS::Mac.version.outdated_release? - who << " (and Apple)" - "old version" + <<~EOS + Putting non-prefixed findutils in your path can cause python builds to fail. + EOS + rescue FormulaUnavailableError + nil end - return if what.blank? - who.freeze + def check_for_unsupported_macos + return if Homebrew::EnvConfig.developer? + return if ENV["HOMEBREW_INTEGRATION_TEST"] - <<~EOS - You are using macOS #{MacOS.version}. - #{who} do not provide support for this #{what}. - #{please_create_pull_requests(what)} - EOS - end + 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? - def check_xcode_up_to_date - return unless MacOS::Xcode.outdated? - - # 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? - - # 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"] - - 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 - - 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} + 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? + 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 + message + end - <<~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_up_to_date + return unless MacOS::CLT.outdated? - def check_clt_minimum_version - return unless MacOS::CLT.below_minimum_version? + # avoid duplicate very similar messages + return if MacOS::CLT.below_minimum_version? - <<~EOS - Your Command Line Tools are too outdated. - #{MacOS::CLT.update_instructions} - EOS - 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_if_xcode_needs_clt_installed - return unless MacOS::Xcode.needs_clt_installed? + <<~EOS + A newer Command Line Tools release is available. + #{MacOS::CLT.update_instructions} + EOS + end - <<~EOS - Xcode alone is not sufficient on #{MacOS.version.pretty_name}. - #{DevelopmentTools.installation_instructions} - EOS - end + def check_xcode_minimum_version + return unless MacOS::Xcode.below_minimum_version? - def check_xcode_prefix - prefix = MacOS::Xcode.prefix - return if prefix.nil? - return unless prefix.to_s.include?(" ") + xcode = MacOS::Xcode.version.to_s + xcode += " => #{MacOS::Xcode.prefix}" unless MacOS::Xcode.default_prefix? - <<~EOS - Xcode is installed to a directory with a space in the name. - This will cause some formulae to fail to build. - EOS - end + <<~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_xcode_prefix_exists - prefix = MacOS::Xcode.prefix - return if prefix.nil? || prefix.exist? + def check_clt_minimum_version + return unless MacOS::CLT.below_minimum_version? - <<~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 + <<~EOS + Your Command Line Tools are too outdated. + #{MacOS::CLT.update_instructions} + 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_if_xcode_needs_clt_installed + return unless MacOS::Xcode.needs_clt_installed? - 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 + <<~EOS + Xcode alone is not sufficient on #{MacOS.version.pretty_name}. + #{::DevelopmentTools.installation_instructions} + 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?) + 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 - 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) + 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 - 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_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_for_gettext - find_relative_paths("lib/libgettextlib.dylib", - "lib/libintl.dylib", - "include/libintl.h") - return if @found.empty? + 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? - # Our gettext formula will be caught by check_linked_keg_only_brews - gettext = begin - Formulary.factory("gettext") - rescue - nil + <<~EOS + You have not agreed to the Xcode license. + Agree to the license by opening Xcode.app or running: + sudo xcodebuild -license + 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 - ] + 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? - return if @found.all? do |path| - realpath = Pathname.new(path).realpath.to_s - allowlist.any? { |rack| realpath.start_with?(rack) } + 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 - 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_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 - def check_for_iconv - find_relative_paths("lib/libiconv.dylib", "include/iconv.h") - return if @found.empty? + 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 - 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 + return if @found.all? do |path| + realpath = Pathname.new(path).realpath.to_s + allowlist.any? { |rack| realpath.start_with?(rack) } + end 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. - - tl;dr: delete these files: + 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 - end - def check_for_multiple_volumes - return unless HOMEBREW_CELLAR.exist? + def check_for_iconv + find_relative_paths("lib/libiconv.dylib", "include/iconv.h") + return if @found.empty? - volumes = Volumes.new + 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. + + tl;dr: delete these files: + EOS + end + end - # Find the volumes for the TMP folder & HOMEBREW_CELLAR - real_cellar = HOMEBREW_CELLAR.realpath - where_cellar = volumes.which real_cellar + 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 + 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 - rescue - return - end - return if where_cellar == where_tmp + 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. + <<~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 + You should set the "HOMEBREW_TEMP" environment variable to a suitable + directory on the same volume as your Cellar. + EOS + 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? + 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? - <<~EOS - You have the following deprecated, cask taps tapped: - #{tapped_caskroom_taps.join("\n ")} - Untap them with `brew untap`. - EOS - 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 + def check_if_supported_sdk_available + return unless ::DevelopmentTools.installed? + return unless MacOS.sdk_root_needed? + return if MacOS.sdk - locator = MacOS.sdk_locator + locator = MacOS.sdk_locator - source = if locator.source == :clt - return if MacOS::CLT.below_minimum_version? # Handled by other diagnostics. + 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::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 + 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 + <<~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 + # 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? + 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 + 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 + 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. + <<~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} + Remove the broken installation before reinstalling: + sudo rm -rf #{path_to_remove} - #{installation_instructions} - EOS + #{installation_instructions} + EOS + end end end end end + +Homebrew::Diagnostic::Checks.prepend(OS::Mac::Diagnostic::Checks) diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb b/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb index 819937b28e0ec..42a2cea1c7a1f 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb @@ -37,6 +37,6 @@ def no_fixup_chains_support? # 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 diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb index c312eb1125234..7aec76c23d50b 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb @@ -1,117 +1,125 @@ # typed: true # rubocop:disable Sorbet/StrictSigil # frozen_string_literal: true -module Stdenv - undef homebrew_extra_pkg_config_paths - - 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 - - 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:) - - append "LDFLAGS", "-Wl,-headerpad_max_install_names" - - # `sed` is strict and errors out when it encounters files with mixed character sets. - delete("LC_ALL") - self["LC_CTYPE"] = "C" - - # Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags: - macosxsdk(formula: @formula, testing_formula:) - - return unless MacOS::Xcode.without_clt? - - append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin" - append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin" - end - - 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" - - 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 +module OS + module Mac + module Stdenv + extend T::Helpers + + requires_ancestor { ::Stdenv } + + 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 + + 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:) + + append "LDFLAGS", "-Wl,-headerpad_max_install_names" + + # `sed` is strict and errors out when it encounters files with mixed character sets. + delete("LC_ALL") + self["LC_CTYPE"] = "C" + + # Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags: + macosxsdk(formula: @formula, testing_formula:) + + return unless MacOS::Xcode.without_clt? + + append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin" + append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin" + end + + 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" + + 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) diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb index 0582969caa4d5..eb894c024b167 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb @@ -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 - - undef bin - - def bin - return unless DevelopmentTools.installed? - - shims_path.realpath - end - end - - 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 +module OS + module Mac + module Superenv + extend T::Helpers - 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 + requires_ancestor { ::Superenv } - 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? + module ClassMethods + # The location of Homebrew's shims on macOS. + def shims_path + HOMEBREW_SHIMS_PATH/"mac/super" + end - 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 bin + return unless ::DevelopmentTools.installed? - 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 + shims_path.realpath + end + end - def homebrew_extra_cmake_frameworks_paths - paths = [] - paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks" if MacOS::Xcode.without_clt? - paths - end + 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 - def determine_cccfg - s = +"" - # Fix issue with >= Mountain Lion apr-1-config having broken paths - s << "a" - s.freeze - end + 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? - # @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 + 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 - if is_xcode_sdk || MacOS.sdk_root_needed? - Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks) - self["HOMEBREW_SDKROOT"] = sdk.path if sdk - 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 - self["HOMEBREW_DEVELOPER_DIR"] = if is_xcode_sdk - MacOS::Xcode.prefix.to_s - else - MacOS::CLT::PKG_PATH - 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 - # 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 + def homebrew_extra_cmake_library_paths + [Pathname( + "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries", + )] + end - generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:, - testing_formula:, debug_symbols:) + def homebrew_extra_cmake_frameworks_paths + paths = [] + paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks" if MacOS::Xcode.without_clt? + paths + end - # 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" + def determine_cccfg + s = +"" + # Fix issue with >= Mountain Lion apr-1-config having broken paths + s << "a" + s.freeze 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" + + # @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 - ENV["ac_cv_search_clock_gettime"] = "no" + def no_weak_imports + append_to_cccfg "w" if no_weak_imports_support? + end - # works around libev.m4 unsetting ac_cv_func_clock_gettime - ENV["ac_have_clock_syscall"] = "no" + 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) diff --git a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb index daa6970d4b3ac..324748d4d979a 100644 --- a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb +++ b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb @@ -97,7 +97,7 @@ def check_flat_namespace(formula) 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? diff --git a/Library/Homebrew/extend/os/mac/formula_installer.rb b/Library/Homebrew/extend/os/mac/formula_installer.rb index a817d924fb061..a59e532f2fbfb 100644 --- a/Library/Homebrew/extend/os/mac/formula_installer.rb +++ b/Library/Homebrew/extend/os/mac/formula_installer.rb @@ -10,7 +10,7 @@ module FormulaInstaller 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 diff --git a/Library/Homebrew/extend/os/mac/hardware/cpu.rb b/Library/Homebrew/extend/os/mac/hardware/cpu.rb index b81e0c2b661bb..b738178ea7fc0 100644 --- a/Library/Homebrew/extend/os/mac/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/mac/hardware/cpu.rb @@ -3,175 +3,179 @@ require "macho" -module Hardware - class CPU - class << self - undef type, family, features, sse4? - - # These methods use info spewed out by sysctl. - # Look in 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 +module OS + module Mac + module Hardware + module CPU + extend T::Helpers + + # These methods use info spewed out by sysctl. + # Look in 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 + # 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 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 sse4? + sysctl_bool("hw.optional.sse4_1") + end - def extmodel - sysctl_int("machdep.cpu.extmodel") - end + def extmodel + sysctl_int("machdep.cpu.extmodel") + end - def aes? - sysctl_bool("hw.optional.aes") - end + def aes? + sysctl_bool("hw.optional.aes") + end - def altivec? - sysctl_bool("hw.optional.altivec") - end + def altivec? + sysctl_bool("hw.optional.altivec") + end - def avx? - sysctl_bool("hw.optional.avx1_0") - end + def avx? + sysctl_bool("hw.optional.avx1_0") + end - def avx2? - sysctl_bool("hw.optional.avx2_0") - end + def avx2? + sysctl_bool("hw.optional.avx2_0") + end - def sse3? - sysctl_bool("hw.optional.sse3") - end + def sse3? + sysctl_bool("hw.optional.sse3") + end - def ssse3? - sysctl_bool("hw.optional.supplementalsse3") - end + def ssse3? + sysctl_bool("hw.optional.supplementalsse3") + end - def sse4_2? - sysctl_bool("hw.optional.sse4_2") - 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 + # 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 + 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 + private + + def arm_family + case sysctl_int("hw.cpufamily") + when 0x2c91a47e # ARMv8.0-A (Typhoon) + :arm_typhoon + when 0x92fb37c8 # ARMv8.0-A (Twister) + :arm_twister + when 0x67ceee93 # ARMv8.1-A (Hurricane, Zephyr) + :arm_hurricane_zephyr + when 0xe81e7ef6 # ARMv8.2-A (Monsoon, Mistral) + :arm_monsoon_mistral + when 0x07d34b9f # ARMv8.3-A (Vortex, Tempest) + :arm_vortex_tempest + when 0x462504d2 # ARMv8.4-A (Lightning, Thunder) + :arm_lightning_thunder + when 0x573b5eec, 0x1b588bb3 # ARMv8.4-A (Firestorm, Icestorm) + :arm_firestorm_icestorm + when 0xda33d83d # ARMv8.5-A (Blizzard, Avalanche) + :arm_blizzard_avalanche + when 0xfa33415e # ARMv8.6-A (M3, Ibiza) + :arm_ibiza + when 0x5f4dea93 # ARMv8.6-A (M3 Pro, Lobos) + :arm_lobos + when 0x72015832 # ARMv8.6-A (M3 Max, Palma) + :arm_palma + else + # When adding new ARM CPU families, please also update + # test/hardware/cpu_spec.rb to include the new families. + :dunno + end end - end - def intel_family(_family = nil, _cpu_model = nil) - 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 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 - end - def sysctl_bool(key) - sysctl_int(key) == 1 - end + def sysctl_bool(key) + sysctl_int(key) == 1 + end - def sysctl_int(key) - sysctl_n(key).to_i & 0xffffffff - 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) + 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) diff --git a/Library/Homebrew/extend/os/mac/keg.rb b/Library/Homebrew/extend/os/mac/keg.rb index 67009e2f38430..8f5ec2b5f9d1e 100644 --- a/Library/Homebrew/extend/os/mac/keg.rb +++ b/Library/Homebrew/extend/os/mac/keg.rb @@ -23,101 +23,101 @@ class Keg GENERIC_MUST_BE_WRITABLE_DIRECTORIES + [HOMEBREW_PREFIX/"Frameworks"] ).sort.uniq.freeze +end - undef binary_executable_or_library_files - - def binary_executable_or_library_files - mach_o_files - end - - 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 - - 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 +module OS + module Mac + module Keg + def binary_executable_or_library_files = mach_o_files + + 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 + + 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 + + # 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? - - # 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 + 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 + 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}" - result = system_command("dsymutil", args: [file], print_stderr: false) - next if result.success? + def prepare_debug_symbols + binary_executable_or_library_files.each do |file| + odebug "Extracting symbols #{file}" - # If it fails again, error out - ofail <<~EOS - Failed to extract symbols from #{file}: - #{result.stderr} - EOS - end - end + result = system_command("dsymutil", args: [file], print_stderr: false) + next if result.success? - undef consistent_reproducible_symlink_permissions! + # If it fails again, error out + ofail <<~EOS + Failed to extract symbols from #{file}: + #{result.stderr} + EOS + end + end - # 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) diff --git a/Library/Homebrew/extend/os/mac/keg_relocate.rb b/Library/Homebrew/extend/os/mac/keg_relocate.rb index bccadd74dbb66..31494e2dd2ea8 100644 --- a/Library/Homebrew/extend/os/mac/keg_relocate.rb +++ b/Library/Homebrew/extend/os/mac/keg_relocate.rb @@ -1,255 +1,262 @@ # typed: true # rubocop:disable Sorbet/StrictSigil # frozen_string_literal: true -class Keg - class << self - undef file_linked_libraries - - 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 - - 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 +module OS + module Mac + module Keg + extend T::Helpers + + requires_ancestor { ::Keg } + + 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 + [] + end end + 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 + 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 - - # 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) + 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 - - modified = change_rpath(bad_name, loader_name, file) - needs_codesigning ||= modified - end + generic_fix_dynamic_linkage + 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 + 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 - modified = delete_rpath(bad_name, file) - needs_codesigning ||= modified + "@loader_path/#{target_dir.relative_path_from(file.dirname)/dylib_suffix}" + else + target end - - # codesign the file if needed - codesign_patched_binary(file) if needs_codesigning 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 + # 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/ + 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 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 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) + 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 + 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)$} + # 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_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? + 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 + 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 + 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 + mach_o_files + end - def prepare_relocation_to_locations - relocation = generic_prepare_relocation_to_locations + 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"]}" + 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) + # 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) + 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, JAVA_PLACEHOLDER, openjdk_path.to_s) - end + 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 - relocation - 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 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 + def egrep_args + grep_bin = "egrep" + grep_args = "--files-with-matches" + [grep_bin, grep_args] + end - private + private - CELLAR_RX = %r{\A#{HOMEBREW_CELLAR}/(?[^/]+)/[^/]+} + CELLAR_RX = %r{\A#{HOMEBREW_CELLAR}/(?[^/]+)/[^/]+} - # 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? + # 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 + 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/") + 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) + filename.start_with?(HOMEBREW_TEMP.to_s) || filename.start_with?(HOMEBREW_TEMP.realpath.to_s) + end + end end end + +Keg.singleton_class.prepend(OS::Mac::Keg::ClassMethods) +Keg.prepend(OS::Mac::Keg) diff --git a/Library/Homebrew/extend/os/mac/readall.rb b/Library/Homebrew/extend/os/mac/readall.rb index 4ad0cd1a05f2f..69a4bd2727e0a 100644 --- a/Library/Homebrew/extend/os/mac/readall.rb +++ b/Library/Homebrew/extend/os/mac/readall.rb @@ -9,7 +9,7 @@ module Readall 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) diff --git a/Library/Homebrew/extend/os/mac/simulate_system.rb b/Library/Homebrew/extend/os/mac/simulate_system.rb index cba78f44e98f0..a8e3329e198ea 100644 --- a/Library/Homebrew/extend/os/mac/simulate_system.rb +++ b/Library/Homebrew/extend/os/mac/simulate_system.rb @@ -13,7 +13,7 @@ def simulating_or_running_on_macos? sig { returns(Symbol) } def current_os - Homebrew::SimulateSystem.os || MacOS.version.to_sym + ::Homebrew::SimulateSystem.os || MacOS.version.to_sym end end end diff --git a/Library/Homebrew/extend/os/mac/system_config.rb b/Library/Homebrew/extend/os/mac/system_config.rb index fc698df453c7f..0f84aca104ead 100644 --- a/Library/Homebrew/extend/os/mac/system_config.rb +++ b/Library/Homebrew/extend/os/mac/system_config.rb @@ -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 diff --git a/Library/Homebrew/hardware.rbi b/Library/Homebrew/hardware.rbi new file mode 100644 index 0000000000000..225606f1f0b2b --- /dev/null +++ b/Library/Homebrew/hardware.rbi @@ -0,0 +1,9 @@ +# typed: strict + +module Hardware + class CPU + class << self + include OS::Mac::Hardware::CPU + end + end +end diff --git a/Library/Homebrew/keg.rbi b/Library/Homebrew/keg.rbi new file mode 100644 index 0000000000000..9f450bdb69c73 --- /dev/null +++ b/Library/Homebrew/keg.rbi @@ -0,0 +1,5 @@ +# typed: strict + +class Keg + include OS::Mac::Keg +end diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index d023d10209b3b..04a2fc3c00c81 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -210,7 +210,6 @@ def recursive_fgrep_args # 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" diff --git a/Library/Homebrew/os/mac/sdk.rb b/Library/Homebrew/os/mac/sdk.rb index a8540fbe0ac4b..1584941c99585 100644 --- a/Library/Homebrew/os/mac/sdk.rb +++ b/Library/Homebrew/os/mac/sdk.rb @@ -151,7 +151,7 @@ def sdk_prefix # 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 diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index 40e6c870be877..5af295fcf69eb 100644 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -227,7 +227,7 @@ def self.detect_version sig { returns(String) } def self.detect_version_from_clang_version - version = DevelopmentTools.clang_version + version = ::DevelopmentTools.clang_version return "dunno" if version.null? diff --git a/Library/Homebrew/tab.rb b/Library/Homebrew/tab.rb index c4d92d6c66ebe..ac04c6880aae0 100644 --- a/Library/Homebrew/tab.rb +++ b/Library/Homebrew/tab.rb @@ -87,7 +87,7 @@ def self.empty "tap" => nil, "tap_git_head" => nil, }, - "built_on" => DevelopmentTools.generic_build_system_info, + "built_on" => DevelopmentTools.build_system_info, } new(attributes) From 0d5b56aa6a7bab4492300f5039bf04a8465a3300 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Sun, 22 Sep 2024 11:10:40 -0700 Subject: [PATCH 2/4] Fix tests --- Library/Homebrew/extend/os/linux/cleanup.rbi | 5 - .../Homebrew/extend/os/mac/hardware/cpu.rb | 228 +++++++++--------- Library/Homebrew/hardware.rbi | 9 - Library/Homebrew/keg.rbi | 1 + 4 files changed, 117 insertions(+), 126 deletions(-) delete mode 100644 Library/Homebrew/extend/os/linux/cleanup.rbi delete mode 100644 Library/Homebrew/hardware.rbi diff --git a/Library/Homebrew/extend/os/linux/cleanup.rbi b/Library/Homebrew/extend/os/linux/cleanup.rbi deleted file mode 100644 index bc5db498cff3d..0000000000000 --- a/Library/Homebrew/extend/os/linux/cleanup.rbi +++ /dev/null @@ -1,5 +0,0 @@ -# typed: strict - -# module OS::Linux::Cleanup -# include Kernel -# end diff --git a/Library/Homebrew/extend/os/mac/hardware/cpu.rb b/Library/Homebrew/extend/os/mac/hardware/cpu.rb index b738178ea7fc0..35fe32d11684c 100644 --- a/Library/Homebrew/extend/os/mac/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/mac/hardware/cpu.rb @@ -12,7 +12,7 @@ module CPU # These methods use info spewed out by sysctl. # Look in for decoding info. def type - case sysctl_int("hw.cputype") + case ::Hardware::CPU.sysctl_int("hw.cputype") when MachO::Headers::CPU_TYPE_I386 :intel when MachO::Headers::CPU_TYPE_ARM64 @@ -24,9 +24,9 @@ def type def family if ::Hardware::CPU.arm? - arm_family + ::Hardware::CPU.arm_family elsif ::Hardware::CPU.intel? - intel_family + ::Hardware::CPU.intel_family else :dunno end @@ -37,11 +37,11 @@ def family # 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") + ::Hardware::CPU.sysctl_bool("sysctl.proc_translated") end def features - @features ||= sysctl_n( + @features ||= ::Hardware::CPU.sysctl_n( "machdep.cpu.features", "machdep.cpu.extfeatures", "machdep.cpu.leaf7_features", @@ -49,133 +49,137 @@ def features end def sse4? - sysctl_bool("hw.optional.sse4_1") + ::Hardware::CPU.sysctl_bool("hw.optional.sse4_1") end + end + end + end +end - def extmodel - sysctl_int("machdep.cpu.extmodel") - end +Hardware::CPU.singleton_class.prepend(OS::Mac::Hardware::CPU) - def aes? - sysctl_bool("hw.optional.aes") - end +module Hardware + class CPU + class << self + def extmodel + sysctl_int("machdep.cpu.extmodel") + end - def altivec? - sysctl_bool("hw.optional.altivec") - end + def aes? + sysctl_bool("hw.optional.aes") + end - def avx? - sysctl_bool("hw.optional.avx1_0") - end + def altivec? + sysctl_bool("hw.optional.altivec") + end - def avx2? - sysctl_bool("hw.optional.avx2_0") - end + def avx? + sysctl_bool("hw.optional.avx1_0") + end - def sse3? - sysctl_bool("hw.optional.sse3") - end + def avx2? + sysctl_bool("hw.optional.avx2_0") + end - def ssse3? - sysctl_bool("hw.optional.supplementalsse3") - end + def sse3? + sysctl_bool("hw.optional.sse3") + end - def sse4_2? - sysctl_bool("hw.optional.sse4_2") - end + def ssse3? + sysctl_bool("hw.optional.supplementalsse3") + 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 sse4_2? + sysctl_bool("hw.optional.sse4_2") + end - def virtualized? - sysctl_bool("kern.hv_vmm_present") - 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 - 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 virtualized? + sysctl_bool("kern.hv_vmm_present") + 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 + 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 sysctl_bool(key) - sysctl_int(key) == 1 + 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_int(key) - sysctl_n(key).to_i & 0xffffffff - end + def sysctl_bool(key) + sysctl_int(key) == 1 + end - def sysctl_n(*keys) - (@properties ||= {}).fetch(keys) do - @properties[keys] = Utils.popen_read("/usr/sbin/sysctl", "-n", *keys) - 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 - -Hardware::CPU.singleton_class.prepend(OS::Mac::Hardware::CPU) diff --git a/Library/Homebrew/hardware.rbi b/Library/Homebrew/hardware.rbi deleted file mode 100644 index 225606f1f0b2b..0000000000000 --- a/Library/Homebrew/hardware.rbi +++ /dev/null @@ -1,9 +0,0 @@ -# typed: strict - -module Hardware - class CPU - class << self - include OS::Mac::Hardware::CPU - end - end -end diff --git a/Library/Homebrew/keg.rbi b/Library/Homebrew/keg.rbi index 9f450bdb69c73..6305c81715350 100644 --- a/Library/Homebrew/keg.rbi +++ b/Library/Homebrew/keg.rbi @@ -1,5 +1,6 @@ # typed: strict class Keg + # This is only true under MacOS, so can lead to true negative type errors include OS::Mac::Keg end From f4a6dce64ab4d6b94bf46d9b6c2ac5af671e036e Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Sun, 22 Sep 2024 11:16:23 -0700 Subject: [PATCH 3/4] Fix ENV --- Library/Homebrew/extend/ENV/std.rb | 1 - Library/Homebrew/extend/ENV/super.rb | 1 - .../extend/os/linux/extend/ENV/std.rb | 69 +++++---- .../extend/os/linux/extend/ENV/super.rb | 131 ++++++++++-------- .../Homebrew/extend/os/mac/extend/ENV/std.rb | 3 +- .../extend/os/mac/extend/ENV/super.rb | 3 +- Library/Homebrew/extend/os/mac/keg.rb | 1 + 7 files changed, 112 insertions(+), 97 deletions(-) diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb index b0c312c24a86c..22f5cb4056f96 100644 --- a/Library/Homebrew/extend/ENV/std.rb +++ b/Library/Homebrew/extend/ENV/std.rb @@ -68,7 +68,6 @@ def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_a gcc_formula = gcc_version_formula(cc) append_path "PATH", gcc_formula.opt_bin.to_s end - alias generic_setup_build_environment setup_build_environment sig { returns(T.nilable(PATH)) } def determine_pkg_config_libdir diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb index 89f7ecfa5e654..812ae68bfddb6 100644 --- a/Library/Homebrew/extend/ENV/super.rb +++ b/Library/Homebrew/extend/ENV/super.rb @@ -119,7 +119,6 @@ def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_a # These flags will also be present: # a - apply fix for apr-1-config path end - alias generic_setup_build_environment setup_build_environment private diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/std.rb b/Library/Homebrew/extend/os/linux/extend/ENV/std.rb index ba2fa12309d4a..8a249311b83f6 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/std.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/std.rb @@ -1,36 +1,45 @@ # typed: true # rubocop:todo Sorbet/StrictSigil # frozen_string_literal: true -module 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:) - - prepend_path "CPATH", HOMEBREW_PREFIX/"include" - prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib" - prepend_path "LD_RUN_PATH", HOMEBREW_PREFIX/"lib" - - return unless @formula - - prepend_path "CPATH", @formula.include - prepend_path "LIBRARY_PATH", @formula.lib - prepend_path "LD_RUN_PATH", @formula.lib - end +module OS + module Linux + module Stdenv + extend T::Helpers + + 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) + super + + prepend_path "CPATH", HOMEBREW_PREFIX/"include" + prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib" + prepend_path "LD_RUN_PATH", HOMEBREW_PREFIX/"lib" - def libxml2 - append "CPPFLAGS", "-I#{Formula["libxml2"].include/"libxml2"}" - rescue FormulaUnavailableError - nil + return unless @formula + + prepend_path "CPATH", @formula.include + prepend_path "LIBRARY_PATH", @formula.lib + prepend_path "LD_RUN_PATH", @formula.lib + end + + def libxml2 + append "CPPFLAGS", "-I#{::Formula["libxml2"].include/"libxml2"}" + rescue FormulaUnavailableError + nil + end + end end end + +Stdenv.prepend(OS::Linux::Stdenv) diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb index f0aa87920edad..6bc4da2d051bb 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb @@ -1,73 +1,82 @@ # typed: true # rubocop:todo Sorbet/StrictSigil # frozen_string_literal: true -module Superenv - sig { returns(Pathname) } - def self.shims_path - HOMEBREW_SHIMS_PATH/"linux/super" - end +module OS + module Linux + module Superenv + extend T::Helpers - sig { returns(T.nilable(Pathname)) } - def self.bin - shims_path.realpath - end + requires_ancestor { ::Superenv } - 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:) - self["HOMEBREW_OPTIMIZATION_LEVEL"] = "O2" - self["HOMEBREW_DYNAMIC_LINKER"] = determine_dynamic_linker_path - self["HOMEBREW_RPATH_PATHS"] = determine_rpath_paths(@formula) - self["M4"] = "#{HOMEBREW_PREFIX}/opt/m4/bin/m4" if deps.any? { |d| d.name == "libtool" || d.name == "bison" } - end + sig { returns(Pathname) } + def self.shims_path + HOMEBREW_SHIMS_PATH/"linux/super" + end - def homebrew_extra_paths - paths = generic_homebrew_extra_paths - paths += %w[binutils make].filter_map do |f| - bin = Formulary.factory(f).opt_bin - bin if bin.directory? - rescue FormulaUnavailableError - nil - end - paths - end + sig { returns(T.nilable(Pathname)) } + def self.bin + shims_path.realpath + end - def homebrew_extra_isystem_paths - paths = [] - # Add paths for GCC headers when building against glibc@2.13 because we have to use -nostdinc. - if deps.any? { |d| d.name == "glibc@2.13" } - gcc_include_dir = Utils.safe_popen_read(cc, "--print-file-name=include").chomp - gcc_include_fixed_dir = Utils.safe_popen_read(cc, "--print-file-name=include-fixed").chomp - paths << gcc_include_dir << gcc_include_fixed_dir - end - paths - end + 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) + super + self["HOMEBREW_OPTIMIZATION_LEVEL"] = "O2" + self["HOMEBREW_DYNAMIC_LINKER"] = determine_dynamic_linker_path + self["HOMEBREW_RPATH_PATHS"] = determine_rpath_paths(@formula) + self["M4"] = "#{HOMEBREW_PREFIX}/opt/m4/bin/m4" if deps.any? { |d| d.name == "libtool" || d.name == "bison" } + end - def determine_rpath_paths(formula) - PATH.new( - *formula&.lib, - "#{HOMEBREW_PREFIX}/opt/gcc/lib/gcc/current", - PATH.new(run_time_deps.map { |dep| dep.opt_lib.to_s }).existing, - "#{HOMEBREW_PREFIX}/lib", - ) - end + def homebrew_extra_paths + paths = generic_homebrew_extra_paths + paths += %w[binutils make].filter_map do |f| + bin = Formulary.factory(f).opt_bin + bin if bin.directory? + rescue FormulaUnavailableError + nil + end + paths + end + + def homebrew_extra_isystem_paths + paths = [] + # Add paths for GCC headers when building against glibc@2.13 because we have to use -nostdinc. + if deps.any? { |d| d.name == "glibc@2.13" } + gcc_include_dir = Utils.safe_popen_read(cc, "--print-file-name=include").chomp + gcc_include_fixed_dir = Utils.safe_popen_read(cc, "--print-file-name=include-fixed").chomp + paths << gcc_include_dir << gcc_include_fixed_dir + end + paths + end - sig { returns(T.nilable(String)) } - def determine_dynamic_linker_path - path = "#{HOMEBREW_PREFIX}/lib/ld.so" - return unless File.readable? path + def determine_rpath_paths(formula) + PATH.new( + *formula&.lib, + "#{HOMEBREW_PREFIX}/opt/gcc/lib/gcc/current", + PATH.new(run_time_deps.map { |dep| dep.opt_lib.to_s }).existing, + "#{HOMEBREW_PREFIX}/lib", + ) + end - path + sig { returns(T.nilable(String)) } + def determine_dynamic_linker_path + path = "#{HOMEBREW_PREFIX}/lib/ld.so" + return unless File.readable? path + + path + end + end end end + +Superenv.prepend(OS::Linux::Superenv) diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb index 7aec76c23d50b..90f3dedacc725 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb @@ -26,8 +26,7 @@ def homebrew_extra_pkg_config_paths } 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:) + super append "LDFLAGS", "-Wl,-headerpad_max_install_names" diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb index eb894c024b167..921e13707c6a5 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb @@ -108,8 +108,7 @@ def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_a self["M4"] = gm4 end - generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:, - testing_formula:, debug_symbols:) + super # Filter out symbols known not to be defined since GNU Autotools can't # reliably figure this out with Xcode 8 and above. diff --git a/Library/Homebrew/extend/os/mac/keg.rb b/Library/Homebrew/extend/os/mac/keg.rb index 8f5ec2b5f9d1e..b71aaee900528 100644 --- a/Library/Homebrew/extend/os/mac/keg.rb +++ b/Library/Homebrew/extend/os/mac/keg.rb @@ -6,6 +6,7 @@ class Keg include SystemCommand::Mixin + # TODO: re-implement these as functions, so that we aren't modifying constants: GENERIC_KEG_LINK_DIRECTORIES = (remove_const :KEG_LINK_DIRECTORIES).freeze KEG_LINK_DIRECTORIES = (GENERIC_KEG_LINK_DIRECTORIES + ["Frameworks"]).freeze GENERIC_MUST_EXIST_SUBDIRECTORIES = (remove_const :MUST_EXIST_SUBDIRECTORIES).freeze From 0855d7c9e06f4085efda1b9f4b843f8d618242b5 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Sat, 5 Oct 2024 12:35:28 -0700 Subject: [PATCH 4/4] Revert ENV changes --- Library/Homebrew/extend/ENV/std.rb | 1 + Library/Homebrew/extend/ENV/super.rb | 1 + .../extend/os/linux/extend/ENV/std.rb | 69 ++-- .../extend/os/linux/extend/ENV/super.rb | 131 ++++---- .../Homebrew/extend/os/mac/extend/ENV/std.rb | 229 +++++++------ .../extend/os/mac/extend/ENV/super.rb | 301 +++++++++--------- 6 files changed, 353 insertions(+), 379 deletions(-) diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb index 22f5cb4056f96..b0c312c24a86c 100644 --- a/Library/Homebrew/extend/ENV/std.rb +++ b/Library/Homebrew/extend/ENV/std.rb @@ -68,6 +68,7 @@ def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_a gcc_formula = gcc_version_formula(cc) append_path "PATH", gcc_formula.opt_bin.to_s end + alias generic_setup_build_environment setup_build_environment sig { returns(T.nilable(PATH)) } def determine_pkg_config_libdir diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb index 812ae68bfddb6..89f7ecfa5e654 100644 --- a/Library/Homebrew/extend/ENV/super.rb +++ b/Library/Homebrew/extend/ENV/super.rb @@ -119,6 +119,7 @@ def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_a # These flags will also be present: # a - apply fix for apr-1-config path end + alias generic_setup_build_environment setup_build_environment private diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/std.rb b/Library/Homebrew/extend/os/linux/extend/ENV/std.rb index 8a249311b83f6..ba2fa12309d4a 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/std.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/std.rb @@ -1,45 +1,36 @@ # typed: true # rubocop:todo Sorbet/StrictSigil # frozen_string_literal: true -module OS - module Linux - module Stdenv - extend T::Helpers - - 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) - super - - prepend_path "CPATH", HOMEBREW_PREFIX/"include" - prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib" - prepend_path "LD_RUN_PATH", HOMEBREW_PREFIX/"lib" - - return unless @formula - - prepend_path "CPATH", @formula.include - prepend_path "LIBRARY_PATH", @formula.lib - prepend_path "LD_RUN_PATH", @formula.lib - end +module 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:) + + prepend_path "CPATH", HOMEBREW_PREFIX/"include" + prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib" + prepend_path "LD_RUN_PATH", HOMEBREW_PREFIX/"lib" + + return unless @formula + + prepend_path "CPATH", @formula.include + prepend_path "LIBRARY_PATH", @formula.lib + prepend_path "LD_RUN_PATH", @formula.lib + end - def libxml2 - append "CPPFLAGS", "-I#{::Formula["libxml2"].include/"libxml2"}" - rescue FormulaUnavailableError - nil - end - end + def libxml2 + append "CPPFLAGS", "-I#{Formula["libxml2"].include/"libxml2"}" + rescue FormulaUnavailableError + nil end end - -Stdenv.prepend(OS::Linux::Stdenv) diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb index 6bc4da2d051bb..f0aa87920edad 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb @@ -1,82 +1,73 @@ # typed: true # rubocop:todo Sorbet/StrictSigil # frozen_string_literal: true -module OS - module Linux - module Superenv - extend T::Helpers - - requires_ancestor { ::Superenv } - - sig { returns(Pathname) } - def self.shims_path - HOMEBREW_SHIMS_PATH/"linux/super" - end +module Superenv + sig { returns(Pathname) } + def self.shims_path + HOMEBREW_SHIMS_PATH/"linux/super" + end - sig { returns(T.nilable(Pathname)) } - def self.bin - shims_path.realpath - end + sig { returns(T.nilable(Pathname)) } + def self.bin + shims_path.realpath + end - 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) - super - self["HOMEBREW_OPTIMIZATION_LEVEL"] = "O2" - self["HOMEBREW_DYNAMIC_LINKER"] = determine_dynamic_linker_path - self["HOMEBREW_RPATH_PATHS"] = determine_rpath_paths(@formula) - self["M4"] = "#{HOMEBREW_PREFIX}/opt/m4/bin/m4" if deps.any? { |d| d.name == "libtool" || d.name == "bison" } - end + 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:) + self["HOMEBREW_OPTIMIZATION_LEVEL"] = "O2" + self["HOMEBREW_DYNAMIC_LINKER"] = determine_dynamic_linker_path + self["HOMEBREW_RPATH_PATHS"] = determine_rpath_paths(@formula) + self["M4"] = "#{HOMEBREW_PREFIX}/opt/m4/bin/m4" if deps.any? { |d| d.name == "libtool" || d.name == "bison" } + end - def homebrew_extra_paths - paths = generic_homebrew_extra_paths - paths += %w[binutils make].filter_map do |f| - bin = Formulary.factory(f).opt_bin - bin if bin.directory? - rescue FormulaUnavailableError - nil - end - paths - end + def homebrew_extra_paths + paths = generic_homebrew_extra_paths + paths += %w[binutils make].filter_map do |f| + bin = Formulary.factory(f).opt_bin + bin if bin.directory? + rescue FormulaUnavailableError + nil + end + paths + end - def homebrew_extra_isystem_paths - paths = [] - # Add paths for GCC headers when building against glibc@2.13 because we have to use -nostdinc. - if deps.any? { |d| d.name == "glibc@2.13" } - gcc_include_dir = Utils.safe_popen_read(cc, "--print-file-name=include").chomp - gcc_include_fixed_dir = Utils.safe_popen_read(cc, "--print-file-name=include-fixed").chomp - paths << gcc_include_dir << gcc_include_fixed_dir - end - paths - end + def homebrew_extra_isystem_paths + paths = [] + # Add paths for GCC headers when building against glibc@2.13 because we have to use -nostdinc. + if deps.any? { |d| d.name == "glibc@2.13" } + gcc_include_dir = Utils.safe_popen_read(cc, "--print-file-name=include").chomp + gcc_include_fixed_dir = Utils.safe_popen_read(cc, "--print-file-name=include-fixed").chomp + paths << gcc_include_dir << gcc_include_fixed_dir + end + paths + end - def determine_rpath_paths(formula) - PATH.new( - *formula&.lib, - "#{HOMEBREW_PREFIX}/opt/gcc/lib/gcc/current", - PATH.new(run_time_deps.map { |dep| dep.opt_lib.to_s }).existing, - "#{HOMEBREW_PREFIX}/lib", - ) - end + def determine_rpath_paths(formula) + PATH.new( + *formula&.lib, + "#{HOMEBREW_PREFIX}/opt/gcc/lib/gcc/current", + PATH.new(run_time_deps.map { |dep| dep.opt_lib.to_s }).existing, + "#{HOMEBREW_PREFIX}/lib", + ) + end - sig { returns(T.nilable(String)) } - def determine_dynamic_linker_path - path = "#{HOMEBREW_PREFIX}/lib/ld.so" - return unless File.readable? path + sig { returns(T.nilable(String)) } + def determine_dynamic_linker_path + path = "#{HOMEBREW_PREFIX}/lib/ld.so" + return unless File.readable? path - path - end - end + path end end - -Superenv.prepend(OS::Linux::Superenv) diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb index 90f3dedacc725..c312eb1125234 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb @@ -1,124 +1,117 @@ # typed: true # rubocop:disable Sorbet/StrictSigil # frozen_string_literal: true -module OS - module Mac - module Stdenv - extend T::Helpers - - requires_ancestor { ::Stdenv } - - 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 - - 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) - super - - append "LDFLAGS", "-Wl,-headerpad_max_install_names" - - # `sed` is strict and errors out when it encounters files with mixed character sets. - delete("LC_ALL") - self["LC_CTYPE"] = "C" - - # Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags: - macosxsdk(formula: @formula, testing_formula:) - - return unless MacOS::Xcode.without_clt? - - append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin" - append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin" - end - - 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" - - 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 +module Stdenv + undef homebrew_extra_pkg_config_paths + + 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 + + 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:) + + append "LDFLAGS", "-Wl,-headerpad_max_install_names" + + # `sed` is strict and errors out when it encounters files with mixed character sets. + delete("LC_ALL") + self["LC_CTYPE"] = "C" + + # Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags: + macosxsdk(formula: @formula, testing_formula:) + + return unless MacOS::Xcode.without_clt? + + append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin" + append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin" + end + + 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" + + 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 -end -Stdenv.prepend(OS::Mac::Stdenv) + # 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 diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb index 921e13707c6a5..940bb6e744646 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb @@ -1,174 +1,171 @@ # typed: true # rubocop:disable Sorbet/StrictSigil # frozen_string_literal: true -module OS - module Mac - module Superenv - extend T::Helpers +module Superenv + class << self + # The location of Homebrew's shims on macOS. + def shims_path + HOMEBREW_SHIMS_PATH/"mac/super" + end - requires_ancestor { ::Superenv } + undef bin - module ClassMethods - # The location of Homebrew's shims on macOS. - def shims_path - HOMEBREW_SHIMS_PATH/"mac/super" - end + def bin + return unless DevelopmentTools.installed? - def bin - return unless ::DevelopmentTools.installed? + shims_path.realpath + end + end - shims_path.realpath - end - end + 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::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? + 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 + 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_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_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_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 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 + 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 - - super - - # 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 + # @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 - def no_weak_imports - append_to_cccfg "w" if no_weak_imports_support? - end + 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 - def no_fixup_chains - append_to_cccfg "f" if no_fixup_chains_support? + 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 -end -Superenv.singleton_class.prepend(OS::Mac::Superenv::ClassMethods) -Superenv.prepend(OS::Mac::Superenv) + 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