class Compiler < Struct.new(:name, :priority) def build MacOS.send("#{name}_build_version") 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 class CompilerQueue def initialize @array = [] end def <<(o) @array << o self end def pop @array.delete(@array.max { |a, b| a.priority <=> b.priority }) end def empty? @array.empty? end end class CompilerSelector def initialize(f, old_compiler) @f = f @old_compiler = old_compiler @compilers = CompilerQueue.new %w{clang llvm gcc}.map(&:to_sym).each do |cc| unless MacOS.send("#{cc}_build_version").nil? @compilers << Compiler.new(cc, priority_for(cc)) end end end # Attempts to select an appropriate alternate compiler, but # if none can be found raises CompilerError instead def compiler begin cc = @compilers.pop end while @f.fails_with?(cc) if cc.nil? raise CompilerSelectionError else cc.name end end private def priority_for(cc) case cc when :clang then MacOS.clang_build_version >= 318 ? 3 : 0.5 when :llvm then 2 when :gcc then 1 when :gcc_4_0 then 0.25 end end end