Rollup merge of #138451 - Kobzol:gcc-ci-build-gcc, r=GuillaumeGomez

Build GCC on CI with GCC, not Clang

It seems that GCC built with Clang misbehaves. I have tested that cg_gcc tests [pass](3873275061) on CI with a downloaded GCC that was built in this way.

Prerequisite for https://github.com/rust-lang/rust/pull/138395.

r? ```@ghost```
This commit is contained in:
León Orell Valerian Liehr 2025-03-15 00:18:23 +01:00 committed by GitHub
commit fc7ac81979
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 90 additions and 44 deletions

View file

@ -2481,7 +2481,7 @@ impl Step for Gcc {
fn run(self, builder: &Builder<'_>) -> Self::Output { fn run(self, builder: &Builder<'_>) -> Self::Output {
let tarball = Tarball::new(builder, "gcc", &self.target.triple); let tarball = Tarball::new(builder, "gcc", &self.target.triple);
let output = builder.ensure(super::gcc::Gcc { target: self.target }); let output = builder.ensure(super::gcc::Gcc { target: self.target });
tarball.add_file(output.libgccjit, ".", 0o644); tarball.add_file(output.libgccjit, "lib", 0o644);
tarball.generate() tarball.generate()
} }
} }

View file

@ -63,11 +63,7 @@ impl Step for Gcc {
} }
build_gcc(&metadata, builder, target); build_gcc(&metadata, builder, target);
create_lib_alias(builder, &libgccjit_path);
let lib_alias = metadata.install_dir.join("lib/libgccjit.so.0");
if !lib_alias.exists() {
t!(builder.symlink_file(&libgccjit_path, lib_alias));
}
t!(metadata.stamp.write()); t!(metadata.stamp.write());
@ -75,6 +71,15 @@ impl Step for Gcc {
} }
} }
/// Creates a libgccjit.so.0 alias next to libgccjit.so if it does not
/// already exist
fn create_lib_alias(builder: &Builder<'_>, libgccjit: &PathBuf) {
let lib_alias = libgccjit.parent().unwrap().join("libgccjit.so.0");
if !lib_alias.exists() {
t!(builder.symlink_file(libgccjit, lib_alias));
}
}
pub struct Meta { pub struct Meta {
stamp: BuildStamp, stamp: BuildStamp,
out_dir: PathBuf, out_dir: PathBuf,
@ -109,8 +114,10 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<Pa
builder.config.download_ci_gcc(&sha, &root); builder.config.download_ci_gcc(&sha, &root);
t!(gcc_stamp.write()); t!(gcc_stamp.write());
} }
// FIXME: put libgccjit.so into a lib directory in dist::Gcc
Some(root.join("libgccjit.so")) let libgccjit = root.join("lib").join("libgccjit.so");
create_lib_alias(builder, &libgccjit);
Some(libgccjit)
} }
#[cfg(test)] #[cfg(test)]
@ -177,6 +184,14 @@ fn libgccjit_built_path(install_dir: &Path) -> PathBuf {
} }
fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
if builder.build.cc_tool(target).is_like_clang()
|| builder.build.cxx_tool(target).is_like_clang()
{
panic!(
"Attempting to build GCC using Clang, which is known to misbehave. Please use GCC as the host C/C++ compiler. "
);
}
let Meta { stamp: _, out_dir, install_dir, root } = metadata; let Meta { stamp: _, out_dir, install_dir, root } = metadata;
t!(fs::create_dir_all(out_dir)); t!(fs::create_dir_all(out_dir));
@ -203,18 +218,13 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
let mut configure_cmd = command(src_dir.join("configure")); let mut configure_cmd = command(src_dir.join("configure"));
configure_cmd configure_cmd
.current_dir(out_dir) .current_dir(out_dir)
// On CI, we compile GCC with Clang.
// The -Wno-everything flag is needed to make GCC compile with Clang 19.
// `-g -O2` are the default flags that are otherwise used by Make.
// FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml.
.env("CXXFLAGS", "-Wno-everything -g -O2")
.env("CFLAGS", "-Wno-everything -g -O2")
.arg("--enable-host-shared") .arg("--enable-host-shared")
.arg("--enable-languages=jit") .arg("--enable-languages=c,jit,lto")
.arg("--enable-checking=release") .arg("--enable-checking=release")
.arg("--disable-bootstrap") .arg("--disable-bootstrap")
.arg("--disable-multilib") .arg("--disable-multilib")
.arg(format!("--prefix={}", install_dir.display())); .arg(format!("--prefix={}", install_dir.display()));
let cc = builder.build.cc(target).display().to_string(); let cc = builder.build.cc(target).display().to_string();
let cc = builder let cc = builder
.build .build

