Skip to content

Install libgccjit into the compiler's sysroot when cg_gcc is enabled #145341

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 13, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 69 additions & 55 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use serde_derive::Deserialize;
#[cfg(feature = "tracing")]
use tracing::{instrument, span};

use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
use crate::core::build_steps::gcc::{Gcc, GccOutput, add_cg_gcc_cargo_flags};
use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};
use crate::core::build_steps::{dist, llvm};
use crate::core::builder;
Expand Down Expand Up @@ -1543,13 +1543,22 @@ impl Step for RustcLink {
}
}

/// Output of the `compile::GccCodegenBackend` step.
/// It includes the path to the libgccjit library on which this backend depends.
#[derive(Clone)]
pub struct GccCodegenBackendOutput {
stamp: BuildStamp,
gcc: GccOutput,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GccCodegenBackend {
compilers: RustcPrivateCompilers,
}

impl Step for GccCodegenBackend {
type Output = BuildStamp;
type Output = GccCodegenBackendOutput;

const ONLY_HOSTS: bool = true;

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
Expand Down Expand Up @@ -1584,6 +1593,8 @@ impl Step for GccCodegenBackend {
&CodegenBackendKind::Gcc,
);

let gcc = builder.ensure(Gcc { target });

if builder.config.keep_stage.contains(&build_compiler.stage) {
trace!("`keep-stage` requested");
builder.info(
Expand All @@ -1592,7 +1603,7 @@ impl Step for GccCodegenBackend {
);
// Codegen backends are linked separately from this step today, so we don't do
// anything here.
return stamp;
return GccCodegenBackendOutput { stamp, gcc };
}

let mut cargo = builder::Cargo::new(
Expand All @@ -1606,13 +1617,16 @@ impl Step for GccCodegenBackend {
cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
rustc_cargo_env(builder, &mut cargo, target);

let gcc = builder.ensure(Gcc { target });
add_cg_gcc_cargo_flags(&mut cargo, &gcc);

let _guard =
builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target);
let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
write_codegen_backend_stamp(stamp, files, builder.config.dry_run())

GccCodegenBackendOutput {
stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),
gcc,
}
}

fn metadata(&self) -> Option<StepMetadata> {
Expand Down Expand Up @@ -2191,53 +2205,6 @@ impl Step for Assemble {
);
build_compiler.stage = actual_stage;

let mut codegen_backend_stamps = vec![];
{
#[cfg(feature = "tracing")]
let _codegen_backend_span =
span!(tracing::Level::DEBUG, "building requested codegen backends").entered();

for backend in builder.config.enabled_codegen_backends(target_compiler.host) {
// FIXME: this is a horrible hack used to make `x check` work when other codegen
// backends are enabled.
// `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot.
// Then it checks codegen backends, which correctly use these rmetas.
// Then it needs to check std, but for that it needs to build stage 1 rustc.
// This copies the build rmetas into the stage0 sysroot, effectively poisoning it,
// because we then have both check and build rmetas in the same sysroot.
// That would be fine on its own. However, when another codegen backend is enabled,
// then building stage 1 rustc implies also building stage 1 codegen backend (even if
// it isn't used for anything). And since that tries to use the poisoned
// rmetas, it fails to build.
// We don't actually need to build rustc-private codegen backends for checking std,
// so instead we skip that.
// Note: this would be also an issue for other rustc-private tools, but that is "solved"
// by check::Std being last in the list of checked things (see
// `Builder::get_step_descriptions`).
if builder.kind == Kind::Check && builder.top_stage == 1 {
continue;
}

let prepare_compilers = || {
RustcPrivateCompilers::from_build_and_target_compiler(
build_compiler,
target_compiler,
)
};

let stamp = match backend {
CodegenBackendKind::Cranelift => {
builder.ensure(CraneliftCodegenBackend { compilers: prepare_compilers() })
}
CodegenBackendKind::Gcc => {
builder.ensure(GccCodegenBackend { compilers: prepare_compilers() })
}
CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
};
codegen_backend_stamps.push(stamp);
}
}

let stage = target_compiler.stage;
let host = target_compiler.host;
let (host_info, dir_name) = if build_compiler.host == host {
Expand Down Expand Up @@ -2296,9 +2263,56 @@ impl Step for Assemble {
}
}

debug!("copying codegen backends to sysroot");
for stamp in codegen_backend_stamps {
copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
{
#[cfg(feature = "tracing")]
let _codegen_backend_span =
span!(tracing::Level::DEBUG, "building requested codegen backends").entered();

for backend in builder.config.enabled_codegen_backends(target_compiler.host) {
// FIXME: this is a horrible hack used to make `x check` work when other codegen
// backends are enabled.
// `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot.
// Then it checks codegen backends, which correctly use these rmetas.
// Then it needs to check std, but for that it needs to build stage 1 rustc.
// This copies the build rmetas into the stage0 sysroot, effectively poisoning it,
// because we then have both check and build rmetas in the same sysroot.
// That would be fine on its own. However, when another codegen backend is enabled,
// then building stage 1 rustc implies also building stage 1 codegen backend (even if
// it isn't used for anything). And since that tries to use the poisoned
// rmetas, it fails to build.
// We don't actually need to build rustc-private codegen backends for checking std,
// so instead we skip that.
// Note: this would be also an issue for other rustc-private tools, but that is "solved"
// by check::Std being last in the list of checked things (see
// `Builder::get_step_descriptions`).
if builder.kind == Kind::Check && builder.top_stage == 1 {
continue;
}

let prepare_compilers = || {
RustcPrivateCompilers::from_build_and_target_compiler(
build_compiler,
target_compiler,
)
};

match backend {
CodegenBackendKind::Cranelift => {
let stamp = builder
.ensure(CraneliftCodegenBackend { compilers: prepare_compilers() });
copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
}
CodegenBackendKind::Gcc => {
let output =
builder.ensure(GccCodegenBackend { compilers: prepare_compilers() });
copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler);
// Also copy libgccjit to the library sysroot, so that it is available for
// the codegen backend.
output.gcc.install_to(builder, &rustc_libdir);
}
CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
}
}
}

if builder.config.lld_enabled {
Expand Down
13 changes: 13 additions & 0 deletions src/bootstrap/src/core/build_steps/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::fs;
use std::path::{Path, PathBuf};
use std::sync::OnceLock;

use crate::FileType;
use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step};
use crate::core::config::TargetSelection;
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
Expand All @@ -28,6 +29,18 @@ pub struct GccOutput {
pub libgccjit: PathBuf,
}

impl GccOutput {
/// Install the required libgccjit library file(s) to the specified `path`.
pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) {
let dst = directory.join(self.libgccjit.file_name().unwrap());
builder.install(&self.libgccjit, directory, FileType::NativeLibrary);
// FIXME: try to remove the alias, it shouldn't be needed
// We just have to teach rustc_codegen_gcc to link to libgccjit.so directly, instead of
// linking to libgccjit.so.0.
create_lib_alias(builder, &dst);
}
}

impl Step for Gcc {
type Output = GccOutput;

Expand Down
Loading