Update Linux GCC code.

Update both the variables that dictate this and the documents that
explain our GCC/glibc policies.

These should ease a future migration to a newer GCC version.
This commit is contained in:
Mike McQuaid 2025-04-03 12:47:21 +01:00
parent 11426c9680
commit 2b4324af9b
No known key found for this signature in database
5 changed files with 30 additions and 19 deletions

View File

@ -102,6 +102,11 @@ class DevelopmentTools
end, T.nilable(Version))
end
sig { returns(Pathname) }
def host_gcc_path
Pathname.new("/usr/bin/gcc")
end
# Get the GCC version.
#
# @api internal

View File

@ -37,17 +37,25 @@ module OS
@needs_libc_formula = !!@needs_libc_formula
end
# Keep this method around for now to make it easier to add this functionality later.
# rubocop:disable Style/UselessMethodDefinition
sig { returns(Pathname) }
def host_gcc_path
# TODO: override this if/when we to pick the GCC based on e.g. the Ubuntu version.
super
end
# rubocop:enable Style/UselessMethodDefinition
sig { returns(T::Boolean) }
def needs_compiler_formula?
return @needs_compiler_formula unless @needs_compiler_formula.nil?
gcc = "/usr/bin/gcc"
@needs_compiler_formula = T.let(if File.exist?(gcc)
::DevelopmentTools.gcc_version(gcc) < OS::LINUX_GCC_CI_VERSION
else
true
end, T.nilable(T::Boolean))
!!@needs_compiler_formula
@needs_compiler_formula = T.let(nil, T.nilable(T::Boolean))
@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
sig { returns(T::Hash[String, T.nilable(String)]) }

View File

@ -19,7 +19,7 @@ module SystemConfig
end
def host_gcc_version
gcc = Pathname.new "/usr/bin/gcc"
gcc = DevelopmentTools.host_gcc_path
return "N/A" unless gcc.executable?
`#{gcc} --version 2>/dev/null`[/ (\d+\.\d+\.\d+)/, 1]
@ -47,7 +47,7 @@ module SystemConfig
out.puts "OS: #{OS::Linux.os_version}"
out.puts "WSL: #{OS::Linux.wsl_version}" if OS::Linux.wsl?
out.puts "Host glibc: #{host_glibc_version}"
out.puts "/usr/bin/gcc: #{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
["glibc", CompilerSelector.preferred_gcc, OS::LINUX_PREFERRED_GCC_RUNTIME_FORMULA, "xorg"].each do |f|
out.puts "#{f}: #{formula_linked_version(f)}"

View File

@ -49,7 +49,7 @@ RSpec.describe CompilerSelector do
it "returns gcc-10 if gcc formula offers gcc-10 on linux", :needs_linux do
software_spec.fails_with(:clang)
allow(Formulary).to receive(:factory)
.with("gcc@11")
.with(OS::LINUX_PREFERRED_GCC_COMPILER_FORMULA)
.and_return(instance_double(Formula, version: Version.new("10.0")))
expect(selector.compiler).to eq("gcc-10")
end
@ -59,7 +59,7 @@ RSpec.describe CompilerSelector do
software_spec.fails_with(gcc: "10")
software_spec.fails_with(gcc: "12")
allow(Formulary).to receive(:factory)
.with("gcc@11")
.with(OS::LINUX_PREFERRED_GCC_COMPILER_FORMULA)
.and_return(instance_double(Formula, version: Version.new("10.0")))
expect(selector.compiler).to eq("gcc-11")
end
@ -68,7 +68,7 @@ RSpec.describe CompilerSelector do
software_spec.fails_with(:clang)
software_spec.fails_with(:gcc) { version "11" }
allow(Formulary).to receive(:factory)
.with("gcc@11")
.with(OS::LINUX_PREFERRED_GCC_COMPILER_FORMULA)
.and_return(instance_double(Formula, version: Version.new("11.0")))
expect(selector.compiler).to eq("gcc-12")
end

View File

@ -1,5 +1,5 @@
---
last_review_date: "1970-01-01"
last_review_date: "2025-03-28"
---
# Linux CI in `homebrew/core`
@ -20,25 +20,23 @@ We have moved our CI to Ubuntu 22.04
Moving from Ubuntu 16.04 to Ubuntu 22.04 (and thus skipping version 18.04 and 20.04) took longer than expected.
We plan to proceed with regular updates from 2022 onwards. We aim to use the latest Ubuntu LTS version for our CI.
We will start using the latest Ubuntu LTS version for our CI no earlier than 3 months after its release and, ideally, no more than 12 months after its release.
We plan to proceed with regular updates from 2022 onwards. We aim to use the oldest supported Ubuntu LTS version for our CI that provides the GCC version we need.
| Distribution | Glibc | GCC | LTS standard security maintenance |
|---|---|---|---|
| Ubuntu 14.04 | 2.19 | 4 | From 2014 to 2017 |
| Ubuntu 16.04 | 2.23 | 5 | From 2017 to 2022 |
| Ubuntu 20.04 | 2.31 | 5 | From 2020 to 2025 |
| Ubuntu 22.04 | 2.35 | 11 | From 2022 to 2027 |
| Ubuntu 22.04 | 2.35 | 11 (provides 12) | From 2022 to 2027 |
| Ubuntu 24.04 | 2.39 | 13 | From 2024 to 2029 |
| Ubuntu 26.04 | ? | ? | ? |
[Source](https://ubuntu.com/about/release-cycle)
## Why always use the latest version?
## Why upgrade to a newer version?
Homebrew is a rolling-release package manager. We try to ship the newest things as quickly as possible, on macOS and Linux.
When a formula needs a newer GCC because our host GCC in CI is too old, we needed to make that formula depend on a newer Homebrew GCC. All C++ dependents of that formula immediately acquire a dependency on Homebrew GCC as well. While we have taken the steps to make sure this no longer holds up GCC updates, it still creates a maintenance burden. This problem is more likely for formula which are very actively maintained and try to use newer features of C++. We decided that we shouldn't have a maintenance burden for formulae which are doing the right thing by staying up to date. It makes a lot of sense for Homebrew maintainers to submit upstream fixes when formulae are not working with newer compilers. It makes a lot less sense for Homebrew maintainers to submit fixes because our host compiler is too old.
Note that `glibc` will need to be installed for more users as their `glibc` version will often be too old: disk space is cheap and we have can handle this situation for our users. This situation will often arise when update to a new LTS version and adoption of the new Ubuntu is still low during the first months. For the same reasons as above: we prefer to stay on the bleeding edge and give our users a gentle nudge to think about updating their OS.
Note that `glibc` will need to be installed for more users as their `glibc` version will often be too old. This is not as smooth as using a newer GCC as we don't test this configuration in CI. This is why we want to balance the newest GCC with a more conservative `glibc`.