2014-07-02 21:57:52 -05:00
|
|
|
module CompilerConstants
|
|
|
|
GNU_GCC_VERSIONS = 3..9
|
2014-07-29 19:30:09 -07:00
|
|
|
GNU_GCC_REGEXP = /^gcc-(4\.[3-9])$/
|
2014-07-02 21:57:52 -05:00
|
|
|
end
|
|
|
|
|
2014-06-11 21:03:23 -05:00
|
|
|
class Compiler < Struct.new(:name, :version, :priority)
|
2013-09-28 12:21:16 -07:00
|
|
|
# The major version for non-Apple compilers. Used to indicate a compiler
|
|
|
|
# series; for instance, if the version is 4.8.2, it would return "4.8".
|
|
|
|
def major_version
|
|
|
|
version.match(/(\d\.\d)/)[0] if name.is_a? String
|
2013-06-28 01:38:09 -05:00
|
|
|
end
|
2012-03-18 13:58:13 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
class CompilerFailure
|
2013-09-28 12:21:16 -07:00
|
|
|
attr_reader :compiler, :major_version
|
|
|
|
attr_rw :cause, :version
|
2012-03-18 13:58:13 -05:00
|
|
|
|
2014-06-16 16:08:41 -05:00
|
|
|
# Allows Apple compiler `fails_with` statements to keep using `build`
|
|
|
|
# even though `build` and `version` are the same internally
|
|
|
|
alias_method :build, :version
|
|
|
|
|
2014-04-04 21:16:09 -07:00
|
|
|
def self.for_standard standard
|
2014-08-01 20:15:58 -05:00
|
|
|
COLLECTIONS.fetch(standard) do
|
2014-04-04 21:16:09 -07:00
|
|
|
raise ArgumentError, "\"#{standard}\" is not a recognized standard"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-08-01 20:15:57 -05:00
|
|
|
def self.create(spec, &block)
|
2013-06-28 01:38:09 -05:00
|
|
|
# Non-Apple compilers are in the format fails_with compiler => version
|
2014-08-01 20:15:57 -05:00
|
|
|
if spec.is_a?(Hash)
|
|
|
|
_, major_version = spec.first
|
|
|
|
compiler = "gcc-#{major_version}"
|
2013-09-28 12:21:16 -07:00
|
|
|
# so fails_with :gcc => '4.8' simply marks all 4.8 releases incompatible
|
2014-08-01 20:15:57 -05:00
|
|
|
version = "#{major_version}.999"
|
2013-12-12 14:53:53 -06:00
|
|
|
else
|
2014-08-01 20:15:57 -05:00
|
|
|
compiler = spec
|
|
|
|
version = 9999
|
|
|
|
major_version = nil
|
2013-09-28 12:21:16 -07:00
|
|
|
end
|
2014-08-01 20:15:57 -05:00
|
|
|
|
|
|
|
new(compiler, version, major_version, &block)
|
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(compiler, version, major_version, &block)
|
|
|
|
@compiler = compiler
|
|
|
|
@version = version
|
|
|
|
@major_version = major_version
|
|
|
|
instance_eval(&block) if block_given?
|
2012-03-18 13:58:13 -05:00
|
|
|
end
|
2014-08-01 20:15:58 -05:00
|
|
|
|
|
|
|
MESSAGES = {
|
|
|
|
:cxx11 => "This compiler does not support C++11"
|
|
|
|
}
|
|
|
|
|
|
|
|
cxx11 = proc { cause MESSAGES[:cxx11] }
|
|
|
|
|
|
|
|
COLLECTIONS = {
|
|
|
|
:cxx11 => [
|
|
|
|
create(:gcc_4_0, &cxx11),
|
|
|
|
create(:gcc, &cxx11),
|
|
|
|
create(:llvm, &cxx11),
|
|
|
|
create(:clang) { build 425; cause MESSAGES[:cxx11] },
|
|
|
|
create(:gcc => "4.3", &cxx11),
|
|
|
|
create(:gcc => "4.4", &cxx11),
|
|
|
|
create(:gcc => "4.5", &cxx11),
|
|
|
|
create(:gcc => "4.6", &cxx11),
|
|
|
|
],
|
|
|
|
:openmp => [
|
|
|
|
create(:clang) { cause "clang does not support OpenMP" },
|
|
|
|
]
|
|
|
|
}
|
2012-03-18 13:58:13 -05:00
|
|
|
end
|
|
|
|
|
2013-03-13 02:07:01 -05:00
|
|
|
class CompilerQueue
|
|
|
|
def initialize
|
|
|
|
@array = []
|
|
|
|
end
|
2012-03-18 13:58:13 -05:00
|
|
|
|
2013-03-13 02:07:01 -05:00
|
|
|
def <<(o)
|
|
|
|
@array << o
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def pop
|
|
|
|
@array.delete(@array.max { |a, b| a.priority <=> b.priority })
|
|
|
|
end
|
2012-03-18 13:58:13 -05:00
|
|
|
|
2013-03-13 02:07:01 -05:00
|
|
|
def empty?
|
|
|
|
@array.empty?
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class CompilerSelector
|
2014-06-11 21:05:31 -05:00
|
|
|
def initialize(f, versions=MacOS)
|
2012-03-18 13:58:13 -05:00
|
|
|
@f = f
|
2014-06-11 21:05:31 -05:00
|
|
|
@versions = versions
|
2013-03-13 02:07:01 -05:00
|
|
|
@compilers = CompilerQueue.new
|
2013-05-20 19:35:48 -05:00
|
|
|
%w{clang llvm gcc gcc_4_0}.map(&:to_sym).each do |cc|
|
2014-06-11 21:05:31 -05:00
|
|
|
version = @versions.send("#{cc}_build_version")
|
2014-06-11 21:03:23 -05:00
|
|
|
unless version.nil?
|
|
|
|
@compilers << Compiler.new(cc, version, priority_for(cc))
|
2013-04-01 13:23:09 -05:00
|
|
|
end
|
2013-03-13 02:07:01 -05:00
|
|
|
end
|
2013-06-28 01:38:09 -05:00
|
|
|
|
|
|
|
# non-Apple GCC 4.x
|
2014-07-02 21:57:52 -05:00
|
|
|
CompilerConstants::GNU_GCC_VERSIONS.each do |v|
|
2014-06-11 21:03:23 -05:00
|
|
|
name = "gcc-4.#{v}"
|
2014-06-11 21:05:31 -05:00
|
|
|
version = @versions.non_apple_gcc_version(name)
|
2014-06-11 21:03:23 -05:00
|
|
|
unless version.nil?
|
2013-06-28 01:38:09 -05:00
|
|
|
# priority is based on version, with newest preferred first
|
2014-06-11 21:03:23 -05:00
|
|
|
@compilers << Compiler.new(name, version, 1.0 + v/10.0)
|
2013-06-28 01:38:09 -05:00
|
|
|
end
|
|
|
|
end
|
2012-03-18 13:58:13 -05:00
|
|
|
end
|
|
|
|
|
2013-05-20 19:35:07 -05:00
|
|
|
# Attempts to select an appropriate alternate compiler, but
|
|
|
|
# if none can be found raises CompilerError instead
|
2013-03-13 02:07:01 -05:00
|
|
|
def compiler
|
2013-03-13 02:07:01 -05:00
|
|
|
begin
|
|
|
|
cc = @compilers.pop
|
|
|
|
end while @f.fails_with?(cc)
|
2013-05-20 19:35:07 -05:00
|
|
|
|
|
|
|
if cc.nil?
|
2013-12-03 22:16:37 -06:00
|
|
|
raise CompilerSelectionError.new(@f)
|
2013-05-20 19:35:07 -05:00
|
|
|
else
|
|
|
|
cc.name
|
|
|
|
end
|
2013-03-13 02:07:01 -05:00
|
|
|
end
|
2012-03-18 13:58:13 -05:00
|
|
|
|
2013-03-13 02:07:01 -05:00
|
|
|
private
|
2012-03-18 13:58:13 -05:00
|
|
|
|
2013-03-13 02:07:01 -05:00
|
|
|
def priority_for(cc)
|
|
|
|
case cc
|
2014-06-11 21:05:31 -05:00
|
|
|
when :clang then @versions.clang_build_version >= 318 ? 3 : 0.5
|
2013-09-10 08:17:28 -07:00
|
|
|
when :gcc then 2.5
|
|
|
|
when :llvm then 2
|
2013-04-13 01:07:46 -05:00
|
|
|
when :gcc_4_0 then 0.25
|
2013-06-28 01:38:09 -05:00
|
|
|
# non-Apple gcc compilers
|
|
|
|
else 1.5
|
2012-03-18 13:58:13 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|