Skip to content

Commit

Permalink
Auto merge of rust-lang#136921 - Kobzol:gcc-build, r=<try>
Browse files Browse the repository at this point in the history
Build GCC on CI

Previously, we have downloaded a specific commit of GCC and prebuilt it inside Docker using the `build-gccjit.sh` script. This PR removes that scripts and uses the bootstrap GCC step. This allows us to use the `src/gcc` submodule for determining which GCC should be built, and it also moves the logic closer to LLVM, which is also built by bootstrap.

A few things to note:
- The `sccache` option is currently in the `llvm` block, so the GCC build uses `llvm.ccache`, which is a bit weird :) We could either add `gcc.ccache`, or (what I think would be better) to just move `ccache` to the `build` section, as I don't think that it will be necessary to use ccache for LLVM, but not for GCC.
- When the GCC codegen backend is built, it needs to depend on a step that first builds GCC. This is currently done in a hacky way. The proper solution is to create a separate step for the GCC codegen backend, but that is a larger change. Let me know what you think.

r? `@onur-ozkan`

try-job: i686-msvc-1
try-job: x86_64-mingw-1
  • Loading branch information
bors committed Feb 25, 2025
2 parents 7d8c6e7 + ba7d5d1 commit 530943f
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 63 deletions.
3 changes: 2 additions & 1 deletion license-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"directories": [],
"files": [
"analyzer-decls.h",
"malloc-macro.h"
"malloc-macro.h",
"sarif-path-role.h"
],
"license": {
"copyright": [
Expand Down
9 changes: 9 additions & 0 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,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::tool::SourceType;
use crate::core::build_steps::{dist, llvm};
use crate::core::builder;
Expand Down Expand Up @@ -1614,6 +1615,14 @@ impl Step for CodegenBackend {
.arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
rustc_cargo_env(builder, &mut cargo, target, compiler.stage);

// Ideally, we'd have a separate step for the individual codegen backends,
// like we have in tests (test::CodegenGCC) but that would require a lot of restructuring.
// If the logic gets more complicated, it should probably be done.
if backend == "gcc" {
let gcc = builder.ensure(Gcc { target });
add_cg_gcc_cargo_flags(&mut cargo, &gcc);
}

let tmp_stamp = BuildStamp::new(&out_dir).with_prefix("tmp");

let _guard = builder.msg_build(compiler, format_args!("codegen backend {backend}"), target);
Expand Down
51 changes: 37 additions & 14 deletions src/bootstrap/src/core/build_steps/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
//! ensure that they're always in place if needed.
use std::fs;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::sync::OnceLock;

use build_helper::ci::CiEnv;

use crate::Kind;
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::core::builder::{Builder, Cargo, RunConfig, ShouldRun, Step};
use crate::core::config::TargetSelection;
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
use crate::utils::exec::command;
Expand All @@ -29,7 +29,8 @@ pub struct Meta {
}

pub enum GccBuildStatus {
AlreadyBuilt,
/// libgccjit is already built at this path
AlreadyBuilt(PathBuf),
ShouldBuild(Meta),
}

Expand All @@ -41,9 +42,6 @@ pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> Gc
// Initialize the gcc submodule if not initialized already.
builder.config.update_submodule("src/gcc");

// FIXME (GuillaumeGomez): To be done once gccjit has been built in the CI.
// builder.config.maybe_download_ci_gcc();

let root = builder.src.join("src/gcc");
let out_dir = builder.gcc_out(target).join("build");
let install_dir = builder.gcc_out(target).join("install");
Expand All @@ -70,19 +68,37 @@ pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> Gc
stamp.path().display()
));
}
return GccBuildStatus::AlreadyBuilt;
let path = libgccjit_built_path(&install_dir);
if path.is_file() {
return GccBuildStatus::AlreadyBuilt(path);
} else {
builder.info(&format!(
"GCC stamp is up-to-date, but the libgccjit.so file was not found at `{}`",
path.display(),
));
}
}

GccBuildStatus::ShouldBuild(Meta { stamp, out_dir, install_dir, root })
}

