bootstrap/core/build_steps/
gcc.rs
1use std::fs;
12use std::path::PathBuf;
13use std::sync::OnceLock;
14
15use build_helper::ci::CiEnv;
16
17use crate::Kind;
18use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
19use crate::core::config::TargetSelection;
20use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
21use crate::utils::exec::command;
22use crate::utils::helpers::{self, t};
23
24pub struct Meta {
25 stamp: BuildStamp,
26 out_dir: PathBuf,
27 install_dir: PathBuf,
28 root: PathBuf,
29}
30
31pub enum GccBuildStatus {
32 AlreadyBuilt,
33 ShouldBuild(Meta),
34}
35
36pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus {
41 builder.config.update_submodule("src/gcc");
43
44 let root = builder.src.join("src/gcc");
48 let out_dir = builder.gcc_out(target).join("build");
49 let install_dir = builder.gcc_out(target).join("install");
50
51 static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
52 let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
53 generate_smart_stamp_hash(
54 builder,
55 &builder.config.src.join("src/gcc"),
56 builder.in_tree_gcc_info.sha().unwrap_or_default(),
57 )
58 });
59
60 let stamp = BuildStamp::new(&out_dir).with_prefix("gcc").add_stamp(smart_stamp_hash);
61
62 if stamp.is_up_to_date() {
63 if stamp.stamp().is_empty() {
64 builder.info(
65 "Could not determine the GCC submodule commit hash. \
66 Assuming that an GCC rebuild is not necessary.",
67 );
68 builder.info(&format!(
69 "To force GCC to rebuild, remove the file `{}`",
70 stamp.path().display()
71 ));
72 }
73 return GccBuildStatus::AlreadyBuilt;
74 }
75
76 GccBuildStatus::ShouldBuild(Meta { stamp, out_dir, install_dir, root })
77}
78
79#[derive(Debug, Clone, Hash, PartialEq, Eq)]
80pub struct Gcc {
81 pub target: TargetSelection,
82}
83
84impl Step for Gcc {
85 type Output = bool;
86
87 const ONLY_HOSTS: bool = true;
88
89 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
90 run.path("src/gcc").alias("gcc")
91 }
92
93 fn make_run(run: RunConfig<'_>) {
94 run.builder.ensure(Gcc { target: run.target });
95 }
96
97 fn run(self, builder: &Builder<'_>) -> bool {
99 let target = self.target;
100
101 let Meta { stamp, out_dir, install_dir, root } = match prebuilt_gcc_config(builder, target)
103 {
104 GccBuildStatus::AlreadyBuilt => return true,
105 GccBuildStatus::ShouldBuild(m) => m,
106 };
107
108 let _guard = builder.msg_unstaged(Kind::Build, "GCC", target);
109 t!(stamp.remove());
110 let _time = helpers::timeit(builder);
111 t!(fs::create_dir_all(&out_dir));
112
113 if builder.config.dry_run() {
114 return true;
115 }
116
117 let src_dir = if CiEnv::is_ci() {
123 let src_dir = builder.gcc_out(target).join("src");
124 if src_dir.exists() {
125 builder.remove_dir(&src_dir);
126 }
127 builder.create_dir(&src_dir);
128 builder.cp_link_r(&root, &src_dir);
129 src_dir
130 } else {
131 root
132 };
133
134 command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder);
135 let mut configure_cmd = command(src_dir.join("configure"));
136 configure_cmd
137 .current_dir(&out_dir)
138 .env("CXXFLAGS", "-Wno-everything -g -O2")
143 .env("CFLAGS", "-Wno-everything -g -O2")
144 .arg("--enable-host-shared")
145 .arg("--enable-languages=jit")
146 .arg("--enable-checking=release")
147 .arg("--disable-bootstrap")
148 .arg("--disable-multilib")
149 .arg(format!("--prefix={}", install_dir.display()));
150 let cc = builder.build.cc(target).display().to_string();
151 let cc = builder
152 .build
153 .config
154 .ccache
155 .as_ref()
156 .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}"));
157 configure_cmd.env("CC", cc);
158
159 if let Ok(ref cxx) = builder.build.cxx(target) {
160 let cxx = cxx.display().to_string();
161 let cxx = builder
162 .build
163 .config
164 .ccache
165 .as_ref()
166 .map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}"));
167 configure_cmd.env("CXX", cxx);
168 }
169 configure_cmd.run(builder);
170
171 command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder);
172 command("make").current_dir(&out_dir).arg("install").run(builder);
173
174 let lib_alias = install_dir.join("lib/libgccjit.so.0");
175 if !lib_alias.exists() {
176 t!(builder.symlink_file(install_dir.join("lib/libgccjit.so"), lib_alias,));
177 }
178
179 t!(stamp.write());
180
181 true
182 }
183}