]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
1 | //! Implementation of compiling various phases of the compiler and standard |
2 | //! library. | |
3 | //! | |
4 | //! This module contains some of the real meat in the rustbuild build system | |
136023e0 XL |
5 | //! which is where Cargo is used to compile the standard library, libtest, and |
6 | //! the compiler. This module is also responsible for assembling the sysroot as it | |
a7813a04 XL |
7 | //! goes along from the output of the previous stage. |
8 | ||
0531ce1d | 9 | use std::borrow::Cow; |
5869c6ff | 10 | use std::collections::HashSet; |
7cac9316 | 11 | use std::env; |
49aad941 | 12 | use std::ffi::OsStr; |
0731742a | 13 | use std::fs; |
7cac9316 | 14 | use std::io::prelude::*; |
dfeec247 | 15 | use std::io::BufReader; |
7453a54e | 16 | use std::path::{Path, PathBuf}; |
064997fb | 17 | use std::process::{Command, Stdio}; |
7cac9316 | 18 | use std::str; |
7453a54e | 19 | |
9ffffee4 | 20 | use serde_derive::Deserialize; |
7453a54e | 21 | |
9c376795 | 22 | use crate::builder::crate_description; |
e1599b0c | 23 | use crate::builder::Cargo; |
353b0b11 | 24 | use crate::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath}; |
f035d41b | 25 | use crate::cache::{Interned, INTERNER}; |
2b03887a | 26 | use crate::config::{LlvmLibunwind, RustcLto, TargetSelection}; |
dfeec247 | 27 | use crate::dist; |
353b0b11 | 28 | use crate::llvm; |
f035d41b | 29 | use crate::tool::SourceType; |
064997fb | 30 | use crate::util::get_clang_cl_resource_dir; |
5e7ed085 | 31 | use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date}; |
a2a8927a | 32 | use crate::LLVM_TOOLS; |
5099ac24 | 33 | use crate::{CLang, Compiler, DependencyType, GitRepo, Mode}; |
3b2f2976 | 34 | |
064997fb | 35 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
3b2f2976 | 36 | pub struct Std { |
3dfed10e | 37 | pub target: TargetSelection, |
3b2f2976 | 38 | pub compiler: Compiler, |
064997fb FG |
39 | /// Whether to build only a subset of crates in the standard library. |
40 | /// | |
41 | /// This shouldn't be used from other steps; see the comment on [`Rustc`]. | |
42 | crates: Interned<Vec<String>>, | |
fe692bf9 FG |
43 | /// When using download-rustc, we need to use a new build of `std` for running unit tests of Std itself, |
44 | /// but we need to use the downloaded copy of std for linking to rustdoc. Allow this to be overriden by `builder.ensure` from other steps. | |
45 | force_recompile: bool, | |
064997fb FG |
46 | } |
47 | ||
48 | impl Std { | |
49 | pub fn new(compiler: Compiler, target: TargetSelection) -> Self { | |
fe692bf9 FG |
50 | Self { target, compiler, crates: Default::default(), force_recompile: false } |
51 | } | |
52 | ||
53 | pub fn force_recompile(compiler: Compiler, target: TargetSelection) -> Self { | |
54 | Self { target, compiler, crates: Default::default(), force_recompile: true } | |
064997fb FG |
55 | } |
56 | } | |
57 | ||
fe692bf9 FG |
58 | /// Given an `alias` selected by the `Step` and the paths passed on the command line, |
59 | /// return a list of the crates that should be built. | |
60 | /// | |
61 | /// Normally, people will pass *just* `library` if they pass it. | |
62 | /// But it's possible (although strange) to pass something like `library std core`. | |
63 | /// Build all crates anyway, as if they hadn't passed the other args. | |
64 | pub(crate) fn make_run_crates(run: &RunConfig<'_>, alias: &str) -> Interned<Vec<String>> { | |
65 | let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with(alias)); | |
66 | if has_alias { Default::default() } else { run.cargo_crates_in_set() } | |
67 | } | |
68 | ||
3b2f2976 XL |
69 | impl Step for Std { |
70 | type Output = (); | |
71 | const DEFAULT: bool = true; | |
72 | ||
9fa01778 | 73 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
6a06907d XL |
74 | // When downloading stage1, the standard library has already been copied to the sysroot, so |
75 | // there's no need to rebuild it. | |
923072b8 | 76 | let builder = run.builder; |
49aad941 | 77 | run.crate_or_deps("sysroot") |
923072b8 FG |
78 | .path("library") |
79 | .lazy_default_condition(Box::new(|| !builder.download_rustc())) | |
3b2f2976 XL |
80 | } |
81 | ||
9fa01778 | 82 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 83 | run.builder.ensure(Std { |
1b1a35ee | 84 | compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), |
3b2f2976 | 85 | target: run.target, |
fe692bf9 FG |
86 | crates: make_run_crates(&run, "library"), |
87 | force_recompile: false, | |
3b2f2976 XL |
88 | }); |
89 | } | |
90 | ||
9fa01778 | 91 | /// Builds the standard library. |
3b2f2976 XL |
92 | /// |
93 | /// This will build the standard library for a particular stage of the build | |
94 | /// using the `compiler` targeting the `target` architecture. The artifacts | |
95 | /// created will also be linked into the sysroot directory. | |
9fa01778 | 96 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
97 | let target = self.target; |
98 | let compiler = self.compiler; | |
99 | ||
fe692bf9 FG |
100 | // When using `download-rustc`, we already have artifacts for the host available. Don't |
101 | // recompile them. | |
102 | if builder.download_rustc() && target == builder.build.build | |
103 | // NOTE: the beta compiler may generate different artifacts than the downloaded compiler, so | |
104 | // its artifacts can't be reused. | |
105 | && compiler.stage != 0 | |
106 | // This check is specific to testing std itself; see `test::Std` for more details. | |
107 | && !self.force_recompile | |
108 | { | |
109 | cp_rustc_component_to_ci_sysroot( | |
110 | builder, | |
111 | compiler, | |
112 | builder.config.ci_rust_std_contents(), | |
113 | ); | |
6a06907d XL |
114 | return; |
115 | } | |
116 | ||
1b1a35ee XL |
117 | if builder.config.keep_stage.contains(&compiler.stage) |
118 | || builder.config.keep_stage_std.contains(&compiler.stage) | |
119 | { | |
8faf50e0 | 120 | builder.info("Warning: Using a potentially old libstd. This may not behave well."); |
fe692bf9 FG |
121 | |
122 | copy_third_party_objects(builder, &compiler, target); | |
123 | copy_self_contained_objects(builder, &compiler, target); | |
124 | ||
064997fb | 125 | builder.ensure(StdLink::from_std(self, compiler)); |
8faf50e0 XL |
126 | return; |
127 | } | |
128 | ||
136023e0 XL |
129 | builder.update_submodule(&Path::new("library").join("stdarch")); |
130 | ||
064997fb FG |
131 | // Profiler information requires LLVM's compiler-rt |
132 | if builder.config.profiler { | |
133 | builder.update_submodule(&Path::new("src/llvm-project")); | |
134 | } | |
135 | ||
e74abb32 | 136 | let mut target_deps = builder.ensure(StartupObjects { compiler, target }); |
3b2f2976 | 137 | |
dc9dc135 XL |
138 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); |
139 | if compiler_to_use != compiler { | |
064997fb | 140 | builder.ensure(Std::new(compiler_to_use, target)); |
9ffffee4 FG |
141 | let msg = if compiler_to_use.host == target { |
142 | format!( | |
143 | "Uplifting library (stage{} -> stage{})", | |
144 | compiler_to_use.stage, compiler.stage | |
145 | ) | |
146 | } else { | |
147 | format!( | |
148 | "Uplifting library (stage{}:{} -> stage{}:{})", | |
149 | compiler_to_use.stage, compiler_to_use.host, compiler.stage, target | |
150 | ) | |
151 | }; | |
152 | builder.info(&msg); | |
3b2f2976 XL |
153 | |
154 | // Even if we're not building std this stage, the new sysroot must | |
0731742a XL |
155 | // still contain the third party objects needed by various targets. |
156 | copy_third_party_objects(builder, &compiler, target); | |
f035d41b | 157 | copy_self_contained_objects(builder, &compiler, target); |
3b2f2976 | 158 | |
064997fb | 159 | builder.ensure(StdLink::from_std(self, compiler_to_use)); |
3b2f2976 XL |
160 | return; |
161 | } | |
162 | ||
f035d41b XL |
163 | target_deps.extend(copy_third_party_objects(builder, &compiler, target)); |
164 | target_deps.extend(copy_self_contained_objects(builder, &compiler, target)); | |
3b2f2976 | 165 | |
f035d41b | 166 | let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build"); |
f9f354fc | 167 | std_cargo(builder, target, compiler.stage, &mut cargo); |
9c376795 FG |
168 | for krate in &*self.crates { |
169 | cargo.arg("-p").arg(krate); | |
170 | } | |
0531ce1d | 171 | |
fe692bf9 FG |
172 | // See src/bootstrap/synthetic_targets.rs |
173 | if target.is_synthetic() { | |
174 | cargo.env("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET", "1"); | |
175 | } | |
176 | ||
49aad941 FG |
177 | let _guard = builder.msg( |
178 | Kind::Build, | |
179 | compiler.stage, | |
180 | format_args!("library artifacts{}", crate_description(&self.crates)), | |
181 | compiler.host, | |
182 | target, | |
183 | ); | |
dfeec247 XL |
184 | run_cargo( |
185 | builder, | |
186 | cargo, | |
9c376795 | 187 | vec![], |
dfeec247 XL |
188 | &libstd_stamp(builder, compiler, target), |
189 | target_deps, | |
190 | false, | |
9c376795 | 191 | false, |
dfeec247 | 192 | ); |
3b2f2976 | 193 | |
064997fb FG |
194 | builder.ensure(StdLink::from_std( |
195 | self, | |
196 | builder.compiler(compiler.stage, builder.config.build), | |
197 | )); | |
3b2f2976 XL |
198 | } |
199 | } | |
200 | ||
f035d41b XL |
201 | fn copy_and_stamp( |
202 | builder: &Builder<'_>, | |
203 | libdir: &Path, | |
204 | sourcedir: &Path, | |
205 | name: &str, | |
206 | target_deps: &mut Vec<(PathBuf, DependencyType)>, | |
207 | dependency_type: DependencyType, | |
208 | ) { | |
209 | let target = libdir.join(name); | |
210 | builder.copy(&sourcedir.join(name), &target); | |
211 | ||
212 | target_deps.push((target, dependency_type)); | |
213 | } | |
214 | ||
94222f64 | 215 | fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: &Path) -> PathBuf { |
353b0b11 | 216 | let libunwind_path = builder.ensure(llvm::Libunwind { target }); |
94222f64 XL |
217 | let libunwind_source = libunwind_path.join("libunwind.a"); |
218 | let libunwind_target = libdir.join("libunwind.a"); | |
219 | builder.copy(&libunwind_source, &libunwind_target); | |
220 | libunwind_target | |
221 | } | |
222 | ||
60c5eb7d | 223 | /// Copies third party objects needed by various targets. |
dfeec247 XL |
224 | fn copy_third_party_objects( |
225 | builder: &Builder<'_>, | |
226 | compiler: &Compiler, | |
3dfed10e | 227 | target: TargetSelection, |
f035d41b | 228 | ) -> Vec<(PathBuf, DependencyType)> { |
e74abb32 XL |
229 | let mut target_deps = vec![]; |
230 | ||
f035d41b XL |
231 | // FIXME: remove this in 2021 |
232 | if target == "x86_64-fortanix-unknown-sgx" { | |
233 | if env::var_os("X86_FORTANIX_SGX_LIBS").is_some() { | |
234 | builder.info("Warning: X86_FORTANIX_SGX_LIBS environment variable is ignored, libunwind is now compiled as part of rustbuild"); | |
235 | } | |
236 | } | |
237 | ||
29967ef6 | 238 | if builder.config.sanitizers_enabled(target) && compiler.stage != 0 { |
f035d41b XL |
239 | // The sanitizers are only copied in stage1 or above, |
240 | // to avoid creating dependency on LLVM. | |
241 | target_deps.extend( | |
242 | copy_sanitizers(builder, &compiler, target) | |
243 | .into_iter() | |
244 | .map(|d| (d, DependencyType::Target)), | |
245 | ); | |
246 | } | |
247 | ||
94222f64 | 248 | if target == "x86_64-fortanix-unknown-sgx" |
923072b8 | 249 | || builder.config.llvm_libunwind(target) == LlvmLibunwind::InTree |
94222f64 XL |
250 | && (target.contains("linux") || target.contains("fuchsia")) |
251 | { | |
252 | let libunwind_path = | |
253 | copy_llvm_libunwind(builder, target, &builder.sysroot_libdir(*compiler, target)); | |
254 | target_deps.push((libunwind_path, DependencyType::Target)); | |
255 | } | |
256 | ||
f035d41b XL |
257 | target_deps |
258 | } | |
259 | ||
260 | /// Copies third party objects needed by various targets for self-contained linkage. | |
261 | fn copy_self_contained_objects( | |
262 | builder: &Builder<'_>, | |
263 | compiler: &Compiler, | |
3dfed10e | 264 | target: TargetSelection, |
f035d41b | 265 | ) -> Vec<(PathBuf, DependencyType)> { |
3dfed10e | 266 | let libdir_self_contained = builder.sysroot_libdir(*compiler, target).join("self-contained"); |
f035d41b XL |
267 | t!(fs::create_dir_all(&libdir_self_contained)); |
268 | let mut target_deps = vec![]; | |
e74abb32 | 269 | |
3c0e092e | 270 | // Copies the libc and CRT objects. |
0731742a | 271 | // |
f9f354fc XL |
272 | // rustc historically provides a more self-contained installation for musl targets |
273 | // not requiring the presence of a native musl toolchain. For example, it can fall back | |
274 | // to using gcc from a glibc-targeting toolchain for linking. | |
275 | // To do that we have to distribute musl startup objects as a part of Rust toolchain | |
276 | // and link with them manually in the self-contained mode. | |
0731742a | 277 | if target.contains("musl") { |
6a06907d XL |
278 | let srcdir = builder.musl_libdir(target).unwrap_or_else(|| { |
279 | panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple) | |
280 | }); | |
3c0e092e | 281 | for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { |
f035d41b XL |
282 | copy_and_stamp( |
283 | builder, | |
284 | &libdir_self_contained, | |
285 | &srcdir, | |
286 | obj, | |
287 | &mut target_deps, | |
288 | DependencyType::TargetSelfContained, | |
289 | ); | |
0731742a | 290 | } |
353b0b11 | 291 | let crt_path = builder.ensure(llvm::CrtBeginEnd { target }); |
6a06907d | 292 | for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] { |
cdc7bbd5 | 293 | let src = crt_path.join(obj); |
6a06907d XL |
294 | let target = libdir_self_contained.join(obj); |
295 | builder.copy(&src, &target); | |
296 | target_deps.push((target, DependencyType::TargetSelfContained)); | |
297 | } | |
94222f64 | 298 | |
5099ac24 FG |
299 | if !target.starts_with("s390x") { |
300 | let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained); | |
301 | target_deps.push((libunwind_path, DependencyType::TargetSelfContained)); | |
302 | } | |
532ac7d7 | 303 | } else if target.ends_with("-wasi") { |
6a06907d XL |
304 | let srcdir = builder |
305 | .wasi_root(target) | |
306 | .unwrap_or_else(|| { | |
307 | panic!("Target {:?} does not have a \"wasi-root\" key", target.triple) | |
308 | }) | |
309 | .join("lib/wasm32-wasi"); | |
3c0e092e | 310 | for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] { |
5869c6ff XL |
311 | copy_and_stamp( |
312 | builder, | |
313 | &libdir_self_contained, | |
314 | &srcdir, | |
315 | obj, | |
316 | &mut target_deps, | |
317 | DependencyType::TargetSelfContained, | |
318 | ); | |
319 | } | |
04454e1e | 320 | } else if target.ends_with("windows-gnu") { |
f035d41b | 321 | for obj in ["crt2.o", "dllcrt2.o"].iter() { |
fe692bf9 | 322 | let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj); |
f035d41b XL |
323 | let target = libdir_self_contained.join(obj); |
324 | builder.copy(&src, &target); | |
325 | target_deps.push((target, DependencyType::TargetSelfContained)); | |
326 | } | |
dfeec247 XL |
327 | } |
328 | ||
e74abb32 | 329 | target_deps |
3b2f2976 XL |
330 | } |
331 | ||
332 | /// Configure cargo to compile the standard library, adding appropriate env vars | |
333 | /// and such. | |
3dfed10e | 334 | pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) { |
041b39d2 | 335 | if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { |
8bb4bdeb XL |
336 | cargo.env("MACOSX_DEPLOYMENT_TARGET", target); |
337 | } | |
338 | ||
dc9dc135 XL |
339 | // Determine if we're going to compile in optimized C intrinsics to |
340 | // the `compiler-builtins` crate. These intrinsics live in LLVM's | |
487cf647 FG |
341 | // `compiler-rt` repository, but our `src/llvm-project` submodule isn't |
342 | // always checked out, so we need to conditionally look for this. (e.g. if | |
343 | // an external LLVM is used we skip the LLVM submodule checkout). | |
dc9dc135 XL |
344 | // |
345 | // Note that this shouldn't affect the correctness of `compiler-builtins`, | |
346 | // but only its speed. Some intrinsics in C haven't been translated to Rust | |
347 | // yet but that's pretty rare. Other intrinsics have optimized | |
348 | // implementations in C which have only had slower versions ported to Rust, | |
349 | // so we favor the C version where we can, but it's not critical. | |
350 | // | |
351 | // If `compiler-rt` is available ensure that the `c` feature of the | |
352 | // `compiler-builtins` crate is enabled and it's configured to learn where | |
353 | // `compiler-rt` is located. | |
487cf647 FG |
354 | let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); |
355 | let compiler_builtins_c_feature = if compiler_builtins_root.exists() { | |
ba9703b0 XL |
356 | // Note that `libprofiler_builtins/build.rs` also computes this so if |
357 | // you're changing something here please also change that. | |
dc9dc135 | 358 | cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); |
29967ef6 | 359 | " compiler-builtins-c" |
dc9dc135 | 360 | } else { |
29967ef6 | 361 | "" |
dc9dc135 XL |
362 | }; |
363 | ||
353b0b11 FG |
364 | // `libtest` uses this to know whether or not to support |
365 | // `-Zunstable-options`. | |
366 | if !builder.unstable_features() { | |
367 | cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); | |
368 | } | |
369 | ||
9c376795 FG |
370 | let mut features = String::new(); |
371 | ||
372 | // Cranelift doesn't support `asm`. | |
373 | if stage != 0 && builder.config.default_codegen_backend().unwrap_or_default() == "cranelift" { | |
374 | features += " compiler-builtins-no-asm"; | |
375 | } | |
376 | ||
83c7162d | 377 | if builder.no_std(target) == Some(true) { |
9c376795 | 378 | features += " compiler-builtins-mem"; |
17df50a5 XL |
379 | if !target.starts_with("bpf") { |
380 | features.push_str(compiler_builtins_c_feature); | |
381 | } | |
dc9dc135 | 382 | |
83c7162d | 383 | // for no-std targets we only compile a few no_std crates |
0731742a | 384 | cargo |
83c7162d | 385 | .args(&["-p", "alloc"]) |
83c7162d | 386 | .arg("--manifest-path") |
3dfed10e | 387 | .arg(builder.src.join("library/alloc/Cargo.toml")) |
0731742a | 388 | .arg("--features") |
29967ef6 | 389 | .arg(features); |
83c7162d | 390 | } else { |
9c376795 | 391 | features += &builder.std_features(target); |
29967ef6 | 392 | features.push_str(compiler_builtins_c_feature); |
8bb4bdeb | 393 | |
dfeec247 XL |
394 | cargo |
395 | .arg("--features") | |
396 | .arg(features) | |
83c7162d | 397 | .arg("--manifest-path") |
49aad941 | 398 | .arg(builder.src.join("library/sysroot/Cargo.toml")); |
7453a54e | 399 | |
e1599b0c XL |
400 | // Help the libc crate compile by assisting it in finding various |
401 | // sysroot native libraries. | |
83c7162d | 402 | if target.contains("musl") { |
f035d41b XL |
403 | if let Some(p) = builder.musl_libdir(target) { |
404 | let root = format!("native={}", p.to_str().unwrap()); | |
e1599b0c | 405 | cargo.rustflag("-L").rustflag(&root); |
83c7162d | 406 | } |
7453a54e | 407 | } |
532ac7d7 XL |
408 | |
409 | if target.ends_with("-wasi") { | |
410 | if let Some(p) = builder.wasi_root(target) { | |
e1599b0c XL |
411 | let root = format!("native={}/lib/wasm32-wasi", p.to_str().unwrap()); |
412 | cargo.rustflag("-L").rustflag(&root); | |
532ac7d7 XL |
413 | } |
414 | } | |
7453a54e | 415 | } |
f9f354fc XL |
416 | |
417 | // By default, rustc uses `-Cembed-bitcode=yes`, and Cargo overrides that | |
418 | // with `-Cembed-bitcode=no` for non-LTO builds. However, libstd must be | |
419 | // built with bitcode so that the produced rlibs can be used for both LTO | |
420 | // builds (which use bitcode) and non-LTO builds (which use object code). | |
421 | // So we override the override here! | |
422 | // | |
423 | // But we don't bother for the stage 0 compiler because it's never used | |
424 | // with LTO. | |
425 | if stage >= 1 { | |
426 | cargo.rustflag("-Cembed-bitcode=yes"); | |
427 | } | |
9ffffee4 FG |
428 | if builder.config.rust_lto == RustcLto::Off { |
429 | cargo.rustflag("-Clto=off"); | |
430 | } | |
f035d41b XL |
431 | |
432 | // By default, rustc does not include unwind tables unless they are required | |
433 | // for a particular target. They are not required by RISC-V targets, but | |
434 | // compiling the standard library with them means that users can get | |
435 | // backtraces without having to recompile the standard library themselves. | |
436 | // | |
437 | // This choice was discussed in https://github.com/rust-lang/rust/pull/69890 | |
438 | if target.contains("riscv") { | |
439 | cargo.rustflag("-Cforce-unwind-tables=yes"); | |
440 | } | |
17df50a5 XL |
441 | |
442 | let html_root = | |
443 | format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),); | |
444 | cargo.rustflag(&html_root); | |
445 | cargo.rustdocflag(&html_root); | |
49aad941 FG |
446 | |
447 | cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)"); | |
7453a54e SL |
448 | } |
449 | ||
3b2f2976 XL |
450 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
451 | struct StdLink { | |
452 | pub compiler: Compiler, | |
453 | pub target_compiler: Compiler, | |
3dfed10e | 454 | pub target: TargetSelection, |
064997fb FG |
455 | /// Not actually used; only present to make sure the cache invalidation is correct. |
456 | crates: Interned<Vec<String>>, | |
fe692bf9 FG |
457 | /// See [`Std::force_recompile`]. |
458 | force_recompile: bool, | |
064997fb FG |
459 | } |
460 | ||
461 | impl StdLink { | |
462 | fn from_std(std: Std, host_compiler: Compiler) -> Self { | |
463 | Self { | |
464 | compiler: host_compiler, | |
465 | target_compiler: std.compiler, | |
466 | target: std.target, | |
467 | crates: std.crates, | |
fe692bf9 | 468 | force_recompile: std.force_recompile, |
064997fb FG |
469 | } |
470 | } | |
54a0048b SL |
471 | } |
472 | ||
3b2f2976 XL |
473 | impl Step for StdLink { |
474 | type Output = (); | |
475 | ||
9fa01778 | 476 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
477 | run.never() |
478 | } | |
479 | ||
480 | /// Link all libstd rlibs/dylibs into the sysroot location. | |
481 | /// | |
a1dfa0c6 | 482 | /// Links those artifacts generated by `compiler` to the `stage` compiler's |
3b2f2976 XL |
483 | /// sysroot for the specified `host` and `target`. |
484 | /// | |
485 | /// Note that this assumes that `compiler` has already generated the libstd | |
486 | /// libraries for `target`, and this method will find them in the relevant | |
487 | /// output directory. | |
9fa01778 | 488 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
489 | let compiler = self.compiler; |
490 | let target_compiler = self.target_compiler; | |
491 | let target = self.target; | |
fe692bf9 FG |
492 | |
493 | // NOTE: intentionally does *not* check `target == builder.build` to avoid having to add the same check in `test::Crate`. | |
494 | let (libdir, hostdir) = if self.force_recompile && builder.download_rustc() { | |
495 | // NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too | |
496 | let lib = builder.sysroot_libdir_relative(self.compiler); | |
497 | let sysroot = builder.ensure(crate::compile::Sysroot { | |
498 | compiler: self.compiler, | |
499 | force_recompile: self.force_recompile, | |
500 | }); | |
501 | let libdir = sysroot.join(lib).join("rustlib").join(target.triple).join("lib"); | |
502 | let hostdir = sysroot.join(lib).join("rustlib").join(compiler.host.triple).join("lib"); | |
503 | (INTERNER.intern_path(libdir), INTERNER.intern_path(hostdir)) | |
504 | } else { | |
505 | let libdir = builder.sysroot_libdir(target_compiler, target); | |
506 | let hostdir = builder.sysroot_libdir(target_compiler, compiler.host); | |
507 | (libdir, hostdir) | |
508 | }; | |
509 | ||
532ac7d7 | 510 | add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); |
54a0048b | 511 | } |
7453a54e SL |
512 | } |
513 | ||
dfeec247 XL |
514 | /// Copies sanitizer runtime libraries into target libdir. |
515 | fn copy_sanitizers( | |
9fa01778 | 516 | builder: &Builder<'_>, |
dfeec247 | 517 | compiler: &Compiler, |
3dfed10e | 518 | target: TargetSelection, |
dfeec247 | 519 | ) -> Vec<PathBuf> { |
353b0b11 | 520 | let runtimes: Vec<llvm::SanitizerRuntime> = builder.ensure(llvm::Sanitizers { target }); |
dfeec247 | 521 | |
487cf647 | 522 | if builder.config.dry_run() { |
dfeec247 XL |
523 | return Vec::new(); |
524 | } | |
525 | ||
526 | let mut target_deps = Vec::new(); | |
527 | let libdir = builder.sysroot_libdir(*compiler, target); | |
528 | ||
529 | for runtime in &runtimes { | |
530 | let dst = libdir.join(&runtime.name); | |
531 | builder.copy(&runtime.path, &dst); | |
532 | ||
9ffffee4 FG |
533 | if target == "x86_64-apple-darwin" |
534 | || target == "aarch64-apple-darwin" | |
535 | || target == "aarch64-apple-ios" | |
536 | || target == "aarch64-apple-ios-sim" | |
537 | || target == "x86_64-apple-ios" | |
538 | { | |
2b03887a | 539 | // Update the library’s install name to reflect that it has been renamed. |
5869c6ff XL |
540 | apple_darwin_update_library_name(&dst, &format!("@rpath/{}", &runtime.name)); |
541 | // Upon renaming the install name, the code signature of the file will invalidate, | |
542 | // so we will sign it again. | |
543 | apple_darwin_sign_file(&dst); | |
dfeec247 XL |
544 | } |
545 | ||
546 | target_deps.push(dst); | |
7cac9316 | 547 | } |
dfeec247 XL |
548 | |
549 | target_deps | |
7cac9316 XL |
550 | } |
551 | ||
5869c6ff XL |
552 | fn apple_darwin_update_library_name(library_path: &Path, new_name: &str) { |
553 | let status = Command::new("install_name_tool") | |
554 | .arg("-id") | |
555 | .arg(new_name) | |
556 | .arg(library_path) | |
557 | .status() | |
558 | .expect("failed to execute `install_name_tool`"); | |
559 | assert!(status.success()); | |
560 | } | |
561 | ||
562 | fn apple_darwin_sign_file(file_path: &Path) { | |
563 | let status = Command::new("codesign") | |
564 | .arg("-f") // Force to rewrite the existing signature | |
565 | .arg("-s") | |
566 | .arg("-") | |
567 | .arg(file_path) | |
568 | .status() | |
569 | .expect("failed to execute `codesign`"); | |
570 | assert!(status.success()); | |
571 | } | |
572 | ||
3b2f2976 XL |
573 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
574 | pub struct StartupObjects { | |
575 | pub compiler: Compiler, | |
3dfed10e | 576 | pub target: TargetSelection, |
3b2f2976 XL |
577 | } |
578 | ||
579 | impl Step for StartupObjects { | |
f035d41b | 580 | type Output = Vec<(PathBuf, DependencyType)>; |
3b2f2976 | 581 | |
9fa01778 | 582 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3dfed10e | 583 | run.path("library/rtstartup") |
3b2f2976 XL |
584 | } |
585 | ||
9fa01778 | 586 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 587 | run.builder.ensure(StartupObjects { |
1b1a35ee | 588 | compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), |
3b2f2976 XL |
589 | target: run.target, |
590 | }); | |
591 | } | |
592 | ||
9fa01778 | 593 | /// Builds and prepare startup objects like rsbegin.o and rsend.o |
3b2f2976 XL |
594 | /// |
595 | /// These are primarily used on Windows right now for linking executables/dlls. | |
596 | /// They don't require any library support as they're just plain old object | |
597 | /// files, so we just use the nightly snapshot compiler to always build them (as | |
598 | /// no other compilers are guaranteed to be available). | |
f035d41b | 599 | fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> { |
3b2f2976 XL |
600 | let for_compiler = self.compiler; |
601 | let target = self.target; | |
04454e1e | 602 | if !target.ends_with("windows-gnu") { |
dfeec247 | 603 | return vec![]; |
8bb4bdeb | 604 | } |
7453a54e | 605 | |
e74abb32 XL |
606 | let mut target_deps = vec![]; |
607 | ||
3dfed10e | 608 | let src_dir = &builder.src.join("library").join("rtstartup"); |
83c7162d | 609 | let dst_dir = &builder.native_dir(target).join("rtstartup"); |
3b2f2976 XL |
610 | let sysroot_dir = &builder.sysroot_libdir(for_compiler, target); |
611 | t!(fs::create_dir_all(dst_dir)); | |
612 | ||
613 | for file in &["rsbegin", "rsend"] { | |
614 | let src_file = &src_dir.join(file.to_string() + ".rs"); | |
615 | let dst_file = &dst_dir.join(file.to_string() + ".o"); | |
616 | if !up_to_date(src_file, dst_file) { | |
83c7162d | 617 | let mut cmd = Command::new(&builder.initial_rustc); |
cdc7bbd5 XL |
618 | cmd.env("RUSTC_BOOTSTRAP", "1"); |
619 | if !builder.local_rebuild { | |
620 | // a local_rebuild compiler already has stage1 features | |
621 | cmd.arg("--cfg").arg("bootstrap"); | |
622 | } | |
dfeec247 | 623 | builder.run( |
cdc7bbd5 | 624 | cmd.arg("--target") |
3dfed10e | 625 | .arg(target.rustc_target_arg()) |
dfeec247 XL |
626 | .arg("--emit=obj") |
627 | .arg("-o") | |
628 | .arg(dst_file) | |
629 | .arg(src_file), | |
630 | ); | |
3b2f2976 XL |
631 | } |
632 | ||
74b04a01 | 633 | let target = sysroot_dir.join((*file).to_string() + ".o"); |
e74abb32 | 634 | builder.copy(dst_file, &target); |
f035d41b | 635 | target_deps.push((target, DependencyType::Target)); |
3b2f2976 | 636 | } |
e74abb32 XL |
637 | |
638 | target_deps | |
7453a54e | 639 | } |
3b2f2976 XL |
640 | } |
641 | ||
fe692bf9 FG |
642 | fn cp_rustc_component_to_ci_sysroot( |
643 | builder: &Builder<'_>, | |
644 | compiler: Compiler, | |
645 | contents: Vec<String>, | |
646 | ) { | |
647 | let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false }); | |
648 | ||
649 | let ci_rustc_dir = builder.out.join(&*builder.build.build.triple).join("ci-rustc"); | |
650 | for file in contents { | |
651 | let src = ci_rustc_dir.join(&file); | |
652 | let dst = sysroot.join(file); | |
653 | if src.is_dir() { | |
654 | t!(fs::create_dir_all(dst)); | |
655 | } else { | |
656 | builder.copy(&src, &dst); | |
657 | } | |
658 | } | |
659 | } | |
660 | ||
83c7162d | 661 | #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] |
3b2f2976 | 662 | pub struct Rustc { |
3dfed10e | 663 | pub target: TargetSelection, |
83c7162d | 664 | pub compiler: Compiler, |
064997fb FG |
665 | /// Whether to build a subset of crates, rather than the whole compiler. |
666 | /// | |
667 | /// This should only be requested by the user, not used within rustbuild itself. | |
668 | /// Using it within rustbuild can lead to confusing situation where lints are replayed | |
669 | /// in two different steps. | |
670 | crates: Interned<Vec<String>>, | |
671 | } | |
672 | ||
673 | impl Rustc { | |
674 | pub fn new(compiler: Compiler, target: TargetSelection) -> Self { | |
675 | Self { target, compiler, crates: Default::default() } | |
676 | } | |
3b2f2976 XL |
677 | } |
678 | ||
679 | impl Step for Rustc { | |
680 | type Output = (); | |
681 | const ONLY_HOSTS: bool = true; | |
3dfed10e | 682 | const DEFAULT: bool = false; |
3b2f2976 | 683 | |
9fa01778 | 684 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
064997fb FG |
685 | let mut crates = run.builder.in_tree_crates("rustc-main", None); |
686 | for (i, krate) in crates.iter().enumerate() { | |
fe692bf9 FG |
687 | // We can't allow `build rustc` as an alias for this Step, because that's reserved by `Assemble`. |
688 | // Ideally Assemble would use `build compiler` instead, but that seems too confusing to be worth the breaking change. | |
064997fb FG |
689 | if krate.name == "rustc-main" { |
690 | crates.swap_remove(i); | |
691 | break; | |
692 | } | |
693 | } | |
694 | run.crates(crates) | |
3b2f2976 XL |
695 | } |
696 | ||
9fa01778 | 697 | fn make_run(run: RunConfig<'_>) { |
9c376795 | 698 | let crates = run.cargo_crates_in_set(); |
3b2f2976 | 699 | run.builder.ensure(Rustc { |
1b1a35ee | 700 | compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), |
3b2f2976 | 701 | target: run.target, |
064997fb | 702 | crates, |
3b2f2976 XL |
703 | }); |
704 | } | |
705 | ||
9fa01778 | 706 | /// Builds the compiler. |
3b2f2976 XL |
707 | /// |
708 | /// This will build the compiler for a particular stage of the build using | |
709 | /// the `compiler` targeting the `target` architecture. The artifacts | |
710 | /// created will also be linked into the sysroot directory. | |
9fa01778 | 711 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
712 | let compiler = self.compiler; |
713 | let target = self.target; | |
714 | ||
cdc7bbd5 XL |
715 | // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler, |
716 | // so its artifacts can't be reused. | |
923072b8 | 717 | if builder.download_rustc() && compiler.stage != 0 { |
6a06907d | 718 | // Copy the existing artifacts instead of rebuilding them. |
49aad941 | 719 | // NOTE: this path is only taken for tools linking to rustc-dev (including ui-fulldeps tests). |
fe692bf9 FG |
720 | cp_rustc_component_to_ci_sysroot( |
721 | builder, | |
722 | compiler, | |
723 | builder.config.ci_rustc_dev_contents(), | |
724 | ); | |
6a06907d XL |
725 | return; |
726 | } | |
727 | ||
064997fb | 728 | builder.ensure(Std::new(compiler, target)); |
3b2f2976 | 729 | |
8faf50e0 XL |
730 | if builder.config.keep_stage.contains(&compiler.stage) { |
731 | builder.info("Warning: Using a potentially old librustc. This may not behave well."); | |
1b1a35ee | 732 | builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); |
064997fb | 733 | builder.ensure(RustcLink::from_rustc(self, compiler)); |
8faf50e0 XL |
734 | return; |
735 | } | |
736 | ||
dc9dc135 XL |
737 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); |
738 | if compiler_to_use != compiler { | |
064997fb | 739 | builder.ensure(Rustc::new(compiler_to_use, target)); |
9ffffee4 FG |
740 | let msg = if compiler_to_use.host == target { |
741 | format!( | |
742 | "Uplifting rustc (stage{} -> stage{})", | |
743 | compiler_to_use.stage, | |
744 | compiler.stage + 1 | |
745 | ) | |
746 | } else { | |
747 | format!( | |
748 | "Uplifting rustc (stage{}:{} -> stage{}:{})", | |
749 | compiler_to_use.stage, | |
750 | compiler_to_use.host, | |
751 | compiler.stage + 1, | |
752 | target | |
753 | ) | |
754 | }; | |
755 | builder.info(&msg); | |
064997fb | 756 | builder.ensure(RustcLink::from_rustc(self, compiler_to_use)); |
3b2f2976 XL |
757 | return; |
758 | } | |
759 | ||
532ac7d7 | 760 | // Ensure that build scripts and proc macros have a std / libproc_macro to link against. |
064997fb FG |
761 | builder.ensure(Std::new( |
762 | builder.compiler(self.compiler.stage, builder.config.build), | |
763 | builder.config.build, | |
764 | )); | |
0531ce1d | 765 | |
f035d41b | 766 | let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build"); |
353b0b11 | 767 | rustc_cargo(builder, &mut cargo, target, compiler.stage); |
3b2f2976 | 768 | |
fc512014 XL |
769 | if builder.config.rust_profile_use.is_some() |
770 | && builder.config.rust_profile_generate.is_some() | |
771 | { | |
772 | panic!("Cannot use and generate PGO profiles at the same time"); | |
773 | } | |
774 | ||
064997fb FG |
775 | // With LLD, we can use ICF (identical code folding) to reduce the executable size |
776 | // of librustc_driver/rustc and to improve i-cache utilization. | |
f2b60f7d FG |
777 | // |
778 | // -Wl,[link options] doesn't work on MSVC. However, /OPT:ICF (technically /OPT:REF,ICF) | |
779 | // is already on by default in MSVC optimized builds, which is interpreted as --icf=all: | |
780 | // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746 | |
781 | // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827 | |
782 | if builder.config.use_lld && !compiler.host.contains("msvc") { | |
064997fb FG |
783 | cargo.rustflag("-Clink-args=-Wl,--icf=all"); |
784 | } | |
785 | ||
fc512014 XL |
786 | let is_collecting = if let Some(path) = &builder.config.rust_profile_generate { |
787 | if compiler.stage == 1 { | |
788 | cargo.rustflag(&format!("-Cprofile-generate={}", path)); | |
789 | // Apparently necessary to avoid overflowing the counters during | |
790 | // a Cargo build profile | |
791 | cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4"); | |
792 | true | |
793 | } else { | |
794 | false | |
795 | } | |
796 | } else if let Some(path) = &builder.config.rust_profile_use { | |
797 | if compiler.stage == 1 { | |
798 | cargo.rustflag(&format!("-Cprofile-use={}", path)); | |
799 | cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function"); | |
800 | true | |
801 | } else { | |
802 | false | |
803 | } | |
804 | } else { | |
805 | false | |
806 | }; | |
807 | if is_collecting { | |
808 | // Ensure paths to Rust sources are relative, not absolute. | |
809 | cargo.rustflag(&format!( | |
810 | "-Cllvm-args=-static-func-strip-dirname-prefix={}", | |
811 | builder.config.src.components().count() | |
812 | )); | |
813 | } | |
814 | ||
9c376795 FG |
815 | // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary |
816 | // and may just be a time sink. | |
2b03887a FG |
817 | if compiler.stage != 0 { |
818 | match builder.config.rust_lto { | |
819 | RustcLto::Thin | RustcLto::Fat => { | |
820 | // Since using LTO for optimizing dylibs is currently experimental, | |
821 | // we need to pass -Zdylib-lto. | |
822 | cargo.rustflag("-Zdylib-lto"); | |
823 | // Cargo by default passes `-Cembed-bitcode=no` and doesn't pass `-Clto` when | |
824 | // compiling dylibs (and their dependencies), even when LTO is enabled for the | |
825 | // crate. Therefore, we need to override `-Clto` and `-Cembed-bitcode` here. | |
826 | let lto_type = match builder.config.rust_lto { | |
827 | RustcLto::Thin => "thin", | |
828 | RustcLto::Fat => "fat", | |
829 | _ => unreachable!(), | |
830 | }; | |
831 | cargo.rustflag(&format!("-Clto={}", lto_type)); | |
832 | cargo.rustflag("-Cembed-bitcode=yes"); | |
833 | } | |
834 | RustcLto::ThinLocal => { /* Do nothing, this is the default */ } | |
9ffffee4 FG |
835 | RustcLto::Off => { |
836 | cargo.rustflag("-Clto=off"); | |
837 | } | |
838 | } | |
839 | } else { | |
840 | if builder.config.rust_lto == RustcLto::Off { | |
841 | cargo.rustflag("-Clto=off"); | |
2b03887a FG |
842 | } |
843 | } | |
844 | ||
9c376795 FG |
845 | for krate in &*self.crates { |
846 | cargo.arg("-p").arg(krate); | |
847 | } | |
848 | ||
49aad941 FG |
849 | let _guard = builder.msg_sysroot_tool( |
850 | Kind::Build, | |
851 | compiler.stage, | |
852 | format_args!("compiler artifacts{}", crate_description(&self.crates)), | |
853 | compiler.host, | |
854 | target, | |
855 | ); | |
dfeec247 XL |
856 | run_cargo( |
857 | builder, | |
858 | cargo, | |
9c376795 | 859 | vec![], |
dfeec247 XL |
860 | &librustc_stamp(builder, compiler, target), |
861 | vec![], | |
862 | false, | |
9c376795 | 863 | true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files. |
dfeec247 | 864 | ); |
3b2f2976 | 865 | |
064997fb FG |
866 | builder.ensure(RustcLink::from_rustc( |
867 | self, | |
868 | builder.compiler(compiler.stage, builder.config.build), | |
869 | )); | |
3b2f2976 XL |
870 | } |
871 | } | |
872 | ||
353b0b11 | 873 | pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, stage: u32) { |
dfeec247 XL |
874 | cargo |
875 | .arg("--features") | |
5e7ed085 | 876 | .arg(builder.rustc_features(builder.kind)) |
dfeec247 | 877 | .arg("--manifest-path") |
1b1a35ee | 878 | .arg(builder.src.join("compiler/rustc/Cargo.toml")); |
49aad941 FG |
879 | |
880 | cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)"); | |
881 | ||
353b0b11 | 882 | rustc_cargo_env(builder, cargo, target, stage); |
2c00a5a8 | 883 | } |
7453a54e | 884 | |
353b0b11 FG |
885 | pub fn rustc_cargo_env( |
886 | builder: &Builder<'_>, | |
887 | cargo: &mut Cargo, | |
888 | target: TargetSelection, | |
889 | stage: u32, | |
890 | ) { | |
7453a54e SL |
891 | // Set some configuration variables picked up by build scripts and |
892 | // the compiler alike | |
dfeec247 XL |
893 | cargo |
894 | .env("CFG_RELEASE", builder.rust_release()) | |
895 | .env("CFG_RELEASE_CHANNEL", &builder.config.channel) | |
17df50a5 | 896 | .env("CFG_VERSION", builder.rust_version()); |
32a655c1 | 897 | |
9c376795 | 898 | if let Some(backend) = builder.config.default_codegen_backend() { |
5e7ed085 FG |
899 | cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", backend); |
900 | } | |
901 | ||
74b04a01 | 902 | let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); |
a2a8927a XL |
903 | let target_config = builder.config.target_config.get(&target); |
904 | ||
2c00a5a8 | 905 | cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); |
7453a54e | 906 | |
487cf647 | 907 | if let Some(ref ver_date) = builder.rust_info().commit_date() { |
7453a54e SL |
908 | cargo.env("CFG_VER_DATE", ver_date); |
909 | } | |
487cf647 | 910 | if let Some(ref ver_hash) = builder.rust_info().sha() { |
7453a54e SL |
911 | cargo.env("CFG_VER_HASH", ver_hash); |
912 | } | |
83c7162d | 913 | if !builder.unstable_features() { |
7453a54e SL |
914 | cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); |
915 | } | |
a2a8927a XL |
916 | |
917 | // Prefer the current target's own default_linker, else a globally | |
918 | // specified one. | |
919 | if let Some(s) = target_config.and_then(|c| c.default_linker.as_ref()) { | |
920 | cargo.env("CFG_DEFAULT_LINKER", s); | |
921 | } else if let Some(ref s) = builder.config.rustc_default_linker { | |
7453a54e SL |
922 | cargo.env("CFG_DEFAULT_LINKER", s); |
923 | } | |
a2a8927a | 924 | |
9fa01778 | 925 | if builder.config.rustc_parallel { |
5e7ed085 FG |
926 | // keep in sync with `bootstrap/lib.rs:Build::rustc_features` |
927 | // `cfg` option for rustc, `features` option for cargo, for conditional compilation | |
e1599b0c | 928 | cargo.rustflag("--cfg=parallel_compiler"); |
17df50a5 | 929 | cargo.rustdocflag("--cfg=parallel_compiler"); |
ff7c6d11 | 930 | } |
0bf4aa26 XL |
931 | if builder.config.rust_verify_llvm_ir { |
932 | cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); | |
933 | } | |
60c5eb7d | 934 | |
60c5eb7d | 935 | // Note that this is disabled if LLVM itself is disabled or we're in a check |
f9f354fc | 936 | // build. If we are in a check build we still go ahead here presuming we've |
5e7ed085 | 937 | // detected that LLVM is already built and good to go which helps prevent |
f9f354fc | 938 | // busting caches (e.g. like #71152). |
353b0b11 FG |
939 | if builder.config.llvm_enabled() { |
940 | let building_is_expensive = crate::llvm::prebuilt_llvm_config(builder, target).is_err(); | |
941 | // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler | |
942 | let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage; | |
943 | let should_skip_build = building_is_expensive && can_skip_build; | |
944 | if !should_skip_build { | |
945 | rustc_llvm_env(builder, cargo, target) | |
60c5eb7d | 946 | } |
353b0b11 FG |
947 | } |
948 | } | |
064997fb | 949 | |
353b0b11 FG |
950 | /// Pass down configuration from the LLVM build into the build of |
951 | /// rustc_llvm and rustc_codegen_llvm. | |
952 | fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { | |
953 | let target_config = builder.config.target_config.get(&target); | |
064997fb | 954 | |
353b0b11 FG |
955 | if builder.is_rust_llvm(target) { |
956 | cargo.env("LLVM_RUSTLLVM", "1"); | |
957 | } | |
958 | let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); | |
959 | cargo.env("LLVM_CONFIG", &llvm_config); | |
960 | if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { | |
961 | cargo.env("CFG_LLVM_ROOT", s); | |
962 | } | |
963 | ||
964 | // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script | |
965 | // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by | |
966 | // whitespace. | |
967 | // | |
968 | // For example: | |
969 | // - on windows, when `clang-cl` is used with instrumentation, we need to manually add | |
970 | // clang's runtime library resource directory so that the profiler runtime library can be | |
971 | // found. This is to avoid the linker errors about undefined references to | |
972 | // `__llvm_profile_instrument_memop` when linking `rustc_driver`. | |
973 | let mut llvm_linker_flags = String::new(); | |
974 | if builder.config.llvm_profile_generate && target.contains("msvc") { | |
975 | if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl { | |
976 | // Add clang's runtime library directory to the search path | |
977 | let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); | |
978 | llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display())); | |
064997fb | 979 | } |
353b0b11 | 980 | } |
064997fb | 981 | |
353b0b11 FG |
982 | // The config can also specify its own llvm linker flags. |
983 | if let Some(ref s) = builder.config.llvm_ldflags { | |
064997fb | 984 | if !llvm_linker_flags.is_empty() { |
353b0b11 | 985 | llvm_linker_flags.push_str(" "); |
60c5eb7d | 986 | } |
353b0b11 FG |
987 | llvm_linker_flags.push_str(s); |
988 | } | |
064997fb | 989 | |
353b0b11 FG |
990 | // Set the linker flags via the env var that `rustc_llvm`'s build script will read. |
991 | if !llvm_linker_flags.is_empty() { | |
992 | cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags); | |
993 | } | |
994 | ||
995 | // Building with a static libstdc++ is only supported on linux right now, | |
996 | // not for MSVC or macOS | |
997 | if builder.config.llvm_static_stdcpp | |
998 | && !target.contains("freebsd") | |
999 | && !target.contains("msvc") | |
1000 | && !target.contains("apple") | |
1001 | && !target.contains("solaris") | |
1002 | { | |
fe692bf9 FG |
1003 | let file = compiler_file( |
1004 | builder, | |
1005 | &builder.cxx(target).unwrap(), | |
1006 | target, | |
1007 | CLang::Cxx, | |
1008 | "libstdc++.a", | |
1009 | ); | |
353b0b11 FG |
1010 | cargo.env("LLVM_STATIC_STDCPP", file); |
1011 | } | |
1012 | if builder.llvm_link_shared() { | |
1013 | cargo.env("LLVM_LINK_SHARED", "1"); | |
1014 | } | |
1015 | if builder.config.llvm_use_libcxx { | |
1016 | cargo.env("LLVM_USE_LIBCXX", "1"); | |
1017 | } | |
1018 | if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo { | |
1019 | cargo.env("LLVM_NDEBUG", "1"); | |
60c5eb7d | 1020 | } |
7453a54e SL |
1021 | } |
1022 | ||
3b2f2976 XL |
1023 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
1024 | struct RustcLink { | |
1025 | pub compiler: Compiler, | |
1026 | pub target_compiler: Compiler, | |
3dfed10e | 1027 | pub target: TargetSelection, |
064997fb FG |
1028 | /// Not actually used; only present to make sure the cache invalidation is correct. |
1029 | crates: Interned<Vec<String>>, | |
1030 | } | |
1031 | ||
1032 | impl RustcLink { | |
1033 | fn from_rustc(rustc: Rustc, host_compiler: Compiler) -> Self { | |
1034 | Self { | |
1035 | compiler: host_compiler, | |
1036 | target_compiler: rustc.compiler, | |
1037 | target: rustc.target, | |
1038 | crates: rustc.crates, | |
1039 | } | |
1040 | } | |
3b2f2976 XL |
1041 | } |
1042 | ||
1043 | impl Step for RustcLink { | |
1044 | type Output = (); | |
1045 | ||
9fa01778 | 1046 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
1047 | run.never() |
1048 | } | |
1049 | ||
1050 | /// Same as `std_link`, only for librustc | |
9fa01778 | 1051 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
1052 | let compiler = self.compiler; |
1053 | let target_compiler = self.target_compiler; | |
1054 | let target = self.target; | |
532ac7d7 XL |
1055 | add_to_sysroot( |
1056 | builder, | |
1057 | &builder.sysroot_libdir(target_compiler, target), | |
1058 | &builder.sysroot_libdir(target_compiler, compiler.host), | |
dfeec247 | 1059 | &librustc_stamp(builder, compiler, target), |
532ac7d7 | 1060 | ); |
3b2f2976 | 1061 | } |
7453a54e SL |
1062 | } |
1063 | ||
29967ef6 XL |
1064 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
1065 | pub struct CodegenBackend { | |
1066 | pub target: TargetSelection, | |
1067 | pub compiler: Compiler, | |
1068 | pub backend: Interned<String>, | |
1069 | } | |
1070 | ||
353b0b11 FG |
1071 | fn needs_codegen_config(run: &RunConfig<'_>) -> bool { |
1072 | let mut needs_codegen_cfg = false; | |
1073 | for path_set in &run.paths { | |
1074 | needs_codegen_cfg = match path_set { | |
1075 | PathSet::Set(set) => set.iter().any(|p| is_codegen_cfg_needed(p, run)), | |
1076 | PathSet::Suite(suite) => is_codegen_cfg_needed(&suite, run), | |
1077 | } | |
1078 | } | |
1079 | needs_codegen_cfg | |
1080 | } | |
1081 | ||
1082 | const CODEGEN_BACKEND_PREFIX: &str = "rustc_codegen_"; | |
1083 | ||
1084 | fn is_codegen_cfg_needed(path: &TaskPath, run: &RunConfig<'_>) -> bool { | |
1085 | if path.path.to_str().unwrap().contains(&CODEGEN_BACKEND_PREFIX) { | |
1086 | let mut needs_codegen_backend_config = true; | |
1087 | for &backend in &run.builder.config.rust_codegen_backends { | |
1088 | if path | |
1089 | .path | |
1090 | .to_str() | |
1091 | .unwrap() | |
1092 | .ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + &backend)) | |
1093 | { | |
1094 | needs_codegen_backend_config = false; | |
1095 | } | |
1096 | } | |
1097 | if needs_codegen_backend_config { | |
1098 | run.builder.info( | |
1099 | "Warning: no codegen-backends config matched the requested path to build a codegen backend. \ | |
1100 | Help: add backend to codegen-backends in config.toml.", | |
1101 | ); | |
1102 | return true; | |
1103 | } | |
1104 | } | |
1105 | ||
1106 | return false; | |
1107 | } | |
1108 | ||
29967ef6 XL |
1109 | impl Step for CodegenBackend { |
1110 | type Output = (); | |
1111 | const ONLY_HOSTS: bool = true; | |
1112 | // Only the backends specified in the `codegen-backends` entry of `config.toml` are built. | |
1113 | const DEFAULT: bool = true; | |
1114 | ||
1115 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
04454e1e | 1116 | run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"]) |
29967ef6 XL |
1117 | } |
1118 | ||
1119 | fn make_run(run: RunConfig<'_>) { | |
353b0b11 FG |
1120 | if needs_codegen_config(&run) { |
1121 | return; | |
1122 | } | |
1123 | ||
29967ef6 XL |
1124 | for &backend in &run.builder.config.rust_codegen_backends { |
1125 | if backend == "llvm" { | |
1126 | continue; // Already built as part of rustc | |
1127 | } | |
1128 | ||
1129 | run.builder.ensure(CodegenBackend { | |
1130 | target: run.target, | |
1131 | compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), | |
1132 | backend, | |
1133 | }); | |
1134 | } | |
1135 | } | |
1136 | ||
1137 | fn run(self, builder: &Builder<'_>) { | |
1138 | let compiler = self.compiler; | |
1139 | let target = self.target; | |
1140 | let backend = self.backend; | |
1141 | ||
064997fb | 1142 | builder.ensure(Rustc::new(compiler, target)); |
29967ef6 XL |
1143 | |
1144 | if builder.config.keep_stage.contains(&compiler.stage) { | |
1145 | builder.info( | |
1146 | "Warning: Using a potentially old codegen backend. \ | |
1147 | This may not behave well.", | |
1148 | ); | |
1149 | // Codegen backends are linked separately from this step today, so we don't do | |
1150 | // anything here. | |
1151 | return; | |
1152 | } | |
1153 | ||
1154 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); | |
1155 | if compiler_to_use != compiler { | |
1156 | builder.ensure(CodegenBackend { compiler: compiler_to_use, target, backend }); | |
1157 | return; | |
1158 | } | |
1159 | ||
1160 | let out_dir = builder.cargo_out(compiler, Mode::Codegen, target); | |
1161 | ||
c295e0f8 | 1162 | let mut cargo = builder.cargo(compiler, Mode::Codegen, SourceType::InTree, target, "build"); |
29967ef6 XL |
1163 | cargo |
1164 | .arg("--manifest-path") | |
1165 | .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend))); | |
353b0b11 | 1166 | rustc_cargo_env(builder, &mut cargo, target, compiler.stage); |
29967ef6 XL |
1167 | |
1168 | let tmp_stamp = out_dir.join(".tmp.stamp"); | |
1169 | ||
49aad941 | 1170 | let _guard = builder.msg_build(compiler, format_args!("codegen backend {backend}"), target); |
9c376795 | 1171 | let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false, false); |
487cf647 | 1172 | if builder.config.dry_run() { |
29967ef6 XL |
1173 | return; |
1174 | } | |
1175 | let mut files = files.into_iter().filter(|f| { | |
1176 | let filename = f.file_name().unwrap().to_str().unwrap(); | |
1177 | is_dylib(filename) && filename.contains("rustc_codegen_") | |
1178 | }); | |
1179 | let codegen_backend = match files.next() { | |
1180 | Some(f) => f, | |
1181 | None => panic!("no dylibs built for codegen backend?"), | |
1182 | }; | |
1183 | if let Some(f) = files.next() { | |
1184 | panic!( | |
1185 | "codegen backend built two dylibs:\n{}\n{}", | |
1186 | codegen_backend.display(), | |
1187 | f.display() | |
1188 | ); | |
1189 | } | |
1190 | let stamp = codegen_backend_stamp(builder, compiler, target, backend); | |
1191 | let codegen_backend = codegen_backend.to_str().unwrap(); | |
1192 | t!(fs::write(&stamp, &codegen_backend)); | |
1193 | } | |
1194 | } | |
1195 | ||
1196 | /// Creates the `codegen-backends` folder for a compiler that's about to be | |
1197 | /// assembled as a complete compiler. | |
1198 | /// | |
1199 | /// This will take the codegen artifacts produced by `compiler` and link them | |
1200 | /// into an appropriate location for `target_compiler` to be a functional | |
1201 | /// compiler. | |
1202 | fn copy_codegen_backends_to_sysroot( | |
1203 | builder: &Builder<'_>, | |
1204 | compiler: Compiler, | |
1205 | target_compiler: Compiler, | |
1206 | ) { | |
1207 | let target = target_compiler.host; | |
1208 | ||
1209 | // Note that this step is different than all the other `*Link` steps in | |
1210 | // that it's not assembling a bunch of libraries but rather is primarily | |
1211 | // moving the codegen backend into place. The codegen backend of rustc is | |
1212 | // not linked into the main compiler by default but is rather dynamically | |
1213 | // selected at runtime for inclusion. | |
1214 | // | |
1215 | // Here we're looking for the output dylib of the `CodegenBackend` step and | |
1216 | // we're copying that into the `codegen-backends` folder. | |
1217 | let dst = builder.sysroot_codegen_backends(target_compiler); | |
fc512014 | 1218 | t!(fs::create_dir_all(&dst), dst); |
29967ef6 | 1219 | |
487cf647 | 1220 | if builder.config.dry_run() { |
29967ef6 XL |
1221 | return; |
1222 | } | |
1223 | ||
1224 | for backend in builder.config.rust_codegen_backends.iter() { | |
1225 | if backend == "llvm" { | |
1226 | continue; // Already built as part of rustc | |
1227 | } | |
1228 | ||
1229 | let stamp = codegen_backend_stamp(builder, compiler, target, *backend); | |
1230 | let dylib = t!(fs::read_to_string(&stamp)); | |
1231 | let file = Path::new(&dylib); | |
1232 | let filename = file.file_name().unwrap().to_str().unwrap(); | |
1233 | // change `librustc_codegen_cranelift-xxxxxx.so` to | |
1234 | // `librustc_codegen_cranelift-release.so` | |
1235 | let target_filename = { | |
1236 | let dash = filename.find('-').unwrap(); | |
1237 | let dot = filename.find('.').unwrap(); | |
1238 | format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..]) | |
1239 | }; | |
1240 | builder.copy(&file, &dst.join(target_filename)); | |
1241 | } | |
1242 | } | |
1243 | ||
7453a54e SL |
1244 | /// Cargo's output path for the standard library in a given stage, compiled |
1245 | /// by a particular compiler for the specified target. | |
3dfed10e | 1246 | pub fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { |
94b46f34 | 1247 | builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp") |
7453a54e SL |
1248 | } |
1249 | ||
cc61c64b XL |
1250 | /// Cargo's output path for librustc in a given stage, compiled by a particular |
1251 | /// compiler for the specified target. | |
9fa01778 XL |
1252 | pub fn librustc_stamp( |
1253 | builder: &Builder<'_>, | |
1254 | compiler: Compiler, | |
3dfed10e | 1255 | target: TargetSelection, |
9fa01778 | 1256 | ) -> PathBuf { |
94b46f34 | 1257 | builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp") |
cc61c64b XL |
1258 | } |
1259 | ||
29967ef6 XL |
1260 | /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular |
1261 | /// compiler for the specified target and backend. | |
1262 | fn codegen_backend_stamp( | |
1263 | builder: &Builder<'_>, | |
1264 | compiler: Compiler, | |
1265 | target: TargetSelection, | |
1266 | backend: Interned<String>, | |
1267 | ) -> PathBuf { | |
1268 | builder | |
1269 | .cargo_out(compiler, Mode::Codegen, target) | |
1270 | .join(format!(".librustc_codegen_{}.stamp", backend)) | |
1271 | } | |
1272 | ||
9fa01778 XL |
1273 | pub fn compiler_file( |
1274 | builder: &Builder<'_>, | |
1275 | compiler: &Path, | |
3dfed10e | 1276 | target: TargetSelection, |
5099ac24 | 1277 | c: CLang, |
9fa01778 XL |
1278 | file: &str, |
1279 | ) -> PathBuf { | |
fe692bf9 FG |
1280 | if builder.config.dry_run() { |
1281 | return PathBuf::new(); | |
1282 | } | |
2c00a5a8 | 1283 | let mut cmd = Command::new(compiler); |
5099ac24 | 1284 | cmd.args(builder.cflags(target, GitRepo::Rustc, c)); |
2c00a5a8 XL |
1285 | cmd.arg(format!("-print-file-name={}", file)); |
1286 | let out = output(&mut cmd); | |
54a0048b | 1287 | PathBuf::from(out.trim()) |
7453a54e SL |
1288 | } |
1289 | ||
3b2f2976 XL |
1290 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
1291 | pub struct Sysroot { | |
1292 | pub compiler: Compiler, | |
fe692bf9 FG |
1293 | /// See [`Std::force_recompile`]. |
1294 | force_recompile: bool, | |
1295 | } | |
1296 | ||
1297 | impl Sysroot { | |
1298 | pub(crate) fn new(compiler: Compiler) -> Self { | |
1299 | Sysroot { compiler, force_recompile: false } | |
1300 | } | |
32a655c1 SL |
1301 | } |
1302 | ||
3b2f2976 XL |
1303 | impl Step for Sysroot { |
1304 | type Output = Interned<PathBuf>; | |
1305 | ||
9fa01778 | 1306 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 1307 | run.never() |
7453a54e SL |
1308 | } |
1309 | ||
3b2f2976 XL |
1310 | /// Returns the sysroot for the `compiler` specified that *this build system |
1311 | /// generates*. | |
1312 | /// | |
1313 | /// That is, the sysroot for the stage0 compiler is not what the compiler | |
1314 | /// thinks it is by default, but it's the same as the default for stages | |
1315 | /// 1-3. | |
9fa01778 | 1316 | fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> { |
3b2f2976 | 1317 | let compiler = self.compiler; |
2b03887a | 1318 | let host_dir = builder.out.join(&compiler.host.triple); |
487cf647 FG |
1319 | |
1320 | let sysroot_dir = |stage| { | |
1321 | if stage == 0 { | |
1322 | host_dir.join("stage0-sysroot") | |
fe692bf9 FG |
1323 | } else if self.force_recompile && stage == compiler.stage { |
1324 | host_dir.join(format!("stage{stage}-test-sysroot")) | |
487cf647 FG |
1325 | } else if builder.download_rustc() && compiler.stage != builder.top_stage { |
1326 | host_dir.join("ci-rustc-sysroot") | |
1327 | } else { | |
1328 | host_dir.join(format!("stage{}", stage)) | |
1329 | } | |
3b2f2976 | 1330 | }; |
487cf647 FG |
1331 | let sysroot = sysroot_dir(compiler.stage); |
1332 | ||
49aad941 | 1333 | builder.verbose(&format!("Removing sysroot {} to avoid caching bugs", sysroot.display())); |
3b2f2976 XL |
1334 | let _ = fs::remove_dir_all(&sysroot); |
1335 | t!(fs::create_dir_all(&sysroot)); | |
ba9703b0 | 1336 | |
6a06907d | 1337 | // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0. |
923072b8 | 1338 | if builder.download_rustc() && compiler.stage != 0 { |
6a06907d XL |
1339 | assert_eq!( |
1340 | builder.config.build, compiler.host, | |
1341 | "Cross-compiling is not yet supported with `download-rustc`", | |
1342 | ); | |
2b03887a | 1343 | |
487cf647 FG |
1344 | // #102002, cleanup old toolchain folders when using download-rustc so people don't use them by accident. |
1345 | for stage in 0..=2 { | |
1346 | if stage != compiler.stage { | |
1347 | let dir = sysroot_dir(stage); | |
1348 | if !dir.ends_with("ci-rustc-sysroot") { | |
1349 | let _ = fs::remove_dir_all(dir); | |
1350 | } | |
1351 | } | |
1352 | } | |
2b03887a | 1353 | |
6a06907d | 1354 | // Copy the compiler into the correct sysroot. |
49aad941 FG |
1355 | // NOTE(#108767): We intentionally don't copy `rustc-dev` artifacts until they're requested with `builder.ensure(Rustc)`. |
1356 | // This fixes an issue where we'd have multiple copies of libc in the sysroot with no way to tell which to load. | |
1357 | // There are a few quirks of bootstrap that interact to make this reliable: | |
1358 | // 1. The order `Step`s are run is hard-coded in `builder.rs` and not configurable. This | |
1359 | // avoids e.g. reordering `test::UiFulldeps` before `test::Ui` and causing the latter to | |
1360 | // fail because of duplicate metadata. | |
1361 | // 2. The sysroot is deleted and recreated between each invocation, so running `x test | |
1362 | // ui-fulldeps && x test ui` can't cause failures. | |
1363 | let mut filtered_files = Vec::new(); | |
fe692bf9 FG |
1364 | let mut add_filtered_files = |suffix, contents| { |
1365 | for path in contents { | |
1366 | let path = Path::new(&path); | |
1367 | if path.parent().map_or(false, |parent| parent.ends_with(&suffix)) { | |
1368 | filtered_files.push(path.file_name().unwrap().to_owned()); | |
1369 | } | |
49aad941 | 1370 | } |
fe692bf9 FG |
1371 | }; |
1372 | let suffix = format!("lib/rustlib/{}/lib", compiler.host); | |
1373 | add_filtered_files(suffix.as_str(), builder.config.ci_rustc_dev_contents()); | |
1374 | // NOTE: we can't copy std eagerly because `stage2-test-sysroot` needs to have only the | |
1375 | // newly compiled std, not the downloaded std. | |
1376 | add_filtered_files("lib", builder.config.ci_rust_std_contents()); | |
1377 | ||
1378 | let filtered_extensions = [ | |
1379 | OsStr::new("rmeta"), | |
1380 | OsStr::new("rlib"), | |
1381 | // FIXME: this is wrong when compiler.host != build, but we don't support that today | |
1382 | OsStr::new(std::env::consts::DLL_EXTENSION), | |
1383 | ]; | |
49aad941 FG |
1384 | let ci_rustc_dir = builder.ci_rustc_dir(builder.config.build); |
1385 | builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| { | |
1386 | if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) { | |
1387 | return true; | |
1388 | } | |
1389 | if !path.parent().map_or(true, |p| p.ends_with(&suffix)) { | |
1390 | return true; | |
1391 | } | |
1392 | if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) { | |
1393 | builder.verbose_than(1, &format!("ignoring {}", path.display())); | |
1394 | false | |
1395 | } else { | |
1396 | true | |
1397 | } | |
1398 | }); | |
6a06907d XL |
1399 | } |
1400 | ||
ba9703b0 XL |
1401 | // Symlink the source root into the same location inside the sysroot, |
1402 | // where `rust-src` component would go (`$sysroot/lib/rustlib/src/rust`), | |
1403 | // so that any tools relying on `rust-src` also work for local builds, | |
1404 | // and also for translating the virtual `/rustc/$hash` back to the real | |
1405 | // directory (for running tests with `rust.remap-debuginfo = true`). | |
1406 | let sysroot_lib_rustlib_src = sysroot.join("lib/rustlib/src"); | |
1407 | t!(fs::create_dir_all(&sysroot_lib_rustlib_src)); | |
1408 | let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust"); | |
1409 | if let Err(e) = symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust) { | |
1410 | eprintln!( | |
1411 | "warning: creating symbolic link `{}` to `{}` failed with {}", | |
1412 | sysroot_lib_rustlib_src_rust.display(), | |
1413 | builder.src.display(), | |
1414 | e, | |
1415 | ); | |
1416 | if builder.config.rust_remap_debuginfo { | |
1417 | eprintln!( | |
9c376795 | 1418 | "warning: some `tests/ui` tests will fail when lacking `{}`", |
ba9703b0 XL |
1419 | sysroot_lib_rustlib_src_rust.display(), |
1420 | ); | |
1421 | } | |
1422 | } | |
2b03887a FG |
1423 | // Same for the rustc-src component. |
1424 | let sysroot_lib_rustlib_rustcsrc = sysroot.join("lib/rustlib/rustc-src"); | |
1425 | t!(fs::create_dir_all(&sysroot_lib_rustlib_rustcsrc)); | |
1426 | let sysroot_lib_rustlib_rustcsrc_rust = sysroot_lib_rustlib_rustcsrc.join("rust"); | |
1427 | if let Err(e) = | |
1428 | symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_rustcsrc_rust) | |
1429 | { | |
1430 | eprintln!( | |
1431 | "warning: creating symbolic link `{}` to `{}` failed with {}", | |
1432 | sysroot_lib_rustlib_rustcsrc_rust.display(), | |
1433 | builder.src.display(), | |
1434 | e, | |
1435 | ); | |
1436 | } | |
ba9703b0 | 1437 | |
3b2f2976 XL |
1438 | INTERNER.intern_path(sysroot) |
1439 | } | |
1440 | } | |
1441 | ||
83c7162d | 1442 | #[derive(Debug, Copy, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] |
3b2f2976 XL |
1443 | pub struct Assemble { |
1444 | /// The compiler which we will produce in this step. Assemble itself will | |
1445 | /// take care of ensuring that the necessary prerequisites to do so exist, | |
1446 | /// that is, this target can be a stage2 compiler and Assemble will build | |
1447 | /// previous stages for you. | |
1448 | pub target_compiler: Compiler, | |
1449 | } | |
7453a54e | 1450 | |
3b2f2976 XL |
1451 | impl Step for Assemble { |
1452 | type Output = Compiler; | |
c295e0f8 | 1453 | const ONLY_HOSTS: bool = true; |
7453a54e | 1454 | |
9fa01778 | 1455 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
04454e1e | 1456 | run.path("compiler/rustc").path("compiler") |
c295e0f8 XL |
1457 | } |
1458 | ||
1459 | fn make_run(run: RunConfig<'_>) { | |
1460 | run.builder.ensure(Assemble { | |
1461 | target_compiler: run.builder.compiler(run.builder.top_stage + 1, run.target), | |
1462 | }); | |
3b2f2976 XL |
1463 | } |
1464 | ||
1465 | /// Prepare a new compiler from the artifacts in `stage` | |
1466 | /// | |
1467 | /// This will assemble a compiler in `build/$host/stage$stage`. The compiler | |
83c7162d | 1468 | /// must have been previously produced by the `stage - 1` builder.build |
3b2f2976 | 1469 | /// compiler. |
9fa01778 | 1470 | fn run(self, builder: &Builder<'_>) -> Compiler { |
3b2f2976 XL |
1471 | let target_compiler = self.target_compiler; |
1472 | ||
1473 | if target_compiler.stage == 0 { | |
dfeec247 XL |
1474 | assert_eq!( |
1475 | builder.config.build, target_compiler.host, | |
1476 | "Cannot obtain compiler for non-native build triple at stage 0" | |
1477 | ); | |
3b2f2976 XL |
1478 | // The stage 0 compiler for the build triple is always pre-built. |
1479 | return target_compiler; | |
1480 | } | |
1481 | ||
1482 | // Get the compiler that we'll use to bootstrap ourselves. | |
2c00a5a8 XL |
1483 | // |
1484 | // Note that this is where the recursive nature of the bootstrap | |
1485 | // happens, as this will request the previous stage's compiler on | |
1486 | // downwards to stage 0. | |
1487 | // | |
1488 | // Also note that we're building a compiler for the host platform. We | |
1489 | // only assume that we can run `build` artifacts, which means that to | |
1490 | // produce some other architecture compiler we need to start from | |
1491 | // `build` to get there. | |
1492 | // | |
2c00a5a8 XL |
1493 | // FIXME: It may be faster if we build just a stage 1 compiler and then |
1494 | // use that to bootstrap this compiler forward. | |
dfeec247 | 1495 | let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); |
3b2f2976 | 1496 | |
6a06907d | 1497 | // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0. |
923072b8 | 1498 | if builder.download_rustc() { |
fe692bf9 FG |
1499 | let sysroot = |
1500 | builder.ensure(Sysroot { compiler: target_compiler, force_recompile: false }); | |
353b0b11 FG |
1501 | // Ensure that `libLLVM.so` ends up in the newly created target directory, |
1502 | // so that tools using `rustc_private` can use it. | |
1503 | dist::maybe_install_llvm_target(builder, target_compiler.host, &sysroot); | |
fe692bf9 FG |
1504 | // Lower stages use `ci-rustc-sysroot`, not stageN |
1505 | if target_compiler.stage == builder.top_stage { | |
1506 | builder.info(&format!("Creating a sysroot for stage{stage} compiler (use `rustup toolchain link 'name' build/host/stage{stage}`)", stage=target_compiler.stage)); | |
1507 | } | |
6a06907d XL |
1508 | return target_compiler; |
1509 | } | |
1510 | ||
3b2f2976 XL |
1511 | // Build the libraries for this compiler to link to (i.e., the libraries |
1512 | // it uses at runtime). NOTE: Crates the target compiler compiles don't | |
1513 | // link to these. (FIXME: Is that correct? It seems to be correct most | |
1514 | // of the time but I think we do link to these for stage2/bin compilers | |
1515 | // when not performing a full bootstrap). | |
064997fb | 1516 | builder.ensure(Rustc::new(build_compiler, target_compiler.host)); |
3b2f2976 | 1517 | |
353b0b11 FG |
1518 | // FIXME: For now patch over problems noted in #90244 by early returning here, even though |
1519 | // we've not properly assembled the target sysroot. A full fix is pending further investigation, | |
1520 | // for now full bootstrap usage is rare enough that this is OK. | |
1521 | if target_compiler.stage >= 3 && !builder.config.full_bootstrap { | |
1522 | return target_compiler; | |
1523 | } | |
1524 | ||
29967ef6 XL |
1525 | for &backend in builder.config.rust_codegen_backends.iter() { |
1526 | if backend == "llvm" { | |
1527 | continue; // Already built as part of rustc | |
1528 | } | |
1529 | ||
1530 | builder.ensure(CodegenBackend { | |
1531 | compiler: build_compiler, | |
1532 | target: target_compiler.host, | |
1533 | backend, | |
1534 | }); | |
1535 | } | |
1536 | ||
83c7162d | 1537 | let lld_install = if builder.config.lld_enabled { |
353b0b11 | 1538 | Some(builder.ensure(llvm::Lld { target: target_compiler.host })) |
0531ce1d XL |
1539 | } else { |
1540 | None | |
1541 | }; | |
1542 | ||
3b2f2976 XL |
1543 | let stage = target_compiler.stage; |
1544 | let host = target_compiler.host; | |
fe692bf9 FG |
1545 | let (host_info, dir_name) = if build_compiler.host == host { |
1546 | ("".into(), "host".into()) | |
9ffffee4 | 1547 | } else { |
fe692bf9 | 1548 | (format!(" ({host})"), host.to_string()) |
9ffffee4 | 1549 | }; |
fe692bf9 FG |
1550 | // NOTE: "Creating a sysroot" is somewhat inconsistent with our internal terminology, since |
1551 | // sysroots can temporarily be empty until we put the compiler inside. However, | |
1552 | // `ensure(Sysroot)` isn't really something that's user facing, so there shouldn't be any | |
1553 | // ambiguity. | |
1554 | let msg = format!( | |
1555 | "Creating a sysroot for stage{stage} compiler{host_info} (use `rustup toolchain link 'name' build/{dir_name}/stage{stage}`)" | |
1556 | ); | |
9ffffee4 | 1557 | builder.info(&msg); |
3b2f2976 XL |
1558 | |
1559 | // Link in all dylibs to the libdir | |
5869c6ff XL |
1560 | let stamp = librustc_stamp(builder, build_compiler, target_compiler.host); |
1561 | let proc_macros = builder | |
1562 | .read_stamp_file(&stamp) | |
1563 | .into_iter() | |
1564 | .filter_map(|(path, dependency_type)| { | |
1565 | if dependency_type == DependencyType::Host { | |
1566 | Some(path.file_name().unwrap().to_owned().into_string().unwrap()) | |
1567 | } else { | |
1568 | None | |
1569 | } | |
1570 | }) | |
1571 | .collect::<HashSet<_>>(); | |
1572 | ||
3b2f2976 | 1573 | let sysroot = builder.sysroot(target_compiler); |
532ac7d7 XL |
1574 | let rustc_libdir = builder.rustc_libdir(target_compiler); |
1575 | t!(fs::create_dir_all(&rustc_libdir)); | |
3b2f2976 | 1576 | let src_libdir = builder.sysroot_libdir(build_compiler, host); |
83c7162d | 1577 | for f in builder.read_dir(&src_libdir) { |
3b2f2976 | 1578 | let filename = f.file_name().into_string().unwrap(); |
6a06907d XL |
1579 | if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename) |
1580 | { | |
532ac7d7 | 1581 | builder.copy(&f.path(), &rustc_libdir.join(&filename)); |
3b2f2976 XL |
1582 | } |
1583 | } | |
1584 | ||
29967ef6 XL |
1585 | copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); |
1586 | ||
fc512014 XL |
1587 | // We prepend this bin directory to the user PATH when linking Rust binaries. To |
1588 | // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. | |
60c5eb7d | 1589 | let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host); |
fc512014 XL |
1590 | let libdir_bin = libdir.parent().unwrap().join("bin"); |
1591 | t!(fs::create_dir_all(&libdir_bin)); | |
0531ce1d | 1592 | if let Some(lld_install) = lld_install { |
3dfed10e XL |
1593 | let src_exe = exe("lld", target_compiler.host); |
1594 | let dst_exe = exe("rust-lld", target_compiler.host); | |
fc512014 | 1595 | builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe)); |
17df50a5 XL |
1596 | // for `-Z gcc-ld=lld` |
1597 | let gcc_ld_dir = libdir_bin.join("gcc-ld"); | |
1598 | t!(fs::create_dir(&gcc_ld_dir)); | |
923072b8 FG |
1599 | let lld_wrapper_exe = builder.ensure(crate::tool::LldWrapper { |
1600 | compiler: build_compiler, | |
1601 | target: target_compiler.host, | |
1602 | }); | |
f2b60f7d FG |
1603 | for name in crate::LLD_FILE_NAMES { |
1604 | builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(name, target_compiler.host))); | |
1605 | } | |
fc512014 XL |
1606 | } |
1607 | ||
5869c6ff | 1608 | if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { |
353b0b11 FG |
1609 | let llvm::LlvmResult { llvm_config, .. } = |
1610 | builder.ensure(llvm::Llvm { target: target_compiler.host }); | |
487cf647 | 1611 | if !builder.config.dry_run() { |
9c376795 | 1612 | let llvm_bin_dir = output(Command::new(llvm_config).arg("--bindir")); |
fc512014 | 1613 | let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); |
a2a8927a XL |
1614 | |
1615 | // Since we've already built the LLVM tools, install them to the sysroot. | |
1616 | // This is the equivalent of installing the `llvm-tools-preview` component via | |
1617 | // rustup, and lets developers use a locally built toolchain to | |
1618 | // build projects that expect llvm tools to be present in the sysroot | |
1619 | // (e.g. the `bootimage` crate). | |
1620 | for tool in LLVM_TOOLS { | |
1621 | let tool_exe = exe(tool, target_compiler.host); | |
1622 | let src_path = llvm_bin_dir.join(&tool_exe); | |
5e7ed085 | 1623 | // When using `download-ci-llvm`, some of the tools |
a2a8927a XL |
1624 | // may not exist, so skip trying to copy them. |
1625 | if src_path.exists() { | |
1626 | builder.copy(&src_path, &libdir_bin.join(&tool_exe)); | |
1627 | } | |
1628 | } | |
fc512014 | 1629 | } |
0531ce1d | 1630 | } |
3b2f2976 | 1631 | |
60c5eb7d XL |
1632 | // Ensure that `libLLVM.so` ends up in the newly build compiler directory, |
1633 | // so that it can be found when the newly built `rustc` is run. | |
f9f354fc XL |
1634 | dist::maybe_install_llvm_runtime(builder, target_compiler.host, &sysroot); |
1635 | dist::maybe_install_llvm_target(builder, target_compiler.host, &sysroot); | |
0731742a | 1636 | |
3b2f2976 | 1637 | // Link the compiler binary itself into place |
94b46f34 | 1638 | let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); |
1b1a35ee | 1639 | let rustc = out_dir.join(exe("rustc-main", host)); |
3b2f2976 XL |
1640 | let bindir = sysroot.join("bin"); |
1641 | t!(fs::create_dir_all(&bindir)); | |
1642 | let compiler = builder.rustc(target_compiler); | |
83c7162d | 1643 | builder.copy(&rustc, &compiler); |
3b2f2976 XL |
1644 | |
1645 | target_compiler | |
7453a54e SL |
1646 | } |
1647 | } | |
1648 | ||
1649 | /// Link some files into a rustc sysroot. | |
1650 | /// | |
7cac9316 XL |
1651 | /// For a particular stage this will link the file listed in `stamp` into the |
1652 | /// `sysroot_dst` provided. | |
532ac7d7 XL |
1653 | pub fn add_to_sysroot( |
1654 | builder: &Builder<'_>, | |
1655 | sysroot_dst: &Path, | |
1656 | sysroot_host_dst: &Path, | |
dfeec247 | 1657 | stamp: &Path, |
532ac7d7 | 1658 | ) { |
f035d41b | 1659 | let self_contained_dst = &sysroot_dst.join("self-contained"); |
7cac9316 | 1660 | t!(fs::create_dir_all(&sysroot_dst)); |
532ac7d7 | 1661 | t!(fs::create_dir_all(&sysroot_host_dst)); |
f035d41b XL |
1662 | t!(fs::create_dir_all(&self_contained_dst)); |
1663 | for (path, dependency_type) in builder.read_stamp_file(stamp) { | |
1664 | let dst = match dependency_type { | |
1665 | DependencyType::Host => sysroot_host_dst, | |
1666 | DependencyType::Target => sysroot_dst, | |
1667 | DependencyType::TargetSelfContained => self_contained_dst, | |
1668 | }; | |
1669 | builder.copy(&path, &dst.join(path.file_name().unwrap())); | |
7453a54e SL |
1670 | } |
1671 | } | |
54a0048b | 1672 | |
dfeec247 XL |
1673 | pub fn run_cargo( |
1674 | builder: &Builder<'_>, | |
1675 | cargo: Cargo, | |
1676 | tail_args: Vec<String>, | |
1677 | stamp: &Path, | |
f035d41b | 1678 | additional_target_deps: Vec<(PathBuf, DependencyType)>, |
dfeec247 | 1679 | is_check: bool, |
9c376795 | 1680 | rlib_only_metadata: bool, |
dfeec247 | 1681 | ) -> Vec<PathBuf> { |
487cf647 | 1682 | if builder.config.dry_run() { |
83c7162d XL |
1683 | return Vec::new(); |
1684 | } | |
1685 | ||
7cac9316 XL |
1686 | // `target_root_dir` looks like $dir/$target/release |
1687 | let target_root_dir = stamp.parent().unwrap(); | |
1688 | // `target_deps_dir` looks like $dir/$target/release/deps | |
1689 | let target_deps_dir = target_root_dir.join("deps"); | |
1690 | // `host_root_dir` looks like $dir/release | |
dfeec247 XL |
1691 | let host_root_dir = target_root_dir |
1692 | .parent() | |
1693 | .unwrap() // chop off `release` | |
1694 | .parent() | |
1695 | .unwrap() // chop off `$target` | |
1696 | .join(target_root_dir.file_name().unwrap()); | |
7cac9316 XL |
1697 | |
1698 | // Spawn Cargo slurping up its JSON output. We'll start building up the | |
1699 | // `deps` array of all files it generated along with a `toplevel` array of | |
1700 | // files we need to probe for later. | |
1701 | let mut deps = Vec::new(); | |
1702 | let mut toplevel = Vec::new(); | |
dc9dc135 | 1703 | let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| { |
532ac7d7 XL |
1704 | let (filenames, crate_types) = match msg { |
1705 | CargoMessage::CompilerArtifact { | |
1706 | filenames, | |
dfeec247 | 1707 | target: CargoTarget { crate_types }, |
532ac7d7 XL |
1708 | .. |
1709 | } => (filenames, crate_types), | |
0531ce1d | 1710 | _ => return, |
7cac9316 | 1711 | }; |
0531ce1d | 1712 | for filename in filenames { |
7cac9316 | 1713 | // Skip files like executables |
9c376795 FG |
1714 | let mut keep = false; |
1715 | if filename.ends_with(".lib") | |
74b04a01 | 1716 | || filename.ends_with(".a") |
6a06907d | 1717 | || is_debug_info(&filename) |
74b04a01 | 1718 | || is_dylib(&filename) |
dfeec247 | 1719 | { |
9c376795 FG |
1720 | // Always keep native libraries, rust dylibs and debuginfo |
1721 | keep = true; | |
1722 | } | |
1723 | if is_check && filename.ends_with(".rmeta") { | |
1724 | // During check builds we need to keep crate metadata | |
1725 | keep = true; | |
1726 | } else if rlib_only_metadata { | |
1727 | if filename.contains("jemalloc_sys") || filename.contains("rustc_smir") { | |
1728 | // jemalloc_sys and rustc_smir are not linked into librustc_driver.so, | |
1729 | // so we need to distribute them as rlib to be able to use them. | |
1730 | keep |= filename.ends_with(".rlib"); | |
1731 | } else { | |
1732 | // Distribute the rest of the rustc crates as rmeta files only to reduce | |
1733 | // the tarball sizes by about 50%. The object files are linked into | |
1734 | // librustc_driver.so, so it is still possible to link against them. | |
1735 | keep |= filename.ends_with(".rmeta"); | |
1736 | } | |
1737 | } else { | |
1738 | // In all other cases keep all rlibs | |
1739 | keep |= filename.ends_with(".rlib"); | |
1740 | } | |
1741 | ||
1742 | if !keep { | |
8faf50e0 | 1743 | continue; |
7cac9316 XL |
1744 | } |
1745 | ||
0531ce1d | 1746 | let filename = Path::new(&*filename); |
7cac9316 XL |
1747 | |
1748 | // If this was an output file in the "host dir" we don't actually | |
532ac7d7 | 1749 | // worry about it, it's not relevant for us |
7cac9316 | 1750 | if filename.starts_with(&host_root_dir) { |
532ac7d7 XL |
1751 | // Unless it's a proc macro used in the compiler |
1752 | if crate_types.iter().any(|t| t == "proc-macro") { | |
f035d41b | 1753 | deps.push((filename.to_path_buf(), DependencyType::Host)); |
532ac7d7 | 1754 | } |
8faf50e0 | 1755 | continue; |
041b39d2 | 1756 | } |
7cac9316 XL |
1757 | |
1758 | // If this was output in the `deps` dir then this is a precise file | |
1759 | // name (hash included) so we start tracking it. | |
041b39d2 | 1760 | if filename.starts_with(&target_deps_dir) { |
f035d41b | 1761 | deps.push((filename.to_path_buf(), DependencyType::Target)); |
8faf50e0 | 1762 | continue; |
041b39d2 | 1763 | } |
7cac9316 XL |
1764 | |
1765 | // Otherwise this was a "top level artifact" which right now doesn't | |
1766 | // have a hash in the name, but there's a version of this file in | |
1767 | // the `deps` folder which *does* have a hash in the name. That's | |
1768 | // the one we'll want to we'll probe for it later. | |
abe05a73 XL |
1769 | // |
1770 | // We do not use `Path::file_stem` or `Path::extension` here, | |
1771 | // because some generated files may have multiple extensions e.g. | |
1772 | // `std-<hash>.dll.lib` on Windows. The aforementioned methods only | |
1773 | // split the file name by the last extension (`.lib`) while we need | |
1774 | // to split by all extensions (`.dll.lib`). | |
1775 | let expected_len = t!(filename.metadata()).len(); | |
1776 | let filename = filename.file_name().unwrap().to_str().unwrap(); | |
1777 | let mut parts = filename.splitn(2, '.'); | |
1778 | let file_stem = parts.next().unwrap().to_owned(); | |
1779 | let extension = parts.next().unwrap().to_owned(); | |
1780 | ||
1781 | toplevel.push((file_stem, extension, expected_len)); | |
7cac9316 | 1782 | } |
0531ce1d | 1783 | }); |
7cac9316 | 1784 | |
0531ce1d | 1785 | if !ok { |
fe692bf9 | 1786 | crate::detail_exit_macro!(1); |
7cac9316 XL |
1787 | } |
1788 | ||
1789 | // Ok now we need to actually find all the files listed in `toplevel`. We've | |
1790 | // got a list of prefix/extensions and we basically just need to find the | |
1791 | // most recent file in the `deps` folder corresponding to each one. | |
1792 | let contents = t!(target_deps_dir.read_dir()) | |
1793 | .map(|e| t!(e)) | |
1794 | .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata()))) | |
1795 | .collect::<Vec<_>>(); | |
abe05a73 XL |
1796 | for (prefix, extension, expected_len) in toplevel { |
1797 | let candidates = contents.iter().filter(|&&(_, ref filename, ref meta)| { | |
f035d41b XL |
1798 | meta.len() == expected_len |
1799 | && filename | |
1800 | .strip_prefix(&prefix[..]) | |
1801 | .map(|s| s.starts_with('-') && s.ends_with(&extension[..])) | |
1802 | .unwrap_or(false) | |
7cac9316 | 1803 | }); |
5e7ed085 FG |
1804 | let max = candidates.max_by_key(|&&(_, _, ref metadata)| { |
1805 | metadata.modified().expect("mtime should be available on all relevant OSes") | |
1806 | }); | |
7cac9316 XL |
1807 | let path_to_add = match max { |
1808 | Some(triple) => triple.0.to_str().unwrap(), | |
1809 | None => panic!("no output generated for {:?} {:?}", prefix, extension), | |
1810 | }; | |
1811 | if is_dylib(path_to_add) { | |
1812 | let candidate = format!("{}.lib", path_to_add); | |
1813 | let candidate = PathBuf::from(candidate); | |
1814 | if candidate.exists() { | |
f035d41b | 1815 | deps.push((candidate, DependencyType::Target)); |
7cac9316 XL |
1816 | } |
1817 | } | |
f035d41b | 1818 | deps.push((path_to_add.into(), DependencyType::Target)); |
7cac9316 XL |
1819 | } |
1820 | ||
f035d41b | 1821 | deps.extend(additional_target_deps); |
7cac9316 | 1822 | deps.sort(); |
7cac9316 | 1823 | let mut new_contents = Vec::new(); |
f035d41b XL |
1824 | for (dep, dependency_type) in deps.iter() { |
1825 | new_contents.extend(match *dependency_type { | |
1826 | DependencyType::Host => b"h", | |
1827 | DependencyType::Target => b"t", | |
1828 | DependencyType::TargetSelfContained => b"s", | |
1829 | }); | |
7cac9316 XL |
1830 | new_contents.extend(dep.to_str().unwrap().as_bytes()); |
1831 | new_contents.extend(b"\0"); | |
1832 | } | |
0731742a | 1833 | t!(fs::write(&stamp, &new_contents)); |
532ac7d7 | 1834 | deps.into_iter().map(|(d, _)| d).collect() |
9e0c209e | 1835 | } |
0531ce1d XL |
1836 | |
1837 | pub fn stream_cargo( | |
9fa01778 | 1838 | builder: &Builder<'_>, |
e1599b0c | 1839 | cargo: Cargo, |
dc9dc135 | 1840 | tail_args: Vec<String>, |
9fa01778 | 1841 | cb: &mut dyn FnMut(CargoMessage<'_>), |
0531ce1d | 1842 | ) -> bool { |
e1599b0c | 1843 | let mut cargo = Command::from(cargo); |
487cf647 | 1844 | if builder.config.dry_run() { |
83c7162d XL |
1845 | return true; |
1846 | } | |
0531ce1d XL |
1847 | // Instruct Cargo to give us json messages on stdout, critically leaving |
1848 | // stderr as piped so we can get those pretty colors. | |
ba9703b0 XL |
1849 | let mut message_format = if builder.config.json_output { |
1850 | String::from("json") | |
1851 | } else { | |
1852 | String::from("json-render-diagnostics") | |
1853 | }; | |
dfeec247 | 1854 | if let Some(s) = &builder.config.rustc_error_format { |
e1599b0c XL |
1855 | message_format.push_str(",json-diagnostic-"); |
1856 | message_format.push_str(s); | |
1857 | } | |
1858 | cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped()); | |
0531ce1d | 1859 | |
dc9dc135 XL |
1860 | for arg in tail_args { |
1861 | cargo.arg(arg); | |
1862 | } | |
1863 | ||
83c7162d | 1864 | builder.verbose(&format!("running: {:?}", cargo)); |
0531ce1d XL |
1865 | let mut child = match cargo.spawn() { |
1866 | Ok(child) => child, | |
1867 | Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e), | |
1868 | }; | |
1869 | ||
1870 | // Spawn Cargo slurping up its JSON output. We'll start building up the | |
1871 | // `deps` array of all files it generated along with a `toplevel` array of | |
1872 | // files we need to probe for later. | |
1873 | let stdout = BufReader::new(child.stdout.take().unwrap()); | |
1874 | for line in stdout.lines() { | |
1875 | let line = t!(line); | |
9fa01778 | 1876 | match serde_json::from_str::<CargoMessage<'_>>(&line) { |
f035d41b XL |
1877 | Ok(msg) => { |
1878 | if builder.config.json_output { | |
1879 | // Forward JSON to stdout. | |
1880 | println!("{}", line); | |
1881 | } | |
1882 | cb(msg) | |
1883 | } | |
0531ce1d | 1884 | // If this was informational, just print it out and continue |
dfeec247 | 1885 | Err(_) => println!("{}", line), |
0531ce1d XL |
1886 | } |
1887 | } | |
1888 | ||
1889 | // Make sure Cargo actually succeeded after we read all of its stdout. | |
1890 | let status = t!(child.wait()); | |
136023e0 | 1891 | if builder.is_verbose() && !status.success() { |
dfeec247 XL |
1892 | eprintln!( |
1893 | "command did not execute successfully: {:?}\n\ | |
0531ce1d | 1894 | expected success, got: {}", |
dfeec247 XL |
1895 | cargo, status |
1896 | ); | |
0531ce1d XL |
1897 | } |
1898 | status.success() | |
1899 | } | |
1900 | ||
532ac7d7 XL |
1901 | #[derive(Deserialize)] |
1902 | pub struct CargoTarget<'a> { | |
1903 | crate_types: Vec<Cow<'a, str>>, | |
1904 | } | |
1905 | ||
0531ce1d XL |
1906 | #[derive(Deserialize)] |
1907 | #[serde(tag = "reason", rename_all = "kebab-case")] | |
1908 | pub enum CargoMessage<'a> { | |
1909 | CompilerArtifact { | |
1910 | package_id: Cow<'a, str>, | |
1911 | features: Vec<Cow<'a, str>>, | |
1912 | filenames: Vec<Cow<'a, str>>, | |
532ac7d7 | 1913 | target: CargoTarget<'a>, |
0531ce1d XL |
1914 | }, |
1915 | BuildScriptExecuted { | |
1916 | package_id: Cow<'a, str>, | |
dc9dc135 | 1917 | }, |
f9f354fc XL |
1918 | BuildFinished { |
1919 | success: bool, | |
1920 | }, | |
dc9dc135 | 1921 | } |