aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/compilers.rb
blob: 6343aa929dc14293c3072e7ab1e200064deb6acc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class Compiler < Struct.new(:name, :priority)
  def build
    MacOS.send("#{name}_build_version")
  end

  def version
    MacOS.non_apple_gcc_version(name) if name.is_a? String
  end
end

class CompilerFailure
  attr_reader :compiler, :version
  attr_rw :build, :version, :cause

  def initialize compiler, &block
    # Non-Apple compilers are in the format fails_with compiler => version
    if compiler.is_a? Hash
      # currently the only compiler for this case is GCC
      _, @version = compiler.shift
      @compiler = 'gcc-' + @version.match(/(\d\.\d)/)[0]
    else
      @compiler = compiler
    end

    instance_eval(&block) if block_given?
    @build = (@build || 9999).to_i unless compiler.is_a? Hash
  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)
    @f = f
    @compilers = CompilerQueue.new
    %w{clang llvm gcc gcc_4_0}.map(&:to_sym).each do |cc|
      unless MacOS.send("#{cc}_build_version").nil?
        @compilers << Compiler.new(cc, priority_for(cc))
      end
    end

    # non-Apple GCC 4.x
    SharedEnvExtension::GNU_GCC_VERSIONS.each do |v|
      unless MacOS.non_apple_gcc_version("gcc-4.#{v}").nil?
        # priority is based on version, with newest preferred first
        @compilers << Compiler.new("gcc-4.#{v}", 1.0 + v/10.0)
      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 :gcc   then 2
    when :llvm  then 1
    when :gcc_4_0 then 0.25
    # non-Apple gcc compilers
    else 1.5
    end
  end
end