compilers: support more fails_with uses on GCC.

This commit is contained in:
Bo Anderson 2021-03-30 03:00:35 +01:00
parent c65a392d47
commit 3cebcd43b7
No known key found for this signature in database
GPG Key ID: 3DB94E204E137D65
3 changed files with 82 additions and 32 deletions

View File

@ -19,7 +19,7 @@ end
#
# @api private
class CompilerFailure
attr_reader :name
attr_reader :type
def version(val = nil)
@version = Version.parse(val.to_s) if val
@ -42,29 +42,51 @@ class CompilerFailure
def self.create(spec, &block)
# Non-Apple compilers are in the format fails_with compiler => version
if spec.is_a?(Hash)
_, major_version = spec.first
name = "gcc-#{major_version}"
compiler, major_version = spec.first
raise ArgumentError, "The hash `fails_with` syntax only supports GCC" if compiler != :gcc
type = compiler
# so fails_with :gcc => '7' simply marks all 7 releases incompatible
version = "#{major_version}.999"
exact_major_match = true
else
name = spec
type = spec
version = 9999
exact_major_match = false
end
new(name, version, &block)
end
def initialize(name, version, &block)
@name = name
@version = Version.parse(version.to_s)
instance_eval(&block) if block
new(type, version, exact_major_match: exact_major_match, &block)
end
def fails_with?(compiler)
name == compiler.name && version >= compiler.version
version_matched = if type != :gcc
version >= compiler.version
elsif @exact_major_match
gcc_major(version) == gcc_major(compiler.version) && version >= compiler.version
else
gcc_major(version) >= gcc_major(compiler.version)
end
type == compiler.type && version_matched
end
def inspect
"#<#{self.class.name}: #{name} #{version}>"
"#<#{self.class.name}: #{type} #{version}>"
end
private
def initialize(type, version, exact_major_match:, &block)
@type = type
@version = Version.parse(version.to_s)
@exact_major_match = exact_major_match
instance_eval(&block) if block
end
def gcc_major(version)
if version.major >= 5
Version.new(version.major.to_s)
else
version.major_minor
end
end
COLLECTIONS = {
@ -81,7 +103,7 @@ class CompilerSelector
extend T::Sig
include CompilerConstants
Compiler = Struct.new(:name, :version)
Compiler = Struct.new(:type, :name, :version)
COMPILER_PRIORITY = {
clang: [:clang, :gnu, :llvm_clang],
@ -130,15 +152,15 @@ class CompilerSelector
case compiler
when :gnu
gnu_gcc_versions.reverse_each do |v|
name = "gcc-#{v}"
version = compiler_version(name)
yield Compiler.new(name, version) unless version.null?
executable = "gcc-#{v}"
version = compiler_version(executable)
yield Compiler.new(:gcc, executable, version) unless version.null?
end
when :llvm
next # no-op. DSL supported, compiler is not.
else
version = compiler_version(compiler)
yield Compiler.new(compiler, version) unless version.null?
yield Compiler.new(compiler, compiler, version) unless version.null?
end
end
end

View File

@ -9,31 +9,31 @@ describe CompilerFailure do
describe "::create" do
it "creates a failure when given a symbol" do
failure = described_class.create(:clang)
expect(failure).to fail_with(double("Compiler", name: :clang, version: 600))
expect(failure).to fail_with(double("Compiler", type: :clang, name: :clang, version: 600))
end
it "can be given a build number in a block" do
failure = described_class.create(:clang) { build 700 }
expect(failure).to fail_with(double("Compiler", name: :clang, version: 700))
expect(failure).to fail_with(double("Compiler", type: :clang, name: :clang, version: 700))
end
it "can be given an empty block" do
failure = described_class.create(:clang) {}
expect(failure).to fail_with(double("Compiler", name: :clang, version: 600))
expect(failure).to fail_with(double("Compiler", type: :clang, name: :clang, version: 600))
end
it "creates a failure when given a hash" do
failure = described_class.create(gcc: "7")
expect(failure).to fail_with(double("Compiler", name: "gcc-7", version: "7"))
expect(failure).to fail_with(double("Compiler", name: "gcc-7", version: "7.1"))
expect(failure).not_to fail_with(double("Compiler", name: "gcc-6", version: "6.0"))
expect(failure).to fail_with(double("Compiler", type: :gcc, name: "gcc-7", version: Version.new("7")))
expect(failure).to fail_with(double("Compiler", type: :gcc, name: "gcc-7", version: Version.new("7.1")))
expect(failure).not_to fail_with(double("Compiler", type: :gcc, name: "gcc-6", version: Version.new("6.0")))
end
it "creates a failure when given a hash and a block with aversion" do
failure = described_class.create(gcc: "7") { version "7.1" }
expect(failure).to fail_with(double("Compiler", name: "gcc-7", version: "7"))
expect(failure).to fail_with(double("Compiler", name: "gcc-7", version: "7.1"))
expect(failure).not_to fail_with(double("Compiler", name: "gcc-7", version: "7.2"))
expect(failure).to fail_with(double("Compiler", type: :gcc, name: "gcc-7", version: Version.new("7")))
expect(failure).to fail_with(double("Compiler", type: :gcc, name: "gcc-7", version: Version.new("7.1")))
expect(failure).not_to fail_with(double("Compiler", type: :gcc, name: "gcc-7", version: Version.new("7.2")))
end
end
end

View File

@ -23,6 +23,7 @@ describe CompilerSelector do
when "gcc-7" then Version.create("7.1")
when "gcc-6" then Version.create("6.1")
when "gcc-5" then Version.create("5.1")
when "gcc-4.9" then Version.create("4.9.1")
else Version::NULL
end
end
@ -45,29 +46,56 @@ describe CompilerSelector do
it "returns gcc-6 if gcc formula offers gcc-6 on mac", :needs_macos do
software_spec.fails_with(:clang)
allow(Formulary).to receive(:factory).with("gcc").and_return(double(version: "6.0"))
allow(Formulary).to receive(:factory).with("gcc").and_return(double(version: Version.new("6.0")))
expect(selector.compiler).to eq("gcc-6")
end
it "returns gcc-5 if gcc formula offers gcc-5 on linux", :needs_linux do
software_spec.fails_with(:clang)
allow(Formulary).to receive(:factory).with("gcc@5").and_return(double(version: "5.0"))
allow(Formulary).to receive(:factory).with("gcc@5").and_return(double(version: Version.new("5.0")))
expect(selector.compiler).to eq("gcc-5")
end
it "returns gcc-6 if gcc formula offers gcc-6 and fails with gcc-5 and gcc-7 on linux", :needs_linux do
it "returns gcc-6 if gcc formula offers gcc-5 and fails with gcc-5 and gcc-7 on linux", :needs_linux do
software_spec.fails_with(:clang)
software_spec.fails_with(gcc: "5")
software_spec.fails_with(gcc: "7")
allow(Formulary).to receive(:factory).with("gcc@5").and_return(double(version: "5.0"))
allow(Formulary).to receive(:factory).with("gcc@5").and_return(double(version: Version.new("5.0")))
expect(selector.compiler).to eq("gcc-6")
end
it "raises an error when gcc or llvm is missing" do
it "returns gcc-7 if gcc formula offers gcc-5 and fails with gcc <= 6 on linux", :needs_linux do
software_spec.fails_with(:clang)
software_spec.fails_with(:gcc) { version "6" }
allow(Formulary).to receive(:factory).with("gcc@5").and_return(double(version: Version.new("5.0")))
expect(selector.compiler).to eq("gcc-7")
end
it "returns gcc-7 if gcc-7 is version 7.1 but spec fails with gcc-7 <= 7.0" do
software_spec.fails_with(:clang)
software_spec.fails_with(gcc: "7") { version "7.0" }
expect(selector.compiler).to eq("gcc-7")
end
it "returns gcc-6 if gcc-7 is version 7.1 but spec fails with gcc-7 <= 7.1" do
software_spec.fails_with(:clang)
software_spec.fails_with(gcc: "7") { version "7.1" }
expect(selector.compiler).to eq("gcc-6")
end
it "raises an error when gcc or llvm is missing (hash syntax)" do
software_spec.fails_with(:clang)
software_spec.fails_with(gcc: "7")
software_spec.fails_with(gcc: "6")
software_spec.fails_with(gcc: "5")
software_spec.fails_with(gcc: "4.9")
expect { selector.compiler }.to raise_error(CompilerSelectionError)
end
it "raises an error when gcc or llvm is missing (symbol syntax)" do
software_spec.fails_with(:clang)
software_spec.fails_with(:gcc)
expect { selector.compiler }.to raise_error(CompilerSelectionError)
end