Replace CompilerQueue with predetermined priority lists
This commit is contained in:
		
							parent
							
								
									288c7974dc
								
							
						
					
					
						commit
						04dae13ae7
					
				@ -68,74 +68,65 @@ class CompilerFailure
 | 
			
		||||
  }
 | 
			
		||||
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
 | 
			
		||||
  Compiler = Struct.new(:name, :version, :priority)
 | 
			
		||||
  include CompilerConstants
 | 
			
		||||
 | 
			
		||||
  attr_reader :formula
 | 
			
		||||
  Compiler = Struct.new(:name, :version)
 | 
			
		||||
 | 
			
		||||
  def initialize(formula, versions=MacOS)
 | 
			
		||||
  COMPILER_PRIORITY = {
 | 
			
		||||
    :clang   => [:clang, :gcc, :llvm, :gnu, :gcc_4_0],
 | 
			
		||||
    :gcc     => [:gcc, :llvm, :gnu, :clang, :gcc_4_0],
 | 
			
		||||
    :llvm    => [:llvm, :gcc, :gnu, :clang, :gcc_4_0],
 | 
			
		||||
    :gcc_4_0 => [:gcc_4_0, :gcc, :llvm, :gnu, :clang],
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def self.select_for(formula)
 | 
			
		||||
    compilers = COMPILER_PRIORITY.fetch(MacOS.default_compiler)
 | 
			
		||||
    new(formula, MacOS, compilers).compiler
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  attr_reader :formula, :failures, :versions, :compilers
 | 
			
		||||
 | 
			
		||||
  def initialize(formula, versions, compilers)
 | 
			
		||||
    @formula = formula
 | 
			
		||||
    @failures = formula.compiler_failures
 | 
			
		||||
    @versions = versions
 | 
			
		||||
    @compilers = CompilerQueue.new
 | 
			
		||||
    %w{clang llvm gcc gcc_4_0}.map(&:to_sym).each do |cc|
 | 
			
		||||
      version = @versions.send("#{cc}_build_version")
 | 
			
		||||
      unless version.nil?
 | 
			
		||||
        @compilers << Compiler.new(cc, version, priority_for(cc))
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # non-Apple GCC 4.x
 | 
			
		||||
    CompilerConstants::GNU_GCC_VERSIONS.each do |v|
 | 
			
		||||
      name = "gcc-4.#{v}"
 | 
			
		||||
      version = @versions.non_apple_gcc_version(name)
 | 
			
		||||
      unless version.nil?
 | 
			
		||||
        # priority is based on version, with newest preferred first
 | 
			
		||||
        @compilers << Compiler.new(name, version, 1.0 + v/10.0)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    @compilers = compilers
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Attempts to select an appropriate alternate compiler, but
 | 
			
		||||
  # if none can be found raises CompilerError instead
 | 
			
		||||
  def compiler
 | 
			
		||||
    while cc = @compilers.pop
 | 
			
		||||
      return cc.name unless fails_with?(cc)
 | 
			
		||||
    end
 | 
			
		||||
    find_compiler { |c| return c.name unless fails_with?(c) }
 | 
			
		||||
    raise CompilerSelectionError.new(formula)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def fails_with?(compiler)
 | 
			
		||||
    @failures.any? { |failure| failure === compiler }
 | 
			
		||||
  def find_compiler
 | 
			
		||||
    compilers.each do |compiler|
 | 
			
		||||
      case compiler
 | 
			
		||||
      when :gnu
 | 
			
		||||
        GNU_GCC_VERSIONS.reverse_each do |v|
 | 
			
		||||
          name = "gcc-4.#{v}"
 | 
			
		||||
          version = compiler_version(name)
 | 
			
		||||
          yield Compiler.new(name, version) if version
 | 
			
		||||
        end
 | 
			
		||||
      else
 | 
			
		||||
        version = compiler_version(compiler)
 | 
			
		||||
        yield Compiler.new(compiler, version) if version
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def priority_for(cc)
 | 
			
		||||
    case cc
 | 
			
		||||
    when :clang   then @versions.clang_build_version >= 318 ? 3 : 0.5
 | 
			
		||||
    when :gcc     then 2.5
 | 
			
		||||
    when :llvm    then 2
 | 
			
		||||
    when :gcc_4_0 then 0.25
 | 
			
		||||
  def fails_with?(compiler)
 | 
			
		||||
    failures.any? { |failure| failure === compiler }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def compiler_version(name)
 | 
			
		||||
    case name
 | 
			
		||||
    when GNU_GCC_REGEXP
 | 
			
		||||
      versions.non_apple_gcc_version(name)
 | 
			
		||||
    else
 | 
			
		||||
      versions.send("#{name}_build_version")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,7 @@ module SharedEnvExtension
 | 
			
		||||
  # an alternate compiler, altering the value of environment variables.
 | 
			
		||||
  # If no valid compiler is found, raises an exception.
 | 
			
		||||
  def validate_cc!(formula)
 | 
			
		||||
    send CompilerSelector.new(formula).compiler
 | 
			
		||||
    send CompilerSelector.select_for(formula)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Snow Leopard defines an NCURSES value the opposite of most distros
 | 
			
		||||
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
require 'testing_env'
 | 
			
		||||
require 'compilers'
 | 
			
		||||
 | 
			
		||||
class CompilerQueueTests < Homebrew::TestCase
 | 
			
		||||
  FakeCompiler = Struct.new(:name, :priority)
 | 
			
		||||
 | 
			
		||||
  def setup
 | 
			
		||||
    @q = CompilerQueue.new
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_shovel_returns_self
 | 
			
		||||
    assert_same @q, @q << Object.new
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_empty
 | 
			
		||||
    assert_empty @q
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_queues_items
 | 
			
		||||
    a = FakeCompiler.new(:foo, 0)
 | 
			
		||||
    b = FakeCompiler.new(:bar, 0)
 | 
			
		||||
    @q << a << b
 | 
			
		||||
    assert_equal a, @q.pop
 | 
			
		||||
    assert_equal b, @q.pop
 | 
			
		||||
    assert_nil @q.pop
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_pops_items_by_priority
 | 
			
		||||
    a = FakeCompiler.new(:foo, 0)
 | 
			
		||||
    b = FakeCompiler.new(:bar, 0.5)
 | 
			
		||||
    c = FakeCompiler.new(:baz, 1)
 | 
			
		||||
    @q << a << b << c
 | 
			
		||||
    assert_equal c, @q.pop
 | 
			
		||||
    assert_equal b, @q.pop
 | 
			
		||||
    assert_equal a, @q.pop
 | 
			
		||||
    assert_nil @q.pop
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -14,17 +14,18 @@ class CompilerSelectorTests < Homebrew::TestCase
 | 
			
		||||
    attr_accessor :gcc_4_0_build_version, :gcc_build_version,
 | 
			
		||||
      :llvm_build_version, :clang_build_version
 | 
			
		||||
 | 
			
		||||
    def initialize(versions={})
 | 
			
		||||
      {
 | 
			
		||||
        :gcc_4_0_build_version => nil,
 | 
			
		||||
        :gcc_build_version     => 5666,
 | 
			
		||||
        :llvm_build_version    => 2336,
 | 
			
		||||
        :clang_build_version   => 425,
 | 
			
		||||
      }.merge(versions).each { |k, v| instance_variable_set("@#{k}", v) }
 | 
			
		||||
    def initialize
 | 
			
		||||
      @gcc_4_0_build_version = nil
 | 
			
		||||
      @gcc_build_version = 5666
 | 
			
		||||
      @llvm_build_version = 2336
 | 
			
		||||
      @clang_build_version = 425
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def non_apple_gcc_version(name)
 | 
			
		||||
      name == "gcc-4.8" ? "4.8.1" : nil
 | 
			
		||||
      case name
 | 
			
		||||
      when "gcc-4.8" then "4.8.1"
 | 
			
		||||
      when "gcc-4.7" then "4.7.1"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -32,14 +33,17 @@ class CompilerSelectorTests < Homebrew::TestCase
 | 
			
		||||
    @f  = Double.new
 | 
			
		||||
    @cc = :clang
 | 
			
		||||
    @versions = CompilerVersions.new
 | 
			
		||||
    @selector = CompilerSelector.new(
 | 
			
		||||
      @f, @versions, [:clang, :gcc, :llvm, :gnu]
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def actual_cc
 | 
			
		||||
    CompilerSelector.new(@f, @versions).compiler
 | 
			
		||||
    @selector.compiler
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_all_compiler_failures
 | 
			
		||||
    @f << :clang << :llvm << :gcc << { :gcc => "4.8" }
 | 
			
		||||
    @f << :clang << :llvm << :gcc << { :gcc => "4.8" } << { :gcc => "4.7" }
 | 
			
		||||
    assert_raises(CompilerSelectionError) { actual_cc }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -68,17 +72,17 @@ class CompilerSelectorTests < Homebrew::TestCase
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_mixed_failures_1
 | 
			
		||||
    @f << :clang << :gcc
 | 
			
		||||
    assert_equal :llvm, actual_cc
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_mixed_failures_2
 | 
			
		||||
    @f << :clang << :llvm
 | 
			
		||||
    assert_equal :gcc, actual_cc
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_mixed_failures_2
 | 
			
		||||
    @f << :gcc << :clang << { :gcc => "4.8" }
 | 
			
		||||
    assert_equal :llvm, actual_cc
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_mixed_failures_3
 | 
			
		||||
    @f << :llvm << :gcc
 | 
			
		||||
    @f << :gcc << :llvm
 | 
			
		||||
    assert_equal :clang, actual_cc
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -87,10 +91,9 @@ class CompilerSelectorTests < Homebrew::TestCase
 | 
			
		||||
    assert_equal :gcc, actual_cc
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_older_clang_precedence
 | 
			
		||||
    @versions.clang_build_version = 211
 | 
			
		||||
    @f << :gcc << { :gcc => "4.8" }
 | 
			
		||||
    assert_equal :llvm, actual_cc
 | 
			
		||||
  def test_mixed_failures_5
 | 
			
		||||
    @f << :clang << :gcc << :llvm << { :gcc => "4.8" }
 | 
			
		||||
    assert_equal "gcc-4.7", actual_cc
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_llvm_precedence
 | 
			
		||||
@ -100,13 +103,13 @@ class CompilerSelectorTests < Homebrew::TestCase
 | 
			
		||||
 | 
			
		||||
  def test_missing_gcc
 | 
			
		||||
    @versions.gcc_build_version = nil
 | 
			
		||||
    @f << :clang << :llvm << { :gcc => "4.8" }
 | 
			
		||||
    @f << :clang << :llvm << { :gcc => "4.8" } << { :gcc => "4.7" }
 | 
			
		||||
    assert_raises(CompilerSelectionError) { actual_cc }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_missing_llvm_and_gcc
 | 
			
		||||
    @versions.gcc_build_version = @versions.llvm_build_version = nil
 | 
			
		||||
    @f << :clang << { :gcc => "4.8" }
 | 
			
		||||
    @f << :clang << { :gcc => "4.8" } << { :gcc => "4.7" }
 | 
			
		||||
    assert_raises(CompilerSelectionError) { actual_cc }
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user