Skip to content

Commit

Permalink
Merge pull request #18378 from Homebrew/no-undefs
Browse files Browse the repository at this point in the history
Move remaining `undef` use in OS extensions to `prepend`
  • Loading branch information
dduugg authored Oct 5, 2024
2 parents 7c4f2c1 + 0855d7c commit 3c51d0c
Show file tree
Hide file tree
Showing 25 changed files with 1,156 additions and 1,099 deletions.
1 change: 0 additions & 1 deletion Library/Homebrew/development_tools.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
190 changes: 96 additions & 94 deletions Library/Homebrew/extend/os/linux/dependency_collector.rb
Original file line number Diff line number Diff line change
@@ -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)
90 changes: 50 additions & 40 deletions Library/Homebrew/extend/os/linux/development_tools.rb
Original file line number Diff line number Diff line change
@@ -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)
Loading

0 comments on commit 3c51d0c

Please sign in to comment.