]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
Rollup merge of #101011 - BlackHoleFox:apple-random-improvements, r=thomcc
[rust.git] / compiler / rustc_codegen_cranelift / build_system / build_sysroot.rs
1 use std::fs;
2 use std::path::{Path, PathBuf};
3 use std::process::{self, Command};
4
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;
8
9 pub(crate) fn build_sysroot(
10     channel: &str,
11     sysroot_kind: SysrootKind,
12     target_dir: &Path,
13     cg_clif_build_dir: &Path,
14     host_triple: &str,
15     target_triple: &str,
16 ) {
17     eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
18
19     if target_dir.exists() {
20         fs::remove_dir_all(target_dir).unwrap();
21     }
22     fs::create_dir_all(target_dir.join("bin")).unwrap();
23     fs::create_dir_all(target_dir.join("lib")).unwrap();
24
25     // Copy the backend
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
30             // binaries.
31             "bin"
32         } else {
33             "lib"
34         })
35         .join(&cg_clif_dylib);
36     try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path);
37
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");
41
42         let mut build_cargo_wrapper_cmd = Command::new("rustc");
43         build_cargo_wrapper_cmd
44             .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
45             .arg("-o")
46             .arg(target_dir.join(wrapper_name))
47             .arg("-g");
48         spawn_and_wait(build_cargo_wrapper_cmd);
49     }
50
51     let default_sysroot = super::rustc_info::get_default_sysroot();
52
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();
58
59     if target_triple == "x86_64-pc-windows-gnu" {
60         if !default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib").exists() {
61             eprintln!(
62                 "The x86_64-pc-windows-gnu target needs to be installed first before it is possible \
63                 to compile a sysroot for it.",
64             );
65             process::exit(1);
66         }
67         for file in fs::read_dir(
68             default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
69         )
70         .unwrap()
71         {
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
75             }
76             try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
77         }
78     }
79
80     match sysroot_kind {
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"),
85             )
86             .unwrap()
87             {
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")
96                 {
97                     // These are large crates that are part of the rustc-dev component and are not
98                     // necessary to run regular programs.
99                     continue;
100                 }
101                 try_hard_link(&file, host_rustlib_lib.join(file.file_name().unwrap()));
102             }
103
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"),
107                 )
108                 .unwrap()
109                 {
110                     let file = file.unwrap().path();
111                     try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
112                 }
113             }
114         }
115         SysrootKind::Clif => {
116             build_clif_sysroot_for_triple(
117                 channel,
118                 target_dir,
119                 host_triple,
120                 &cg_clif_dylib_path,
121                 None,
122             );
123
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")
128                 } else {
129                     None
130                 };
131                 build_clif_sysroot_for_triple(
132                     channel,
133                     target_dir,
134                     target_triple,
135                     &cg_clif_dylib_path,
136                     linker,
137                 );
138             }
139
140             // Copy std for the host to the lib dir. This is necessary for the jit mode to find
141             // libstd.
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()));
147                 }
148             }
149         }
150     }
151 }
152
153 fn build_clif_sysroot_for_triple(
154     channel: &str,
155     target_dir: &Path,
156     triple: &str,
157     cg_clif_dylib_path: &Path,
158     linker: Option<&str>,
159 ) {
160     match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
161         Err(e) => {
162             eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
163             eprintln!("Hint: Try `./y.rs prepare` to patch the sysroot source");
164             process::exit(1);
165         }
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");
173                 process::exit(1);
174             }
175         }
176     }
177
178     let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
179
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();
185         }
186     }
187
188     // Build sysroot
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");
196     }
197     if let Some(linker) = linker {
198         use std::fmt::Write;
199         write!(rustflags, " -Clinker={}", linker).unwrap();
200     }
201     build_cmd.env("RUSTFLAGS", rustflags);
202     build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
203     spawn_and_wait(build_cmd);
204
205     // Copy all relevant files to the sysroot
206     for entry in
207         fs::read_dir(Path::new("build_sysroot/target").join(triple).join(channel).join("deps"))
208             .unwrap()
209     {
210         let entry = entry.unwrap();
211         if let Some(ext) = entry.path().extension() {
212             if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" {
213                 continue;
214             }
215         } else {
216             continue;
217         };
218         try_hard_link(
219             entry.path(),
220             target_dir.join("lib").join("rustlib").join(triple).join("lib").join(entry.file_name()),
221         );
222     }
223 }