mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00

Given the current state of OS X compilers, the original fails_with behavior is becoming less useful, mostly resulting in build failures each time the compiler is updated. So make the following changes: When a build is specified, we retain the old behavior: switch compilers if the available compiler is <= the build, don't switch if it is > the build. When no build is specified, unconditionally switch compilers, and don't output the advice message. This allows us to mark formulae as perpetually failing, avoiding the need to update formulae each time a new compiler build is made available. As a bonus, this makes the logic much easier to reason about. Closes Homebrew/homebrew#18175.
130 lines
2.9 KiB
Ruby
130 lines
2.9 KiB
Ruby
class Compilers
|
|
include Enumerable
|
|
|
|
def initialize(*args)
|
|
@compilers = Array.new(*args)
|
|
end
|
|
|
|
def each(*args, &block)
|
|
@compilers.each(*args, &block)
|
|
end
|
|
|
|
def include?(cc)
|
|
cc = cc.name if cc.is_a? Compiler
|
|
@compilers.any? { |c| c.name == cc }
|
|
end
|
|
|
|
def <<(o)
|
|
@compilers << o
|
|
self
|
|
end
|
|
end
|
|
|
|
|
|
class CompilerFailures
|
|
include Enumerable
|
|
|
|
def initialize(*args)
|
|
@failures = Array.new(*args)
|
|
end
|
|
|
|
def each(*args, &block)
|
|
@failures.each(*args, &block)
|
|
end
|
|
|
|
def include?(cc)
|
|
cc = Compiler.new(cc) unless cc.is_a? Compiler
|
|
@failures.any? { |failure| failure.compiler == cc.name }
|
|
end
|
|
|
|
def <<(o)
|
|
@failures << o unless include? o.compiler
|
|
self
|
|
end
|
|
end
|
|
|
|
|
|
class Compiler
|
|
attr_reader :name, :build
|
|
|
|
def initialize name
|
|
@name = name
|
|
@build = case name
|
|
when :clang then MacOS.clang_build_version.to_i
|
|
when :llvm then MacOS.llvm_build_version.to_i
|
|
when :gcc then MacOS.gcc_42_build_version.to_i
|
|
end
|
|
end
|
|
|
|
def ==(other)
|
|
@name.to_sym == other.to_sym
|
|
end
|
|
end
|
|
|
|
|
|
class CompilerFailure
|
|
attr_reader :compiler
|
|
|
|
def initialize compiler, &block
|
|
@compiler = compiler
|
|
instance_eval(&block) if block_given?
|
|
@build ||= 9999
|
|
end
|
|
|
|
def build val=nil
|
|
val.nil? ? @build.to_i : @build = val.to_i
|
|
end
|
|
|
|
def cause val=nil
|
|
val.nil? ? @cause : @cause = val
|
|
end
|
|
end
|
|
|
|
|
|
# CompilerSelector is used to process a formula's CompilerFailures.
|
|
# If no viable compilers are available, ENV.compiler is left as-is.
|
|
class CompilerSelector
|
|
NAMES = { :clang => "Clang", :gcc => "GCC", :llvm => "LLVM" }
|
|
|
|
def initialize f
|
|
@f = f
|
|
@old_compiler = ENV.compiler
|
|
@compilers = Compilers.new
|
|
@compilers << Compiler.new(:clang) if MacOS.clang_build_version
|
|
@compilers << Compiler.new(:llvm) if MacOS.llvm_build_version
|
|
@compilers << Compiler.new(:gcc) if MacOS.gcc_42_build_version
|
|
end
|
|
|
|
def select_compiler
|
|
# @compilers is our list of available compilers. If @f declares a
|
|
# failure with compiler foo, then we remove foo from the list if
|
|
# the failing build is >= the currently installed version of foo.
|
|
@compilers = @compilers.reject do |cc|
|
|
failure = @f.fails_with? cc
|
|
failure && failure.build >= cc.build
|
|
end
|
|
|
|
return if @compilers.empty? or @compilers.include? ENV.compiler
|
|
|
|
ENV.send case ENV.compiler
|
|
when :clang
|
|
if @compilers.include? :llvm then :llvm
|
|
elsif @compilers.include? :gcc then :gcc
|
|
else ENV.compiler
|
|
end
|
|
when :llvm
|
|
if @compilers.include? :clang and MacOS.clang_build_version >= 211 then :clang
|
|
elsif @compilers.include? :gcc then :gcc
|
|
elsif @compilers.include? :clang then :clang
|
|
else ENV.compiler
|
|
end
|
|
when :gcc
|
|
if @compilers.include? :clang and MacOS.clang_build_version >= 211 then :clang
|
|
elsif @compilers.include? :llvm then :llvm
|
|
elsif @compilers.include? :clang then :clang
|
|
else ENV.compiler
|
|
end
|
|
end
|
|
end
|
|
end
|