Cleanup use of CxxStdlib

- remove usage on macOS as we don't care about it there
- don't error out on incompatibility but still store stdlib on Linux
- remove (now) unused methods
This commit is contained in:
Mike McQuaid 2021-04-02 12:38:39 +01:00
parent f266acff2d
commit 04abc51d1f
No known key found for this signature in database
GPG Key ID: 48A898132FD8EE70
5 changed files with 5 additions and 119 deletions

View File

@ -8,7 +8,6 @@ old_trap = trap("INT") { exit! 130 }
require_relative "global" require_relative "global"
require "build_options" require "build_options"
require "cxxstdlib"
require "keg" require "keg"
require "extend/ENV" require "extend/ENV"
require "debrew" require "debrew"
@ -174,7 +173,7 @@ class Build
"#{formula.full_name} #{formula.build.used_options.sort.join(" ")}".strip "#{formula.full_name} #{formula.build.used_options.sort.join(" ")}".strip
formula.install formula.install
stdlibs = detect_stdlibs(ENV.compiler) stdlibs = detect_stdlibs
tab = Tab.create(formula, ENV.compiler, stdlibs.first) tab = Tab.create(formula, ENV.compiler, stdlibs.first)
tab.write tab.write
@ -186,9 +185,8 @@ class Build
end end
end end
def detect_stdlibs(compiler) def detect_stdlibs
keg = Keg.new(formula.prefix) keg = Keg.new(formula.prefix)
CxxStdlib.check_compatibility(formula, deps, keg, compiler)
# The stdlib recorded in the install receipt is used during dependency # The stdlib recorded in the install receipt is used during dependency
# compatibility checks, so we only care about the stdlib that libraries # compatibility checks, so we only care about the stdlib that libraries

View File

@ -22,52 +22,14 @@ class CxxStdlib
def self.create(type, compiler) def self.create(type, compiler)
raise ArgumentError, "Invalid C++ stdlib type: #{type}" if type && [:libstdcxx, :libcxx].exclude?(type) raise ArgumentError, "Invalid C++ stdlib type: #{type}" if type && [:libstdcxx, :libcxx].exclude?(type)
apple_compiler = !compiler.to_s.match?(GNU_GCC_REGEXP) CxxStdlib.new(type, compiler)
CxxStdlib.new(type, compiler, apple_compiler)
end
def self.check_compatibility(formula, deps, keg, compiler)
return if formula.skip_cxxstdlib_check?
stdlib = create(keg.detect_cxx_stdlibs.first, compiler)
begin
stdlib.check_dependencies(formula, deps)
rescue CompatibilityError => e
opoo e.message
end
end end
attr_reader :type, :compiler attr_reader :type, :compiler
def initialize(type, compiler, apple_compiler) def initialize(type, compiler)
@type = type @type = type
@compiler = compiler.to_sym @compiler = compiler.to_sym
@apple_compiler = apple_compiler
end
# If either package doesn't use C++, all is well.
# libstdc++ and libc++ aren't ever intercompatible.
# libstdc++ is compatible across Apple compilers, but
# not between Apple and GNU compilers, nor between GNU compiler versions.
def compatible_with?(other)
return true if type.nil? || other.type.nil?
return false unless type == other.type
apple_compiler? && other.apple_compiler? ||
!other.apple_compiler? && compiler.to_s[4..6] == other.compiler.to_s[4..6]
end
def check_dependencies(formula, deps)
deps.each do |dep|
# Software is unlikely to link against libraries from build-time deps, so
# it doesn't matter if they link against different C++ stdlibs.
next if dep.build?
dep_stdlib = Tab.for_formula(dep.to_formula).cxxstdlib
raise CompatibilityError.new(formula, dep, dep_stdlib) unless compatible_with? dep_stdlib
end
end end
def type_string def type_string
@ -78,8 +40,4 @@ class CxxStdlib
def inspect def inspect
"#<#{self.class.name}: #{compiler} #{type}>" "#<#{self.class.name}: #{compiler} #{type}>"
end end
def apple_compiler?
@apple_compiler
end
end end

View File