View file

@ -27,6 +27,7 @@ use std::{env, fs, io, str};
use build_helper::ci::gha; use build_helper::ci::gha;
use build_helper::exit; use build_helper::exit;
use cc::Tool;
use termcolor::{ColorChoice, StandardStream, WriteColor}; use termcolor::{ColorChoice, StandardStream, WriteColor};
use utils::build_stamp::BuildStamp; use utils::build_stamp::BuildStamp;
use utils::channel::GitInfo; use utils::channel::GitInfo;
@ -1218,6 +1219,16 @@ Executed at: {executed_at}"#,
self.cc.borrow()[&target].path().into() self.cc.borrow()[&target].path().into()
} }
/// Returns the internal `cc::Tool` for the C compiler.
fn cc_tool(&self, target: TargetSelection) -> Tool {
self.cc.borrow()[&target].clone()
}
/// Returns the internal `cc::Tool` for the C++ compiler.
fn cxx_tool(&self, target: TargetSelection) -> Tool {
self.cxx.borrow()[&target].clone()
}
/// Returns C flags that `cc-rs` thinks should be enabled for the /// Returns C flags that `cc-rs` thinks should be enabled for the
/// specified target by default. /// specified target by default.
fn cc_handled_clags(&self, target: TargetSelection, c: CLang) -> Vec<String> { fn cc_handled_clags(&self, target: TargetSelection, c: CLang) -> Vec<String> {

View file

@ -101,7 +101,9 @@ ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \
./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \
--host $HOSTS --target $HOSTS \ --host $HOSTS --target $HOSTS \
--include-default-paths \ --include-default-paths \
build-manifest bootstrap gcc build-manifest bootstrap && \
# Use GCC for building GCC, as it seems to behave badly when built with Clang
CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
# This is the only builder which will create source tarballs # This is the only builder which will create source tarballs

View file

@ -1,3 +1,5 @@
use std::path::Path;
use anyhow::Context; use anyhow::Context;
use camino::{Utf8Path, Utf8PathBuf}; use camino::{Utf8Path, Utf8PathBuf};
@ -86,36 +88,57 @@ llvm-config = "{llvm_config}"
log::info!("Using following `config.toml` for running tests:\n{config_content}"); log::info!("Using following `config.toml` for running tests:\n{config_content}");
// Simulate a stage 0 compiler with the extracted optimized dist artifacts. // Simulate a stage 0 compiler with the extracted optimized dist artifacts.
std::fs::write("config.toml", config_content)?; with_backed_up_file(Path::new("config.toml"), &config_content, || {
let x_py = env.checkout_path().join("x.py");
let mut args = vec![
env.python_binary(),
x_py.as_str(),
"test",
"--build",
env.host_tuple(),
"--stage",
"0",
"tests/assembly",
"tests/codegen",
"tests/codegen-units",
"tests/incremental",
"tests/mir-opt",
"tests/pretty",
"tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu",
"tests/ui",
"tests/crashes",
];
for test_path in env.skipped_tests() {
args.extend(["--skip", test_path]);
}
cmd(&args)
.env("COMPILETEST_FORCE_STAGE0", "1")
// Also run dist-only tests
.env("COMPILETEST_ENABLE_DIST_TESTS", "1")
.run()
.context("Cannot execute tests")
})
}
let x_py = env.checkout_path().join("x.py"); /// Backup `path` (if it exists), then write `contents` into it, and then restore the original
let mut args = vec![ /// contents of the file.
env.python_binary(), fn with_backed_up_file<F>(path: &Path, contents: &str, func: F) -> anyhow::Result<()>
x_py.as_str(), where
"test", F: FnOnce() -> anyhow::Result<()>,
"--build", {
env.host_tuple(), let original_contents =
"--stage", if path.is_file() { Some(std::fs::read_to_string(path)?) } else { None };
"0",
"tests/assembly", // Overwrite it with new contents
"tests/codegen", std::fs::write(path, contents)?;
"tests/codegen-units",
"tests/incremental", let ret = func();
"tests/mir-opt",
"tests/pretty", if let Some(original_contents) = original_contents {
"tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu", std::fs::write(path, original_contents)?;
"tests/ui",
"tests/crashes",
];
for test_path in env.skipped_tests() {
args.extend(["--skip", test_path]);
} }
cmd(&args)
.env("COMPILETEST_FORCE_STAGE0", "1") ret
// Also run dist-only tests
.env("COMPILETEST_ENABLE_DIST_TESTS", "1")
.run()
.context("Cannot execute tests")
} }
/// Tries to find the version of the dist artifacts (either nightly, beta, or 1.XY.Z). /// Tries to find the version of the dist artifacts (either nightly, beta, or 1.XY.Z).