aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
Diffstat (limited to 'Library')
-rwxr-xr-xLibrary/Homebrew/build.rb3
-rw-r--r--Library/Homebrew/cxxstdlib.rb44
-rw-r--r--Library/Homebrew/tab.rb22
-rw-r--r--Library/Homebrew/test/test_stdlib.rb62
4 files changed, 126 insertions, 5 deletions
diff --git a/Library/Homebrew/build.rb b/Library/Homebrew/build.rb
index ac60221d9..9d25c9a86 100755
--- a/Library/Homebrew/build.rb
+++ b/Library/Homebrew/build.rb
@@ -170,7 +170,8 @@ class Build
begin
f.install
- Tab.create(f, Options.coerce(ARGV.options_only)).write
+ Tab.create(f, ENV.compiler,
+ Options.coerce(ARGV.options_only)).write
rescue Exception => e
if ARGV.debug?
debrew e, f
diff --git a/Library/Homebrew/cxxstdlib.rb b/Library/Homebrew/cxxstdlib.rb
new file mode 100644
index 000000000..4e3bed22e
--- /dev/null
+++ b/Library/Homebrew/cxxstdlib.rb
@@ -0,0 +1,44 @@
+class CxxStdlib
+ attr_accessor :type, :compiler
+
+ def initialize(type, compiler)
+ if ![:libstdcxx, :libcxx].include? type
+ raise ArgumentError, "Invalid C++ stdlib type: #{type}"
+ end
+
+ @type = type.to_sym
+ @compiler = compiler.to_sym
+ end
+
+ def apple_compiler?
+ not compiler.to_s =~ SharedEnvExtension::GNU_GCC_REGEXP
+ end
+
+ def compatible_with?(other)
+ # 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 =~ SharedEnvExtension::GNU_GCC_REGEXP
+ return false unless other.compiler.to_s =~ SharedEnvExtension::GNU_GCC_REGEXP
+ return false unless compiler.to_s[4..6] == other.compiler.to_s[4..6]
+ end
+
+ true
+ end
+
+ def check_dependencies(formula, deps)
+ deps.each do |dep|
+ dep_stdlib = Tab.for_formula(dep.to_formula).cxxstdlib
+ if !compatible_with? dep_stdlib
+ raise IncompatibleCxxStdlibs.new(formula, dep, dep_stdlib, self)
+ end
+ end
+ end
+
+ def type_string
+ type.to_s.gsub(/cxx$/, 'c++')
+ end
+end
diff --git a/Library/Homebrew/tab.rb b/Library/Homebrew/tab.rb
index a55df156d..9b19e9510 100644
--- a/Library/Homebrew/tab.rb
+++ b/Library/Homebrew/tab.rb
@@ -1,3 +1,4 @@
+require 'cxxstdlib'
require 'ostruct'
require 'options'
require 'utils/json'
@@ -9,7 +10,7 @@ require 'utils/json'
class Tab < OpenStruct
FILENAME = 'INSTALL_RECEIPT.json'
- def self.create f, args
+ def self.create f, stdlib, compiler, args
f.build.args = args
sha = HOMEBREW_REPOSITORY.cd do
@@ -23,7 +24,9 @@ class Tab < OpenStruct
:poured_from_bottle => false,
:tapped_from => f.tap,
:time => Time.now.to_i, # to_s would be better but Ruby has no from_s function :P
- :HEAD => sha
+ :HEAD => sha,
+ :compiler => compiler,
+ :stdlib => stdlib
end
def self.from_file path
@@ -59,7 +62,9 @@ class Tab < OpenStruct
:poured_from_bottle => false,
:tapped_from => "",
:time => nil,
- :HEAD => nil
+ :HEAD => nil,
+ :stdlib => :libstdcxx,
+ :compiler => :clang
end
def with? name
@@ -92,6 +97,13 @@ class Tab < OpenStruct
used_options + unused_options
end
+ def cxxstdlib
+ # Older tabs won't have these values, so provide sensible defaults
+ lib = stdlib || :libstdcxx
+ cc = compiler || MacOS.default_compiler
+ CxxStdlib.new(lib.to_sym, cc.to_sym)
+ end
+
def to_json
Utils::JSON.dump({
:used_options => used_options.map(&:to_s),
@@ -100,7 +112,9 @@ class Tab < OpenStruct
:poured_from_bottle => poured_from_bottle,
:tapped_from => tapped_from,
:time => time,
- :HEAD => send("HEAD")})
+ :HEAD => send("HEAD"),
+ :stdlib => (stdlib.to_s if stdlib),
+ :compiler => (compiler.to_s if compiler)})
end
def write
diff --git a/Library/Homebrew/test/test_stdlib.rb b/Library/Homebrew/test/test_stdlib.rb
new file mode 100644
index 000000000..a5e276746
--- /dev/null
+++ b/Library/Homebrew/test/test_stdlib.rb
@@ -0,0 +1,62 @@
+require 'testing_env'
+require 'test/testball'
+require 'formula'
+require 'cxxstdlib'
+require 'tab'
+
+class CxxStdlibTests < Test::Unit::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)
+ end
+
+ def test_apple_libstdcxx_intercompatibility
+ assert @clang.compatible_with?(@gcc)
+ assert @clang.compatible_with?(@llvm)
+ assert @clang.compatible_with?(@gcc4)
+ end
+
+ def test_compatibility_same_compilers_and_type
+ assert @gcc48.compatible_with?(@gcc48)
+ assert @clang.compatible_with?(@clang)
+ end
+
+ def test_apple_gnu_libstdcxx_incompatibility
+ assert !@clang.compatible_with?(@gcc48)
+ assert !@gcc48.compatible_with?(@clang)
+ end
+
+ def test_gnu_cross_version_incompatibility
+ assert !@clang.compatible_with?(@gcc48)
+ assert !@gcc48.compatible_with?(@clang)
+ end
+
+ def test_libstdcxx_libcxx_incompatibility
+ assert !@clang.compatible_with?(@lcxx)
+ assert !@lcxx.compatible_with?(@clang)
+ end
+
+ def test_apple_compiler_reporting
+ assert @clang.apple_compiler?
+ assert @gcc.apple_compiler?
+ assert @llvm.apple_compiler?
+ assert @gcc4.apple_compiler?
+ assert !@gcc48.apple_compiler?
+ end
+
+ def test_type_string_formatting
+ assert_equal @clang.type_string, 'libstdc++'
+ assert_equal @lcxx.type_string, 'libc++'
+ end
+
+ def test_constructing_from_tab
+ stdlib = Tab.dummy_tab.cxxstdlib
+ assert_equal stdlib.compiler, :clang
+ assert_equal stdlib.type, :libstdcxx
+ end
+end