@ -16,7 +16,7 @@ class Keg
end end
end end
undef relocate_dynamic_linkage, detect_cxx_stdlibs undef relocate_dynamic_linkage
def relocate_dynamic_linkage(relocation) def relocate_dynamic_linkage(relocation)
mach_o_files.each do |file| mach_o_files.each do |file|
@ -39,25 +39,6 @@ class Keg
end end
end end
# Detects the C++ dynamic libraries in-place, scanning the dynamic links
# of the files within the keg.
# Note that this doesn't attempt to distinguish between libstdc++ versions,
# for instance between Apple libstdc++ and GNU libstdc++.
def detect_cxx_stdlibs(options = {})
skip_executables = options.fetch(:skip_executables, false)
results = Set.new
mach_o_files.each do |file|
next if file.mach_o_executable? && skip_executables
dylibs = file.dynamically_linked_libraries
results << :libcxx unless dylibs.grep(/libc\+\+.+\.dylib/).empty?
results << :libstdcxx unless dylibs.grep(/libstdc\+\+.+\.dylib/).empty?
end
results.to_a
end
def fix_dynamic_linkage def fix_dynamic_linkage
mach_o_files.each do |file| mach_o_files.each do |file|
file.ensure_writable do file.ensure_writable do

View File

@ -1,7 +1,6 @@
# typed: false # typed: false
# frozen_string_literal: true # frozen_string_literal: true
require "cxxstdlib"
require "formula" require "formula"
require "keg" require "keg"
require "tab" require "tab"
@ -1137,13 +1136,6 @@ class FormulaInstaller
skip_linkage = formula.bottle_specification.skip_relocation? skip_linkage = formula.bottle_specification.skip_relocation?
keg.replace_placeholders_with_locations tab.changed_files, skip_linkage: skip_linkage keg.replace_placeholders_with_locations tab.changed_files, skip_linkage: skip_linkage
unless ignore_deps?
CxxStdlib.check_compatibility(
formula, formula.recursive_dependencies,
Keg.new(formula.prefix), tab.compiler
)
end
# fill in missing/outdated parts of the tab # fill in missing/outdated parts of the tab
# keep in sync with Tab#to_bottle_json # keep in sync with Tab#to_bottle_json
tab.used_options = [] tab.used_options = []

View File

@ -6,50 +6,7 @@ require "cxxstdlib"
describe CxxStdlib do describe CxxStdlib do
let(:clang) { described_class.create(:libstdcxx, :clang) } let(:clang) { described_class.create(:libstdcxx, :clang) }
let(:gcc6) { described_class.create(:libstdcxx, "gcc-6") }
let(:gcc7) { described_class.create(:libstdcxx, "gcc-7") }
let(:lcxx) { described_class.create(:libcxx, :clang) } let(:lcxx) { described_class.create(:libcxx, :clang) }
let(:purec) { described_class.create(nil, :clang) }
describe "#compatible_with?" do
specify "compatibility with itself" do
expect(gcc7).to be_compatible_with(gcc7)
expect(clang).to be_compatible_with(clang)
end
specify "Apple/GNU libstdcxx incompatibility" do
expect(clang).not_to be_compatible_with(gcc7)
expect(gcc7).not_to be_compatible_with(clang)
end
specify "GNU cross-version incompatibility" do
expect(gcc6).not_to be_compatible_with(gcc7)
expect(gcc7).not_to be_compatible_with(gcc6)
end
specify "libstdcxx and libcxx incompatibility" do
expect(clang).not_to be_compatible_with(lcxx)
expect(lcxx).not_to be_compatible_with(clang)
end
specify "compatibility for non-cxx software" do
expect(purec).to be_compatible_with(clang)
expect(clang).to be_compatible_with(purec)
expect(purec).to be_compatible_with(purec)
expect(purec).to be_compatible_with(gcc7)
expect(gcc7).to be_compatible_with(purec)
end
end
describe "#apple_compiler?" do
it "returns true for Apple compilers" do
expect(clang).to be_an_apple_compiler
end
it "returns false for non-Apple compilers" do
expect(gcc7).not_to be_an_apple_compiler
end
end
describe "#type_string" do describe "#type_string" do
specify "formatting" do specify "formatting" do