2 use std::path::{Path, PathBuf};
3 use std::process::{self, Command};
5 use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
6 use super::utils::{spawn_and_wait, try_hard_link};
7 use super::SysrootKind;
9 pub(crate) fn build_sysroot(
11 sysroot_kind: SysrootKind,
13 cg_clif_build_dir: &Path,
17 eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
19 if target_dir.exists() {
20 fs::remove_dir_all(target_dir).unwrap();
22 fs::create_dir_all(target_dir.join("bin")).unwrap();
23 fs::create_dir_all(target_dir.join("lib")).unwrap();
26 let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib");
27 let cg_clif_dylib_path = target_dir
28 .join(if cfg!(windows) {
29 // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
35 .join(&cg_clif_dylib);
36 try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path);
38 // Build and copy rustc and cargo wrappers
39 for wrapper in ["rustc-clif", "cargo-clif"] {
40 let wrapper_name = get_wrapper_file_name(wrapper, "bin");
42 let mut build_cargo_wrapper_cmd = Command::new("rustc");
43 build_cargo_wrapper_cmd
44 .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
46 .arg(target_dir.join(wrapper_name))
48 spawn_and_wait(build_cargo_wrapper_cmd);
51 let default_sysroot = super::rustc_info::get_default_sysroot();
53 let rustlib = target_dir.join("lib").join("rustlib");
54 let host_rustlib_lib = rustlib.join(host_triple).join("lib");
55 let target_rustlib_lib = rustlib.join(target_triple).join("lib");
56 fs::create_dir_all(&host_rustlib_lib).unwrap();
57 fs::create_dir_all(&target_rustlib_lib).unwrap();
59 if target_triple == "x86_64-pc-windows-gnu" {
60 if !default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib").exists() {
62 "The x86_64-pc-windows-gnu target needs to be installed first before it is possible \
63 to compile a sysroot for it.",
67 for file in fs::read_dir(
68 default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
72 let file = file.unwrap().path();
73 if file.extension().map_or(true, |ext| ext.to_str().unwrap() != "o") {
74 continue; // only copy object files
76 try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
81 SysrootKind::None => {} // Nothing to do
82 SysrootKind::Llvm => {
83 for file in fs::read_dir(
84 default_sysroot.join("lib").join("rustlib").join(host_triple).join("lib"),
88 let file = file.unwrap().path();
89 let file_name_str = file.file_name().unwrap().to_str().unwrap();
90 if (file_name_str.contains("rustc_")
91 && !file_name_str.contains("rustc_std_workspace_")
92 && !file_name_str.contains("rustc_demangle"))
93 || file_name_str.contains("chalk")
94 || file_name_str.contains("tracing")
95 || file_name_str.contains("regex")
97 // These are large crates that are part of the rustc-dev component and are not
98 // necessary to run regular programs.
101 try_hard_link(&file, host_rustlib_lib.join(file.file_name().unwrap()));
104 if target_triple != host_triple {
105 for file in fs::read_dir(
106 default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
110 let file = file.unwrap().path();
111 try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
115 SysrootKind::Clif => {
116 build_clif_sysroot_for_triple(
124 if host_triple != target_triple {
125 // When cross-compiling it is often necessary to manually pick the right linker
126 let linker = if target_triple == "aarch64-unknown-linux-gnu" {
127 Some("aarch64-linux-gnu-gcc")
131 build_clif_sysroot_for_triple(
140 // Copy std for the host to the lib dir. This is necessary for the jit mode to find
142 for file in fs::read_dir(host_rustlib_lib).unwrap() {
143 let file = file.unwrap().path();
144 let filename = file.file_name().unwrap().to_str().unwrap();
145 if filename.contains("std-") && !filename.contains(".rlib") {
146 try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap()));
153 fn build_clif_sysroot_for_triple(
157 cg_clif_dylib_path: &Path,
158 linker: Option<&str>,
160 match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
162 eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
163 eprintln!("Hint: Try `./y.rs prepare` to patch the sysroot source");
166 Ok(source_version) => {
167 let rustc_version = get_rustc_version();
168 if source_version != rustc_version {
169 eprintln!("The patched sysroot source is outdated");
170 eprintln!("Source version: {}", source_version.trim());
171 eprintln!("Rustc version: {}", rustc_version.trim());
172 eprintln!("Hint: Try `./y.rs prepare` to update the patched sysroot source");
178 let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
180 if !super::config::get_bool("keep_sysroot") {
181 // Cleanup the deps dir, but keep build scripts and the incremental cache for faster
182 // recompilation as they are not affected by changes in cg_clif.
183 if build_dir.join("deps").exists() {
184 fs::remove_dir_all(build_dir.join("deps")).unwrap();
189 let mut build_cmd = Command::new("cargo");
190 build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot");
191 let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
192 rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
193 if channel == "release" {
194 build_cmd.arg("--release");
195 rustflags.push_str(" -Zmir-opt-level=3");
197 if let Some(linker) = linker {
199 write!(rustflags, " -Clinker={}", linker).unwrap();
201 build_cmd.env("RUSTFLAGS", rustflags);
202 build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
203 spawn_and_wait(build_cmd);
205 // Copy all relevant files to the sysroot
207 fs::read_dir(Path::new("build_sysroot/target").join(triple).join(channel).join("deps"))
210 let entry = entry.unwrap();
211 if let Some(ext) = entry.path().extension() {
212 if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" {
220 target_dir.join("lib").join("rustlib").join(triple).join("lib").join(entry.file_name()),