diff --git a/Library/Homebrew/api/analytics.rb b/Library/Homebrew/api/analytics.rb index 2bf4a62e49..ce105b9fd9 100644 --- a/Library/Homebrew/api/analytics.rb +++ b/Library/Homebrew/api/analytics.rb @@ -10,7 +10,6 @@ module Homebrew def analytics_api_path "analytics" end - alias generic_analytics_api_path analytics_api_path sig { params(category: String, days: T.any(Integer, String)).returns(T::Hash[String, T.untyped]) } def fetch(category, days) diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb index 45a0257797..ec22c04843 100644 --- a/Library/Homebrew/dev-cmd/update-test.rb +++ b/Library/Homebrew/dev-cmd/update-test.rb @@ -142,6 +142,7 @@ module Homebrew private + sig { returns(String) } def git_tags tags = Utils.popen_read("git", "tag", "--list", "--sort=-version:refname") if tags.blank? diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 80921c4cc6..2f701b22be 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -350,7 +350,6 @@ module Homebrew sudo chmod +t #{HOMEBREW_TEMP} EOS end - alias generic_check_tmpdir_sticky_bit check_tmpdir_sticky_bit def check_exist_directories return if HOMEBREW_PREFIX.writable? diff --git a/Library/Homebrew/extend/ENV/shared.rb b/Library/Homebrew/extend/ENV/shared.rb index d80724a8fa..38b7c16f4e 100644 --- a/Library/Homebrew/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/ENV/shared.rb @@ -54,8 +54,6 @@ module SharedEnvExtension @debug_symbols = debug_symbols reset end - alias generic_shared_setup_build_environment setup_build_environment - private :generic_shared_setup_build_environment sig { void } def reset diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb index b0c312c24a..22f5cb4056 100644 --- a/Library/Homebrew/extend/ENV/std.rb +++ b/Library/Homebrew/extend/ENV/std.rb @@ -68,7 +68,6 @@ module Stdenv 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 5dceddbac1..2e2be4f57e 100644 --- a/Library/Homebrew/extend/ENV/super.rb +++ b/Library/Homebrew/extend/ENV/super.rb @@ -125,7 +125,6 @@ module Superenv # These flags will also be present: # a - apply fix for apr-1-config path end - alias generic_setup_build_environment setup_build_environment private @@ -152,7 +151,6 @@ module Superenv .reverse .map { |d| d.opt_libexec/"bin" } end - alias generic_homebrew_extra_paths homebrew_extra_paths sig { returns(T.nilable(PATH)) } def determine_path @@ -372,8 +370,8 @@ module Superenv append_to_cccfg "O" end + # This is an exception where we want to use this method name format. # rubocop: disable Naming/MethodName - # Fixes style error `Naming/MethodName: Use snake_case for method names.` sig { params(block: T.nilable(T.proc.void)).void } def O0(&block) if block diff --git a/Library/Homebrew/extend/os/linux/dev-cmd/update-test.rb b/Library/Homebrew/extend/os/linux/dev-cmd/update-test.rb index 836a80c702..346fc1aa2a 100644 --- a/Library/Homebrew/extend/os/linux/dev-cmd/update-test.rb +++ b/Library/Homebrew/extend/os/linux/dev-cmd/update-test.rb @@ -1,19 +1,19 @@ # typed: strict # frozen_string_literal: true -module Homebrew - module DevCmd - class UpdateTest < AbstractCommand - alias generic_git_tags git_tags +module OS + module Linux + module DevCmd + module UpdateTest + private - private - - sig { returns(String) } - def git_tags - tags = generic_git_tags - tags = Utils.popen_read("git tag --list | sort -rV") if tags.blank? - tags + sig { returns(String) } + def git_tags + super.presence || Utils.popen_read("git tag --list | sort -rV") + end end end end end + +Homebrew::DevCmd::UpdateTest.prepend(OS::Linux::DevCmd::UpdateTest) diff --git a/Library/Homebrew/extend/os/linux/development_tools.rb b/Library/Homebrew/extend/os/linux/development_tools.rb index e65e5f8043..d725933391 100644 --- a/Library/Homebrew/extend/os/linux/development_tools.rb +++ b/Library/Homebrew/extend/os/linux/development_tools.rb @@ -62,7 +62,7 @@ module OS def build_system_info super.merge({ "glibc_version" => OS::Linux::Glibc.version.to_s.presence, - "oldest_cpu_family" => Hardware.oldest_cpu.to_s, + "oldest_cpu_family" => ::Hardware.oldest_cpu.to_s, }) end end diff --git a/Library/Homebrew/extend/os/linux/diagnostic.rb b/Library/Homebrew/extend/os/linux/diagnostic.rb index 034d047961..3cdf01a4d7 100644 --- a/Library/Homebrew/extend/os/linux/diagnostic.rb +++ b/Library/Homebrew/extend/os/linux/diagnostic.rb @@ -32,7 +32,7 @@ module OS end def check_tmpdir_sticky_bit - message = generic_check_tmpdir_sticky_bit + message = super return if message.nil? message + <<~EOS @@ -74,11 +74,11 @@ module OS end def check_supported_architecture - return if Hardware::CPU.intel? - return if Homebrew::EnvConfig.developer? && ENV["HOMEBREW_ARM64_TESTING"].present? && Hardware::CPU.arm? + return if ::Hardware::CPU.intel? + return if Homebrew::EnvConfig.developer? && ENV["HOMEBREW_ARM64_TESTING"].present? && ::Hardware::CPU.arm? <<~EOS - Your CPU architecture (#{Hardware::CPU.arch}) is not supported. We only support + 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). #{support_tier_message(tier: 2)} diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/shared.rb b/Library/Homebrew/extend/os/linux/extend/ENV/shared.rb index fe4410d22e..284f62aa6b 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/shared.rb @@ -1,16 +1,22 @@ # typed: true # rubocop:todo Sorbet/StrictSigil # frozen_string_literal: true -module SharedEnvExtension - def effective_arch - if @build_bottle && @bottle_arch - @bottle_arch.to_sym - elsif @build_bottle - Hardware.oldest_cpu - elsif Hardware::CPU.intel? || Hardware::CPU.arm? - :native - else - :dunno +module OS + module Linux + module SharedEnvExtension + def effective_arch + if @build_bottle && @bottle_arch + @bottle_arch.to_sym + elsif @build_bottle + ::Hardware.oldest_cpu + elsif ::Hardware::CPU.intel? || ::Hardware::CPU.arm? + :native + else + :dunno + end + end end end end + +SharedEnvExtension.prepend(OS::Linux::SharedEnvExtension) diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/std.rb b/Library/Homebrew/extend/os/linux/extend/ENV/std.rb index ba2fa12309..67f2620405 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:) +module OS + module Linux + module Stdenv + extend T::Helpers - prepend_path "CPATH", HOMEBREW_PREFIX/"include" - prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib" - prepend_path "LD_RUN_PATH", HOMEBREW_PREFIX/"lib" + requires_ancestor { ::SharedEnvExtension } - return unless @formula + 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", @formula.include - prepend_path "LIBRARY_PATH", @formula.lib - prepend_path "LD_RUN_PATH", @formula.lib - end + 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 6c5fb6ff4c..7c6d518fce 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb @@ -1,79 +1,93 @@ # 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 { SharedEnvExtension } + 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) - m4_path_deps = ["libtool", "bison"] - self["M4"] = "#{HOMEBREW_PREFIX}/opt/m4/bin/m4" if deps.any? { m4_path_deps.include?(_1.name) } + module ClassMethods + sig { returns(Pathname) } + def shims_path + HOMEBREW_SHIMS_PATH/"linux/super" + end - # Pointer authentication and BTI are hardening techniques most distros - # use by default on their packages. arm64 Linux we're packaging - # everything from scratch so the entire dependency tree can have it. - append_to_cccfg "b" if Hardware::CPU.arch == :arm64 && DevelopmentTools.gcc_version("gcc") >= 9 - end + sig { returns(T.nilable(Pathname)) } + def bin + shims_path.realpath + end + 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 + 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) + m4_path_deps = ["libtool", "bison"] + self["M4"] = "#{HOMEBREW_PREFIX}/opt/m4/bin/m4" if deps.any? { m4_path_deps.include?(_1.name) } + + # Pointer authentication and BTI are hardening techniques most distros + # use by default on their packages. arm64 Linux we're packaging + # everything from scratch so the entire dependency tree can have it. + append_to_cccfg "b" if ::Hardware::CPU.arch == :arm64 && ::DevelopmentTools.gcc_version("gcc") >= 9 + end + + def homebrew_extra_paths + paths = super + 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 versioned glibc because we have to use -nostdinc. + if deps.any? { |d| d.name.match?(/^glibc@.+$/) } + 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 + + sig { returns(T.nilable(String)) } + def determine_dynamic_linker_path + path = "#{HOMEBREW_PREFIX}/lib/ld.so" + return unless File.readable? path + + path + end end - paths - end - - def homebrew_extra_isystem_paths - paths = [] - # Add paths for GCC headers when building against versioned glibc because we have to use -nostdinc. - if deps.any? { |d| d.name.match?(/^glibc@.+$/) } - 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 - - sig { returns(T.nilable(String)) } - def determine_dynamic_linker_path - path = "#{HOMEBREW_PREFIX}/lib/ld.so" - return unless File.readable? path - - path end end + +Superenv.singleton_class.prepend(OS::Linux::Superenv::ClassMethods) +Superenv.prepend(OS::Linux::Superenv) diff --git a/Library/Homebrew/extend/os/linux/formula_cellar_checks.rb b/Library/Homebrew/extend/os/linux/formula_cellar_checks.rb index b08411fb1b..a56c0c5582 100644 --- a/Library/Homebrew/extend/os/linux/formula_cellar_checks.rb +++ b/Library/Homebrew/extend/os/linux/formula_cellar_checks.rb @@ -1,9 +1,15 @@ # typed: strict # frozen_string_literal: true -module FormulaCellarChecks - sig { params(filename: Pathname).returns(T::Boolean) } - def valid_library_extension?(filename) - generic_valid_library_extension?(filename) || filename.basename.to_s.include?(".so.") +module OS + module Linux + module FormulaCellarChecks + sig { params(filename: Pathname).returns(T::Boolean) } + def valid_library_extension?(filename) + super || filename.basename.to_s.include?(".so.") + end + end end end + +FormulaCellarChecks.prepend(OS::Linux::FormulaCellarChecks) diff --git a/Library/Homebrew/extend/os/linux/hardware/cpu.rb b/Library/Homebrew/extend/os/linux/hardware/cpu.rb index b5c81ee078..2597af4eae 100644 --- a/Library/Homebrew/extend/os/linux/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/linux/hardware/cpu.rb @@ -1,161 +1,171 @@ # typed: true # rubocop:todo Sorbet/StrictSigil # frozen_string_literal: true -module Hardware - class CPU - class << self - def optimization_flags - @optimization_flags ||= begin - flags = generic_optimization_flags.dup - flags[:native] = arch_flag(Homebrew::EnvConfig.arch) - flags - end - end +module OS + module Linux + module Hardware + module CPU + module ClassMethods + extend T::Helpers - def family - return :arm if arm? - return :ppc if ppc? - return :dunno unless intel? + requires_ancestor { T.class_of(::Hardware::CPU) } - # See https://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers - # and https://github.com/llvm/llvm-project/blob/main/llvm/lib/TargetParser/Host.cpp - # and https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures#Roadmap - vendor_id = cpuinfo[/^vendor_id\s*: (.*)/, 1] - cpu_family = cpuinfo[/^cpu family\s*: ([0-9]+)/, 1].to_i - cpu_model = cpuinfo[/^model\s*: ([0-9]+)/, 1].to_i - unknown = :"unknown_0x#{cpu_family.to_s(16)}_0x#{cpu_model.to_s(16)}" - case vendor_id - when "GenuineIntel" - intel_family(cpu_family, cpu_model) - when "AuthenticAMD" - amd_family(cpu_family, cpu_model) - end || unknown - end - - def intel_family(family, cpu_model) - case family - when 0x06 - case cpu_model - when 0x3a, 0x3e - :ivybridge - when 0x2a, 0x2d - :sandybridge - when 0x25, 0x2c, 0x2f - :westmere - when 0x1a, 0x1e, 0x1f, 0x2e - :nehalem - when 0x17, 0x1d - :penryn - when 0x0f, 0x16 - :merom - when 0x0d - :dothan - when 0x1c, 0x26, 0x27, 0x35, 0x36 - :atom - when 0x3c, 0x3f, 0x45, 0x46 - :haswell - when 0x3d, 0x47, 0x4f, 0x56 - :broadwell - when 0x4e, 0x5e, 0x8e, 0x9e, 0xa5, 0xa6 - :skylake - when 0x66 - :cannonlake - when 0x6a, 0x6c, 0x7d, 0x7e - :icelake - when 0xa7 - :rocketlake - when 0x8c, 0x8d - :tigerlake - when 0x97, 0x9a, 0xbe, 0xb7, 0xba, 0xbf, 0xaa, 0xac - :alderlake - when 0xc5, 0xb5, 0xc6, 0xbd - :arrowlake - when 0xcc - :pantherlake - when 0xad, 0xae - :graniterapids - when 0xcf, 0x8f - :sapphirerapids + def optimization_flags + @optimization_flags ||= begin + flags = super.dup + flags[:native] = arch_flag(Homebrew::EnvConfig.arch) + flags + end end - when 0x0f - case cpu_model - when 0x06 - :presler - when 0x03, 0x04 - :prescott + + def family + return :arm if arm? + return :ppc if ppc? + return :dunno unless intel? + + # See https://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers + # and https://github.com/llvm/llvm-project/blob/main/llvm/lib/TargetParser/Host.cpp + # and https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures#Roadmap + vendor_id = cpuinfo[/^vendor_id\s*: (.*)/, 1] + cpu_family = cpuinfo[/^cpu family\s*: ([0-9]+)/, 1].to_i + cpu_model = cpuinfo[/^model\s*: ([0-9]+)/, 1].to_i + unknown = :"unknown_0x#{cpu_family.to_s(16)}_0x#{cpu_model.to_s(16)}" + case vendor_id + when "GenuineIntel" + intel_family(cpu_family, cpu_model) + when "AuthenticAMD" + amd_family(cpu_family, cpu_model) + end || unknown + end + + def intel_family(family, cpu_model) + case family + when 0x06 + case cpu_model + when 0x3a, 0x3e + :ivybridge + when 0x2a, 0x2d + :sandybridge + when 0x25, 0x2c, 0x2f + :westmere + when 0x1a, 0x1e, 0x1f, 0x2e + :nehalem + when 0x17, 0x1d + :penryn + when 0x0f, 0x16 + :merom + when 0x0d + :dothan + when 0x1c, 0x26, 0x27, 0x35, 0x36 + :atom + when 0x3c, 0x3f, 0x45, 0x46 + :haswell + when 0x3d, 0x47, 0x4f, 0x56 + :broadwell + when 0x4e, 0x5e, 0x8e, 0x9e, 0xa5, 0xa6 + :skylake + when 0x66 + :cannonlake + when 0x6a, 0x6c, 0x7d, 0x7e + :icelake + when 0xa7 + :rocketlake + when 0x8c, 0x8d + :tigerlake + when 0x97, 0x9a, 0xbe, 0xb7, 0xba, 0xbf, 0xaa, 0xac + :alderlake + when 0xc5, 0xb5, 0xc6, 0xbd + :arrowlake + when 0xcc + :pantherlake + when 0xad, 0xae + :graniterapids + when 0xcf, 0x8f + :sapphirerapids + end + when 0x0f + case cpu_model + when 0x06 + :presler + when 0x03, 0x04 + :prescott + end + end + end + + def amd_family(family, cpu_model) + case family + when 0x06 + :amd_k7 + when 0x0f + :amd_k8 + when 0x10 + :amd_k10 + when 0x11 + :amd_k8_k10_hybrid + when 0x12 + :amd_k10_llano + when 0x14 + :bobcat + when 0x15 + :bulldozer + when 0x16 + :jaguar + when 0x17 + case cpu_model + when 0x10..0x2f + :zen + when 0x30..0x3f, 0x47, 0x60..0x7f, 0x84..0x87, 0x90..0xaf + :zen2 + end + when 0x19 + case cpu_model + when ..0x0f, 0x20..0x5f + :zen3 + when 0x10..0x1f, 0x60..0x7f, 0xa0..0xaf + :zen4 + end + when 0x1a + :zen5 + end + end + + # Supported CPU instructions + def flags + @flags ||= cpuinfo[/^(?:flags|Features)\s*: (.*)/, 1]&.split + @flags ||= [] + end + + # Compatibility with Mac method, which returns lowercase symbols + # instead of strings. + def features + @features ||= flags[1..].map(&:intern) + end + + %w[aes altivec avx avx2 lm ssse3 sse4_2].each do |flag| + define_method(:"#{flag}?") do + T.bind(self, OS::Linux::Hardware::CPU::ClassMethods) + flags.include? flag + end + end + + def sse3? + flags.include?("pni") || flags.include?("sse3") + end + + def sse4? + flags.include? "sse4_1" + end + + private + + def cpuinfo + @cpuinfo ||= File.read("/proc/cpuinfo") end end end - - def amd_family(family, cpu_model) - case family - when 0x06 - :amd_k7 - when 0x0f - :amd_k8 - when 0x10 - :amd_k10 - when 0x11 - :amd_k8_k10_hybrid - when 0x12 - :amd_k10_llano - when 0x14 - :bobcat - when 0x15 - :bulldozer - when 0x16 - :jaguar - when 0x17 - case cpu_model - when 0x10..0x2f - :zen - when 0x30..0x3f, 0x47, 0x60..0x7f, 0x84..0x87, 0x90..0xaf - :zen2 - end - when 0x19 - case cpu_model - when ..0x0f, 0x20..0x5f - :zen3 - when 0x10..0x1f, 0x60..0x7f, 0xa0..0xaf - :zen4 - end - when 0x1a - :zen5 - end - end - - # Supported CPU instructions - def flags - @flags ||= cpuinfo[/^(?:flags|Features)\s*: (.*)/, 1]&.split - @flags ||= [] - end - - # Compatibility with Mac method, which returns lowercase symbols - # instead of strings. - def features - @features ||= flags[1..].map(&:intern) - end - - %w[aes altivec avx avx2 lm ssse3 sse4_2].each do |flag| - define_method(:"#{flag}?") do - T.bind(self, T.class_of(Hardware::CPU)) - flags.include? flag - end - end - - def sse3? - flags.include?("pni") || flags.include?("sse3") - end - - def sse4? - flags.include? "sse4_1" - end - - private - - def cpuinfo - @cpuinfo ||= File.read("/proc/cpuinfo") - end end end end + +Hardware::CPU.singleton_class.prepend(OS::Linux::Hardware::CPU::ClassMethods) diff --git a/Library/Homebrew/extend/os/linux/install.rb b/Library/Homebrew/extend/os/linux/install.rb index 0fc3cd16dc..d035a2f547 100644 --- a/Library/Homebrew/extend/os/linux/install.rb +++ b/Library/Homebrew/extend/os/linux/install.rb @@ -1,132 +1,132 @@ # typed: true # rubocop:todo Sorbet/StrictSigil # frozen_string_literal: true -module Homebrew - module Install - # This is a list of known paths to the host dynamic linker on Linux if - # the host glibc is new enough. The symlink_ld_so method will fail if - # the host linker cannot be found in this list. - DYNAMIC_LINKERS = %w[ - /lib64/ld-linux-x86-64.so.2 - /lib64/ld64.so.2 - /lib/ld-linux.so.3 - /lib/ld-linux.so.2 - /lib/ld-linux-aarch64.so.1 - /lib/ld-linux-armhf.so.3 - /system/bin/linker64 - /system/bin/linker - ].freeze - private_constant :DYNAMIC_LINKERS +module OS + module Linux + module Install + module ClassMethods + # This is a list of known paths to the host dynamic linker on Linux if + # the host glibc is new enough. The symlink_ld_so method will fail if + # the host linker cannot be found in this list. + DYNAMIC_LINKERS = %w[ + /lib64/ld-linux-x86-64.so.2 + /lib64/ld64.so.2 + /lib/ld-linux.so.3 + /lib/ld-linux.so.2 + /lib/ld-linux-aarch64.so.1 + /lib/ld-linux-armhf.so.3 + /system/bin/linker64 + /system/bin/linker + ].freeze - # We link GCC runtime libraries that are not specifically used for Fortran, - # which are linked by the GCC formula. We only use the versioned shared libraries - # as the other shared and static libraries are only used at build time where - # GCC can find its own libraries. - GCC_RUNTIME_LIBS = %w[ - libatomic.so.1 - libgcc_s.so.1 - libgomp.so.1 - libstdc++.so.6 - ].freeze - private_constant :GCC_RUNTIME_LIBS + # We link GCC runtime libraries that are not specifically used for Fortran, + # which are linked by the GCC formula. We only use the versioned shared libraries + # as the other shared and static libraries are only used at build time where + # GCC can find its own libraries. + GCC_RUNTIME_LIBS = %w[ + libatomic.so.1 + libgcc_s.so.1 + libgomp.so.1 + libstdc++.so.6 + ].freeze - def self.perform_preinstall_checks(all_fatal: false) - generic_perform_preinstall_checks(all_fatal:) - symlink_ld_so - setup_preferred_gcc_libs - end - private_class_method :perform_preinstall_checks - - def self.global_post_install - generic_global_post_install - symlink_ld_so - setup_preferred_gcc_libs - end - - def self.check_cpu - return if Hardware::CPU.intel? && Hardware::CPU.is_64_bit? - return if Hardware::CPU.arm? - - message = "Sorry, Homebrew does not support your computer's CPU architecture!" - if Hardware::CPU.ppc64le? - message += <<~EOS - For OpenPOWER Linux (PPC64LE) support, see: - #{Formatter.url("https://github.com/homebrew-ppc64le/brew")} - EOS - end - abort message - end - private_class_method :check_cpu - - def self.symlink_ld_so - brew_ld_so = HOMEBREW_PREFIX/"lib/ld.so" - - ld_so = HOMEBREW_PREFIX/"opt/glibc/bin/ld.so" - unless ld_so.readable? - ld_so = DYNAMIC_LINKERS.find { |s| File.executable? s } - if ld_so.blank? - raise "Unable to locate the system's dynamic linker" unless brew_ld_so.readable? - - return - end - end - - return if brew_ld_so.readable? && (brew_ld_so.readlink == ld_so) - - FileUtils.mkdir_p HOMEBREW_PREFIX/"lib" - FileUtils.ln_sf ld_so, brew_ld_so - end - private_class_method :symlink_ld_so - - def self.setup_preferred_gcc_libs - gcc_opt_prefix = HOMEBREW_PREFIX/"opt/#{OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA}" - glibc_installed = (HOMEBREW_PREFIX/"opt/glibc/bin/ld.so").readable? - - return unless gcc_opt_prefix.readable? - - if glibc_installed - ld_so_conf_d = HOMEBREW_PREFIX/"etc/ld.so.conf.d" - unless ld_so_conf_d.exist? - ld_so_conf_d.mkpath - FileUtils.chmod "go-w", ld_so_conf_d + def perform_preinstall_checks(all_fatal: false) + super + symlink_ld_so + setup_preferred_gcc_libs end - # Add gcc to ld search paths - ld_gcc_conf = ld_so_conf_d/"50-homebrew-preferred-gcc.conf" - ld_gcc_conf_content = <<~EOS - # This file is generated by Homebrew. Do not modify. - #{gcc_opt_prefix}/lib/gcc/current - EOS - - if !ld_gcc_conf.exist? || (ld_gcc_conf.read != ld_gcc_conf_content) - ld_gcc_conf.atomic_write ld_gcc_conf_content - FileUtils.chmod "u=rw,go-wx", ld_gcc_conf - - FileUtils.rm_f HOMEBREW_PREFIX/"etc/ld.so.cache" - system HOMEBREW_PREFIX/"opt/glibc/sbin/ldconfig" + def global_post_install + super + symlink_ld_so + setup_preferred_gcc_libs end - else - odie "#{HOMEBREW_PREFIX}/lib does not exist!" unless (HOMEBREW_PREFIX/"lib").readable? - end - GCC_RUNTIME_LIBS.each do |library| - gcc_library_symlink = HOMEBREW_PREFIX/"lib/#{library}" + def check_cpu + return if ::Hardware::CPU.intel? && ::Hardware::CPU.is_64_bit? + return if ::Hardware::CPU.arm? - if glibc_installed - # Remove legacy symlinks - FileUtils.rm gcc_library_symlink if gcc_library_symlink.symlink? - else - gcc_library = gcc_opt_prefix/"lib/gcc/current/#{library}" - # Skip if the link target doesn't exist. - next unless gcc_library.readable? + message = "Sorry, Homebrew does not support your computer's CPU architecture!" + if ::Hardware::CPU.ppc64le? + message += <<~EOS + For OpenPOWER Linux (PPC64LE) support, see: + #{Formatter.url("https://github.com/homebrew-ppc64le/brew")} + EOS + end + ::Kernel.abort message + end - # Also skip if the symlink already exists. - next if gcc_library_symlink.readable? && (gcc_library_symlink.readlink == gcc_library) + def symlink_ld_so + brew_ld_so = HOMEBREW_PREFIX/"lib/ld.so" - FileUtils.ln_sf gcc_library, gcc_library_symlink + ld_so = HOMEBREW_PREFIX/"opt/glibc/bin/ld.so" + unless ld_so.readable? + ld_so = DYNAMIC_LINKERS.find { |s| File.executable? s } + if ld_so.blank? + ::Kernel.raise "Unable to locate the system's dynamic linker" unless brew_ld_so.readable? + + return + end + end + + return if brew_ld_so.readable? && (brew_ld_so.readlink == ld_so) + + FileUtils.mkdir_p HOMEBREW_PREFIX/"lib" + FileUtils.ln_sf ld_so, brew_ld_so + end + + def setup_preferred_gcc_libs + gcc_opt_prefix = HOMEBREW_PREFIX/"opt/#{OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA}" + glibc_installed = (HOMEBREW_PREFIX/"opt/glibc/bin/ld.so").readable? + + return unless gcc_opt_prefix.readable? + + if glibc_installed + ld_so_conf_d = HOMEBREW_PREFIX/"etc/ld.so.conf.d" + unless ld_so_conf_d.exist? + ld_so_conf_d.mkpath + FileUtils.chmod "go-w", ld_so_conf_d + end + + # Add gcc to ld search paths + ld_gcc_conf = ld_so_conf_d/"50-homebrew-preferred-gcc.conf" + ld_gcc_conf_content = <<~EOS + # This file is generated by Homebrew. Do not modify. + #{gcc_opt_prefix}/lib/gcc/current + EOS + + if !ld_gcc_conf.exist? || (ld_gcc_conf.read != ld_gcc_conf_content) + ld_gcc_conf.atomic_write ld_gcc_conf_content + FileUtils.chmod "u=rw,go-wx", ld_gcc_conf + + FileUtils.rm_f HOMEBREW_PREFIX/"etc/ld.so.cache" + ::Kernel.system HOMEBREW_PREFIX/"opt/glibc/sbin/ldconfig" + end + else + ::Kernel.odie "#{HOMEBREW_PREFIX}/lib does not exist!" unless (HOMEBREW_PREFIX/"lib").readable? + end + + GCC_RUNTIME_LIBS.each do |library| + gcc_library_symlink = HOMEBREW_PREFIX/"lib/#{library}" + + if glibc_installed + # Remove legacy symlinks + FileUtils.rm gcc_library_symlink if gcc_library_symlink.symlink? + else + gcc_library = gcc_opt_prefix/"lib/gcc/current/#{library}" + # Skip if the link target doesn't exist. + next unless gcc_library.readable? + + # Also skip if the symlink already exists. + next if gcc_library_symlink.readable? && (gcc_library_symlink.readlink == gcc_library) + + FileUtils.ln_sf gcc_library, gcc_library_symlink + end + end end end end - private_class_method :setup_preferred_gcc_libs end end + +Homebrew::Install.singleton_class.prepend(OS::Linux::Install::ClassMethods) diff --git a/Library/Homebrew/extend/os/linux/linkage_checker.rb b/Library/Homebrew/extend/os/linux/linkage_checker.rb index c2392f7d7b..634bd5b71f 100644 --- a/Library/Homebrew/extend/os/linux/linkage_checker.rb +++ b/Library/Homebrew/extend/os/linux/linkage_checker.rb @@ -3,48 +3,55 @@ require "compilers" -class LinkageChecker - # Libraries provided by glibc and gcc. - SYSTEM_LIBRARY_ALLOWLIST = %w[ - ld-linux-x86-64.so.2 - ld-linux-aarch64.so.1 - libanl.so.1 - libatomic.so.1 - libc.so.6 - libdl.so.2 - libm.so.6 - libmvec.so.1 - libnss_files.so.2 - libpthread.so.0 - libresolv.so.2 - librt.so.1 - libthread_db.so.1 - libutil.so.1 - libgcc_s.so.1 - libgomp.so.1 - libstdc++.so.6 - libquadmath.so.0 - ].freeze +module OS + module Linux + module LinkageChecker + # Libraries provided by glibc and gcc. + SYSTEM_LIBRARY_ALLOWLIST = %w[ + ld-linux-x86-64.so.2 + ld-linux-aarch64.so.1 + libanl.so.1 + libatomic.so.1 + libc.so.6 + libdl.so.2 + libm.so.6 + libmvec.so.1 + libnss_files.so.2 + libpthread.so.0 + libresolv.so.2 + librt.so.1 + libthread_db.so.1 + libutil.so.1 + libgcc_s.so.1 + libgomp.so.1 + libstdc++.so.6 + libquadmath.so.0 + ].freeze - private + private - def check_dylibs(rebuild_cache:) - generic_check_dylibs(rebuild_cache:) + def check_dylibs(rebuild_cache:) + super - # glibc and gcc are implicit dependencies. - # No other linkage to system libraries is expected or desired. - @unwanted_system_dylibs = @system_dylibs.reject do |s| - SYSTEM_LIBRARY_ALLOWLIST.include? File.basename(s) + # glibc and gcc are implicit dependencies. + # No other linkage to system libraries is expected or desired. + @unwanted_system_dylibs = @system_dylibs.reject do |s| + SYSTEM_LIBRARY_ALLOWLIST.include? File.basename(s) + end + + # We build all formulae with an RPATH that includes the gcc formula's runtime lib directory. + # See: https://github.com/Homebrew/brew/blob/e689cc07/Library/Homebrew/extend/os/linux/extend/ENV/super.rb#L53 + # This results in formulae showing linkage with gcc whenever it is installed, even if no dependency is + # declared. + # See discussions at: + # https://github.com/Homebrew/brew/pull/13659 + # https://github.com/Homebrew/brew/pull/13796 + # TODO: Find a nicer way to handle this. (e.g. examining the ELF file to determine the required libstdc++.) + @undeclared_deps.delete("gcc") + @indirect_deps.delete("gcc") + end end - - # We build all formulae with an RPATH that includes the gcc formula's runtime lib directory. - # See: https://github.com/Homebrew/brew/blob/e689cc07/Library/Homebrew/extend/os/linux/extend/ENV/super.rb#L53 - # This results in formulae showing linkage with gcc whenever it is installed, even if no dependency is declared. - # See discussions at: - # https://github.com/Homebrew/brew/pull/13659 - # https://github.com/Homebrew/brew/pull/13796 - # TODO: Find a nicer way to handle this. (e.g. examining the ELF file to determine the required libstdc++.) - @undeclared_deps.delete("gcc") - @indirect_deps.delete("gcc") end end + +LinkageChecker.prepend(OS::Linux::LinkageChecker) diff --git a/Library/Homebrew/extend/os/linux/system_config.rb b/Library/Homebrew/extend/os/linux/system_config.rb index 13ded66558..90dc2de624 100644 --- a/Library/Homebrew/extend/os/linux/system_config.rb +++ b/Library/Homebrew/extend/os/linux/system_config.rb @@ -5,53 +5,59 @@ require "compilers" require "os/linux/glibc" require "system_command" -module SystemConfig - include SystemCommand::Mixin +module OS + module Linux + module SystemConfig + module ClassMethods + include SystemCommand::Mixin - HOST_RUBY_PATH = "/usr/bin/ruby" + HOST_RUBY_PATH = "/usr/bin/ruby" - class << self - def host_glibc_version - version = OS::Linux::Glibc.system_version - return "N/A" if version.null? + def host_glibc_version + version = OS::Linux::Glibc.system_version + return "N/A" if version.null? - version - end + version + end - def host_gcc_version - gcc = DevelopmentTools.host_gcc_path - return "N/A" unless gcc.executable? + def host_gcc_version + gcc = ::DevelopmentTools.host_gcc_path + return "N/A" unless gcc.executable? - `#{gcc} --version 2>/dev/null`[/ (\d+\.\d+\.\d+)/, 1] - end + Utils.popen_read(gcc, "--version")[/ (\d+\.\d+\.\d+)/, 1] + end - def formula_linked_version(formula) - return "N/A" if Homebrew::EnvConfig.no_install_from_api? && !CoreTap.instance.installed? + def formula_linked_version(formula) + return "N/A" if Homebrew::EnvConfig.no_install_from_api? && !CoreTap.instance.installed? - Formulary.factory(formula).any_installed_version || "N/A" - rescue FormulaUnavailableError - "N/A" - end + Formulary.factory(formula).any_installed_version || "N/A" + rescue FormulaUnavailableError + "N/A" + end - def host_ruby_version - out, _, status = system_command(HOST_RUBY_PATH, args: ["-e", "puts RUBY_VERSION"], print_stderr: false) - return "N/A" unless status.success? + def host_ruby_version + out, _, status = system_command(HOST_RUBY_PATH, args: ["-e", "puts RUBY_VERSION"], print_stderr: false) + return "N/A" unless status.success? - out - end + out + end - def dump_verbose_config(out = $stdout) - kernel = Utils.safe_popen_read("uname", "-mors").chomp - dump_generic_verbose_config(out) - out.puts "Kernel: #{kernel}" - out.puts "OS: #{OS::Linux.os_version}" - out.puts "WSL: #{OS::Linux.wsl_version}" if OS::Linux.wsl? - out.puts "Host glibc: #{host_glibc_version}" - out.puts "#{DevelopmentTools.host_gcc_path}: #{host_gcc_version}" - out.puts "/usr/bin/ruby: #{host_ruby_version}" if RUBY_PATH != HOST_RUBY_PATH - ["glibc", CompilerSelector.preferred_gcc, OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA, "xorg"].each do |f| - out.puts "#{f}: #{formula_linked_version(f)}" + def dump_verbose_config(out = $stdout) + kernel = Utils.safe_popen_read("uname", "-mors").chomp + super + out.puts "Kernel: #{kernel}" + out.puts "OS: #{OS::Linux.os_version}" + out.puts "WSL: #{OS::Linux.wsl_version}" if OS::Linux.wsl? + out.puts "Host glibc: #{host_glibc_version}" + out.puts "#{::DevelopmentTools.host_gcc_path}: #{host_gcc_version}" + out.puts "/usr/bin/ruby: #{host_ruby_version}" if RUBY_PATH != HOST_RUBY_PATH + ["glibc", CompilerSelector.preferred_gcc, OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA, "xorg"].each do |f| + out.puts "#{f}: #{formula_linked_version(f)}" + end + end end end end end + +SystemConfig.singleton_class.prepend(OS::Linux::SystemConfig::ClassMethods) diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb b/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb index 42a2cea1c7..30c7848af6 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/shared.rb @@ -1,42 +1,50 @@ # typed: strict # frozen_string_literal: true -module SharedEnvExtension - 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_shared_setup_build_environment(formula:, cc:, build_bottle:, - bottle_arch:, testing_formula:, - debug_symbols:) +module OS + module Mac + module SharedEnvExtension + extend T::Helpers - # Normalise the system Perl version used, where multiple may be available - self["VERSIONER_PERL_VERSION"] = MacOS.preferred_perl_version - end + requires_ancestor { ::SharedEnvExtension } - sig { returns(T::Boolean) } - def no_weak_imports_support? - return false if compiler != :clang + 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 - return false if !MacOS::Xcode.version.null? && MacOS::Xcode.version < "8.0" - return false if !MacOS::CLT.version.null? && MacOS::CLT.version < "8.0" + # Normalise the system Perl version used, where multiple may be available + self["VERSIONER_PERL_VERSION"] = MacOS.preferred_perl_version + end - true - end + sig { returns(T::Boolean) } + def no_weak_imports_support? + return false if compiler != :clang - sig { returns(T::Boolean) } - 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 - OS::Mac::DevelopmentTools.ld64_version >= 711 + return false if !MacOS::Xcode.version.null? && MacOS::Xcode.version < "8.0" + return false if !MacOS::CLT.version.null? && MacOS::CLT.version < "8.0" + + true + end + + sig { returns(T::Boolean) } + 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 + OS::Mac::DevelopmentTools.ld64_version >= 711 + end + end end end + +SharedEnvExtension.prepend(OS::Mac::SharedEnvExtension) diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb index c312eb1125..28298fedac 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 +module OS + module Mac + module Stdenv + extend T::Helpers - sig { returns(T::Array[Pathname]) } - def homebrew_extra_pkg_config_paths - [Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")] - end - private :homebrew_extra_pkg_config_paths + requires_ancestor { SharedEnvExtension } + requires_ancestor { ::Stdenv } - sig { - params( - formula: T.nilable(Formula), - cc: T.nilable(String), - build_bottle: T.nilable(T::Boolean), - bottle_arch: T.nilable(String), - testing_formula: T::Boolean, - debug_symbols: T.nilable(T::Boolean), - ).void - } - def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false, - debug_symbols: false) - generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:, - testing_formula:, debug_symbols:) + sig { returns(T::Array[Pathname]) } + def homebrew_extra_pkg_config_paths + [Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")] + end + private :homebrew_extra_pkg_config_paths - append "LDFLAGS", "-Wl,-headerpad_max_install_names" + sig { + params( + formula: T.nilable(Formula), + cc: T.nilable(String), + build_bottle: T.nilable(T::Boolean), + bottle_arch: T.nilable(String), + testing_formula: T::Boolean, + debug_symbols: T.nilable(T::Boolean), + ).void + } + def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, + testing_formula: false, debug_symbols: false) + super - # `sed` is strict and errors out when it encounters files with mixed character sets. - delete("LC_ALL") - self["LC_CTYPE"] = "C" + append "LDFLAGS", "-Wl,-headerpad_max_install_names" - # Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags: - macosxsdk(formula: @formula, testing_formula:) + # `sed` is strict and errors out when it encounters files with mixed character sets. + delete("LC_ALL") + self["LC_CTYPE"] = "C" - return unless MacOS::Xcode.without_clt? + # Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags: + macosxsdk(formula: @formula, testing_formula:) - append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin" - append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin" - end + return unless MacOS::Xcode.without_clt? - def remove_macosxsdk(version = nil) - # Clear all `lib` and `include` dirs from `CFLAGS`, `CPPFLAGS`, `LDFLAGS` that were - # previously added by `macosxsdk`. - remove_from_cflags(/ ?-mmacosx-version-min=\d+\.\d+/) - delete("CPATH") - remove "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib" + append_path "PATH", "#{MacOS::Xcode.prefix}/usr/bin" + append_path "PATH", "#{MacOS::Xcode.toolchain_path}/usr/bin" + end - sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed(version) - return unless sdk + def remove_macosxsdk(version = nil) + # Clear all `lib` and `include` dirs from `CFLAGS`, `CPPFLAGS`, `LDFLAGS` that were + # previously added by `macosxsdk`. + remove_from_cflags(/ ?-mmacosx-version-min=\d+\.\d+/) + delete("CPATH") + remove "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib" - delete("SDKROOT") - remove_from_cflags "-isysroot#{sdk}" - remove "CPPFLAGS", "-isysroot#{sdk}" - remove "LDFLAGS", "-isysroot#{sdk}" - if HOMEBREW_PREFIX.to_s == "/usr/local" - delete("CMAKE_PREFIX_PATH") - else - # It was set in `setup_build_environment`, so we have to restore it here. - self["CMAKE_PREFIX_PATH"] = HOMEBREW_PREFIX.to_s + sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed(version) + return unless sdk + + delete("SDKROOT") + remove_from_cflags "-isysroot#{sdk}" + remove "CPPFLAGS", "-isysroot#{sdk}" + remove "LDFLAGS", "-isysroot#{sdk}" + if HOMEBREW_PREFIX.to_s == "/usr/local" + delete("CMAKE_PREFIX_PATH") + else + # It was set in `setup_build_environment`, so we have to restore it here. + self["CMAKE_PREFIX_PATH"] = HOMEBREW_PREFIX.to_s + end + remove "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks" + end + + def macosxsdk(version = nil, formula: nil, testing_formula: false) + # Sets all needed `lib` and `include` dirs to `CFLAGS`, `CPPFLAGS`, `LDFLAGS`. + remove_macosxsdk + min_version = version || MacOS.version + append_to_cflags("-mmacosx-version-min=#{min_version}") + self["CPATH"] = "#{HOMEBREW_PREFIX}/include" + prepend "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib" + + sdk = if formula + MacOS.sdk_for_formula(formula, version, check_only_runtime_requirements: testing_formula) + else + MacOS.sdk(version) + end + return if !MacOS.sdk_root_needed? && sdk&.source != :xcode + + Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks) + sdk = sdk.path + + # Extra setup to support Xcode 4.3+ without CLT. + self["SDKROOT"] = sdk + # Tell clang/gcc where system include's are: + append_path "CPATH", "#{sdk}/usr/include" + # The -isysroot is needed, too, because of the Frameworks + append_to_cflags "-isysroot#{sdk}" + append "CPPFLAGS", "-isysroot#{sdk}" + # And the linker needs to find sdk/usr/lib + append "LDFLAGS", "-isysroot#{sdk}" + # Needed to build cmake itself and perhaps some cmake projects: + append_path "CMAKE_PREFIX_PATH", "#{sdk}/usr" + append_path "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks" + end + + # Some configure scripts won't find libxml2 without help. + # This is a no-op with macOS SDK 10.15.4 and later. + def libxml2 + sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed + if !sdk + append "CPPFLAGS", "-I/usr/include/libxml2" + elsif !Pathname("#{sdk}/usr/include/libxml").directory? + # Use the includes form the sdk + append "CPPFLAGS", "-I#{sdk}/usr/include/libxml2" + end + end + + def no_weak_imports + append "LDFLAGS", "-Wl,-no_weak_imports" if no_weak_imports_support? + end + + def no_fixup_chains + append "LDFLAGS", "-Wl,-no_fixup_chains" if no_fixup_chains_support? + end end - remove "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks" - end - - def macosxsdk(version = nil, formula: nil, testing_formula: false) - # Sets all needed `lib` and `include` dirs to `CFLAGS`, `CPPFLAGS`, `LDFLAGS`. - remove_macosxsdk - min_version = version || MacOS.version - append_to_cflags("-mmacosx-version-min=#{min_version}") - self["CPATH"] = "#{HOMEBREW_PREFIX}/include" - prepend "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib" - - sdk = if formula - MacOS.sdk_for_formula(formula, version, check_only_runtime_requirements: testing_formula) - else - MacOS.sdk(version) - end - return if !MacOS.sdk_root_needed? && sdk&.source != :xcode - - Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks) - sdk = sdk.path - - # Extra setup to support Xcode 4.3+ without CLT. - self["SDKROOT"] = sdk - # Tell clang/gcc where system include's are: - append_path "CPATH", "#{sdk}/usr/include" - # The -isysroot is needed, too, because of the Frameworks - append_to_cflags "-isysroot#{sdk}" - append "CPPFLAGS", "-isysroot#{sdk}" - # And the linker needs to find sdk/usr/lib - append "LDFLAGS", "-isysroot#{sdk}" - # Needed to build cmake itself and perhaps some cmake projects: - append_path "CMAKE_PREFIX_PATH", "#{sdk}/usr" - append_path "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks" - end - - # Some configure scripts won't find libxml2 without help. - # This is a no-op with macOS SDK 10.15.4 and later. - def libxml2 - sdk = self["SDKROOT"] || MacOS.sdk_path_if_needed - if !sdk - append "CPPFLAGS", "-I/usr/include/libxml2" - elsif !Pathname("#{sdk}/usr/include/libxml").directory? - # Use the includes form the sdk - append "CPPFLAGS", "-I#{sdk}/usr/include/libxml2" - end - end - - def no_weak_imports - append "LDFLAGS", "-Wl,-no_weak_imports" if no_weak_imports_support? - end - - def no_fixup_chains - append "LDFLAGS", "-Wl,-no_fixup_chains" if no_fixup_chains_support? end end + +Stdenv.prepend(OS::Mac::Stdenv) diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb index 8ed7ef263f..cf111ec8c7 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb @@ -1,171 +1,173 @@ # typed: true # rubocop:disable Sorbet/StrictSigil # frozen_string_literal: true -module Superenv - class << self - # The location of Homebrew's shims on macOS. - def shims_path - HOMEBREW_SHIMS_PATH/"mac/super" - end +module OS + module Mac + module Superenv + extend T::Helpers - undef bin + requires_ancestor { SharedEnvExtension } + requires_ancestor { ::Superenv } - def bin - return unless DevelopmentTools.installed? + module ClassMethods + sig { returns(Pathname) } + def shims_path + HOMEBREW_SHIMS_PATH/"mac/super" + end - shims_path.realpath - end - end + sig { returns(T.nilable(Pathname)) } + def bin + return unless ::DevelopmentTools.installed? - undef homebrew_extra_pkg_config_paths, - homebrew_extra_isystem_paths, homebrew_extra_library_paths, - homebrew_extra_cmake_include_paths, - homebrew_extra_cmake_library_paths, - homebrew_extra_cmake_frameworks_paths, - determine_cccfg - - sig { returns(T::Array[Pathname]) } - def homebrew_extra_pkg_config_paths - [Pathname("/usr/lib/pkgconfig"), Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")] - end - private :homebrew_extra_pkg_config_paths - - sig { returns(T::Boolean) } - def libxml2_include_needed? - return false if deps.any? { |d| d.name == "libxml2" } - return false if Pathname("#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml").directory? - - true - end - private :libxml2_include_needed? - - def homebrew_extra_isystem_paths - paths = [] - paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml2" if libxml2_include_needed? - paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/apache2" if MacOS::Xcode.without_clt? - paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers" - paths - end - - def homebrew_extra_library_paths - paths = [] - if compiler == :llvm_clang - paths << "#{self["HOMEBREW_SDKROOT"]}/usr/lib" - paths << Formula["llvm"].opt_lib.to_s - end - paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries" - paths - end - - def homebrew_extra_cmake_include_paths - paths = [] - paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml2" if libxml2_include_needed? - paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/apache2" if MacOS::Xcode.without_clt? - paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers" - paths - end - - def homebrew_extra_cmake_library_paths - [Pathname("#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries")] - end - - def homebrew_extra_cmake_frameworks_paths - paths = [] - paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks" if MacOS::Xcode.without_clt? - paths - end - - def determine_cccfg - s = +"" - # Fix issue with >= Mountain Lion apr-1-config having broken paths - s << "a" - s.freeze - end - - # @private - def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false, - debug_symbols: false) - sdk = formula ? MacOS.sdk_for_formula(formula) : MacOS.sdk - is_xcode_sdk = sdk&.source == :xcode - - if is_xcode_sdk || MacOS.sdk_root_needed? - Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks) - self["HOMEBREW_SDKROOT"] = sdk.path if sdk - end - - self["HOMEBREW_DEVELOPER_DIR"] = if is_xcode_sdk - MacOS::Xcode.prefix.to_s - else - MacOS::CLT::PKG_PATH - end - - # This is a workaround for the missing `m4` in Xcode CLT 15.3, which was - # reported in FB13679972. Apple has fixed this in Xcode CLT 16.0. - # See https://github.com/Homebrew/homebrew-core/issues/165388 - if deps.none? { |d| d.name == "m4" } && - MacOS.active_developer_dir == MacOS::CLT::PKG_PATH && - !File.exist?("#{MacOS::CLT::PKG_PATH}/usr/bin/m4") && - (gm4 = DevelopmentTools.locate("gm4").to_s).present? - self["M4"] = gm4 - end - - generic_setup_build_environment(formula:, cc:, build_bottle:, bottle_arch:, - testing_formula:, debug_symbols:) - - # Filter out symbols known not to be defined since GNU Autotools can't - # reliably figure this out with Xcode 8 and above. - if MacOS.version == "10.12" && MacOS::Xcode.version >= "9.0" - %w[fmemopen futimens open_memstream utimensat].each do |s| - ENV["ac_cv_func_#{s}"] = "no" - end - elsif MacOS.version == "10.11" && MacOS::Xcode.version >= "8.0" - %w[basename_r clock_getres clock_gettime clock_settime dirname_r - getentropy mkostemp mkostemps timingsafe_bcmp].each do |s| - ENV["ac_cv_func_#{s}"] = "no" + shims_path.realpath + end end - ENV["ac_cv_search_clock_gettime"] = "no" + sig { returns(T::Array[Pathname]) } + def homebrew_extra_pkg_config_paths + [Pathname("/usr/lib/pkgconfig"), Pathname("#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}")] + end - # works around libev.m4 unsetting ac_cv_func_clock_gettime - ENV["ac_have_clock_syscall"] = "no" + sig { returns(T::Boolean) } + def libxml2_include_needed? + return false if deps.any? { |d| d.name == "libxml2" } + return false if Pathname("#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml").directory? + + true + end + + def homebrew_extra_isystem_paths + paths = [] + paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml2" if libxml2_include_needed? + paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/apache2" if MacOS::Xcode.without_clt? + paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers" + paths + end + + def homebrew_extra_library_paths + paths = [] + if compiler == :llvm_clang + paths << "#{self["HOMEBREW_SDKROOT"]}/usr/lib" + paths << ::Formula["llvm"].opt_lib.to_s + end + paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries" + paths + end + + def homebrew_extra_cmake_include_paths + paths = [] + paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/libxml2" if libxml2_include_needed? + paths << "#{self["HOMEBREW_SDKROOT"]}/usr/include/apache2" if MacOS::Xcode.without_clt? + paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers" + paths + end + + def homebrew_extra_cmake_library_paths + brew_sdkroot = self["HOMEBREW_SDKROOT"] + [Pathname("#{brew_sdkroot}/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries")] + end + + def homebrew_extra_cmake_frameworks_paths + paths = [] + paths << "#{self["HOMEBREW_SDKROOT"]}/System/Library/Frameworks" if MacOS::Xcode.without_clt? + paths + end + + def determine_cccfg + s = +"" + # Fix issue with >= Mountain Lion apr-1-config having broken paths + s << "a" + s.freeze + end + + # @private + def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, + testing_formula: false, debug_symbols: false) + sdk = formula ? MacOS.sdk_for_formula(formula) : MacOS.sdk + is_xcode_sdk = sdk&.source == :xcode + + if is_xcode_sdk || MacOS.sdk_root_needed? + Homebrew::Diagnostic.checks(:fatal_setup_build_environment_checks) + self["HOMEBREW_SDKROOT"] = sdk.path if sdk + end + + self["HOMEBREW_DEVELOPER_DIR"] = if is_xcode_sdk + MacOS::Xcode.prefix.to_s + else + MacOS::CLT::PKG_PATH + end + + # This is a workaround for the missing `m4` in Xcode CLT 15.3, which was + # reported in FB13679972. Apple has fixed this in Xcode CLT 16.0. + # See https://github.com/Homebrew/homebrew-core/issues/165388 + if deps.none? { |d| d.name == "m4" } && + MacOS.active_developer_dir == MacOS::CLT::PKG_PATH && + !File.exist?("#{MacOS::CLT::PKG_PATH}/usr/bin/m4") && + (gm4 = ::DevelopmentTools.locate("gm4").to_s).present? + self["M4"] = gm4 + end + + 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. + return unless OS::Mac::DevelopmentTools.ld64_version.between?("1015.7", "1022.1") + + append_to_cccfg "c" + end + + def no_weak_imports + append_to_cccfg "w" if no_weak_imports_support? + end + + def no_fixup_chains + append_to_cccfg "f" if no_fixup_chains_support? + end end - - # On macOS Sonoma (at least release candidate), iconv() is generally - # present and working, but has a minor regression that defeats the - # test implemented in gettext's configure script (and used by many - # gettext dependents). - ENV["am_cv_func_iconv_works"] = "yes" if MacOS.version == "14" - - # The tools in /usr/bin proxy to the active developer directory. - # This means we can use them for any combination of CLT and Xcode. - self["HOMEBREW_PREFER_CLT_PROXIES"] = "1" - - # Deterministic timestamping. - # This can work on older Xcode versions, but they contain some bugs. - # Notably, Xcode 10.2 fixes issues where ZERO_AR_DATE affected file mtimes. - # Xcode 11.0 contains fixes for lldb reading things built with ZERO_AR_DATE. - self["ZERO_AR_DATE"] = "1" if MacOS::Xcode.version >= "11.0" || MacOS::CLT.version >= "11.0" - - # Pass `-no_fixup_chains` whenever the linker is invoked with `-undefined dynamic_lookup`. - # See: https://github.com/python/cpython/issues/97524 - # https://github.com/pybind/pybind11/pull/4301 - no_fixup_chains - - # Strip build prefixes from linker where supported, for deterministic builds. - append_to_cccfg "o" if 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. - return unless OS::Mac::DevelopmentTools.ld64_version.between?("1015.7", "1022.1") - - append_to_cccfg "c" - 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 324748d4d9..4aa06cc1eb 100644 --- a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb +++ b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb @@ -4,133 +4,145 @@ require "cache_store" require "linkage_checker" -module FormulaCellarChecks - sig { returns(T.nilable(String)) } - def check_shadowed_headers - return if ["libtool", "subversion", "berkeley-db"].any? do |formula_name| - formula.name.start_with?(formula_name) - end +module OS + module Mac + module FormulaCellarChecks + extend T::Helpers - return if formula.name.match?(Version.formula_optionally_versioned_regex(:php)) - return if formula.keg_only? || !formula.include.directory? + requires_ancestor { Homebrew::FormulaAuditor } + requires_ancestor { ::FormulaCellarChecks } - files = relative_glob(formula.include, "**/*.h") - files &= relative_glob("#{MacOS.sdk_path}/usr/include", "**/*.h") - files.map! { |p| File.join(formula.include, p) } + sig { returns(T.nilable(String)) } + def check_shadowed_headers + return if ["libtool", "subversion", "berkeley-db"].any? do |formula_name| + formula.name.start_with?(formula_name) + end - return if files.empty? + return if formula.name.match?(Version.formula_optionally_versioned_regex(:php)) + return if formula.keg_only? || !formula.include.directory? - <<~EOS - Header files that shadow system header files were installed to "#{formula.include}" - The offending files are: - #{files * "\n "} - EOS - end + files = relative_glob(formula.include, "**/*.h") + files &= relative_glob("#{MacOS.sdk_path}/usr/include", "**/*.h") + files.map! { |p| File.join(formula.include, p) } - sig { returns(T.nilable(String)) } - def check_openssl_links - return unless formula.prefix.directory? + return if files.empty? - keg = Keg.new(formula.prefix) - system_openssl = keg.mach_o_files.select do |obj| - dlls = obj.dynamically_linked_libraries - dlls.any? { |dll| %r{/usr/lib/lib(crypto|ssl|tls)\..*dylib}.match? dll } - end - return if system_openssl.empty? - - <<~EOS - object files were linked against system openssl - These object files were linked against the deprecated system OpenSSL or - the system's private LibreSSL. - Adding `depends_on "openssl"` to the formula may help. - #{system_openssl * "\n "} - EOS - end - - sig { params(lib: Pathname).returns(T.nilable(String)) } - def check_python_framework_links(lib) - python_modules = Pathname.glob lib/"python*/site-packages/**/*.so" - framework_links = python_modules.select do |obj| - dlls = obj.dynamically_linked_libraries - dlls.any? { |dll| dll.include?("Python.framework") } - end - return if framework_links.empty? - - <<~EOS - python modules have explicit framework links - These python extension modules were linked directly to a Python - framework binary. They should be linked with -undefined dynamic_lookup - instead of -lpython or -framework Python. - #{framework_links * "\n "} - EOS - end - - sig { void } - def check_linkage - return unless formula.prefix.directory? - - keg = Keg.new(formula.prefix) - - CacheStoreDatabase.use(:linkage) do |db| - checker = LinkageChecker.new(keg, formula, cache_db: db) - next unless checker.broken_library_linkage? - - output = <<~EOS - #{formula} has broken dynamic library links: - #{checker.display_test_output} - EOS - - tab = keg.tab - if tab.poured_from_bottle - output += <<~EOS - Rebuild this from source with: - brew reinstall --build-from-source #{formula} - If that's successful, file an issue#{formula.tap ? " here:\n #{T.must(formula.tap).issues_url}" : "."} + <<~EOS + Header files that shadow system header files were installed to "#{formula.include}" + The offending files are: + #{files * "\n "} EOS end - problem_if_output output - end - end - sig { params(formula: Formula).returns(T.nilable(String)) } - def check_flat_namespace(formula) - return unless formula.prefix.directory? - return if formula.tap&.audit_exception(:flat_namespace_allowlist, formula.name) + sig { returns(T.nilable(String)) } + def check_openssl_links + return unless formula.prefix.directory? - keg = ::Keg.new(formula.prefix) - flat_namespace_files = keg.mach_o_files.reject do |file| - next true unless file.dylib? + keg = ::Keg.new(formula.prefix) + system_openssl = keg.mach_o_files.select do |obj| + dlls = obj.dynamically_linked_libraries + dlls.any? { |dll| %r{/usr/lib/lib(crypto|ssl|tls)\..*dylib}.match? dll } + end + return if system_openssl.empty? - macho = MachO.open(file) - if MachO::Utils.fat_magic?(macho.magic) - macho.machos.map(&:header).all? { |h| h.flag? :MH_TWOLEVEL } - else - macho.header.flag? :MH_TWOLEVEL + <<~EOS + object files were linked against system openssl + These object files were linked against the deprecated system OpenSSL or + the system's private LibreSSL. + Adding `depends_on "openssl"` to the formula may help. + #{system_openssl * "\n "} + EOS + end + + sig { params(lib: Pathname).returns(T.nilable(String)) } + def check_python_framework_links(lib) + python_modules = Pathname.glob lib/"python*/site-packages/**/*.so" + framework_links = python_modules.select do |obj| + dlls = obj.dynamically_linked_libraries + dlls.any? { |dll| dll.include?("Python.framework") } + end + return if framework_links.empty? + + <<~EOS + python modules have explicit framework links + These python extension modules were linked directly to a Python + framework binary. They should be linked with -undefined dynamic_lookup + instead of -lpython or -framework Python. + #{framework_links * "\n "} + EOS + end + + sig { void } + def check_linkage + return unless formula.prefix.directory? + + keg = ::Keg.new(formula.prefix) + + CacheStoreDatabase.use(:linkage) do |db| + checker = ::LinkageChecker.new(keg, formula, cache_db: db) + next unless checker.broken_library_linkage? + + output = <<~EOS + #{formula} has broken dynamic library links: + #{checker.display_test_output} + EOS + + tab = keg.tab + if tab.poured_from_bottle + output += <<~EOS + Rebuild this from source with: + brew reinstall --build-from-source #{formula} + If that's successful, file an issue#{formula.tap ? " here:\n #{formula.tap.issues_url}" : "."} + EOS + end + problem_if_output output + end + end + + sig { params(formula: ::Formula).returns(T.nilable(String)) } + 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) + flat_namespace_files = keg.mach_o_files.reject do |file| + next true unless file.dylib? + + macho = MachO.open(file) + if MachO::Utils.fat_magic?(macho.magic) + macho.machos.map(&:header).all? { |h| h.flag? :MH_TWOLEVEL } + else + macho.header.flag? :MH_TWOLEVEL + end + end + return if flat_namespace_files.empty? + + <<~EOS + Libraries were compiled with a flat namespace. + This can cause linker errors due to name collisions and + is often due to a bug in detecting the macOS version. + #{flat_namespace_files * "\n "} + EOS + end + + sig { void } + def audit_installed + super + problem_if_output(check_shadowed_headers) + problem_if_output(check_openssl_links) + problem_if_output(check_python_framework_links(formula.lib)) + check_linkage + problem_if_output(check_flat_namespace(formula)) + end + + MACOS_LIB_EXTENSIONS = %w[.dylib .framework].freeze + + sig { params(filename: Pathname).returns(T::Boolean) } + def valid_library_extension?(filename) + super || MACOS_LIB_EXTENSIONS.include?(filename.extname) end end - return if flat_namespace_files.empty? - - <<~EOS - Libraries were compiled with a flat namespace. - This can cause linker errors due to name collisions and - is often due to a bug in detecting the macOS version. - #{flat_namespace_files * "\n "} - EOS - end - - sig { void } - def audit_installed - generic_audit_installed - problem_if_output(check_shadowed_headers) - problem_if_output(check_openssl_links) - problem_if_output(check_python_framework_links(formula.lib)) - check_linkage - problem_if_output(check_flat_namespace(formula)) - end - - sig { params(filename: Pathname).returns(T::Boolean) } - def valid_library_extension?(filename) - macos_lib_extensions = %w[.dylib .framework] - generic_valid_library_extension?(filename) || macos_lib_extensions.include?(filename.extname) end end + +FormulaCellarChecks.prepend(OS::Mac::FormulaCellarChecks) diff --git a/Library/Homebrew/extend/os/mac/hardware.rb b/Library/Homebrew/extend/os/mac/hardware.rb index d984567c69..38a12686ce 100644 --- a/Library/Homebrew/extend/os/mac/hardware.rb +++ b/Library/Homebrew/extend/os/mac/hardware.rb @@ -1,25 +1,33 @@ # typed: strict # frozen_string_literal: true -module Hardware - sig { params(version: T.nilable(Version)).returns(Symbol) } - def self.oldest_cpu(version = nil) - version = if version - MacOSVersion.new(version.to_s) - else - MacOS.version - end - if CPU.arch == :arm64 - :arm_vortex_tempest - # This cannot use a newer CPU e.g. haswell because Rosetta 2 does not - # support AVX instructions in bottles: - # https://github.com/Homebrew/homebrew-core/issues/67713 - elsif version >= :ventura - :westmere - elsif version >= :mojave - :nehalem - else - generic_oldest_cpu +module OS + module Mac + module Hardware + module ClassMethods + sig { params(version: T.nilable(MacOSVersion)).returns(Symbol) } + def oldest_cpu(version = nil) + version = if version + MacOSVersion.new(version.to_s) + else + MacOS.version + end + if ::Hardware::CPU.arch == :arm64 + :arm_vortex_tempest + # This cannot use a newer CPU e.g. haswell because Rosetta 2 does not + # support AVX instructions in bottles: + # https://github.com/Homebrew/homebrew-core/issues/67713 + elsif version >= :ventura + :westmere + elsif version >= :mojave + :nehalem + else + super + end + end + end end end end + +Hardware.singleton_class.prepend(OS::Mac::Hardware::ClassMethods) diff --git a/Library/Homebrew/extend/os/mac/keg_relocate.rb b/Library/Homebrew/extend/os/mac/keg_relocate.rb index 5b56011faf..3c0a5d34ae 100644 --- a/Library/Homebrew/extend/os/mac/keg_relocate.rb +++ b/Library/Homebrew/extend/os/mac/keg_relocate.rb @@ -95,7 +95,7 @@ module OS end end - generic_fix_dynamic_linkage + super end def loader_name_for(file, target) @@ -199,7 +199,7 @@ module OS end def prepare_relocation_to_locations - relocation = generic_prepare_relocation_to_locations + relocation = super brewed_perl = runtime_dependencies&.any? { |dep| dep["full_name"] == "perl" && dep["declared_directly"] } perl_path = if brewed_perl || name == "perl" diff --git a/Library/Homebrew/extend/os/mac/missing_formula.rb b/Library/Homebrew/extend/os/mac/missing_formula.rb index 8721980e76..6933c305d6 100644 --- a/Library/Homebrew/extend/os/mac/missing_formula.rb +++ b/Library/Homebrew/extend/os/mac/missing_formula.rb @@ -5,55 +5,59 @@ require "cask/info" require "cask/cask_loader" require "cask/caskroom" -module Homebrew - module MissingFormula - class << self - sig { params(name: String).returns(T.nilable(String)) } - def disallowed_reason(name) - case name.downcase - when "xcode" - <<~EOS - Xcode can be installed from the App Store. - EOS - else - generic_disallowed_reason(name) +module OS + module Mac + module MissingFormula + module ClassMethods + sig { params(name: String).returns(T.nilable(String)) } + def disallowed_reason(name) + case name.downcase + when "xcode" + <<~EOS + Xcode can be installed from the App Store. + EOS + else + super + end end - end - sig { params(name: String, silent: T::Boolean, show_info: T::Boolean).returns(T.nilable(String)) } - def cask_reason(name, silent: false, show_info: false) - return if silent + sig { params(name: String, silent: T::Boolean, show_info: T::Boolean).returns(T.nilable(String)) } + def cask_reason(name, silent: false, show_info: false) + return if silent - suggest_command(name, show_info ? "info" : "install") - end + suggest_command(name, show_info ? "info" : "install") + end - sig { params(name: String, command: String).returns(T.nilable(String)) } - def suggest_command(name, command) - suggestion = <<~EOS - Found a cask named "#{name}" instead. Try - brew #{command} --cask #{name} - - EOS - case command - when "install" - Cask::CaskLoader.load(name) - when "uninstall" - cask = Cask::Caskroom.casks.find { |installed_cask| installed_cask.to_s == name } - raise Cask::CaskUnavailableError, name if cask.nil? - when "info" - cask = Cask::CaskLoader.load(name) + sig { params(name: String, command: String).returns(T.nilable(String)) } + def suggest_command(name, command) suggestion = <<~EOS - Found a cask named "#{name}" instead. + Found a cask named "#{name}" instead. Try + brew #{command} --cask #{name} - #{Cask::Info.get_info(cask)} EOS - else - return + case command + when "install" + ::Cask::CaskLoader.load(name) + when "uninstall" + cask = ::Cask::Caskroom.casks.find { |installed_cask| installed_cask.to_s == name } + Kernel.raise ::Cask::CaskUnavailableError, name if cask.nil? + when "info" + cask = ::Cask::CaskLoader.load(name) + suggestion = <<~EOS + Found a cask named "#{name}" instead. + + #{::Cask::Info.get_info(cask)} + EOS + else + return + end + suggestion + rescue ::Cask::CaskUnavailableError + nil end - suggestion - rescue Cask::CaskUnavailableError - nil end end end end + +Homebrew::MissingFormula.singleton_class.prepend(OS::Mac::MissingFormula::ClassMethods) diff --git a/Library/Homebrew/extend/os/mac/system_config.rb b/Library/Homebrew/extend/os/mac/system_config.rb index 0f84aca104..e7d33e4b56 100644 --- a/Library/Homebrew/extend/os/mac/system_config.rb +++ b/Library/Homebrew/extend/os/mac/system_config.rb @@ -6,46 +6,45 @@ require "system_command" module OS module Mac module SystemConfig - sig { returns(String) } - def describe_clang - return "N/A" if ::SystemConfig.clang.null? + module ClassMethods + extend T::Helpers - clang_build_info = ::SystemConfig.clang_build.null? ? "(parse error)" : ::SystemConfig.clang_build - "#{::SystemConfig.clang} build #{clang_build_info}" + requires_ancestor { T.class_of(::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 + + def xcode + @xcode ||= if MacOS::Xcode.installed? + xcode = MacOS::Xcode.version.to_s + xcode += " => #{MacOS::Xcode.prefix}" unless MacOS::Xcode.default_prefix? + xcode + end + end + + def clt + @clt ||= MacOS::CLT.version if MacOS::CLT.installed? + end + + def core_tap_config(out = $stdout) + dump_tap_config(CoreTap.instance, out) + dump_tap_config(CoreCaskTap.instance, out) + end + + def dump_verbose_config(out = $stdout) + super + out.puts "macOS: #{MacOS.full_version}-#{kernel}" + out.puts "CLT: #{clt || "N/A"}" + out.puts "Xcode: #{xcode || "N/A"}" + out.puts "Rosetta 2: #{::Hardware::CPU.in_rosetta2?}" if ::Hardware::CPU.physical_cpu_arm64? + end end end end end - -SystemConfig.prepend(OS::Mac::SystemConfig) - -module SystemConfig - class << self - include SystemCommand::Mixin - - def xcode - @xcode ||= if MacOS::Xcode.installed? - xcode = MacOS::Xcode.version.to_s - xcode += " => #{MacOS::Xcode.prefix}" unless MacOS::Xcode.default_prefix? - xcode - end - end - - def clt - @clt ||= MacOS::CLT.version if MacOS::CLT.installed? - end - - def core_tap_config(out = $stdout) - dump_tap_config(CoreTap.instance, out) - dump_tap_config(CoreCaskTap.instance, out) - end - - def dump_verbose_config(out = $stdout) - dump_generic_verbose_config(out) - out.puts "macOS: #{MacOS.full_version}-#{kernel}" - out.puts "CLT: #{clt || "N/A"}" - out.puts "Xcode: #{xcode || "N/A"}" - out.puts "Rosetta 2: #{Hardware::CPU.in_rosetta2?}" if Hardware::CPU.physical_cpu_arm64? - end - end -end +SystemConfig.singleton_class.prepend(OS::Mac::SystemConfig::ClassMethods) diff --git a/Library/Homebrew/extend/os/mac/utils/bottles.rb b/Library/Homebrew/extend/os/mac/utils/bottles.rb index 9b4c71a914..f982a4dca3 100644 --- a/Library/Homebrew/extend/os/mac/utils/bottles.rb +++ b/Library/Homebrew/extend/os/mac/utils/bottles.rb @@ -1,59 +1,66 @@ # typed: strict # frozen_string_literal: true -module Utils - module Bottles - class << self - module MacOSOverride - sig { params(tag: T.nilable(T.any(Symbol, Tag))).returns(Tag) } +module OS + module Mac + module Bottles + module ClassMethods + sig { params(tag: T.nilable(T.any(Symbol, Utils::Bottles::Tag))).returns(Utils::Bottles::Tag) } def tag(tag = nil) - return Tag.new(system: MacOS.version.to_sym, arch: Hardware::CPU.arch) if tag.nil? - - super + if tag.nil? + Utils::Bottles::Tag.new(system: MacOS.version.to_sym, arch: ::Hardware::CPU.arch) + else + super + end end end - prepend MacOSOverride - end + module Collector + extend T::Helpers - class Collector - private + requires_ancestor { Utils::Bottles::Collector } - alias generic_find_matching_tag find_matching_tag + private - sig { params(tag: Utils::Bottles::Tag, no_older_versions: T::Boolean).returns(T.nilable(Utils::Bottles::Tag)) } - def find_matching_tag(tag, no_older_versions: false) - # Used primarily by developers testing beta macOS releases. - if no_older_versions || - (OS::Mac.version.prerelease? && - Homebrew::EnvConfig.developer? && - Homebrew::EnvConfig.skip_or_later_bottles?) - generic_find_matching_tag(tag) - else - generic_find_matching_tag(tag) || - find_older_compatible_tag(tag) - end - end - - # Find a bottle built for a previous version of macOS. - sig { params(tag: Utils::Bottles::Tag).returns(T.nilable(Utils::Bottles::Tag)) } - def find_older_compatible_tag(tag) - tag_version = begin - tag.to_macos_version - rescue MacOSVersion::Error - nil + sig { + params(tag: Utils::Bottles::Tag, + no_older_versions: T::Boolean).returns(T.nilable(Utils::Bottles::Tag)) + } + def find_matching_tag(tag, no_older_versions: false) + # Used primarily by developers testing beta macOS releases. + if no_older_versions || + (OS::Mac.version.prerelease? && + Homebrew::EnvConfig.developer? && + Homebrew::EnvConfig.skip_or_later_bottles?) + super(tag) + else + super(tag) || find_older_compatible_tag(tag) + end end - return if tag_version.blank? + # Find a bottle built for a previous version of macOS. + sig { params(tag: Utils::Bottles::Tag).returns(T.nilable(Utils::Bottles::Tag)) } + def find_older_compatible_tag(tag) + tag_version = begin + tag.to_macos_version + rescue MacOSVersion::Error + nil + end - tags.find do |candidate| - next if candidate.standardized_arch != tag.standardized_arch + return if tag_version.blank? - candidate.to_macos_version <= tag_version - rescue MacOSVersion::Error - false + tags.find do |candidate| + next if candidate.standardized_arch != tag.standardized_arch + + candidate.to_macos_version <= tag_version + rescue MacOSVersion::Error + false + end end end end end end + +Utils::Bottles.singleton_class.prepend(OS::Mac::Bottles::ClassMethods) +Utils::Bottles::Collector.prepend(OS::Mac::Bottles::Collector) diff --git a/Library/Homebrew/formula_cellar_checks.rb b/Library/Homebrew/formula_cellar_checks.rb index 42609a20db..eff5063169 100644 --- a/Library/Homebrew/formula_cellar_checks.rb +++ b/Library/Homebrew/formula_cellar_checks.rb @@ -84,7 +84,6 @@ module FormulaCellarChecks def valid_library_extension?(filename) VALID_LIBRARY_EXTENSIONS.include? filename.extname end - alias generic_valid_library_extension? valid_library_extension? sig { returns(T.nilable(String)) } def check_non_libraries @@ -437,7 +436,6 @@ module FormulaCellarChecks problem_if_output(check_cpuid_instruction(formula)) problem_if_output(check_binary_arches(formula)) end - alias generic_audit_installed audit_installed private diff --git a/Library/Homebrew/hardware.rb b/Library/Homebrew/hardware.rb index d7334667b5..6c21c8cdc9 100644 --- a/Library/Homebrew/hardware.rb +++ b/Library/Homebrew/hardware.rb @@ -42,7 +42,6 @@ module Hardware ppc64le: "-mcpu=powerpc64le", }.freeze, T.nilable(T::Hash[Symbol, String])) end - alias generic_optimization_flags optimization_flags sig { returns(Symbol) } def arch_32_bit @@ -219,6 +218,7 @@ module Hardware end end + sig { params(_version: T.nilable(MacOSVersion)).returns(Symbol) } def oldest_cpu(_version = nil) if Hardware::CPU.intel? if Hardware::CPU.is_64_bit? @@ -242,7 +242,6 @@ module Hardware Hardware::CPU.family end end - alias generic_oldest_cpu oldest_cpu # Returns a Rust flag to set the target CPU if necessary. # Defaults to nil. diff --git a/Library/Homebrew/install.rb b/Library/Homebrew/install.rb index 8fba7fabf7..7c614bcab1 100644 --- a/Library/Homebrew/install.rb +++ b/Library/Homebrew/install.rb @@ -37,7 +37,6 @@ module Homebrew end def global_post_install; end - alias generic_global_post_install global_post_install def check_prefix if (Hardware::CPU.intel? || Hardware::CPU.in_rosetta2?) && @@ -366,7 +365,6 @@ module Homebrew Diagnostic.checks(:supported_configuration_checks, fatal: all_fatal) Diagnostic.checks(:fatal_preinstall_checks) end - alias generic_perform_preinstall_checks perform_preinstall_checks def attempt_directory_creation Keg.must_exist_directories.each do |dir| diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index 5ae085f769..5b54c45bfa 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -77,7 +77,6 @@ class Keg FileUtils.ln_s(new_src, file) end end - alias generic_fix_dynamic_linkage fix_dynamic_linkage def relocate_dynamic_linkage(_relocation) [] @@ -102,7 +101,6 @@ class Keg relocation end - alias generic_prepare_relocation_to_placeholders prepare_relocation_to_placeholders def replace_locations_with_placeholders relocation = prepare_relocation_to_placeholders.freeze @@ -123,7 +121,6 @@ class Keg relocation end - alias generic_prepare_relocation_to_locations prepare_relocation_to_locations def replace_placeholders_with_locations(files, skip_linkage: false) relocation = prepare_relocation_to_locations.freeze @@ -221,7 +218,6 @@ class Keg [grep_bin, grep_args] end - alias generic_egrep_args egrep_args def each_unique_file_matching(string) Utils.popen_read("fgrep", recursive_fgrep_args, string, to_s) do |io| diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index 6d11765b2b..0db9ad05db 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -188,12 +188,10 @@ class LinkageChecker store&.update!(keg_files_dylibs:) end - alias generic_check_dylibs check_dylibs def system_libraries_exist_in_cache? false end - alias generic_system_libraries_exist_in_cache? system_libraries_exist_in_cache? def dylib_found_in_shared_cache?(dylib) @dyld_shared_cache_contains_path ||= begin diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb index 4b9dbdaee4..43e82914e3 100644 --- a/Library/Homebrew/missing_formula.rb +++ b/Library/Homebrew/missing_formula.rb @@ -93,7 +93,6 @@ module Homebrew EOS end end - alias generic_disallowed_reason disallowed_reason sig { params(name: String).returns(T.nilable(String)) } def tap_migration_reason(name) @@ -195,8 +194,10 @@ module Homebrew end end + sig { params(name: String, silent: T::Boolean, show_info: T::Boolean).returns(T.nilable(String)) } def cask_reason(name, silent: false, show_info: false); end + sig { params(name: String, command: String).returns(T.nilable(String)) } def suggest_command(name, command); end require "extend/os/missing_formula" diff --git a/Library/Homebrew/system_config.rb b/Library/Homebrew/system_config.rb index 47105e650d..80183666fa 100644 --- a/Library/Homebrew/system_config.rb +++ b/Library/Homebrew/system_config.rb @@ -195,7 +195,6 @@ module SystemConfig out.puts hardware if hardware host_software_config(out) end - alias dump_generic_verbose_config dump_verbose_config end end