]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/builder.rs
New upstream version 1.49.0~beta.4+dfsg1
[rustc.git] / src / bootstrap / builder.rs
CommitLineData
ea8adc8c 1use std::any::Any;
0531ce1d 2use std::cell::{Cell, RefCell};
ea8adc8c
XL
3use std::collections::BTreeSet;
4use std::env;
e1599b0c 5use std::ffi::OsStr;
3b2f2976 6use std::fmt::Debug;
ea8adc8c 7use std::fs;
3b2f2976 8use std::hash::Hash;
ea8adc8c 9use std::ops::Deref;
3b2f2976
XL
10use std::path::{Path, PathBuf};
11use std::process::Command;
94b46f34 12use std::time::{Duration, Instant};
3b2f2976 13
ba9703b0 14use build_helper::{output, t};
48663c56 15
0731742a
XL
16use crate::cache::{Cache, Interned, INTERNER};
17use crate::check;
18use crate::compile;
3dfed10e 19use crate::config::TargetSelection;
0731742a
XL
20use crate::dist;
21use crate::doc;
22use crate::flags::Subcommand;
23use crate::install;
24use crate::native;
ba9703b0 25use crate::run;
0731742a 26use crate::test;
f035d41b 27use crate::tool::{self, SourceType};
ba9703b0 28use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir};
dfeec247 29use crate::{Build, DocTests, GitRepo, Mode};
0731742a
XL
30
31pub use crate::Compiler;
3b2f2976
XL
32
33pub struct Builder<'a> {
34 pub build: &'a Build,
35 pub top_stage: u32,
36 pub kind: Kind,
37 cache: Cache,
8faf50e0 38 stack: RefCell<Vec<Box<dyn Any>>>,
0531ce1d 39 time_spent_on_dependencies: Cell<Duration>,
83c7162d 40 pub paths: Vec<PathBuf>,
3b2f2976
XL
41}
42
43impl<'a> Deref for Builder<'a> {
44 type Target = Build;
45
46 fn deref(&self) -> &Self::Target {
47 self.build
48 }
49}
50
51pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
52 /// `PathBuf` when directories are created or to return a `Compiler` once
53 /// it's been assembled.
54 type Output: Clone;
55
f035d41b
XL
56 /// Whether this step is run by default as part of its respective phase.
57 /// `true` here can still be overwritten by `should_run` calling `default_condition`.
3b2f2976
XL
58 const DEFAULT: bool = false;
59
dc9dc135 60 /// If true, then this rule should be skipped if --target was specified, but --host was not
3b2f2976
XL
61 const ONLY_HOSTS: bool = false;
62
9fa01778 63 /// Primary function to execute this rule. Can call `builder.ensure()`
3b2f2976 64 /// with other steps to run those.
9fa01778 65 fn run(self, builder: &Builder<'_>) -> Self::Output;
3b2f2976
XL
66
67 /// When bootstrap is passed a set of paths, this controls whether this rule
68 /// will execute. However, it does not get called in a "default" context
9fa01778 69 /// when we are not passed any paths; in that case, `make_run` is called
3b2f2976 70 /// directly.
9fa01778 71 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_>;
3b2f2976 72
9fa01778 73 /// Builds up a "root" rule, either as a default rule or from a path passed
3b2f2976
XL
74 /// to us.
75 ///
76 /// When path is `None`, we are executing in a context where no paths were
77 /// passed. When `./x.py build` is run, for example, this rule could get
78 /// called if it is in the correct list below with a path of `None`.
9fa01778 79 fn make_run(_run: RunConfig<'_>) {
3b2f2976
XL
80 // It is reasonable to not have an implementation of make_run for rules
81 // who do not want to get called from the root context. This means that
82 // they are likely dependencies (e.g., sysroot creation) or similar, and
83 // as such calling them from ./x.py isn't logical.
84 unimplemented!()
85 }
86}
87
88pub struct RunConfig<'a> {
89 pub builder: &'a Builder<'a>,
3dfed10e 90 pub target: TargetSelection,
2c00a5a8 91 pub path: PathBuf,
3b2f2976
XL
92}
93
1b1a35ee
XL
94impl RunConfig<'_> {
95 pub fn build_triple(&self) -> TargetSelection {
96 self.builder.build.build
97 }
98}
99
3b2f2976
XL
100struct StepDescription {
101 default: bool,
102 only_hosts: bool,
9fa01778
XL
103 should_run: fn(ShouldRun<'_>) -> ShouldRun<'_>,
104 make_run: fn(RunConfig<'_>),
2c00a5a8
XL
105 name: &'static str,
106}
107
f035d41b 108/// Collection of paths used to match a task rule.
2c00a5a8 109#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
94b46f34 110pub enum PathSet {
f035d41b
XL
111 /// A collection of individual paths.
112 ///
113 /// These are generally matched as a path suffix. For example, a
114 /// command-line value of `libstd` will match if `src/libstd` is in the
115 /// set.
94b46f34 116 Set(BTreeSet<PathBuf>),
f035d41b
XL
117 /// A "suite" of paths.
118 ///
119 /// These can match as a path suffix (like `Set`), or as a prefix. For
120 /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs`
121 /// will match `src/test/ui`. A command-line value of `ui` would also
122 /// match `src/test/ui`.
94b46f34 123 Suite(PathBuf),
2c00a5a8
XL
124}
125
126impl PathSet {
127 fn empty() -> PathSet {
94b46f34 128 PathSet::Set(BTreeSet::new())
2c00a5a8
XL
129 }
130
131 fn one<P: Into<PathBuf>>(path: P) -> PathSet {
132 let mut set = BTreeSet::new();
133 set.insert(path.into());
94b46f34 134 PathSet::Set(set)
2c00a5a8
XL
135 }
136
137 fn has(&self, needle: &Path) -> bool {
94b46f34
XL
138 match self {
139 PathSet::Set(set) => set.iter().any(|p| p.ends_with(needle)),
13cf67c4 140 PathSet::Suite(suite) => suite.ends_with(needle),
94b46f34 141 }
2c00a5a8
XL
142 }
143
9fa01778 144 fn path(&self, builder: &Builder<'_>) -> PathBuf {
94b46f34 145 match self {
dfeec247 146 PathSet::Set(set) => set.iter().next().unwrap_or(&builder.build.src).to_path_buf(),
94b46f34
XL
147 PathSet::Suite(path) => PathBuf::from(path),
148 }
2c00a5a8 149 }
3b2f2976
XL
150}
151
152impl StepDescription {
153 fn from<S: Step>() -> StepDescription {
154 StepDescription {
155 default: S::DEFAULT,
156 only_hosts: S::ONLY_HOSTS,
3b2f2976
XL
157 should_run: S::should_run,
158 make_run: S::make_run,
e1599b0c 159 name: std::any::type_name::<S>(),
3b2f2976
XL
160 }
161 }
162
9fa01778 163 fn maybe_run(&self, builder: &Builder<'_>, pathset: &PathSet) {
2c00a5a8
XL
164 if builder.config.exclude.iter().any(|e| pathset.has(e)) {
165 eprintln!("Skipping {:?} because it is excluded", pathset);
166 return;
167 } else if !builder.config.exclude.is_empty() {
94b46f34
XL
168 eprintln!(
169 "{:?} not skipped for {:?} -- not in {:?}",
170 pathset, self.name, builder.config.exclude
171 );
2c00a5a8 172 }
3b2f2976
XL
173
174 // Determine the targets participating in this rule.
1b1a35ee 175 let targets = if self.only_hosts { &builder.hosts } else { &builder.targets };
3b2f2976 176
1b1a35ee
XL
177 for target in targets {
178 let run = RunConfig { builder, path: pathset.path(builder), target: *target };
179 (self.make_run)(run);
3b2f2976
XL
180 }
181 }
182
9fa01778 183 fn run(v: &[StepDescription], builder: &Builder<'_>, paths: &[PathBuf]) {
dfeec247
XL
184 let should_runs =
185 v.iter().map(|desc| (desc.should_run)(ShouldRun::new(builder))).collect::<Vec<_>>();
2c00a5a8
XL
186
187 // sanity checks on rules
188 for (desc, should_run) in v.iter().zip(&should_runs) {
94b46f34
XL
189 assert!(
190 !should_run.paths.is_empty(),
191 "{:?} should have at least one pathset",
192 desc.name
193 );
2c00a5a8
XL
194 }
195
1b1a35ee
XL
196 if paths.is_empty() || builder.config.include_default_paths {
197 for (desc, should_run) in v.iter().zip(&should_runs) {
3b2f2976 198 if desc.default && should_run.is_really_default {
2c00a5a8
XL
199 for pathset in &should_run.paths {
200 desc.maybe_run(builder, pathset);
201 }
3b2f2976
XL
202 }
203 }
1b1a35ee 204 }
8faf50e0 205
1b1a35ee
XL
206 for path in paths {
207 // strip CurDir prefix if present
208 let path = match path.strip_prefix(".") {
209 Ok(p) => p,
210 Err(_) => path,
211 };
3b2f2976 212
1b1a35ee
XL
213 let mut attempted_run = false;
214 for (desc, should_run) in v.iter().zip(&should_runs) {
215 if let Some(suite) = should_run.is_suite_path(path) {
216 attempted_run = true;
217 desc.maybe_run(builder, suite);
218 } else if let Some(pathset) = should_run.pathset_for_path(path) {
219 attempted_run = true;
220 desc.maybe_run(builder, pathset);
3b2f2976
XL
221 }
222 }
1b1a35ee
XL
223
224 if !attempted_run {
225 panic!("error: no rules matched {}", path.display());
226 }
3b2f2976
XL
227 }
228 }
229}
230
231#[derive(Clone)]
232pub struct ShouldRun<'a> {
233 pub builder: &'a Builder<'a>,
234 // use a BTreeSet to maintain sort order
2c00a5a8 235 paths: BTreeSet<PathSet>,
3b2f2976
XL
236
237 // If this is a default rule, this is an additional constraint placed on
0531ce1d 238 // its run. Generally something like compiler docs being enabled.
3b2f2976
XL
239 is_really_default: bool,
240}
241
242impl<'a> ShouldRun<'a> {
9fa01778 243 fn new(builder: &'a Builder<'_>) -> ShouldRun<'a> {
3b2f2976
XL
244 ShouldRun {
245 builder,
246 paths: BTreeSet::new(),
247 is_really_default: true, // by default no additional conditions
248 }
249 }
250
251 pub fn default_condition(mut self, cond: bool) -> Self {
252 self.is_really_default = cond;
253 self
254 }
255
f035d41b
XL
256 /// Indicates it should run if the command-line selects the given crate or
257 /// any of its (local) dependencies.
258 ///
259 /// Compared to `krate`, this treats the dependencies as aliases for the
260 /// same job. Generally it is preferred to use `krate`, and treat each
261 /// individual path separately. For example `./x.py test src/liballoc`
262 /// (which uses `krate`) will test just `liballoc`. However, `./x.py check
263 /// src/liballoc` (which uses `all_krates`) will check all of `libtest`.
264 /// `all_krates` should probably be removed at some point.
2c00a5a8
XL
265 pub fn all_krates(mut self, name: &str) -> Self {
266 let mut set = BTreeSet::new();
29967ef6 267 for krate in self.builder.in_tree_crates(name, None) {
f035d41b
XL
268 let path = krate.local_path(self.builder);
269 set.insert(path);
2c00a5a8 270 }
94b46f34 271 self.paths.insert(PathSet::Set(set));
2c00a5a8
XL
272 self
273 }
274
f035d41b
XL
275 /// Indicates it should run if the command-line selects the given crate or
276 /// any of its (local) dependencies.
277 ///
278 /// `make_run` will be called separately for each matching command-line path.
3b2f2976 279 pub fn krate(mut self, name: &str) -> Self {
29967ef6 280 for krate in self.builder.in_tree_crates(name, None) {
f035d41b
XL
281 let path = krate.local_path(self.builder);
282 self.paths.insert(PathSet::one(path));
3b2f2976
XL
283 }
284 self
285 }
286
2c00a5a8
XL
287 // single, non-aliased path
288 pub fn path(self, path: &str) -> Self {
289 self.paths(&[path])
290 }
291
292 // multiple aliases for the same job
293 pub fn paths(mut self, paths: &[&str]) -> Self {
dfeec247 294 self.paths.insert(PathSet::Set(paths.iter().map(PathBuf::from).collect()));
94b46f34
XL
295 self
296 }
297
298 pub fn is_suite_path(&self, path: &Path) -> Option<&PathSet> {
299 self.paths.iter().find(|pathset| match pathset {
300 PathSet::Suite(p) => path.starts_with(p),
301 PathSet::Set(_) => false,
302 })
303 }
304
305 pub fn suite_path(mut self, suite: &str) -> Self {
306 self.paths.insert(PathSet::Suite(PathBuf::from(suite)));
3b2f2976
XL
307 self
308 }
309
310 // allows being more explicit about why should_run in Step returns the value passed to it
2c00a5a8
XL
311 pub fn never(mut self) -> ShouldRun<'a> {
312 self.paths.insert(PathSet::empty());
3b2f2976
XL
313 self
314 }
315
2c00a5a8
XL
316 fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> {
317 self.paths.iter().find(|pathset| pathset.has(path))
3b2f2976
XL
318 }
319}
320
321#[derive(Copy, Clone, PartialEq, Eq, Debug)]
322pub enum Kind {
323 Build,
2c00a5a8 324 Check,
dc9dc135
XL
325 Clippy,
326 Fix,
dfeec247 327 Format,
3b2f2976
XL
328 Test,
329 Bench,
330 Dist,
331 Doc,
332 Install,
ba9703b0 333 Run,
3b2f2976
XL
334}
335
336impl<'a> Builder<'a> {
337 fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
338 macro_rules! describe {
9fa01778 339 ($($rule:ty),+ $(,)?) => {{
3b2f2976
XL
340 vec![$(StepDescription::from::<$rule>()),+]
341 }};
342 }
343 match kind {
94b46f34
XL
344 Kind::Build => describe!(
345 compile::Std,
94b46f34 346 compile::Rustc,
29967ef6 347 compile::CodegenBackend,
94b46f34
XL
348 compile::StartupObjects,
349 tool::BuildManifest,
350 tool::Rustbook,
351 tool::ErrorIndex,
352 tool::UnstableBookGen,
353 tool::Tidy,
354 tool::Linkchecker,
355 tool::CargoTest,
356 tool::Compiletest,
357 tool::RemoteTestServer,
358 tool::RemoteTestClient,
359 tool::RustInstaller,
360 tool::Cargo,
361 tool::Rls,
f035d41b 362 tool::RustAnalyzer,
3dfed10e 363 tool::RustDemangler,
94b46f34
XL
364 tool::Rustdoc,
365 tool::Clippy,
f9f354fc 366 tool::CargoClippy,
94b46f34 367 native::Llvm,
dfeec247 368 native::Sanitizers,
94b46f34
XL
369 tool::Rustfmt,
370 tool::Miri,
f9f354fc 371 tool::CargoMiri,
94b46f34
XL
372 native::Lld
373 ),
29967ef6
XL
374 Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!(
375 check::Std,
376 check::Rustc,
377 check::Rustdoc,
378 check::CodegenBackend,
379 check::Clippy,
380 check::Bootstrap
381 ),
94b46f34 382 Kind::Test => describe!(
60c5eb7d 383 crate::toolstate::ToolStateCheck,
ba9703b0 384 test::ExpandYamlAnchors,
94b46f34
XL
385 test::Tidy,
386 test::Ui,
94b46f34 387 test::CompileFail,
94b46f34
XL
388 test::RunPassValgrind,
389 test::MirOpt,
390 test::Codegen,
391 test::CodegenUnits,
532ac7d7 392 test::Assembly,
94b46f34
XL
393 test::Incremental,
394 test::Debuginfo,
395 test::UiFullDeps,
94b46f34
XL
396 test::Rustdoc,
397 test::Pretty,
94b46f34
XL
398 test::Crate,
399 test::CrateLibrustc,
400 test::CrateRustdoc,
401 test::Linkcheck,
3dfed10e 402 test::TierCheck,
94b46f34
XL
403 test::Cargotest,
404 test::Cargo,
405 test::Rls,
406 test::ErrorIndex,
407 test::Distcheck,
0531ce1d 408 test::RunMakeFullDeps,
94b46f34
XL
409 test::Nomicon,
410 test::Reference,
411 test::RustdocBook,
412 test::RustByExample,
413 test::TheBook,
414 test::UnstableBook,
415 test::RustcBook,
416331ca 416 test::RustcGuide,
9fa01778 417 test::EmbeddedBook,
532ac7d7 418 test::EditionGuide,
94b46f34
XL
419 test::Rustfmt,
420 test::Miri,
421 test::Clippy,
0731742a 422 test::CompiletestTest,
9fa01778
XL
423 test::RustdocJSStd,
424 test::RustdocJSNotStd,
94b46f34 425 test::RustdocTheme,
532ac7d7 426 test::RustdocUi,
94b46f34
XL
427 // Run bootstrap close to the end as it's unlikely to fail
428 test::Bootstrap,
0531ce1d 429 // Run run-make last, since these won't pass without make on Windows
94b46f34 430 test::RunMake,
94b46f34 431 ),
2c00a5a8 432 Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
94b46f34
XL
433 Kind::Doc => describe!(
434 doc::UnstableBook,
435 doc::UnstableBookGen,
436 doc::TheBook,
437 doc::Standalone,
438 doc::Std,
94b46f34
XL
439 doc::Rustc,
440 doc::Rustdoc,
441 doc::ErrorIndex,
442 doc::Nomicon,
443 doc::Reference,
444 doc::RustdocBook,
445 doc::RustByExample,
446 doc::RustcBook,
450edc1f 447 doc::CargoBook,
9fa01778 448 doc::EmbeddedBook,
450edc1f 449 doc::EditionGuide,
94b46f34
XL
450 ),
451 Kind::Dist => describe!(
452 dist::Docs,
453 dist::RustcDocs,
454 dist::Mingw,
455 dist::Rustc,
456 dist::DebuggerScripts,
457 dist::Std,
e74abb32 458 dist::RustcDev,
94b46f34
XL
459 dist::Analysis,
460 dist::Src,
461 dist::PlainSourceTarball,
462 dist::Cargo,
463 dist::Rls,
f035d41b 464 dist::RustAnalyzer,
94b46f34 465 dist::Rustfmt,
8faf50e0 466 dist::Clippy,
0731742a 467 dist::Miri,
8faf50e0 468 dist::LlvmTools,
1b1a35ee 469 dist::RustDev,
94b46f34 470 dist::Extended,
1b1a35ee 471 dist::BuildManifest,
94b46f34
XL
472 ),
473 Kind::Install => describe!(
474 install::Docs,
475 install::Std,
476 install::Cargo,
477 install::Rls,
f035d41b 478 install::RustAnalyzer,
94b46f34 479 install::Rustfmt,
8faf50e0 480 install::Clippy,
0731742a 481 install::Miri,
94b46f34
XL
482 install::Analysis,
483 install::Src,
484 install::Rustc
485 ),
29967ef6 486 Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest),
3b2f2976
XL
487 }
488 }
489
490 pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
491 let kind = match subcommand {
492 "build" => Kind::Build,
493 "doc" => Kind::Doc,
494 "test" => Kind::Test,
495 "bench" => Kind::Bench,
496 "dist" => Kind::Dist,
497 "install" => Kind::Install,
498 _ => return None,
499 };
500
3dfed10e 501 let builder = Self::new_internal(build, kind, vec![]);
3b2f2976
XL
502 let builder = &builder;
503 let mut should_run = ShouldRun::new(builder);
504 for desc in Builder::get_step_descriptions(builder.kind) {
505 should_run = (desc.should_run)(should_run);
506 }
507 let mut help = String::from("Available paths:\n");
f035d41b
XL
508 let mut add_path = |path: &Path| {
509 help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display()));
510 };
2c00a5a8 511 for pathset in should_run.paths {
f035d41b
XL
512 match pathset {
513 PathSet::Set(set) => {
514 for path in set {
515 add_path(&path);
516 }
517 }
518 PathSet::Suite(path) => {
519 add_path(&path.join("..."));
520 }
2c00a5a8 521 }
3b2f2976
XL
522 }
523 Some(help)
524 }
525
3dfed10e 526 fn new_internal(build: &Build, kind: Kind, paths: Vec<PathBuf>) -> Builder<'_> {
3dfed10e
XL
527 Builder {
528 build,
1b1a35ee 529 top_stage: build.config.stage,
3dfed10e
XL
530 kind,
531 cache: Cache::new(),
532 stack: RefCell::new(Vec::new()),
533 time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
534 paths,
535 }
536 }
537
9fa01778 538 pub fn new(build: &Build) -> Builder<'_> {
3b2f2976
XL
539 let (kind, paths) = match build.config.cmd {
540 Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
29967ef6
XL
541 Subcommand::Check { ref paths, all_targets: _ } => (Kind::Check, &paths[..]),
542 Subcommand::Clippy { ref paths, .. } => (Kind::Clippy, &paths[..]),
dc9dc135 543 Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
f9f354fc 544 Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]),
3b2f2976
XL
545 Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
546 Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
547 Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
548 Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
ba9703b0 549 Subcommand::Run { ref paths } => (Kind::Run, &paths[..]),
1b1a35ee
XL
550 Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
551 panic!()
3dfed10e 552 }
1b1a35ee 553 };
3dfed10e 554
1b1a35ee 555 Self::new_internal(build, kind, paths.to_owned())
83c7162d
XL
556 }
557
dfeec247 558 pub fn execute_cli(&self) {
83c7162d 559 self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths);
3b2f2976
XL
560 }
561
562 pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
563 let paths = paths.unwrap_or(&[]);
83c7162d
XL
564 self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
565 }
566
567 fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
568 StepDescription::run(v, self, paths);
3b2f2976
XL
569 }
570
571 /// Obtain a compiler at a given stage and for a given host. Explicitly does
572 /// not take `Compiler` since all `Compiler` instances are meant to be
573 /// obtained through this function, since it ensures that they are valid
574 /// (i.e., built and assembled).
3dfed10e 575 pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler {
dfeec247 576 self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
3b2f2976
XL
577 }
578
dc9dc135
XL
579 /// Similar to `compiler`, except handles the full-bootstrap option to
580 /// silently use the stage1 compiler instead of a stage2 compiler if one is
581 /// requested.
582 ///
583 /// Note that this does *not* have the side effect of creating
584 /// `compiler(stage, host)`, unlike `compiler` above which does have such
585 /// a side effect. The returned compiler here can only be used to compile
586 /// new artifacts, it can't be used to rely on the presence of a particular
587 /// sysroot.
588 ///
589 /// See `force_use_stage1` for documentation on what each argument is.
590 pub fn compiler_for(
591 &self,
592 stage: u32,
3dfed10e
XL
593 host: TargetSelection,
594 target: TargetSelection,
dc9dc135
XL
595 ) -> Compiler {
596 if self.build.force_use_stage1(Compiler { stage, host }, target) {
597 self.compiler(1, self.config.build)
598 } else {
599 self.compiler(stage, host)
600 }
601 }
602
3b2f2976
XL
603 pub fn sysroot(&self, compiler: Compiler) -> Interned<PathBuf> {
604 self.ensure(compile::Sysroot { compiler })
605 }
606
607 /// Returns the libdir where the standard library and other artifacts are
608 /// found for a compiler's sysroot.
3dfed10e 609 pub fn sysroot_libdir(&self, compiler: Compiler, target: TargetSelection) -> Interned<PathBuf> {
3b2f2976
XL
610 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
611 struct Libdir {
612 compiler: Compiler,
3dfed10e 613 target: TargetSelection,
3b2f2976
XL
614 }
615 impl Step for Libdir {
616 type Output = Interned<PathBuf>;
617
9fa01778 618 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976
XL
619 run.never()
620 }
621
9fa01778 622 fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> {
e1599b0c 623 let lib = builder.sysroot_libdir_relative(self.compiler);
94b46f34
XL
624 let sysroot = builder
625 .sysroot(self.compiler)
626 .join(lib)
627 .join("rustlib")
3dfed10e 628 .join(self.target.triple)
94b46f34 629 .join("lib");
3b2f2976
XL
630 let _ = fs::remove_dir_all(&sysroot);
631 t!(fs::create_dir_all(&sysroot));
632 INTERNER.intern_path(sysroot)
633 }
634 }
635 self.ensure(Libdir { compiler, target })
636 }
637
29967ef6
XL
638 pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
639 self.sysroot_libdir(compiler, compiler.host).with_file_name("codegen-backends")
640 }
641
3b2f2976
XL
642 /// Returns the compiler's libdir where it stores the dynamic libraries that
643 /// it itself links against.
644 ///
645 /// For example this returns `<sysroot>/lib` on Unix and `<sysroot>/bin` on
646 /// Windows.
647 pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf {
648 if compiler.is_snapshot(self) {
83c7162d 649 self.rustc_snapshot_libdir()
3b2f2976 650 } else {
532ac7d7 651 match self.config.libdir_relative() {
dfeec247
XL
652 Some(relative_libdir) if compiler.stage >= 1 => {
653 self.sysroot(compiler).join(relative_libdir)
654 }
3dfed10e 655 _ => self.sysroot(compiler).join(libdir(compiler.host)),
532ac7d7
XL
656 }
657 }
658 }
659
660 /// Returns the compiler's relative libdir where it stores the dynamic libraries that
661 /// it itself links against.
662 ///
663 /// For example this returns `lib` on Unix and `bin` on
664 /// Windows.
665 pub fn libdir_relative(&self, compiler: Compiler) -> &Path {
666 if compiler.is_snapshot(self) {
3dfed10e 667 libdir(self.config.build).as_ref()
532ac7d7
XL
668 } else {
669 match self.config.libdir_relative() {
dfeec247 670 Some(relative_libdir) if compiler.stage >= 1 => relative_libdir,
3dfed10e 671 _ => libdir(compiler.host).as_ref(),
532ac7d7 672 }
3b2f2976
XL
673 }
674 }
675
e1599b0c
XL
676 /// Returns the compiler's relative libdir where the standard library and other artifacts are
677 /// found for a compiler's sysroot.
678 ///
679 /// For example this returns `lib` on Unix and Windows.
680 pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path {
681 match self.config.libdir_relative() {
dfeec247 682 Some(relative_libdir) if compiler.stage >= 1 => relative_libdir,
f9f354fc 683 _ if compiler.stage == 0 => &self.build.initial_libdir,
dfeec247 684 _ => Path::new("lib"),
e1599b0c
XL
685 }
686 }
687
3b2f2976
XL
688 /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
689 /// library lookup path.
1b1a35ee 690 pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) {
3b2f2976
XL
691 // Windows doesn't need dylib path munging because the dlls for the
692 // compiler live next to the compiler and the system will find them
693 // automatically.
694 if cfg!(windows) {
94b46f34 695 return;
3b2f2976
XL
696 }
697
1b1a35ee 698 add_dylib_path(vec![self.rustc_libdir(compiler)], cmd);
3b2f2976
XL
699 }
700
9fa01778 701 /// Gets a path to the compiler specified.
3b2f2976
XL
702 pub fn rustc(&self, compiler: Compiler) -> PathBuf {
703 if compiler.is_snapshot(self) {
704 self.initial_rustc.clone()
705 } else {
3dfed10e 706 self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
3b2f2976
XL
707 }
708 }
709
29967ef6
XL
710 /// Gets the paths to all of the compiler's codegen backends.
711 fn codegen_backends(&self, compiler: Compiler) -> impl Iterator<Item = PathBuf> {
712 fs::read_dir(self.sysroot_codegen_backends(compiler))
713 .into_iter()
714 .flatten()
715 .filter_map(Result::ok)
716 .map(|entry| entry.path())
717 }
718
532ac7d7
XL
719 pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
720 self.ensure(tool::Rustdoc { compiler })
3b2f2976
XL
721 }
722
532ac7d7 723 pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
3b2f2976 724 let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
abe05a73 725 cmd.env("RUSTC_STAGE", compiler.stage.to_string())
94b46f34 726 .env("RUSTC_SYSROOT", self.sysroot(compiler))
9fa01778
XL
727 // Note that this is *not* the sysroot_libdir because rustdoc must be linked
728 // equivalently to rustc.
729 .env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler))
94b46f34 730 .env("CFG_RELEASE_CHANNEL", &self.config.channel)
532ac7d7 731 .env("RUSTDOC_REAL", self.rustdoc(compiler))
3dfed10e
XL
732 .env("RUSTC_BOOTSTRAP", "1")
733 .arg("-Winvalid_codeblock_attributes");
734 if self.config.deny_warnings {
735 cmd.arg("-Dwarnings");
736 }
0731742a
XL
737
738 // Remove make-related flags that can cause jobserver problems.
739 cmd.env_remove("MAKEFLAGS");
740 cmd.env_remove("MFLAGS");
741
1b1a35ee
XL
742 if let Some(linker) = self.linker(compiler.host) {
743 cmd.env("RUSTDOC_LINKER", linker);
744 }
745 if self.is_fuse_ld_lld(compiler.host) {
746 cmd.env("RUSTDOC_FUSE_LD_LLD", "1");
abe05a73 747 }
3b2f2976
XL
748 cmd
749 }
750
ba9703b0
XL
751 /// Return the path to `llvm-config` for the target, if it exists.
752 ///
753 /// Note that this returns `None` if LLVM is disabled, or if we're in a
754 /// check build or dry-run, where there's no need to build all of LLVM.
3dfed10e 755 fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
ba9703b0
XL
756 if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run {
757 let llvm_config = self.ensure(native::Llvm { target });
758 if llvm_config.is_file() {
759 return Some(llvm_config);
760 }
761 }
762 None
763 }
764
3b2f2976
XL
765 /// Prepares an invocation of `cargo` to be run.
766 ///
767 /// This will create a `Command` that represents a pending execution of
768 /// Cargo. This cargo will be configured to use `compiler` as the actual
769 /// rustc compiler, its output will be scoped by `mode`'s output directory,
770 /// it will pass the `--target` flag for the specified `target`, and will be
771 /// executing the Cargo command `cmd`.
94b46f34
XL
772 pub fn cargo(
773 &self,
774 compiler: Compiler,
775 mode: Mode,
f035d41b 776 source_type: SourceType,
3dfed10e 777 target: TargetSelection,
94b46f34 778 cmd: &str,
e1599b0c 779 ) -> Cargo {
3b2f2976
XL
780 let mut cargo = Command::new(&self.initial_cargo);
781 let out_dir = self.stage_out(compiler, mode);
b7449926 782
29967ef6
XL
783 // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
784 // so we need to explicitly clear out if they've been updated.
785 for backend in self.codegen_backends(compiler) {
786 self.clear_if_dirty(&out_dir, &backend);
787 }
788
a1dfa0c6 789 if cmd == "doc" || cmd == "rustdoc" {
e1599b0c 790 let my_out = match mode {
b7449926 791 // This is the intended out directory for compiler documentation.
1b1a35ee 792 Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
3dfed10e
XL
793 Mode::Std => out_dir.join(target.triple).join("doc"),
794 _ => panic!("doc mode {:?} not expected", mode),
e1599b0c 795 };
532ac7d7 796 let rustdoc = self.rustdoc(compiler);
b7449926 797 self.clear_if_dirty(&my_out, &rustdoc);
b7449926
XL
798 }
799
74b04a01
XL
800 cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
801
e1599b0c 802 let profile_var = |name: &str| {
dfeec247 803 let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" };
e1599b0c
XL
804 format!("CARGO_PROFILE_{}_{}", profile, name)
805 };
94b46f34 806
1b1a35ee 807 // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config
9fa01778
XL
808 // needs to not accidentally link to libLLVM in stage0/lib.
809 cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var());
810 if let Some(e) = env::var_os(util::dylib_path_var()) {
811 cargo.env("REAL_LIBRARY_PATH", e);
812 }
813
94b46f34 814 if cmd != "install" {
3dfed10e 815 cargo.arg("--target").arg(target.rustc_target_arg());
94b46f34
XL
816 } else {
817 assert_eq!(target, compiler.host);
818 }
3b2f2976 819
dc9dc135 820 // Set a flag for `check`/`clippy`/`fix`, so that certain build
f9f354fc 821 // scripts can do less work (i.e. not building/requiring LLVM).
dc9dc135 822 if cmd == "check" || cmd == "clippy" || cmd == "fix" {
f9f354fc 823 // If we've not yet built LLVM, or it's stale, then bust
1b1a35ee 824 // the rustc_llvm cache. That will always work, even though it
f9f354fc 825 // may mean that on the next non-check build we'll need to rebuild
1b1a35ee 826 // rustc_llvm. But if LLVM is stale, that'll be a tiny amount
f9f354fc
XL
827 // of work comparitively, and we'd likely need to rebuild it anyway,
828 // so that's okay.
829 if crate::native::prebuilt_llvm_config(self, target).is_err() {
830 cargo.env("RUST_CHECK", "1");
831 }
83c7162d
XL
832 }
833
74b04a01 834 let stage = if compiler.stage == 0 && self.local_rebuild {
e1599b0c 835 // Assume the local-rebuild rustc already has stage1 features.
74b04a01 836 1
e1599b0c 837 } else {
74b04a01
XL
838 compiler.stage
839 };
e1599b0c 840
3dfed10e 841 let mut rustflags = Rustflags::new(target);
e1599b0c 842 if stage != 0 {
e74abb32
XL
843 if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
844 cargo.args(s.split_whitespace());
845 }
e1599b0c
XL
846 rustflags.env("RUSTFLAGS_NOT_BOOTSTRAP");
847 } else {
e74abb32
XL
848 if let Ok(s) = env::var("CARGOFLAGS_BOOTSTRAP") {
849 cargo.args(s.split_whitespace());
850 }
e1599b0c 851 rustflags.env("RUSTFLAGS_BOOTSTRAP");
29967ef6
XL
852 if cmd == "clippy" {
853 // clippy overwrites sysroot if we pass it to cargo.
854 // Pass it directly to clippy instead.
855 // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`,
856 // so it has no way of knowing the sysroot.
857 rustflags.arg("--sysroot");
858 rustflags.arg(
859 self.sysroot(compiler)
860 .as_os_str()
861 .to_str()
862 .expect("sysroot must be valid UTF-8"),
863 );
864 // Only run clippy on a very limited subset of crates (in particular, not build scripts).
865 cargo.arg("-Zunstable-options");
866 // Explicitly does *not* set `--cfg=bootstrap`, since we're using a nightly clippy.
867 let host_version = Command::new("rustc").arg("--version").output().map_err(|_| ());
868 let output = host_version.and_then(|output| {
869 if output.status.success() {
870 Ok(output)
871 } else {
872 Err(())
873 }
874 }).unwrap_or_else(|_| {
875 eprintln!(
876 "error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component"
877 );
878 eprintln!("help: try `rustup component add clippy`");
879 std::process::exit(1);
880 });
881 if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") {
882 rustflags.arg("--cfg=bootstrap");
883 }
884 } else {
885 rustflags.arg("--cfg=bootstrap");
886 }
e1599b0c
XL
887 }
888
3dfed10e
XL
889 if self.config.rust_new_symbol_mangling {
890 rustflags.arg("-Zsymbol-mangling-version=v0");
891 }
892
f9f354fc
XL
893 // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
894 // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
895 // #71458.
3dfed10e 896 let mut rustdocflags = rustflags.clone();
f9f354fc 897
e74abb32
XL
898 if let Ok(s) = env::var("CARGOFLAGS") {
899 cargo.args(s.split_whitespace());
900 }
901
532ac7d7 902 match mode {
dfeec247 903 Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
29967ef6 904 Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
532ac7d7
XL
905 // Build proc macros both for the host and the target
906 if target != compiler.host && cmd != "check" {
907 cargo.arg("-Zdual-proc-macros");
e1599b0c 908 rustflags.arg("-Zdual-proc-macros");
532ac7d7 909 }
dfeec247 910 }
532ac7d7
XL
911 }
912
e1599b0c
XL
913 // This tells Cargo (and in turn, rustc) to output more complete
914 // dependency information. Most importantly for rustbuild, this
915 // includes sysroot artifacts, like libstd, which means that we don't
916 // need to track those in rustbuild (an error prone process!). This
917 // feature is currently unstable as there may be some bugs and such, but
918 // it represents a big improvement in rustbuild's reliability on
919 // rebuilds, so we're using it here.
920 //
921 // For some additional context, see #63470 (the PR originally adding
922 // this), as well as #63012 which is the tracking issue for this
923 // feature on the rustc side.
924 cargo.arg("-Zbinary-dep-depinfo");
925
94b46f34
XL
926 cargo.arg("-j").arg(self.jobs().to_string());
927 // Remove make-related flags to ensure Cargo can correctly set things up
928 cargo.env_remove("MAKEFLAGS");
929 cargo.env_remove("MFLAGS");
ea8adc8c 930
3b2f2976
XL
931 // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
932 // Force cargo to output binaries with disambiguating hashes in the name
48663c56
XL
933 let mut metadata = if compiler.stage == 0 {
934 // Treat stage0 like a special channel, whether it's a normal prior-
94b46f34
XL
935 // release rustc or a local rebuild with the same version, so we
936 // never mix these libraries by accident.
48663c56 937 "bootstrap".to_string()
94b46f34 938 } else {
48663c56 939 self.config.channel.to_string()
94b46f34 940 };
48663c56
XL
941 // We want to make sure that none of the dependencies between
942 // std/test/rustc unify with one another. This is done for weird linkage
943 // reasons but the gist of the problem is that if librustc, libtest, and
944 // libstd all depend on libc from crates.io (which they actually do) we
945 // want to make sure they all get distinct versions. Things get really
946 // weird if we try to unify all these dependencies right now, namely
947 // around how many times the library is linked in dynamic libraries and
948 // such. If rustc were a static executable or if we didn't ship dylibs
949 // this wouldn't be a problem, but we do, so it is. This is in general
950 // just here to make sure things build right. If you can remove this and
951 // things still build right, please do!
952 match mode {
953 Mode::Std => metadata.push_str("std"),
e74abb32
XL
954 // When we're building rustc tools, they're built with a search path
955 // that contains things built during the rustc build. For example,
956 // bitflags is built during the rustc build, and is a dependency of
957 // rustdoc as well. We're building rustdoc in a different target
958 // directory, though, which means that Cargo will rebuild the
959 // dependency. When we go on to build rustdoc, we'll look for
960 // bitflags, and find two different copies: one built during the
961 // rustc step and one that we just built. This isn't always a
962 // problem, somehow -- not really clear why -- but we know that this
963 // fixes things.
964 Mode::ToolRustc => metadata.push_str("tool-rustc"),
29967ef6
XL
965 // Same for codegen backends.
966 Mode::Codegen => metadata.push_str("codegen"),
e74abb32 967 _ => {}
48663c56 968 }
94b46f34 969 cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata);
3b2f2976 970
dc9dc135 971 if cmd == "clippy" {
e1599b0c 972 rustflags.arg("-Zforce-unstable-if-unmarked");
2c00a5a8
XL
973 }
974
ba9703b0 975 rustflags.arg("-Zmacro-backtrace");
e1599b0c 976
83c7162d
XL
977 let want_rustdoc = self.doc_tests != DocTests::No;
978
8faf50e0
XL
979 // We synthetically interpret a stage0 compiler used to build tools as a
980 // "raw" compiler in that it's the exact snapshot we download. Normally
981 // the stage0 build means it uses libraries build by the stage0
982 // compiler, but for tools we just use the precompiled libraries that
983 // we've downloaded
984 let use_snapshot = mode == Mode::ToolBootstrap;
985 assert!(!use_snapshot || stage == 0 || self.local_rebuild);
986
987 let maybe_sysroot = self.sysroot(compiler);
dfeec247 988 let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot };
9fa01778 989 let libdir = self.rustc_libdir(compiler);
8faf50e0 990
dfeec247
XL
991 // Clear the output directory if the real rustc we're using has changed;
992 // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc.
993 //
994 // Avoid doing this during dry run as that usually means the relevant
995 // compiler is not yet linked/copied properly.
996 //
997 // Only clear out the directory if we're compiling std; otherwise, we
998 // should let Cargo take care of things for us (via depdep info)
999 if !self.config.dry_run && mode == Mode::Std && cmd == "build" {
1000 self.clear_if_dirty(&out_dir, &self.rustc(compiler));
1001 }
1002
3b2f2976
XL
1003 // Customize the compiler we're running. Specify the compiler to cargo
1004 // as our shim and then pass it some various options used to configure
1005 // how the actual compiler itself is called.
1006 //
1007 // These variables are primarily all read by
1008 // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
94b46f34
XL
1009 cargo
1010 .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
94b46f34
XL
1011 .env("RUSTC_REAL", self.rustc(compiler))
1012 .env("RUSTC_STAGE", stage.to_string())
8faf50e0
XL
1013 .env("RUSTC_SYSROOT", &sysroot)
1014 .env("RUSTC_LIBDIR", &libdir)
94b46f34
XL
1015 .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
1016 .env(
1017 "RUSTDOC_REAL",
a1dfa0c6 1018 if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
532ac7d7 1019 self.rustdoc(compiler)
94b46f34
XL
1020 } else {
1021 PathBuf::from("/path/to/nowhere/rustdoc/not/required")
1022 },
1023 )
e1599b0c
XL
1024 .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir())
1025 .env("RUSTC_BREAK_ON_ICE", "1");
29967ef6
XL
1026 // Clippy support is a hack and uses the default `cargo-clippy` in path.
1027 // Don't override RUSTC so that the `cargo-clippy` in path will be run.
1028 if cmd != "clippy" {
1029 cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"));
1030 }
e1599b0c
XL
1031
1032 // Dealing with rpath here is a little special, so let's go into some
1033 // detail. First off, `-rpath` is a linker option on Unix platforms
1034 // which adds to the runtime dynamic loader path when looking for
1035 // dynamic libraries. We use this by default on Unix platforms to ensure
1036 // that our nightlies behave the same on Windows, that is they work out
1037 // of the box. This can be disabled, of course, but basically that's why
1038 // we're gated on RUSTC_RPATH here.
1039 //
1040 // Ok, so the astute might be wondering "why isn't `-C rpath` used
f035d41b 1041 // here?" and that is indeed a good question to ask. This codegen
e1599b0c
XL
1042 // option is the compiler's current interface to generating an rpath.
1043 // Unfortunately it doesn't quite suffice for us. The flag currently
1044 // takes no value as an argument, so the compiler calculates what it
1045 // should pass to the linker as `-rpath`. This unfortunately is based on
1046 // the **compile time** directory structure which when building with
1047 // Cargo will be very different than the runtime directory structure.
1048 //
1049 // All that's a really long winded way of saying that if we use
1050 // `-Crpath` then the executables generated have the wrong rpath of
1051 // something like `$ORIGIN/deps` when in fact the way we distribute
1052 // rustc requires the rpath to be `$ORIGIN/../lib`.
1053 //
1054 // So, all in all, to set up the correct rpath we pass the linker
1055 // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
1056 // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
1057 // to change a flag in a binary?
3dfed10e 1058 if self.config.rust_rpath && util::use_host_linker(target) {
e1599b0c 1059 let rpath = if target.contains("apple") {
e1599b0c
XL
1060 // Note that we need to take one extra step on macOS to also pass
1061 // `-Wl,-instal_name,@rpath/...` to get things to work right. To
1062 // do that we pass a weird flag to the compiler to get it to do
1063 // so. Note that this is definitely a hack, and we should likely
1064 // flesh out rpath support more fully in the future.
1065 rustflags.arg("-Zosx-rpath-install-name");
1066 Some("-Wl,-rpath,@loader_path/../lib")
60c5eb7d 1067 } else if !target.contains("windows") {
e1599b0c
XL
1068 Some("-Wl,-rpath,$ORIGIN/../lib")
1069 } else {
1070 None
1071 };
1072 if let Some(rpath) = rpath {
1073 rustflags.arg(&format!("-Clink-args={}", rpath));
1074 }
1075 }
abe05a73 1076
1b1a35ee 1077 if let Some(host_linker) = self.linker(compiler.host) {
abe05a73
XL
1078 cargo.env("RUSTC_HOST_LINKER", host_linker);
1079 }
1b1a35ee
XL
1080 if self.is_fuse_ld_lld(compiler.host) {
1081 cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1");
1082 }
74b04a01 1083
1b1a35ee 1084 if let Some(target_linker) = self.linker(target) {
3dfed10e 1085 let target = crate::envify(&target.triple);
e1599b0c 1086 cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker);
0531ce1d 1087 }
1b1a35ee 1088 if self.is_fuse_ld_lld(target) {
3dfed10e
XL
1089 rustflags.arg("-Clink-args=-fuse-ld=lld");
1090 }
1091
dc9dc135 1092 if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
9fa01778 1093 cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
2c00a5a8 1094 }
3b2f2976 1095
dc9dc135 1096 let debuginfo_level = match mode {
29967ef6 1097 Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
e1599b0c 1098 Mode::Std => self.config.rust_debuginfo_level_std,
dfeec247
XL
1099 Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => {
1100 self.config.rust_debuginfo_level_tools
1101 }
dc9dc135 1102 };
e1599b0c 1103 cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
f035d41b
XL
1104 cargo.env(
1105 profile_var("DEBUG_ASSERTIONS"),
1106 if mode == Mode::Std {
1107 self.config.rust_debug_assertions_std.to_string()
1108 } else {
1109 self.config.rust_debug_assertions.to_string()
1110 },
1111 );
dc9dc135 1112
1b1a35ee
XL
1113 if self.config.cmd.bless() {
1114 // Bless `expect!` tests.
1115 cargo.env("UPDATE_EXPECT", "1");
1116 }
1117
dc9dc135 1118 if !mode.is_tool() {
ff7c6d11 1119 cargo.env("RUSTC_FORCE_UNSTABLE", "1");
3b2f2976
XL
1120 }
1121
1122 if let Some(x) = self.crt_static(target) {
e1599b0c
XL
1123 if x {
1124 rustflags.arg("-Ctarget-feature=+crt-static");
1125 } else {
1126 rustflags.arg("-Ctarget-feature=-crt-static");
1127 }
3b2f2976
XL
1128 }
1129
94b46f34
XL
1130 if let Some(x) = self.crt_static(compiler.host) {
1131 cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
1132 }
1133
ba9703b0
XL
1134 if let Some(map_to) = self.build.debuginfo_map_to(GitRepo::Rustc) {
1135 let map = format!("{}={}", self.build.src.display(), map_to);
b7449926 1136 cargo.env("RUSTC_DEBUGINFO_MAP", map);
ba9703b0
XL
1137
1138 // `rustc` needs to know the virtual `/rustc/$hash` we're mapping to,
1139 // in order to opportunistically reverse it later.
1140 cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to);
b7449926
XL
1141 }
1142
3b2f2976
XL
1143 // Enable usage of unstable features
1144 cargo.env("RUSTC_BOOTSTRAP", "1");
1145 self.add_rust_test_threads(&mut cargo);
1146
1147 // Almost all of the crates that we compile as part of the bootstrap may
1148 // have a build script, including the standard library. To compile a
1149 // build script, however, it itself needs a standard library! This
1150 // introduces a bit of a pickle when we're compiling the standard
1151 // library itself.
1152 //
1153 // To work around this we actually end up using the snapshot compiler
1154 // (stage0) for compiling build scripts of the standard library itself.
1155 // The stage0 compiler is guaranteed to have a libstd available for use.
1156 //
1157 // For other crates, however, we know that we've already got a standard
1158 // library up and running, so we can use the normal compiler to compile
1159 // build scripts in that situation.
532ac7d7 1160 if mode == Mode::Std {
94b46f34
XL
1161 cargo
1162 .env("RUSTC_SNAPSHOT", &self.initial_rustc)
1163 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
3b2f2976 1164 } else {
94b46f34
XL
1165 cargo
1166 .env("RUSTC_SNAPSHOT", self.rustc(compiler))
1167 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler));
3b2f2976
XL
1168 }
1169
ba9703b0
XL
1170 // Tools that use compiler libraries may inherit the `-lLLVM` link
1171 // requirement, but the `-L` library path is not propagated across
1172 // separate Cargo projects. We can add LLVM's library path to the
1173 // platform-specific environment variable as a workaround.
1174 if mode == Mode::ToolRustc {
1175 if let Some(llvm_config) = self.llvm_config(target) {
1176 let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
1177 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo);
1178 }
1179 }
1180
29967ef6
XL
1181 // Compile everything except libraries and proc macros with the more
1182 // efficient initial-exec TLS model. This doesn't work with `dlopen`,
1183 // so we can't use it by default in general, but we can use it for tools
1184 // and our own internal libraries.
1185 if !mode.must_support_dlopen() {
1186 rustflags.arg("-Ztls-model=initial-exec");
1187 }
1188
8faf50e0 1189 if self.config.incremental {
2c00a5a8 1190 cargo.env("CARGO_INCREMENTAL", "1");
9fa01778
XL
1191 } else {
1192 // Don't rely on any default setting for incr. comp. in Cargo
1193 cargo.env("CARGO_INCREMENTAL", "0");
3b2f2976
XL
1194 }
1195
1196 if let Some(ref on_fail) = self.config.on_fail {
1197 cargo.env("RUSTC_ON_FAIL", on_fail);
1198 }
1199
0531ce1d
XL
1200 if self.config.print_step_timings {
1201 cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
1202 }
1203
83c7162d
XL
1204 if self.config.backtrace_on_ice {
1205 cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
1206 }
1207
8faf50e0 1208 cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
3b2f2976 1209
f035d41b
XL
1210 if source_type == SourceType::InTree {
1211 let mut lint_flags = Vec::new();
e1599b0c
XL
1212 // When extending this list, add the new lints to the RUSTFLAGS of the
1213 // build_bootstrap function of src/bootstrap/bootstrap.py as well as
1214 // some code doesn't go through this `rustc` wrapper.
f035d41b
XL
1215 lint_flags.push("-Wrust_2018_idioms");
1216 lint_flags.push("-Wunused_lifetimes");
e1599b0c
XL
1217
1218 if self.config.deny_warnings {
f035d41b 1219 lint_flags.push("-Dwarnings");
3dfed10e 1220 rustdocflags.arg("-Dwarnings");
f9f354fc 1221 }
ba9703b0 1222
f9f354fc
XL
1223 // FIXME(#58633) hide "unused attribute" errors in incremental
1224 // builds of the standard library, as the underlying checks are
1225 // not yet properly integrated with incremental recompilation.
1226 if mode == Mode::Std && compiler.stage == 0 && self.config.incremental {
f035d41b 1227 lint_flags.push("-Aunused-attributes");
e1599b0c 1228 }
f035d41b
XL
1229 // This does not use RUSTFLAGS due to caching issues with Cargo.
1230 // Clippy is treated as an "in tree" tool, but shares the same
1231 // cache as other "submodule" tools. With these options set in
1232 // RUSTFLAGS, that causes *every* shared dependency to be rebuilt.
1233 // By injecting this into the rustc wrapper, this circumvents
1234 // Cargo's fingerprint detection. This is fine because lint flags
1235 // are always ignored in dependencies. Eventually this should be
1236 // fixed via better support from Cargo.
1237 cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" "));
3dfed10e
XL
1238
1239 rustdocflags.arg("-Winvalid_codeblock_attributes");
e1599b0c
XL
1240 }
1241
1b1a35ee 1242 if mode == Mode::Rustc {
e1599b0c
XL
1243 rustflags.arg("-Zunstable-options");
1244 rustflags.arg("-Wrustc::internal");
83c7162d
XL
1245 }
1246
abe05a73
XL
1247 // Throughout the build Cargo can execute a number of build scripts
1248 // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
1249 // obtained previously to those build scripts.
1250 // Build scripts use either the `cc` crate or `configure/make` so we pass
1251 // the options through environment variables that are fetched and understood by both.
3b2f2976
XL
1252 //
1253 // FIXME: the guard against msvc shouldn't need to be here
94b46f34
XL
1254 if target.contains("msvc") {
1255 if let Some(ref cl) = self.config.llvm_clang_cl {
1256 cargo.env("CC", cl).env("CXX", cl);
1257 }
1258 } else {
0531ce1d
XL
1259 let ccache = self.config.ccache.as_ref();
1260 let ccacheify = |s: &Path| {
1261 let ccache = match ccache {
1262 Some(ref s) => s,
1263 None => return s.display().to_string(),
1264 };
1265 // FIXME: the cc-rs crate only recognizes the literal strings
1266 // `ccache` and `sccache` when doing caching compilations, so we
1267 // mirror that here. It should probably be fixed upstream to
1268 // accept a new env var or otherwise work with custom ccache
1269 // vars.
1270 match &ccache[..] {
1271 "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
1272 _ => s.display().to_string(),
1273 }
1274 };
1275 let cc = ccacheify(&self.cc(target));
3dfed10e 1276 cargo.env(format!("CC_{}", target.triple), &cc);
abe05a73 1277
b7449926 1278 let cflags = self.cflags(target, GitRepo::Rustc).join(" ");
1b1a35ee 1279 cargo.env(format!("CFLAGS_{}", target.triple), &cflags);
abe05a73
XL
1280
1281 if let Some(ar) = self.ar(target) {
1282 let ranlib = format!("{} s", ar.display());
3dfed10e
XL
1283 cargo
1284 .env(format!("AR_{}", target.triple), ar)
1285 .env(format!("RANLIB_{}", target.triple), ranlib);
abe05a73 1286 }
3b2f2976
XL
1287
1288 if let Ok(cxx) = self.cxx(target) {
0531ce1d 1289 let cxx = ccacheify(&cxx);
94b46f34 1290 cargo
3dfed10e
XL
1291 .env(format!("CXX_{}", target.triple), &cxx)
1292 .env(format!("CXXFLAGS_{}", target.triple), cflags);
3b2f2976
XL
1293 }
1294 }
1295
dfeec247 1296 if mode == Mode::Std && self.config.extended && compiler.is_final_stage(self) {
e1599b0c 1297 rustflags.arg("-Zsave-analysis");
dfeec247
XL
1298 cargo.env(
1299 "RUST_SAVE_ANALYSIS_CONFIG",
1300 "{\"output_file\": null,\"full_docs\": false,\
e1599b0c 1301 \"pub_only\": true,\"reachable_only\": false,\
dfeec247
XL
1302 \"distro_crate\": true,\"signatures\": false,\"borrow_data\": false}",
1303 );
3b2f2976
XL
1304 }
1305
f035d41b 1306 // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
74b04a01
XL
1307 // when compiling the standard library, since this might be linked into the final outputs
1308 // produced by rustc. Since this mitigation is only available on Windows, only enable it
1309 // for the standard library in case the compiler is run on a non-Windows platform.
1310 // This is not needed for stage 0 artifacts because these will only be used for building
1311 // the stage 1 compiler.
1312 if cfg!(windows)
1313 && mode == Mode::Std
1314 && self.config.control_flow_guard
1315 && compiler.stage >= 1
1316 {
3dfed10e 1317 rustflags.arg("-Ccontrol-flow-guard");
74b04a01
XL
1318 }
1319
abe05a73 1320 // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
3dfed10e
XL
1321 // This replaces spaces with newlines because RUSTDOCFLAGS does not
1322 // support arguments with regular spaces. Hopefully someday Cargo will
1323 // have space support.
1324 let rust_version = self.rust_version().replace(' ', "\n");
1325 rustdocflags.arg("--crate-version").arg(&rust_version);
abe05a73 1326
3b2f2976
XL
1327 // Environment variables *required* throughout the build
1328 //
1329 // FIXME: should update code to not require this env var
3dfed10e 1330 cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple);
3b2f2976
XL
1331
1332 // Set this for all builds to make sure doc builds also get it.
83c7162d 1333 cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
3b2f2976 1334
2c00a5a8
XL
1335 // This one's a bit tricky. As of the time of this writing the compiler
1336 // links to the `winapi` crate on crates.io. This crate provides raw
1337 // bindings to Windows system functions, sort of like libc does for
1338 // Unix. This crate also, however, provides "import libraries" for the
1339 // MinGW targets. There's an import library per dll in the windows
1340 // distribution which is what's linked to. These custom import libraries
1341 // are used because the winapi crate can reference Windows functions not
1342 // present in the MinGW import libraries.
1343 //
1344 // For example MinGW may ship libdbghelp.a, but it may not have
1345 // references to all the functions in the dbghelp dll. Instead the
1346 // custom import library for dbghelp in the winapi crates has all this
1347 // information.
1348 //
1349 // Unfortunately for us though the import libraries are linked by
1350 // default via `-ldylib=winapi_foo`. That is, they're linked with the
1351 // `dylib` type with a `winapi_` prefix (so the winapi ones don't
1352 // conflict with the system MinGW ones). This consequently means that
94b46f34 1353 // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm
2c00a5a8
XL
1354 // DLL) when linked against *again*, for example with procedural macros
1355 // or plugins, will trigger the propagation logic of `-ldylib`, passing
1356 // `-lwinapi_foo` to the linker again. This isn't actually available in
1357 // our distribution, however, so the link fails.
1358 //
1359 // To solve this problem we tell winapi to not use its bundled import
1360 // libraries. This means that it will link to the system MinGW import
1361 // libraries by default, and the `-ldylib=foo` directives will still get
1362 // passed to the final linker, but they'll look like `-lfoo` which can
1363 // be resolved because MinGW has the import library. The downside is we
1364 // don't get newer functions from Windows, but we don't use any of them
1365 // anyway.
94b46f34 1366 if !mode.is_tool() {
0531ce1d
XL
1367 cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
1368 }
2c00a5a8 1369
0531ce1d 1370 for _ in 1..self.verbosity {
3b2f2976
XL
1371 cargo.arg("-v");
1372 }
2c00a5a8 1373
a1dfa0c6 1374 match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) {
dfeec247 1375 (Mode::Std, Some(n), _) | (_, _, Some(n)) => {
e1599b0c 1376 cargo.env(profile_var("CODEGEN_UNITS"), n.to_string());
a1dfa0c6
XL
1377 }
1378 _ => {
1379 // Don't set anything
1380 }
2c00a5a8
XL
1381 }
1382
abe05a73 1383 if self.config.rust_optimize {
94b46f34
XL
1384 // FIXME: cargo bench/install do not accept `--release`
1385 if cmd != "bench" && cmd != "install" {
abe05a73
XL
1386 cargo.arg("--release");
1387 }
3b2f2976 1388 }
2c00a5a8 1389
3b2f2976
XL
1390 if self.config.locked_deps {
1391 cargo.arg("--locked");
1392 }
1393 if self.config.vendor || self.is_sudo {
1394 cargo.arg("--frozen");
1395 }
1396
60c5eb7d
XL
1397 // Try to use a sysroot-relative bindir, in case it was configured absolutely.
1398 cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative());
e1599b0c 1399
3b2f2976
XL
1400 self.ci_env.force_coloring_in_ci(&mut cargo);
1401
e1599b0c
XL
1402 // When we build Rust dylibs they're all intended for intermediate
1403 // usage, so make sure we pass the -Cprefer-dynamic flag instead of
1404 // linking all deps statically into the dylib.
1b1a35ee 1405 if matches!(mode, Mode::Std | Mode::Rustc) {
e1599b0c
XL
1406 rustflags.arg("-Cprefer-dynamic");
1407 }
1408
dfeec247
XL
1409 // When building incrementally we default to a lower ThinLTO import limit
1410 // (unless explicitly specified otherwise). This will produce a somewhat
1411 // slower code but give way better compile times.
1412 {
1413 let limit = match self.config.rust_thin_lto_import_instr_limit {
1414 Some(limit) => Some(limit),
1415 None if self.config.incremental => Some(10),
1416 _ => None,
1417 };
1418
1419 if let Some(limit) = limit {
1420 rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={}", limit));
1421 }
e1599b0c 1422 }
dfeec247 1423
f9f354fc 1424 Cargo { command: cargo, rustflags, rustdocflags }
3b2f2976
XL
1425 }
1426
83c7162d 1427 /// Ensure that a given step is built, returning its output. This will
3b2f2976
XL
1428 /// cache the step, so it is safe (and good!) to call this as often as
1429 /// needed to ensure that all dependencies are built.
1430 pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
1431 {
1432 let mut stack = self.stack.borrow_mut();
1433 for stack_step in stack.iter() {
1434 // should skip
dfeec247 1435 if stack_step.downcast_ref::<S>().map_or(true, |stack_step| *stack_step != step) {
3b2f2976
XL
1436 continue;
1437 }
1438 let mut out = String::new();
1439 out += &format!("\n\nCycle in build detected when adding {:?}\n", step);
1440 for el in stack.iter().rev() {
1441 out += &format!("\t{:?}\n", el);
1442 }
1443 panic!(out);
1444 }
1445 if let Some(out) = self.cache.get(&step) {
83c7162d
XL
1446 self.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step));
1447
3b2f2976
XL
1448 return out;
1449 }
83c7162d 1450 self.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
3b2f2976
XL
1451 stack.push(Box::new(step.clone()));
1452 }
0531ce1d
XL
1453
1454 let (out, dur) = {
1455 let start = Instant::now();
1456 let zero = Duration::new(0, 0);
1457 let parent = self.time_spent_on_dependencies.replace(zero);
1458 let out = step.clone().run(self);
1459 let dur = start.elapsed();
1460 let deps = self.time_spent_on_dependencies.replace(parent + dur);
1461 (out, dur - deps)
1462 };
1463
1b1a35ee 1464 if self.config.print_step_timings && !self.config.dry_run {
74b04a01 1465 println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis());
0531ce1d
XL
1466 }
1467
3b2f2976
XL
1468 {
1469 let mut stack = self.stack.borrow_mut();
1470 let cur_step = stack.pop().expect("step stack empty");
1471 assert_eq!(cur_step.downcast_ref(), Some(&step));
1472 }
dfeec247 1473 self.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
3b2f2976
XL
1474 self.cache.put(step, out.clone());
1475 out
1476 }
1477}
83c7162d
XL
1478
1479#[cfg(test)]
dc9dc135 1480mod tests;
e1599b0c 1481
f9f354fc 1482#[derive(Debug, Clone)]
e1599b0c
XL
1483struct Rustflags(String);
1484
1485impl Rustflags {
3dfed10e 1486 fn new(target: TargetSelection) -> Rustflags {
e1599b0c
XL
1487 let mut ret = Rustflags(String::new());
1488
1489 // Inherit `RUSTFLAGS` by default ...
1490 ret.env("RUSTFLAGS");
1491
1492 // ... and also handle target-specific env RUSTFLAGS if they're
1493 // configured.
3dfed10e 1494 let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(&target.triple));
e1599b0c
XL
1495 ret.env(&target_specific);
1496
1497 ret
1498 }
1499
1500 fn env(&mut self, env: &str) {
1501 if let Ok(s) = env::var(env) {
3dfed10e 1502 for part in s.split(' ') {
e1599b0c
XL
1503 self.arg(part);
1504 }
1505 }
1506 }
1507
1508 fn arg(&mut self, arg: &str) -> &mut Self {
3dfed10e 1509 assert_eq!(arg.split(' ').count(), 1);
74b04a01 1510 if !self.0.is_empty() {
e1599b0c
XL
1511 self.0.push_str(" ");
1512 }
1513 self.0.push_str(arg);
1514 self
1515 }
1516}
1517
1518#[derive(Debug)]
1519pub struct Cargo {
1520 command: Command,
1521 rustflags: Rustflags,
f9f354fc 1522 rustdocflags: Rustflags,
e1599b0c
XL
1523}
1524
1525impl Cargo {
3dfed10e
XL
1526 pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
1527 self.rustdocflags.arg(arg);
1528 self
1529 }
e1599b0c
XL
1530 pub fn rustflag(&mut self, arg: &str) -> &mut Cargo {
1531 self.rustflags.arg(arg);
1532 self
1533 }
1534
1535 pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Cargo {
1536 self.command.arg(arg.as_ref());
1537 self
1538 }
1539
1540 pub fn args<I, S>(&mut self, args: I) -> &mut Cargo
dfeec247
XL
1541 where
1542 I: IntoIterator<Item = S>,
1543 S: AsRef<OsStr>,
e1599b0c
XL
1544 {
1545 for arg in args {
1546 self.arg(arg.as_ref());
1547 }
1548 self
1549 }
1550
1551 pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Cargo {
3dfed10e
XL
1552 // These are managed through rustflag/rustdocflag interfaces.
1553 assert_ne!(key.as_ref(), "RUSTFLAGS");
1554 assert_ne!(key.as_ref(), "RUSTDOCFLAGS");
e1599b0c
XL
1555 self.command.env(key.as_ref(), value.as_ref());
1556 self
1557 }
1b1a35ee
XL
1558
1559 pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
1560 builder.add_rustc_lib_path(compiler, &mut self.command);
1561 }
e1599b0c
XL
1562}
1563
1564impl From<Cargo> for Command {
1565 fn from(mut cargo: Cargo) -> Command {
f9f354fc
XL
1566 let rustflags = &cargo.rustflags.0;
1567 if !rustflags.is_empty() {
1568 cargo.command.env("RUSTFLAGS", rustflags);
1569 }
1570
1571 let rustdocflags = &cargo.rustdocflags.0;
1572 if !rustdocflags.is_empty() {
1573 cargo.command.env("RUSTDOCFLAGS", rustdocflags);
1574 }
1575
e1599b0c
XL
1576 cargo.command
1577 }
1578}