Use polymorphism to simplify stdlib compatibility check

This commit is contained in:
Jack Nagel 2014-08-02 19:29:59 -05:00
parent 90e370d2ef
commit 142beddd7a
5 changed files with 46 additions and 32 deletions

View File

@ -172,7 +172,7 @@ class Build
# This currently only tracks a single C++ stdlib per dep,
# though it's possible for different libs/executables in
# a given formula to link to different ones.
stdlib_in_use = CxxStdlib.new(stdlibs.first, ENV.compiler)
stdlib_in_use = CxxStdlib.create(stdlibs.first, ENV.compiler)
begin
stdlib_in_use.check_dependencies(f, deps)
rescue IncompatibleCxxStdlibs => e

View File

@ -1,37 +1,29 @@
require "compilers"
class CxxStdlib
attr_reader :type, :compiler
include CompilerConstants
def initialize(type, compiler)
def self.create(type, compiler)
if type && ![:libstdcxx, :libcxx].include?(type)
raise ArgumentError, "Invalid C++ stdlib type: #{type}"
end
klass = GNU_GCC_REGEXP === compiler.to_s ? GnuStdlib : AppleStdlib
klass.new(type, compiler)
end
attr_reader :type, :compiler
def initialize(type, compiler)
@type = type
@compiler = compiler.to_sym
end
def apple_compiler?
not compiler.to_s =~ CompilerConstants::GNU_GCC_REGEXP
end
def compatible_with?(other)
# If either package doesn't use C++, all is well
return true if type.nil? || other.type.nil?
# libstdc++ and libc++ aren't ever intercompatible
return false unless type == other.type
# libstdc++ is compatible across Apple compilers, but
# not between Apple and GNU compilers, or between GNU compiler versions
return false if apple_compiler? && !other.apple_compiler?
if compiler.to_s =~ CompilerConstants::GNU_GCC_REGEXP
return false unless other.compiler.to_s =~ CompilerConstants::GNU_GCC_REGEXP
return false unless compiler.to_s[4..6] == other.compiler.to_s[4..6]
end
true
def compatible_with?(other)
(type.nil? || other.type.nil?) || type == other.type
end
def check_dependencies(formula, deps)
@ -53,4 +45,26 @@ class CxxStdlib
def type_string
type.to_s.gsub(/cxx$/, 'c++')
end
class AppleStdlib < CxxStdlib
def apple_compiler?
true
end
def compatible_with?(other)
super && other.apple_compiler?
end
end
class GnuStdlib < CxxStdlib
def apple_compiler?
false
end
def compatible_with?(other)
super &&
!other.apple_compiler? &&
compiler.to_s[4..6] == other.compiler.to_s[4..6]
end
end
end

View File

@ -159,7 +159,7 @@ class FormulaInstaller
@poured_bottle = true
stdlibs = Keg.new(f.prefix).detect_cxx_stdlibs
stdlib_in_use = CxxStdlib.new(stdlibs.first, MacOS.default_compiler)
stdlib_in_use = CxxStdlib.create(stdlibs.first, MacOS.default_compiler)
begin
stdlib_in_use.check_dependencies(f, f.recursive_dependencies)
rescue IncompatibleCxxStdlibs => e

View File

@ -119,7 +119,7 @@ class Tab < OpenStruct
# Older tabs won't have these values, so provide sensible defaults
lib = stdlib.to_sym if stdlib
cc = compiler || MacOS.default_compiler
CxxStdlib.new(lib, cc.to_sym)
CxxStdlib.create(lib, cc.to_sym)
end
def to_json

View File

@ -5,14 +5,14 @@ require 'cxxstdlib'
class CxxStdlibTests < Homebrew::TestCase
def setup
@clang = CxxStdlib.new(:libstdcxx, :clang)
@gcc = CxxStdlib.new(:libstdcxx, :gcc)
@llvm = CxxStdlib.new(:libstdcxx, :llvm)
@gcc4 = CxxStdlib.new(:libstdcxx, :gcc_4_0)
@gcc48 = CxxStdlib.new(:libstdcxx, 'gcc-4.8')
@gcc49 = CxxStdlib.new(:libstdcxx, 'gcc-4.9')
@lcxx = CxxStdlib.new(:libcxx, :clang)
@purec = CxxStdlib.new(nil, :clang)
@clang = CxxStdlib.create(:libstdcxx, :clang)
@gcc = CxxStdlib.create(:libstdcxx, :gcc)
@llvm = CxxStdlib.create(:libstdcxx, :llvm)
@gcc4 = CxxStdlib.create(:libstdcxx, :gcc_4_0)
@gcc48 = CxxStdlib.create(:libstdcxx, 'gcc-4.8')
@gcc49 = CxxStdlib.create(:libstdcxx, 'gcc-4.9')
@lcxx = CxxStdlib.create(:libcxx, :clang)
@purec = CxxStdlib.create(nil, :clang)
end
def test_apple_libstdcxx_intercompatibility