Merge pull request #20682 from Homebrew/libstdcxx
Check host libstdc++ for brew `gcc` dependency
This commit is contained in:
commit
47b7bf378e
@ -42,14 +42,14 @@ module OS
|
|||||||
@needs_libc_formula ||= OS::Linux::Glibc.below_ci_version?
|
@needs_libc_formula ||= OS::Linux::Glibc.below_ci_version?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Keep this method around for now to make it easier to add this functionality later.
|
|
||||||
# rubocop:disable Lint/UselessMethodDefinition
|
|
||||||
sig { returns(Pathname) }
|
sig { returns(Pathname) }
|
||||||
def host_gcc_path
|
def host_gcc_path
|
||||||
# TODO: override this if/when we to pick the GCC based on e.g. the Ubuntu version.
|
# Prioritise versioned path if installed
|
||||||
|
path = Pathname.new("/usr/bin/#{OS::LINUX_PREFERRED_GCC_COMPILER_FORMULA.tr("@", "-")}")
|
||||||
|
return path if path.exist?
|
||||||
|
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
# rubocop:enable Lint/UselessMethodDefinition
|
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def needs_compiler_formula?
|
def needs_compiler_formula?
|
||||||
@ -60,12 +60,7 @@ module OS
|
|||||||
# Undocumented environment variable to make it easier to test compiler
|
# Undocumented environment variable to make it easier to test compiler
|
||||||
# formula automatic installation.
|
# formula automatic installation.
|
||||||
@needs_compiler_formula = true if ENV["HOMEBREW_FORCE_COMPILER_FORMULA"]
|
@needs_compiler_formula = true if ENV["HOMEBREW_FORCE_COMPILER_FORMULA"]
|
||||||
|
@needs_compiler_formula ||= OS::Linux::Libstdcxx.below_ci_version?
|
||||||
@needs_compiler_formula ||= if host_gcc_path.exist?
|
|
||||||
::DevelopmentTools.gcc_version(host_gcc_path.to_s) < OS::LINUX_GCC_CI_VERSION
|
|
||||||
else
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(T::Hash[String, T.nilable(String)]) }
|
sig { returns(T::Hash[String, T.nilable(String)]) }
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "os/linux/ld"
|
require "os/linux/ld"
|
||||||
|
require "os/linux/libstdcxx"
|
||||||
require "utils/output"
|
require "utils/output"
|
||||||
|
|
||||||
module OS
|
module OS
|
||||||
@ -12,12 +13,12 @@ module OS
|
|||||||
# which are linked by the GCC formula. We only use the versioned shared libraries
|
# which are linked by the GCC formula. We only use the versioned shared libraries
|
||||||
# as the other shared and static libraries are only used at build time where
|
# as the other shared and static libraries are only used at build time where
|
||||||
# GCC can find its own libraries.
|
# GCC can find its own libraries.
|
||||||
GCC_RUNTIME_LIBS = %w[
|
GCC_RUNTIME_LIBS = T.let(%W[
|
||||||
libatomic.so.1
|
libatomic.so.1
|
||||||
libgcc_s.so.1
|
libgcc_s.so.1
|
||||||
libgomp.so.1
|
libgomp.so.1
|
||||||
libstdc++.so.6
|
#{OS::Linux::Libstdcxx::SONAME}
|
||||||
].freeze
|
].freeze, T::Array[String])
|
||||||
|
|
||||||
sig { params(all_fatal: T::Boolean).void }
|
sig { params(all_fatal: T::Boolean).void }
|
||||||
def perform_preinstall_checks(all_fatal: false)
|
def perform_preinstall_checks(all_fatal: false)
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "compilers"
|
require "compilers"
|
||||||
|
require "os/linux/libstdcxx"
|
||||||
|
|
||||||
module OS
|
module OS
|
||||||
module Linux
|
module Linux
|
||||||
module LinkageChecker
|
module LinkageChecker
|
||||||
# Libraries provided by glibc and gcc.
|
# Libraries provided by glibc and gcc.
|
||||||
SYSTEM_LIBRARY_ALLOWLIST = %w[
|
SYSTEM_LIBRARY_ALLOWLIST = %W[
|
||||||
ld-linux-x86-64.so.2
|
ld-linux-x86-64.so.2
|
||||||
ld-linux-aarch64.so.1
|
ld-linux-aarch64.so.1
|
||||||
libanl.so.1
|
libanl.so.1
|
||||||
@ -24,7 +25,7 @@ module OS
|
|||||||
libutil.so.1
|
libutil.so.1
|
||||||
libgcc_s.so.1
|
libgcc_s.so.1
|
||||||
libgomp.so.1
|
libgomp.so.1
|
||||||
libstdc++.so.6
|
#{OS::Linux::Libstdcxx::SONAME}
|
||||||
libquadmath.so.0
|
libquadmath.so.0
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
require "compilers"
|
require "compilers"
|
||||||
require "os/linux/glibc"
|
require "os/linux/glibc"
|
||||||
|
require "os/linux/libstdcxx"
|
||||||
require "system_command"
|
require "system_command"
|
||||||
|
|
||||||
module OS
|
module OS
|
||||||
@ -20,6 +21,13 @@ module OS
|
|||||||
version
|
version
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def host_libstdcxx_version
|
||||||
|
version = OS::Linux::Libstdcxx.system_version
|
||||||
|
return "N/A" if version.null?
|
||||||
|
|
||||||
|
version
|
||||||
|
end
|
||||||
|
|
||||||
def host_gcc_version
|
def host_gcc_version
|
||||||
gcc = ::DevelopmentTools.host_gcc_path
|
gcc = ::DevelopmentTools.host_gcc_path
|
||||||
return "N/A" unless gcc.executable?
|
return "N/A" unless gcc.executable?
|
||||||
@ -49,6 +57,7 @@ module OS
|
|||||||
out.puts "OS: #{OS::Linux.os_version}"
|
out.puts "OS: #{OS::Linux.os_version}"
|
||||||
out.puts "WSL: #{OS::Linux.wsl_version}" if OS::Linux.wsl?
|
out.puts "WSL: #{OS::Linux.wsl_version}" if OS::Linux.wsl?
|
||||||
out.puts "Host glibc: #{host_glibc_version}"
|
out.puts "Host glibc: #{host_glibc_version}"
|
||||||
|
out.puts "Host libstdc++: #{host_libstdcxx_version}"
|
||||||
out.puts "#{::DevelopmentTools.host_gcc_path}: #{host_gcc_version}"
|
out.puts "#{::DevelopmentTools.host_gcc_path}: #{host_gcc_version}"
|
||||||
out.puts "/usr/bin/ruby: #{host_ruby_version}" if RUBY_PATH != HOST_RUBY_PATH
|
out.puts "/usr/bin/ruby: #{host_ruby_version}" if RUBY_PATH != HOST_RUBY_PATH
|
||||||
["glibc", ::CompilerSelector.preferred_gcc, OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA, "xorg"].each do |f|
|
["glibc", ::CompilerSelector.preferred_gcc, OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA, "xorg"].each do |f|
|
||||||
|
@ -50,6 +50,7 @@ module OS
|
|||||||
LINUX_GLIBC_CI_VERSION = "2.35"
|
LINUX_GLIBC_CI_VERSION = "2.35"
|
||||||
LINUX_GLIBC_NEXT_CI_VERSION = "2.39"
|
LINUX_GLIBC_NEXT_CI_VERSION = "2.39"
|
||||||
LINUX_GCC_CI_VERSION = "11.0"
|
LINUX_GCC_CI_VERSION = "11.0"
|
||||||
|
LINUX_LIBSTDCXX_CI_VERSION = "6.0.30" # https://packages.ubuntu.com/jammy/libstdc++6
|
||||||
LINUX_PREFERRED_GCC_COMPILER_FORMULA = "gcc@11" # https://packages.ubuntu.com/jammy/gcc
|
LINUX_PREFERRED_GCC_COMPILER_FORMULA = "gcc@11" # https://packages.ubuntu.com/jammy/gcc
|
||||||
LINUX_PREFERRED_GCC_RUNTIME_FORMULA = "gcc"
|
LINUX_PREFERRED_GCC_RUNTIME_FORMULA = "gcc"
|
||||||
|
|
||||||
|
47
Library/Homebrew/os/linux/libstdcxx.rb
Normal file
47
Library/Homebrew/os/linux/libstdcxx.rb
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# typed: strict
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "os/linux/ld"
|
||||||
|
|
||||||
|
module OS
|
||||||
|
module Linux
|
||||||
|
# Helper functions for querying `libstdc++` information.
|
||||||
|
module Libstdcxx
|
||||||
|
SOVERSION = 6
|
||||||
|
SONAME = T.let("libstdc++.so.#{SOVERSION}".freeze, String)
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
|
def self.below_ci_version?
|
||||||
|
system_version < LINUX_LIBSTDCXX_CI_VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(Version) }
|
||||||
|
def self.system_version
|
||||||
|
@system_version ||= T.let(nil, T.nilable(Version))
|
||||||
|
@system_version ||= if (path = system_path)
|
||||||
|
Version.new("#{SOVERSION}#{path.realpath.basename.to_s.delete_prefix!(SONAME)}")
|
||||||
|
else
|
||||||
|
Version::NULL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(Pathname)) }
|
||||||
|
def self.system_path
|
||||||
|
@system_path ||= T.let(nil, T.nilable(Pathname))
|
||||||
|
@system_path ||= find_library(OS::Linux::Ld.library_paths(brewed: false))
|
||||||
|
@system_path ||= find_library(OS::Linux::Ld.system_dirs(brewed: false))
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { params(paths: T::Array[String]).returns(T.nilable(Pathname)) }
|
||||||
|
private_class_method def self.find_library(paths)
|
||||||
|
paths.each do |path|
|
||||||
|
next if path.start_with?(HOMEBREW_PREFIX)
|
||||||
|
|
||||||
|
candidate = Pathname(path)/SONAME
|
||||||
|
return candidate if candidate.exist? && candidate.elf?
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
58
Library/Homebrew/test/os/linux/libstdcxx_spec.rb
Normal file
58
Library/Homebrew/test/os/linux/libstdcxx_spec.rb
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "os/linux/libstdcxx"
|
||||||
|
|
||||||
|
RSpec.describe OS::Linux::Libstdcxx do
|
||||||
|
describe "::below_ci_version?" do
|
||||||
|
it "returns false when system version matches CI version" do
|
||||||
|
allow(described_class).to receive(:system_version).and_return(Version.new(OS::LINUX_LIBSTDCXX_CI_VERSION))
|
||||||
|
expect(described_class.below_ci_version?).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true when system version cannot be detected" do
|
||||||
|
allow(described_class).to receive(:system_version).and_return(Version::NULL)
|
||||||
|
expect(described_class.below_ci_version?).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::system_version" do
|
||||||
|
let(:tmpdir) { mktmpdir }
|
||||||
|
let(:libstdcxx) { tmpdir/described_class::SONAME }
|
||||||
|
let(:soversion) { Version.new(described_class::SOVERSION.to_s) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
tmpdir.mkpath
|
||||||
|
described_class.instance_variable_set(:@system_version, nil)
|
||||||
|
allow(described_class).to receive(:system_path).and_return(libstdcxx)
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
FileUtils.rm_rf(tmpdir)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns NULL when unable to find system path" do
|
||||||
|
allow(described_class).to receive(:system_path).and_return(nil)
|
||||||
|
expect(described_class.system_version).to be Version::NULL
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns full version from filename" do
|
||||||
|
full_version = Version.new("#{soversion}.0.999")
|
||||||
|
libstdcxx_real = libstdcxx.sub_ext(".#{full_version}")
|
||||||
|
FileUtils.touch libstdcxx_real
|
||||||
|
FileUtils.ln_s libstdcxx_real, libstdcxx
|
||||||
|
expect(described_class.system_version).to eq full_version
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns major version when non-standard libstdc++ filename without full version" do
|
||||||
|
FileUtils.touch libstdcxx
|
||||||
|
expect(described_class.system_version).to eq soversion
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns major version when non-standard libstdc++ filename with unexpected realpath" do
|
||||||
|
libstdcxx_real = tmpdir/"libstdc++.so.real"
|
||||||
|
FileUtils.touch libstdcxx_real
|
||||||
|
FileUtils.ln_s libstdcxx_real, libstdcxx
|
||||||
|
expect(described_class.system_version).to eq soversion
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user