Migrate Linux to GCC 12 and check libstdc++

* Update Dockerfile to install `g++12`
* Check version of host libstdc++ for runtime dependency
This commit is contained in:
Michael Cho 2025-08-30 12:03:37 -04:00
parent 47e07fb269
commit 5ef3bb32a6
No known key found for this signature in database
GPG Key ID: 55E85E28A7CD1E85
7 changed files with 73 additions and 16 deletions

View File

@ -45,6 +45,7 @@ RUN apt-get update \
tzdata \ tzdata \
jq \ jq \
&& if [ "$(. /etc/lsb-release; echo "${DISTRIB_RELEASE}" | cut -d. -f1)" -ge 22 ]; then apt-get install -y --no-install-recommends skopeo; fi \ && if [ "$(. /etc/lsb-release; echo "${DISTRIB_RELEASE}" | cut -d. -f1)" -ge 22 ]; then apt-get install -y --no-install-recommends skopeo; fi \
&& if [ "$(. /etc/lsb-release; echo "${DISTRIB_RELEASE}" | cut -d. -f1)" -eq 22 ]; then apt-get install -y --no-install-recommends gcc-12 g++-12; fi \
&& mkdir -p /etc/apt/keyrings \ && mkdir -p /etc/apt/keyrings \
&& chmod 0755 /etc /etc/apt /etc/apt/keyrings \ && chmod 0755 /etc /etc/apt /etc/apt/keyrings \
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null \ && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null \

View File

@ -43,13 +43,14 @@ module OS
end end
# Keep this method around for now to make it easier to add this functionality later. # 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 +61,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)]) }

View File

@ -1,6 +1,7 @@
# typed: strict # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
require "os/linux/libstdcxx"
require "utils/output" require "utils/output"
module OS module OS
@ -25,12 +26,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)

View File

@ -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

View File

@ -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|

View File

@ -49,8 +49,10 @@ module OS
LINUX_CI_OS_VERSION = "Ubuntu 22.04" LINUX_CI_OS_VERSION = "Ubuntu 22.04"
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 = "12" # https://packages.ubuntu.com/jammy/gcc-12
LINUX_PREFERRED_GCC_COMPILER_FORMULA = "gcc@11" # https://packages.ubuntu.com/jammy/gcc LINUX_LIBSTDCXX_CI_VERSION = "6.0.30" # https://packages.ubuntu.com/jammy/libstdc++6
LINUX_LIBSTDCXX_NEXT_CI_VERSION = "6.0.33" # https://packages.ubuntu.com/noble/libstdc++6
LINUX_PREFERRED_GCC_COMPILER_FORMULA = T.let("gcc@#{LINUX_GCC_CI_VERSION}".freeze, String)
LINUX_PREFERRED_GCC_RUNTIME_FORMULA = "gcc" LINUX_PREFERRED_GCC_RUNTIME_FORMULA = "gcc"
if OS.mac? if OS.mac?

View File

@ -0,0 +1,47 @@
# typed: strict
# frozen_string_literal: true
module OS
module Linux
# Helper functions for querying libstdc++ information.
module Libstdcxx
SONAME = "libstdc++.so.6"
SYSTEM_LIBDIRS = %w[/lib64 /lib /usr/lib64 /usr/lib].freeze
private_constant :SYSTEM_LIBDIRS
sig { returns(Version) }
def self.system_version
@system_version ||= T.let(nil, T.nilable(Version))
@system_version ||= if (path = system_path) &&
(version = File.realpath(path)[%r{/libstdc\+\+\.so\.(\d+(?:\.\d+)*)$}, 1])
Version.new(version)
else
Version::NULL
end
end
sig { returns(T::Boolean) }
def self.below_ci_version?
system_version < LINUX_LIBSTDCXX_CI_VERSION
end
sig { returns(T.nilable(String)) }
private_class_method def self.system_path
if (ldconfig = which("ldconfig"))
path = Utils.popen_read(ldconfig, "-p")[%r{=> (/.*/#{Regexp.escape(SONAME)})$}o, 1]
return path if path.present? && File.file?(path) && Pathname(path).dylib?
end
if (gcc = ::DevelopmentTools.host_gcc_path).executable?
path = Utils.popen_read(gcc, "--print-file-name=#{SONAME}").strip
return path if path.start_with?("/") && File.file?(path) && Pathname(path).dylib?
end
libdirs = SYSTEM_LIBDIRS.filter_map { |path| File.realpath(path) if File.directory?(path) }
libdirs.uniq!
Find.find(*libdirs).find do |path|
path = Pathname(path)
path.basename.to_s == SONAME && path.file? && path.dylib? && path.arch_compatible?(::Hardware::CPU.arch)
end
end
end
end
end