Skip to content

Commit 53237c8

Browse files
committed
Refactor GCC compilation
1 parent 2c6a12e commit 53237c8

File tree

1 file changed

+112
-105
lines changed
  • src/bootstrap/src/core/build_steps

1 file changed

+112
-105
lines changed

Diff for: src/bootstrap/src/core/build_steps/gcc.rs

+112-105
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,68 @@ use std::sync::OnceLock;
1414

1515
use build_helper::ci::CiEnv;
1616

17-
use crate::Kind;
18-
use crate::core::builder::{Builder, Cargo, RunConfig, ShouldRun, Step};
17+
use crate::Config;
18+
use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step};
1919
use crate::core::config::TargetSelection;
2020
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
2121
use crate::utils::exec::command;
2222
use crate::utils::helpers::{self, t};
2323

24+
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
25+
pub struct Gcc {
26+
pub target: TargetSelection,
27+
}
28+
29+
#[derive(Clone)]
30+
pub struct GccOutput {
31+
pub libgccjit: PathBuf,
32+
}
33+
34+
impl Step for Gcc {
35+
type Output = GccOutput;
36+
37+
const ONLY_HOSTS: bool = true;
38+
39+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
40+
run.path("src/gcc").alias("gcc")
41+
}
42+
43+
fn make_run(run: RunConfig<'_>) {
44+
run.builder.ensure(Gcc { target: run.target });
45+
}
46+
47+
/// Compile GCC (specifically `libgccjit`) for `target`.
48+
fn run(self, builder: &Builder<'_>) -> Self::Output {
49+
let target = self.target;
50+
51+
// If GCC has already been built, we avoid building it again.
52+
let metadata = match get_gcc_build_status(builder, target) {
53+
GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path },
54+
GccBuildStatus::ShouldBuild(m) => m,
55+
};
56+
57+
let _guard = builder.msg_unstaged(Kind::Build, "GCC", target);
58+
t!(metadata.stamp.remove());
59+
let _time = helpers::timeit(builder);
60+
61+
let libgccjit_path = libgccjit_built_path(&metadata.install_dir);
62+
if builder.config.dry_run() {
63+
return GccOutput { libgccjit: libgccjit_path };
64+
}
65+
66+
build_gcc(&metadata, builder, target);
67+
68+
let lib_alias = metadata.install_dir.join("lib/libgccjit.so.0");
69+
if !lib_alias.exists() {
70+
t!(builder.symlink_file(&libgccjit_path, lib_alias));
71+
}
72+
73+
t!(metadata.stamp.write());
74+
75+
GccOutput { libgccjit: libgccjit_path }
76+
}
77+
}
78+
2479
pub struct Meta {
2580
stamp: BuildStamp,
2681
out_dir: PathBuf,
@@ -38,7 +93,7 @@ pub enum GccBuildStatus {
3893
///
3994
/// It's used to avoid busting caches during x.py check -- if we've already built
4095
/// GCC, it's fine for us to not try to avoid doing so.
41-
pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus {
96+
pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus {
4297
// Initialize the gcc submodule if not initialized already.
4398
builder.config.update_submodule("src/gcc");
4499

@@ -87,104 +142,65 @@ fn libgccjit_built_path(install_dir: &Path) -> PathBuf {
87142
install_dir.join("lib/libgccjit.so")
88143
}
89144

90-
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
91-
pub struct Gcc {
92-
pub target: TargetSelection,
93-
}
94-
95-
#[derive(Clone)]
96-
pub struct GccOutput {
97-
pub libgccjit: PathBuf,
98-
}
99-
100-
impl Step for Gcc {
101-
type Output = GccOutput;
102-
103-
const ONLY_HOSTS: bool = true;
104-
105-
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
106-
run.path("src/gcc").alias("gcc")
107-
}
108-
109-
fn make_run(run: RunConfig<'_>) {
110-
run.builder.ensure(Gcc { target: run.target });
111-
}
112-
113-
/// Compile GCC (specifically `libgccjit`) for `target`.
114-
fn run(self, builder: &Builder<'_>) -> Self::Output {
115-
let target = self.target;
116-
117-
// If GCC has already been built, we avoid building it again.
118-
let Meta { stamp, out_dir, install_dir, root } = match prebuilt_gcc_config(builder, target)
119-
{
120-
GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path },
121-
GccBuildStatus::ShouldBuild(m) => m,
122-
};
123-
124-
let _guard = builder.msg_unstaged(Kind::Build, "GCC", target);
125-
t!(stamp.remove());
126-
let _time = helpers::timeit(builder);
127-
t!(fs::create_dir_all(&out_dir));
128-
t!(fs::create_dir_all(&install_dir));
129-
130-
let libgccjit_path = libgccjit_built_path(&install_dir);
131-
if builder.config.dry_run() {
132-
return GccOutput { libgccjit: libgccjit_path };
145+
fn build_gcc(metadata: &Meta, builder: &Builder, target: TargetSelection) {
146+
let Meta { stamp: _, out_dir, install_dir, root } = metadata;
147+
148+
t!(fs::create_dir_all(out_dir));
149+
t!(fs::create_dir_all(install_dir));
150+
151+
// GCC creates files (e.g. symlinks to the downloaded dependencies)
152+
// in the source directory, which does not work with our CI setup, where we mount
153+
// source directories as read-only on Linux.
154+
// Therefore, as a part of the build in CI, we first copy the whole source directory
155+
// to the build directory, and perform the build from there.
156+
let src_dir = if CiEnv::is_ci() {
157+
let src_dir = builder.gcc_out(target).join("src");
158+
if src_dir.exists() {
159+
builder.remove_dir(&src_dir);
133160
}
134-
135-
// GCC creates files (e.g. symlinks to the downloaded dependencies)
136-
// in the source directory, which does not work with our CI setup, where we mount
137-
// source directories as read-only on Linux.
138-
// Therefore, as a part of the build in CI, we first copy the whole source directory
139-
// to the build directory, and perform the build from there.
140-
let src_dir = if CiEnv::is_ci() {
141-
let src_dir = builder.gcc_out(target).join("src");
142-
if src_dir.exists() {
143-
builder.remove_dir(&src_dir);
144-
}
145-
builder.create_dir(&src_dir);
146-
builder.cp_link_r(&root, &src_dir);
147-
src_dir
148-
} else {
149-
root
150-
};
151-
152-
command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder);
153-
let mut configure_cmd = command(src_dir.join("configure"));
154-
configure_cmd
155-
.current_dir(&out_dir)
156-
// On CI, we compile GCC with Clang.
157-
// The -Wno-everything flag is needed to make GCC compile with Clang 19.
158-
// `-g -O2` are the default flags that are otherwise used by Make.
159-
// FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml.
160-
.env("CXXFLAGS", "-Wno-everything -g -O2")
161-
.env("CFLAGS", "-Wno-everything -g -O2")
162-
.arg("--enable-host-shared")
163-
.arg("--enable-languages=jit")
164-
.arg("--enable-checking=release")
165-
.arg("--disable-bootstrap")
166-
.arg("--disable-multilib")
167-
.arg(format!("--prefix={}", install_dir.display()));
168-
let cc = builder.build.cc(target).display().to_string();
169-
let cc = builder
161+
builder.create_dir(&src_dir);
162+
builder.cp_link_r(root, &src_dir);
163+
src_dir
164+
} else {
165+
root.clone()
166+
};
167+
168+
command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder);
169+
let mut configure_cmd = command(src_dir.join("configure"));
170+
configure_cmd
171+
.current_dir(out_dir)
172+
// On CI, we compile GCC with Clang.
173+
// The -Wno-everything flag is needed to make GCC compile with Clang 19.
174+
// `-g -O2` are the default flags that are otherwise used by Make.
175+
// FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml.
176+
.env("CXXFLAGS", "-Wno-everything -g -O2")
177+
.env("CFLAGS", "-Wno-everything -g -O2")
178+
.arg("--enable-host-shared")
179+
.arg("--enable-languages=jit")
180+
.arg("--enable-checking=release")
181+
.arg("--disable-bootstrap")
182+
.arg("--disable-multilib")
183+
.arg(format!("--prefix={}", install_dir.display()));
184+
let cc = builder.build.cc(target).display().to_string();
185+
let cc = builder
186+
.build
187+
.config
188+
.ccache
189+
.as_ref()
190+
.map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}"));
191+
configure_cmd.env("CC", cc);
192+
193+
if let Ok(ref cxx) = builder.build.cxx(target) {
194+
let cxx = cxx.display().to_string();
195+
let cxx = builder
170196
.build
171197
.config
172198
.ccache
173199
.as_ref()
174-
.map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}"));
175-
configure_cmd.env("CC", cc);
176-
177-
if let Ok(ref cxx) = builder.build.cxx(target) {
178-
let cxx = cxx.display().to_string();
179-
let cxx = builder
180-
.build
181-
.config
182-
.ccache
183-
.as_ref()
184-
.map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}"));
185-
configure_cmd.env("CXX", cxx);
186-
}
187-
configure_cmd.run(builder);
200+
.map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}"));
201+
configure_cmd.env("CXX", cxx);
202+
}
203+
configure_cmd.run(builder);
188204

189205
command("make")
190206
.current_dir(&out_dir)
@@ -196,15 +212,6 @@ impl Step for Gcc {
196212
.arg("--silent")
197213
.arg("install")
198214
.run_capture_stdout(builder);
199-
200-
let lib_alias = install_dir.join("lib/libgccjit.so.0");
201-
if !lib_alias.exists() {
202-
t!(builder.symlink_file(&libgccjit_path, lib_alias));
203-
}
204-
205-
t!(stamp.write());
206-
207-
GccOutput { libgccjit: libgccjit_path }
208215
}
209216
}
210217

0 commit comments

Comments
 (0)