/// Returns the path to a libgccjit.so file in the install directory of GCC.
fn libgccjit_built_path(install_dir: &Path) -> PathBuf {
install_dir.join("lib/libgccjit.so")
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Gcc {
pub target: TargetSelection,
}

#[derive(Clone)]
pub struct GccOutput {
pub libgccjit: PathBuf,
}

impl Step for Gcc {
type Output = bool;
type Output = GccOutput;

const ONLY_HOSTS: bool = true;

Expand All @@ -94,14 +110,14 @@ impl Step for Gcc {
run.builder.ensure(Gcc { target: run.target });
}

/// Compile GCC for `target`.
fn run(self, builder: &Builder<'_>) -> bool {
/// Compile GCC (specifically `libgccjit`) for `target`.
fn run(self, builder: &Builder<'_>) -> Self::Output {
let target = self.target;

// If GCC has already been built, we avoid building it again.
let Meta { stamp, out_dir, install_dir, root } = match prebuilt_gcc_config(builder, target)
{
GccBuildStatus::AlreadyBuilt => return true,
GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path },
GccBuildStatus::ShouldBuild(m) => m,
};

Expand All @@ -110,8 +126,9 @@ impl Step for Gcc {
let _time = helpers::timeit(builder);
t!(fs::create_dir_all(&out_dir));

let libgccjit_path = libgccjit_built_path(&install_dir);
if builder.config.dry_run() {
return true;
return GccOutput { libgccjit: libgccjit_path };
}

// GCC creates files (e.g. symlinks to the downloaded dependencies)
Expand Down Expand Up @@ -173,11 +190,17 @@ impl Step for Gcc {

let lib_alias = install_dir.join("lib/libgccjit.so.0");
if !lib_alias.exists() {
t!(builder.symlink_file(install_dir.join("lib/libgccjit.so"), lib_alias,));
t!(builder.symlink_file(&libgccjit_path, lib_alias));
}

t!(stamp.write());

true
GccOutput { libgccjit: libgccjit_path }
}
}

/// Configures a Cargo invocation so that it can build the GCC codegen backend.
pub fn add_cg_gcc_cargo_flags(cargo: &mut Cargo, gcc: &GccOutput) {
// Add the path to libgccjit.so to the linker search paths.
cargo.rustflag(&format!("-L{}", gcc.libgccjit.parent().unwrap().to_str().unwrap()));
}
7 changes: 6 additions & 1 deletion src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use clap_complete::shells;

use crate::core::build_steps::compile::run_cargo;
use crate::core::build_steps::doc::DocumentationFormat;
use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
use crate::core::build_steps::llvm::get_llvm_version;
use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
use crate::core::build_steps::tool::{self, SourceType, Tool};
Expand Down Expand Up @@ -3531,6 +3532,8 @@ impl Step for CodegenGCC {
let compiler = self.compiler;
let target = self.target;

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

builder.ensure(
compile::Std::new(compiler, target)
.extra_rust_args(&["-Csymbol-mangling-version=v0", "-Cpanic=abort"]),
Expand All @@ -3557,6 +3560,7 @@ impl Step for CodegenGCC {
.arg("--manifest-path")
.arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml"));
compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
add_cg_gcc_cargo_flags(&mut cargo, &gcc);

// Avoid incremental cache issues when changing rustc
cargo.env("CARGO_BUILD_INCREMENTAL", "false");
Expand Down Expand Up @@ -3589,9 +3593,10 @@ impl Step for CodegenGCC {
.env("CG_RUSTFLAGS", "-Alinker-messages")
.arg("--")
.arg("test")
.arg("--use-system-gcc")
.arg("--use-backend")
.arg("gcc")
.arg("--gcc-path")
.arg(gcc.libgccjit.parent().unwrap())
.arg("--out-dir")
.arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_gcc"))
.arg("--release")
Expand Down
4 changes: 1 addition & 3 deletions src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM ubuntu:24.04
ARG DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y --no-install-recommends \
bzip2 \
g++ \
gcc-multilib \
make \
Expand Down Expand Up @@ -55,9 +56,6 @@ ENV RUST_CONFIGURE_ARGS \
--set rust.thin-lto-import-instr-limit=10

COPY scripts/shared.sh /scripts/
COPY scripts/build-gccjit.sh /scripts/

RUN /scripts/build-gccjit.sh /scripts

ARG SCRIPT_ARG

Expand Down
3 changes: 0 additions & 3 deletions src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ ENV RUST_CONFIGURE_ARGS \
--set rust.thin-lto-import-instr-limit=10

COPY scripts/shared.sh /scripts/
COPY scripts/build-gccjit.sh /scripts/

RUN /scripts/build-gccjit.sh /scripts

ARG SCRIPT_ARG

Expand Down
3 changes: 0 additions & 3 deletions src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,6 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu
#ENV FORCE_CI_RUSTC 1

COPY scripts/shared.sh /scripts/
COPY scripts/build-gccjit.sh /scripts/

RUN /scripts/build-gccjit.sh /scripts

# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
# to create a new folder. For reference:
Expand Down
37 changes: 0 additions & 37 deletions src/ci/docker/scripts/build-gccjit.sh

This file was deleted.

2 changes: 1 addition & 1 deletion src/gcc
Submodule gcc updated 19134 files

0 comments on commit 530943f

Please sign in to comment.