]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/builder.rs
New upstream version 1.54.0+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;
fc512014 22use crate::flags::{Color, Subcommand};
0731742a
XL
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,
cdc7bbd5
XL
372 native::Lld,
373 native::CrtBeginEnd
94b46f34 374 ),
29967ef6
XL
375 Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!(
376 check::Std,
377 check::Rustc,
378 check::Rustdoc,
379 check::CodegenBackend,
380 check::Clippy,
17df50a5
XL
381 check::Miri,
382 check::Rls,
383 check::Rustfmt,
29967ef6
XL
384 check::Bootstrap
385 ),
94b46f34 386 Kind::Test => describe!(
60c5eb7d 387 crate::toolstate::ToolStateCheck,
ba9703b0 388 test::ExpandYamlAnchors,
94b46f34
XL
389 test::Tidy,
390 test::Ui,
94b46f34
XL
391 test::RunPassValgrind,
392 test::MirOpt,
393 test::Codegen,
394 test::CodegenUnits,
532ac7d7 395 test::Assembly,
94b46f34
XL
396 test::Incremental,
397 test::Debuginfo,
398 test::UiFullDeps,
94b46f34
XL
399 test::Rustdoc,
400 test::Pretty,
94b46f34
XL
401 test::Crate,
402 test::CrateLibrustc,
403 test::CrateRustdoc,
6a06907d 404 test::CrateRustdocJsonTypes,
94b46f34 405 test::Linkcheck,
3dfed10e 406 test::TierCheck,
94b46f34
XL
407 test::Cargotest,
408 test::Cargo,
409 test::Rls,
410 test::ErrorIndex,
411 test::Distcheck,
0531ce1d 412 test::RunMakeFullDeps,
94b46f34
XL
413 test::Nomicon,
414 test::Reference,
415 test::RustdocBook,
416 test::RustByExample,
417 test::TheBook,
418 test::UnstableBook,
419 test::RustcBook,
fc512014 420 test::LintDocs,
416331ca 421 test::RustcGuide,
9fa01778 422 test::EmbeddedBook,
532ac7d7 423 test::EditionGuide,
94b46f34
XL
424 test::Rustfmt,
425 test::Miri,
426 test::Clippy,
cdc7bbd5 427 test::RustDemangler,
0731742a 428 test::CompiletestTest,
9fa01778
XL
429 test::RustdocJSStd,
430 test::RustdocJSNotStd,
6a06907d 431 test::RustdocGUI,
94b46f34 432 test::RustdocTheme,
532ac7d7 433 test::RustdocUi,
fc512014 434 test::RustdocJson,
94b46f34
XL
435 // Run bootstrap close to the end as it's unlikely to fail
436 test::Bootstrap,
0531ce1d 437 // Run run-make last, since these won't pass without make on Windows
94b46f34 438 test::RunMake,
94b46f34 439 ),
2c00a5a8 440 Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
94b46f34
XL
441 Kind::Doc => describe!(
442 doc::UnstableBook,
443 doc::UnstableBookGen,
444 doc::TheBook,
445 doc::Standalone,
446 doc::Std,
94b46f34
XL
447 doc::Rustc,
448 doc::Rustdoc,
449 doc::ErrorIndex,
450 doc::Nomicon,
451 doc::Reference,
452 doc::RustdocBook,
453 doc::RustByExample,
454 doc::RustcBook,
450edc1f 455 doc::CargoBook,
9fa01778 456 doc::EmbeddedBook,
450edc1f 457 doc::EditionGuide,
94b46f34
XL
458 ),
459 Kind::Dist => describe!(
460 dist::Docs,
461 dist::RustcDocs,
462 dist::Mingw,
463 dist::Rustc,
464 dist::DebuggerScripts,
465 dist::Std,
e74abb32 466 dist::RustcDev,
94b46f34
XL
467 dist::Analysis,
468 dist::Src,
469 dist::PlainSourceTarball,
470 dist::Cargo,
471 dist::Rls,
f035d41b 472 dist::RustAnalyzer,
94b46f34 473 dist::Rustfmt,
cdc7bbd5 474 dist::RustDemangler,
8faf50e0 475 dist::Clippy,
0731742a 476 dist::Miri,
8faf50e0 477 dist::LlvmTools,
1b1a35ee 478 dist::RustDev,
94b46f34 479 dist::Extended,
1b1a35ee 480 dist::BuildManifest,
fc512014 481 dist::ReproducibleArtifacts,
94b46f34
XL
482 ),
483 Kind::Install => describe!(
484 install::Docs,
485 install::Std,
486 install::Cargo,
487 install::Rls,
f035d41b 488 install::RustAnalyzer,
94b46f34 489 install::Rustfmt,
cdc7bbd5 490 install::RustDemangler,
8faf50e0 491 install::Clippy,
0731742a 492 install::Miri,
94b46f34
XL
493 install::Analysis,
494 install::Src,
495 install::Rustc
496 ),
29967ef6 497 Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest),
3b2f2976
XL
498 }
499 }
500
501 pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
502 let kind = match subcommand {
503 "build" => Kind::Build,
504 "doc" => Kind::Doc,
505 "test" => Kind::Test,
506 "bench" => Kind::Bench,
507 "dist" => Kind::Dist,
508 "install" => Kind::Install,
509 _ => return None,
510 };
511
3dfed10e 512 let builder = Self::new_internal(build, kind, vec![]);
3b2f2976
XL
513 let builder = &builder;
514 let mut should_run = ShouldRun::new(builder);
515 for desc in Builder::get_step_descriptions(builder.kind) {
516 should_run = (desc.should_run)(should_run);
517 }
518 let mut help = String::from("Available paths:\n");
f035d41b
XL
519 let mut add_path = |path: &Path| {
520 help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display()));
521 };
2c00a5a8 522 for pathset in should_run.paths {
f035d41b
XL
523 match pathset {
524 PathSet::Set(set) => {
525 for path in set {
526 add_path(&path);
527 }
528 }
529 PathSet::Suite(path) => {
530 add_path(&path.join("..."));
531 }
2c00a5a8 532 }
3b2f2976
XL
533 }
534 Some(help)
535 }
536
3dfed10e 537 fn new_internal(build: &Build, kind: Kind, paths: Vec<PathBuf>) -> Builder<'_> {
3dfed10e
XL
538 Builder {
539 build,
1b1a35ee 540 top_stage: build.config.stage,
3dfed10e
XL
541 kind,
542 cache: Cache::new(),
543 stack: RefCell::new(Vec::new()),
544 time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
545 paths,
546 }
547 }
548
9fa01778 549 pub fn new(build: &Build) -> Builder<'_> {
3b2f2976
XL
550 let (kind, paths) = match build.config.cmd {
551 Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
29967ef6
XL
552 Subcommand::Check { ref paths, all_targets: _ } => (Kind::Check, &paths[..]),
553 Subcommand::Clippy { ref paths, .. } => (Kind::Clippy, &paths[..]),
dc9dc135 554 Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
f9f354fc 555 Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]),
3b2f2976
XL
556 Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
557 Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
558 Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
559 Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
ba9703b0 560 Subcommand::Run { ref paths } => (Kind::Run, &paths[..]),
1b1a35ee
XL
561 Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
562 panic!()
3dfed10e 563 }
1b1a35ee 564 };
3dfed10e 565
1b1a35ee 566 Self::new_internal(build, kind, paths.to_owned())
83c7162d
XL
567 }
568
dfeec247 569 pub fn execute_cli(&self) {
83c7162d 570 self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths);
3b2f2976
XL
571 }
572
6a06907d 573 pub fn default_doc(&self, paths: &[PathBuf]) {
83c7162d
XL
574 self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
575 }
576
17df50a5
XL
577 /// NOTE: keep this in sync with `rustdoc::clean::utils::doc_rust_lang_org_channel`, or tests will fail on beta/stable.
578 pub fn doc_rust_lang_org_channel(&self) -> String {
579 let channel = match &*self.config.channel {
580 "stable" => &self.version,
581 "beta" => "beta",
582 "nightly" | "dev" => "nightly",
583 // custom build of rustdoc maybe? link to the latest stable docs just in case
584 _ => "stable",
585 };
586 "https://doc.rust-lang.org/".to_owned() + channel
587 }
588
83c7162d
XL
589 fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
590 StepDescription::run(v, self, paths);
3b2f2976
XL
591 }
592
593 /// Obtain a compiler at a given stage and for a given host. Explicitly does
594 /// not take `Compiler` since all `Compiler` instances are meant to be
595 /// obtained through this function, since it ensures that they are valid
596 /// (i.e., built and assembled).
3dfed10e 597 pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler {
dfeec247 598 self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
3b2f2976
XL
599 }
600
dc9dc135
XL
601 /// Similar to `compiler`, except handles the full-bootstrap option to
602 /// silently use the stage1 compiler instead of a stage2 compiler if one is
603 /// requested.
604 ///
605 /// Note that this does *not* have the side effect of creating
606 /// `compiler(stage, host)`, unlike `compiler` above which does have such
607 /// a side effect. The returned compiler here can only be used to compile
608 /// new artifacts, it can't be used to rely on the presence of a particular
609 /// sysroot.
610 ///
611 /// See `force_use_stage1` for documentation on what each argument is.
612 pub fn compiler_for(
613 &self,
614 stage: u32,
3dfed10e
XL
615 host: TargetSelection,
616 target: TargetSelection,
dc9dc135
XL
617 ) -> Compiler {
618 if self.build.force_use_stage1(Compiler { stage, host }, target) {
619 self.compiler(1, self.config.build)
620 } else {
621 self.compiler(stage, host)
622 }
623 }
624
3b2f2976
XL
625 pub fn sysroot(&self, compiler: Compiler) -> Interned<PathBuf> {
626 self.ensure(compile::Sysroot { compiler })
627 }
628
629 /// Returns the libdir where the standard library and other artifacts are
630 /// found for a compiler's sysroot.
3dfed10e 631 pub fn sysroot_libdir(&self, compiler: Compiler, target: TargetSelection) -> Interned<PathBuf> {
3b2f2976
XL
632 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
633 struct Libdir {
634 compiler: Compiler,
3dfed10e 635 target: TargetSelection,
3b2f2976
XL
636 }
637 impl Step for Libdir {
638 type Output = Interned<PathBuf>;
639
9fa01778 640 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976
XL
641 run.never()
642 }
643
9fa01778 644 fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> {
e1599b0c 645 let lib = builder.sysroot_libdir_relative(self.compiler);
94b46f34
XL
646 let sysroot = builder
647 .sysroot(self.compiler)
648 .join(lib)
649 .join("rustlib")
3dfed10e 650 .join(self.target.triple)
94b46f34 651 .join("lib");
6a06907d
XL
652 // Avoid deleting the rustlib/ directory we just copied
653 // (in `impl Step for Sysroot`).
654 if !builder.config.download_rustc {
655 let _ = fs::remove_dir_all(&sysroot);
656 t!(fs::create_dir_all(&sysroot));
657 }
3b2f2976
XL
658 INTERNER.intern_path(sysroot)
659 }
660 }
661 self.ensure(Libdir { compiler, target })
662 }
663
29967ef6
XL
664 pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
665 self.sysroot_libdir(compiler, compiler.host).with_file_name("codegen-backends")
666 }
667
3b2f2976
XL
668 /// Returns the compiler's libdir where it stores the dynamic libraries that
669 /// it itself links against.
670 ///
671 /// For example this returns `<sysroot>/lib` on Unix and `<sysroot>/bin` on
672 /// Windows.
673 pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf {
674 if compiler.is_snapshot(self) {
83c7162d 675 self.rustc_snapshot_libdir()
3b2f2976 676 } else {
532ac7d7 677 match self.config.libdir_relative() {
dfeec247
XL
678 Some(relative_libdir) if compiler.stage >= 1 => {
679 self.sysroot(compiler).join(relative_libdir)
680 }
3dfed10e 681 _ => self.sysroot(compiler).join(libdir(compiler.host)),
532ac7d7
XL
682 }
683 }
684 }
685
686 /// Returns the compiler's relative libdir where it stores the dynamic libraries that
687 /// it itself links against.
688 ///
689 /// For example this returns `lib` on Unix and `bin` on
690 /// Windows.
691 pub fn libdir_relative(&self, compiler: Compiler) -> &Path {
692 if compiler.is_snapshot(self) {
3dfed10e 693 libdir(self.config.build).as_ref()
532ac7d7
XL
694 } else {
695 match self.config.libdir_relative() {
dfeec247 696 Some(relative_libdir) if compiler.stage >= 1 => relative_libdir,
3dfed10e 697 _ => libdir(compiler.host).as_ref(),
532ac7d7 698 }
3b2f2976
XL
699 }
700 }
701
e1599b0c
XL
702 /// Returns the compiler's relative libdir where the standard library and other artifacts are
703 /// found for a compiler's sysroot.
704 ///
705 /// For example this returns `lib` on Unix and Windows.
706 pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path {
707 match self.config.libdir_relative() {
dfeec247 708 Some(relative_libdir) if compiler.stage >= 1 => relative_libdir,
f9f354fc 709 _ if compiler.stage == 0 => &self.build.initial_libdir,
dfeec247 710 _ => Path::new("lib"),
e1599b0c
XL
711 }
712 }
713
3b2f2976
XL
714 /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
715 /// library lookup path.
1b1a35ee 716 pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) {
3b2f2976
XL
717 // Windows doesn't need dylib path munging because the dlls for the
718 // compiler live next to the compiler and the system will find them
719 // automatically.
720 if cfg!(windows) {
94b46f34 721 return;
3b2f2976
XL
722 }
723
17df50a5
XL
724 let mut dylib_dirs = vec![self.rustc_libdir(compiler)];
725
726 // Ensure that the downloaded LLVM libraries can be found.
727 if self.config.llvm_from_ci {
728 let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib");
729 dylib_dirs.push(ci_llvm_lib);
730 }
731
732 add_dylib_path(dylib_dirs, cmd);
3b2f2976
XL
733 }
734
9fa01778 735 /// Gets a path to the compiler specified.
3b2f2976
XL
736 pub fn rustc(&self, compiler: Compiler) -> PathBuf {
737 if compiler.is_snapshot(self) {
738 self.initial_rustc.clone()
739 } else {
3dfed10e 740 self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
3b2f2976
XL
741 }
742 }
743
29967ef6
XL
744 /// Gets the paths to all of the compiler's codegen backends.
745 fn codegen_backends(&self, compiler: Compiler) -> impl Iterator<Item = PathBuf> {
746 fs::read_dir(self.sysroot_codegen_backends(compiler))
747 .into_iter()
748 .flatten()
749 .filter_map(Result::ok)
750 .map(|entry| entry.path())
751 }
752
532ac7d7
XL
753 pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
754 self.ensure(tool::Rustdoc { compiler })
3b2f2976
XL
755 }
756
532ac7d7 757 pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
3b2f2976 758 let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
abe05a73 759 cmd.env("RUSTC_STAGE", compiler.stage.to_string())
94b46f34 760 .env("RUSTC_SYSROOT", self.sysroot(compiler))
9fa01778
XL
761 // Note that this is *not* the sysroot_libdir because rustdoc must be linked
762 // equivalently to rustc.
763 .env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler))
94b46f34 764 .env("CFG_RELEASE_CHANNEL", &self.config.channel)
532ac7d7 765 .env("RUSTDOC_REAL", self.rustdoc(compiler))
6a06907d
XL
766 .env("RUSTC_BOOTSTRAP", "1");
767
cdc7bbd5 768 cmd.arg("-Wrustdoc::invalid_codeblock_attributes");
6a06907d 769
3dfed10e
XL
770 if self.config.deny_warnings {
771 cmd.arg("-Dwarnings");
772 }
5869c6ff 773 cmd.arg("-Znormalize-docs");
0731742a
XL
774
775 // Remove make-related flags that can cause jobserver problems.
776 cmd.env_remove("MAKEFLAGS");
777 cmd.env_remove("MFLAGS");
778
1b1a35ee
XL
779 if let Some(linker) = self.linker(compiler.host) {
780 cmd.env("RUSTDOC_LINKER", linker);
781 }
782 if self.is_fuse_ld_lld(compiler.host) {
783 cmd.env("RUSTDOC_FUSE_LD_LLD", "1");
abe05a73 784 }
3b2f2976
XL
785 cmd
786 }
787
ba9703b0
XL
788 /// Return the path to `llvm-config` for the target, if it exists.
789 ///
790 /// Note that this returns `None` if LLVM is disabled, or if we're in a
791 /// check build or dry-run, where there's no need to build all of LLVM.
3dfed10e 792 fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
ba9703b0
XL
793 if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run {
794 let llvm_config = self.ensure(native::Llvm { target });
795 if llvm_config.is_file() {
796 return Some(llvm_config);
797 }
798 }
799 None
800 }
801
3b2f2976
XL
802 /// Prepares an invocation of `cargo` to be run.
803 ///
804 /// This will create a `Command` that represents a pending execution of
805 /// Cargo. This cargo will be configured to use `compiler` as the actual
806 /// rustc compiler, its output will be scoped by `mode`'s output directory,
807 /// it will pass the `--target` flag for the specified `target`, and will be
808 /// executing the Cargo command `cmd`.
94b46f34
XL
809 pub fn cargo(
810 &self,
811 compiler: Compiler,
812 mode: Mode,
f035d41b 813 source_type: SourceType,
3dfed10e 814 target: TargetSelection,
94b46f34 815 cmd: &str,
e1599b0c 816 ) -> Cargo {
3b2f2976
XL
817 let mut cargo = Command::new(&self.initial_cargo);
818 let out_dir = self.stage_out(compiler, mode);
b7449926 819
29967ef6
XL
820 // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
821 // so we need to explicitly clear out if they've been updated.
822 for backend in self.codegen_backends(compiler) {
823 self.clear_if_dirty(&out_dir, &backend);
824 }
825
a1dfa0c6 826 if cmd == "doc" || cmd == "rustdoc" {
e1599b0c 827 let my_out = match mode {
b7449926 828 // This is the intended out directory for compiler documentation.
1b1a35ee 829 Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
3dfed10e
XL
830 Mode::Std => out_dir.join(target.triple).join("doc"),
831 _ => panic!("doc mode {:?} not expected", mode),
e1599b0c 832 };
532ac7d7 833 let rustdoc = self.rustdoc(compiler);
b7449926 834 self.clear_if_dirty(&my_out, &rustdoc);
b7449926
XL
835 }
836
74b04a01
XL
837 cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
838
e1599b0c 839 let profile_var = |name: &str| {
dfeec247 840 let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" };
e1599b0c
XL
841 format!("CARGO_PROFILE_{}_{}", profile, name)
842 };
94b46f34 843
1b1a35ee 844 // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config
9fa01778
XL
845 // needs to not accidentally link to libLLVM in stage0/lib.
846 cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var());
847 if let Some(e) = env::var_os(util::dylib_path_var()) {
848 cargo.env("REAL_LIBRARY_PATH", e);
849 }
850
5869c6ff
XL
851 // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
852 // from out of tree it shouldn't matter, since x.py is only used for
853 // building in-tree.
854 let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
fc512014
XL
855 match self.build.config.color {
856 Color::Always => {
857 cargo.arg("--color=always");
5869c6ff
XL
858 for log in &color_logs {
859 cargo.env(log, "always");
860 }
fc512014
XL
861 }
862 Color::Never => {
863 cargo.arg("--color=never");
5869c6ff
XL
864 for log in &color_logs {
865 cargo.env(log, "never");
866 }
fc512014
XL
867 }
868 Color::Auto => {} // nothing to do
869 }
870
94b46f34 871 if cmd != "install" {
3dfed10e 872 cargo.arg("--target").arg(target.rustc_target_arg());
94b46f34
XL
873 } else {
874 assert_eq!(target, compiler.host);
875 }
3b2f2976 876
dc9dc135 877 // Set a flag for `check`/`clippy`/`fix`, so that certain build
f9f354fc 878 // scripts can do less work (i.e. not building/requiring LLVM).
dc9dc135 879 if cmd == "check" || cmd == "clippy" || cmd == "fix" {
f9f354fc 880 // If we've not yet built LLVM, or it's stale, then bust
1b1a35ee 881 // the rustc_llvm cache. That will always work, even though it
f9f354fc 882 // may mean that on the next non-check build we'll need to rebuild
1b1a35ee 883 // rustc_llvm. But if LLVM is stale, that'll be a tiny amount
f9f354fc
XL
884 // of work comparitively, and we'd likely need to rebuild it anyway,
885 // so that's okay.
886 if crate::native::prebuilt_llvm_config(self, target).is_err() {
887 cargo.env("RUST_CHECK", "1");
888 }
83c7162d
XL
889 }
890
74b04a01 891 let stage = if compiler.stage == 0 && self.local_rebuild {
e1599b0c 892 // Assume the local-rebuild rustc already has stage1 features.
74b04a01 893 1
e1599b0c 894 } else {
74b04a01
XL
895 compiler.stage
896 };
e1599b0c 897
3dfed10e 898 let mut rustflags = Rustflags::new(target);
e1599b0c 899 if stage != 0 {
e74abb32
XL
900 if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
901 cargo.args(s.split_whitespace());
902 }
e1599b0c
XL
903 rustflags.env("RUSTFLAGS_NOT_BOOTSTRAP");
904 } else {
e74abb32
XL
905 if let Ok(s) = env::var("CARGOFLAGS_BOOTSTRAP") {
906 cargo.args(s.split_whitespace());
907 }
e1599b0c 908 rustflags.env("RUSTFLAGS_BOOTSTRAP");
29967ef6
XL
909 if cmd == "clippy" {
910 // clippy overwrites sysroot if we pass it to cargo.
911 // Pass it directly to clippy instead.
912 // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`,
913 // so it has no way of knowing the sysroot.
914 rustflags.arg("--sysroot");
915 rustflags.arg(
916 self.sysroot(compiler)
917 .as_os_str()
918 .to_str()
919 .expect("sysroot must be valid UTF-8"),
920 );
921 // Only run clippy on a very limited subset of crates (in particular, not build scripts).
922 cargo.arg("-Zunstable-options");
923 // Explicitly does *not* set `--cfg=bootstrap`, since we're using a nightly clippy.
924 let host_version = Command::new("rustc").arg("--version").output().map_err(|_| ());
925 let output = host_version.and_then(|output| {
926 if output.status.success() {
927 Ok(output)
928 } else {
929 Err(())
930 }
931 }).unwrap_or_else(|_| {
932 eprintln!(
933 "error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component"
934 );
935 eprintln!("help: try `rustup component add clippy`");
936 std::process::exit(1);
937 });
938 if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") {
939 rustflags.arg("--cfg=bootstrap");
940 }
941 } else {
942 rustflags.arg("--cfg=bootstrap");
943 }
e1599b0c
XL
944 }
945
3dfed10e
XL
946 if self.config.rust_new_symbol_mangling {
947 rustflags.arg("-Zsymbol-mangling-version=v0");
948 }
949
f9f354fc
XL
950 // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
951 // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
952 // #71458.
3dfed10e 953 let mut rustdocflags = rustflags.clone();
6a06907d
XL
954 rustdocflags.propagate_cargo_env("RUSTDOCFLAGS");
955 if stage == 0 {
956 rustdocflags.env("RUSTDOCFLAGS_BOOTSTRAP");
957 } else {
958 rustdocflags.env("RUSTDOCFLAGS_NOT_BOOTSTRAP");
959 }
f9f354fc 960
e74abb32
XL
961 if let Ok(s) = env::var("CARGOFLAGS") {
962 cargo.args(s.split_whitespace());
963 }
964
532ac7d7 965 match mode {
dfeec247 966 Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
29967ef6 967 Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
532ac7d7
XL
968 // Build proc macros both for the host and the target
969 if target != compiler.host && cmd != "check" {
970 cargo.arg("-Zdual-proc-macros");
e1599b0c 971 rustflags.arg("-Zdual-proc-macros");
532ac7d7 972 }
dfeec247 973 }
532ac7d7
XL
974 }
975
e1599b0c
XL
976 // This tells Cargo (and in turn, rustc) to output more complete
977 // dependency information. Most importantly for rustbuild, this
978 // includes sysroot artifacts, like libstd, which means that we don't
979 // need to track those in rustbuild (an error prone process!). This
980 // feature is currently unstable as there may be some bugs and such, but
981 // it represents a big improvement in rustbuild's reliability on
982 // rebuilds, so we're using it here.
983 //
984 // For some additional context, see #63470 (the PR originally adding
985 // this), as well as #63012 which is the tracking issue for this
986 // feature on the rustc side.
987 cargo.arg("-Zbinary-dep-depinfo");
988
94b46f34
XL
989 cargo.arg("-j").arg(self.jobs().to_string());
990 // Remove make-related flags to ensure Cargo can correctly set things up
991 cargo.env_remove("MAKEFLAGS");
992 cargo.env_remove("MFLAGS");
ea8adc8c 993
3b2f2976
XL
994 // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
995 // Force cargo to output binaries with disambiguating hashes in the name
48663c56
XL
996 let mut metadata = if compiler.stage == 0 {
997 // Treat stage0 like a special channel, whether it's a normal prior-
94b46f34
XL
998 // release rustc or a local rebuild with the same version, so we
999 // never mix these libraries by accident.
48663c56 1000 "bootstrap".to_string()
94b46f34 1001 } else {
48663c56 1002 self.config.channel.to_string()
94b46f34 1003 };
48663c56
XL
1004 // We want to make sure that none of the dependencies between
1005 // std/test/rustc unify with one another. This is done for weird linkage
1006 // reasons but the gist of the problem is that if librustc, libtest, and
1007 // libstd all depend on libc from crates.io (which they actually do) we
1008 // want to make sure they all get distinct versions. Things get really
1009 // weird if we try to unify all these dependencies right now, namely
1010 // around how many times the library is linked in dynamic libraries and
1011 // such. If rustc were a static executable or if we didn't ship dylibs
1012 // this wouldn't be a problem, but we do, so it is. This is in general
1013 // just here to make sure things build right. If you can remove this and
1014 // things still build right, please do!
1015 match mode {
1016 Mode::Std => metadata.push_str("std"),
e74abb32
XL
1017 // When we're building rustc tools, they're built with a search path
1018 // that contains things built during the rustc build. For example,
1019 // bitflags is built during the rustc build, and is a dependency of
1020 // rustdoc as well. We're building rustdoc in a different target
1021 // directory, though, which means that Cargo will rebuild the
1022 // dependency. When we go on to build rustdoc, we'll look for
1023 // bitflags, and find two different copies: one built during the
1024 // rustc step and one that we just built. This isn't always a
1025 // problem, somehow -- not really clear why -- but we know that this
1026 // fixes things.
1027 Mode::ToolRustc => metadata.push_str("tool-rustc"),
29967ef6
XL
1028 // Same for codegen backends.
1029 Mode::Codegen => metadata.push_str("codegen"),
e74abb32 1030 _ => {}
48663c56 1031 }
94b46f34 1032 cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata);
3b2f2976 1033
dc9dc135 1034 if cmd == "clippy" {
e1599b0c 1035 rustflags.arg("-Zforce-unstable-if-unmarked");
2c00a5a8
XL
1036 }
1037
ba9703b0 1038 rustflags.arg("-Zmacro-backtrace");
e1599b0c 1039
83c7162d
XL
1040 let want_rustdoc = self.doc_tests != DocTests::No;
1041
8faf50e0
XL
1042 // We synthetically interpret a stage0 compiler used to build tools as a
1043 // "raw" compiler in that it's the exact snapshot we download. Normally
1044 // the stage0 build means it uses libraries build by the stage0
1045 // compiler, but for tools we just use the precompiled libraries that
1046 // we've downloaded
1047 let use_snapshot = mode == Mode::ToolBootstrap;
1048 assert!(!use_snapshot || stage == 0 || self.local_rebuild);
1049
1050 let maybe_sysroot = self.sysroot(compiler);
dfeec247 1051 let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot };
9fa01778 1052 let libdir = self.rustc_libdir(compiler);
8faf50e0 1053
dfeec247
XL
1054 // Clear the output directory if the real rustc we're using has changed;
1055 // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc.
1056 //
1057 // Avoid doing this during dry run as that usually means the relevant
1058 // compiler is not yet linked/copied properly.
1059 //
1060 // Only clear out the directory if we're compiling std; otherwise, we
1061 // should let Cargo take care of things for us (via depdep info)
1062 if !self.config.dry_run && mode == Mode::Std && cmd == "build" {
1063 self.clear_if_dirty(&out_dir, &self.rustc(compiler));
1064 }
1065
3b2f2976
XL
1066 // Customize the compiler we're running. Specify the compiler to cargo
1067 // as our shim and then pass it some various options used to configure
1068 // how the actual compiler itself is called.
1069 //
1070 // These variables are primarily all read by
1071 // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
94b46f34
XL
1072 cargo
1073 .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
94b46f34
XL
1074 .env("RUSTC_REAL", self.rustc(compiler))
1075 .env("RUSTC_STAGE", stage.to_string())
8faf50e0
XL
1076 .env("RUSTC_SYSROOT", &sysroot)
1077 .env("RUSTC_LIBDIR", &libdir)
94b46f34
XL
1078 .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
1079 .env(
1080 "RUSTDOC_REAL",
a1dfa0c6 1081 if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
532ac7d7 1082 self.rustdoc(compiler)
94b46f34
XL
1083 } else {
1084 PathBuf::from("/path/to/nowhere/rustdoc/not/required")
1085 },
1086 )
e1599b0c
XL
1087 .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir())
1088 .env("RUSTC_BREAK_ON_ICE", "1");
29967ef6
XL
1089 // Clippy support is a hack and uses the default `cargo-clippy` in path.
1090 // Don't override RUSTC so that the `cargo-clippy` in path will be run.
1091 if cmd != "clippy" {
1092 cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"));
1093 }
e1599b0c
XL
1094
1095 // Dealing with rpath here is a little special, so let's go into some
1096 // detail. First off, `-rpath` is a linker option on Unix platforms
1097 // which adds to the runtime dynamic loader path when looking for
1098 // dynamic libraries. We use this by default on Unix platforms to ensure
1099 // that our nightlies behave the same on Windows, that is they work out
1100 // of the box. This can be disabled, of course, but basically that's why
1101 // we're gated on RUSTC_RPATH here.
1102 //
1103 // Ok, so the astute might be wondering "why isn't `-C rpath` used
f035d41b 1104 // here?" and that is indeed a good question to ask. This codegen
e1599b0c
XL
1105 // option is the compiler's current interface to generating an rpath.
1106 // Unfortunately it doesn't quite suffice for us. The flag currently
1107 // takes no value as an argument, so the compiler calculates what it
1108 // should pass to the linker as `-rpath`. This unfortunately is based on
1109 // the **compile time** directory structure which when building with
1110 // Cargo will be very different than the runtime directory structure.
1111 //
1112 // All that's a really long winded way of saying that if we use
1113 // `-Crpath` then the executables generated have the wrong rpath of
1114 // something like `$ORIGIN/deps` when in fact the way we distribute
1115 // rustc requires the rpath to be `$ORIGIN/../lib`.
1116 //
1117 // So, all in all, to set up the correct rpath we pass the linker
1118 // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
1119 // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
1120 // to change a flag in a binary?
3dfed10e 1121 if self.config.rust_rpath && util::use_host_linker(target) {
e1599b0c 1122 let rpath = if target.contains("apple") {
e1599b0c
XL
1123 // Note that we need to take one extra step on macOS to also pass
1124 // `-Wl,-instal_name,@rpath/...` to get things to work right. To
1125 // do that we pass a weird flag to the compiler to get it to do
1126 // so. Note that this is definitely a hack, and we should likely
1127 // flesh out rpath support more fully in the future.
1128 rustflags.arg("-Zosx-rpath-install-name");
1129 Some("-Wl,-rpath,@loader_path/../lib")
60c5eb7d 1130 } else if !target.contains("windows") {
e1599b0c
XL
1131 Some("-Wl,-rpath,$ORIGIN/../lib")
1132 } else {
1133 None
1134 };
1135 if let Some(rpath) = rpath {
1136 rustflags.arg(&format!("-Clink-args={}", rpath));
1137 }
1138 }
abe05a73 1139
1b1a35ee 1140 if let Some(host_linker) = self.linker(compiler.host) {
abe05a73
XL
1141 cargo.env("RUSTC_HOST_LINKER", host_linker);
1142 }
1b1a35ee
XL
1143 if self.is_fuse_ld_lld(compiler.host) {
1144 cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1");
17df50a5 1145 cargo.env("RUSTDOC_FUSE_LD_LLD", "1");
1b1a35ee 1146 }
74b04a01 1147
1b1a35ee 1148 if let Some(target_linker) = self.linker(target) {
3dfed10e 1149 let target = crate::envify(&target.triple);
e1599b0c 1150 cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker);
0531ce1d 1151 }
1b1a35ee 1152 if self.is_fuse_ld_lld(target) {
3dfed10e
XL
1153 rustflags.arg("-Clink-args=-fuse-ld=lld");
1154 }
17df50a5
XL
1155 self.lld_flags(target).for_each(|flag| {
1156 rustdocflags.arg(&flag);
1157 });
3dfed10e 1158
dc9dc135 1159 if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
9fa01778 1160 cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
2c00a5a8 1161 }
3b2f2976 1162
dc9dc135 1163 let debuginfo_level = match mode {
29967ef6 1164 Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
e1599b0c 1165 Mode::Std => self.config.rust_debuginfo_level_std,
dfeec247
XL
1166 Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => {
1167 self.config.rust_debuginfo_level_tools
1168 }
dc9dc135 1169 };
e1599b0c 1170 cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
f035d41b
XL
1171 cargo.env(
1172 profile_var("DEBUG_ASSERTIONS"),
1173 if mode == Mode::Std {
1174 self.config.rust_debug_assertions_std.to_string()
1175 } else {
1176 self.config.rust_debug_assertions.to_string()
1177 },
1178 );
dc9dc135 1179
fc512014
XL
1180 // `dsymutil` adds time to builds on Apple platforms for no clear benefit, and also makes
1181 // it more difficult for debuggers to find debug info. The compiler currently defaults to
1182 // running `dsymutil` to preserve its historical default, but when compiling the compiler
1183 // itself, we skip it by default since we know it's safe to do so in that case.
1184 // See https://github.com/rust-lang/rust/issues/79361 for more info on this flag.
1185 if target.contains("apple") {
6a06907d
XL
1186 if self.config.rust_run_dsymutil {
1187 rustflags.arg("-Csplit-debuginfo=packed");
fc512014 1188 } else {
6a06907d 1189 rustflags.arg("-Csplit-debuginfo=unpacked");
fc512014
XL
1190 }
1191 }
1192
1b1a35ee
XL
1193 if self.config.cmd.bless() {
1194 // Bless `expect!` tests.
1195 cargo.env("UPDATE_EXPECT", "1");
1196 }
1197
dc9dc135 1198 if !mode.is_tool() {
ff7c6d11 1199 cargo.env("RUSTC_FORCE_UNSTABLE", "1");
3b2f2976
XL
1200 }
1201
1202 if let Some(x) = self.crt_static(target) {
e1599b0c
XL
1203 if x {
1204 rustflags.arg("-Ctarget-feature=+crt-static");
1205 } else {
1206 rustflags.arg("-Ctarget-feature=-crt-static");
1207 }
3b2f2976
XL
1208 }
1209
94b46f34
XL
1210 if let Some(x) = self.crt_static(compiler.host) {
1211 cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
1212 }
1213
ba9703b0
XL
1214 if let Some(map_to) = self.build.debuginfo_map_to(GitRepo::Rustc) {
1215 let map = format!("{}={}", self.build.src.display(), map_to);
b7449926 1216 cargo.env("RUSTC_DEBUGINFO_MAP", map);
ba9703b0
XL
1217
1218 // `rustc` needs to know the virtual `/rustc/$hash` we're mapping to,
1219 // in order to opportunistically reverse it later.
1220 cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to);
b7449926
XL
1221 }
1222
3b2f2976
XL
1223 // Enable usage of unstable features
1224 cargo.env("RUSTC_BOOTSTRAP", "1");
1225 self.add_rust_test_threads(&mut cargo);
1226
1227 // Almost all of the crates that we compile as part of the bootstrap may
1228 // have a build script, including the standard library. To compile a
1229 // build script, however, it itself needs a standard library! This
1230 // introduces a bit of a pickle when we're compiling the standard
1231 // library itself.
1232 //
1233 // To work around this we actually end up using the snapshot compiler
1234 // (stage0) for compiling build scripts of the standard library itself.
1235 // The stage0 compiler is guaranteed to have a libstd available for use.
1236 //
1237 // For other crates, however, we know that we've already got a standard
1238 // library up and running, so we can use the normal compiler to compile
1239 // build scripts in that situation.
532ac7d7 1240 if mode == Mode::Std {
94b46f34
XL
1241 cargo
1242 .env("RUSTC_SNAPSHOT", &self.initial_rustc)
1243 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
3b2f2976 1244 } else {
94b46f34
XL
1245 cargo
1246 .env("RUSTC_SNAPSHOT", self.rustc(compiler))
1247 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler));
3b2f2976
XL
1248 }
1249
ba9703b0
XL
1250 // Tools that use compiler libraries may inherit the `-lLLVM` link
1251 // requirement, but the `-L` library path is not propagated across
1252 // separate Cargo projects. We can add LLVM's library path to the
1253 // platform-specific environment variable as a workaround.
1254 if mode == Mode::ToolRustc {
1255 if let Some(llvm_config) = self.llvm_config(target) {
1256 let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
1257 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo);
1258 }
1259 }
1260
29967ef6
XL
1261 // Compile everything except libraries and proc macros with the more
1262 // efficient initial-exec TLS model. This doesn't work with `dlopen`,
1263 // so we can't use it by default in general, but we can use it for tools
1264 // and our own internal libraries.
1265 if !mode.must_support_dlopen() {
1266 rustflags.arg("-Ztls-model=initial-exec");
1267 }
1268
8faf50e0 1269 if self.config.incremental {
2c00a5a8 1270 cargo.env("CARGO_INCREMENTAL", "1");
9fa01778
XL
1271 } else {
1272 // Don't rely on any default setting for incr. comp. in Cargo
1273 cargo.env("CARGO_INCREMENTAL", "0");
3b2f2976
XL
1274 }
1275
1276 if let Some(ref on_fail) = self.config.on_fail {
1277 cargo.env("RUSTC_ON_FAIL", on_fail);
1278 }
1279
0531ce1d
XL
1280 if self.config.print_step_timings {
1281 cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
1282 }
1283
6a06907d
XL
1284 if self.config.print_step_rusage {
1285 cargo.env("RUSTC_PRINT_STEP_RUSAGE", "1");
1286 }
1287
83c7162d
XL
1288 if self.config.backtrace_on_ice {
1289 cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
1290 }
1291
8faf50e0 1292 cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
3b2f2976 1293
f035d41b
XL
1294 if source_type == SourceType::InTree {
1295 let mut lint_flags = Vec::new();
e1599b0c
XL
1296 // When extending this list, add the new lints to the RUSTFLAGS of the
1297 // build_bootstrap function of src/bootstrap/bootstrap.py as well as
1298 // some code doesn't go through this `rustc` wrapper.
f035d41b
XL
1299 lint_flags.push("-Wrust_2018_idioms");
1300 lint_flags.push("-Wunused_lifetimes");
17df50a5 1301 lint_flags.push("-Wsemicolon_in_expressions_from_macros");
e1599b0c
XL
1302
1303 if self.config.deny_warnings {
f035d41b 1304 lint_flags.push("-Dwarnings");
3dfed10e 1305 rustdocflags.arg("-Dwarnings");
f9f354fc 1306 }
ba9703b0 1307
f9f354fc
XL
1308 // FIXME(#58633) hide "unused attribute" errors in incremental
1309 // builds of the standard library, as the underlying checks are
1310 // not yet properly integrated with incremental recompilation.
1311 if mode == Mode::Std && compiler.stage == 0 && self.config.incremental {
f035d41b 1312 lint_flags.push("-Aunused-attributes");
e1599b0c 1313 }
f035d41b
XL
1314 // This does not use RUSTFLAGS due to caching issues with Cargo.
1315 // Clippy is treated as an "in tree" tool, but shares the same
1316 // cache as other "submodule" tools. With these options set in
1317 // RUSTFLAGS, that causes *every* shared dependency to be rebuilt.
1318 // By injecting this into the rustc wrapper, this circumvents
1319 // Cargo's fingerprint detection. This is fine because lint flags
1320 // are always ignored in dependencies. Eventually this should be
1321 // fixed via better support from Cargo.
1322 cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" "));
3dfed10e 1323
cdc7bbd5 1324 rustdocflags.arg("-Wrustdoc::invalid_codeblock_attributes");
e1599b0c
XL
1325 }
1326
1b1a35ee 1327 if mode == Mode::Rustc {
e1599b0c
XL
1328 rustflags.arg("-Zunstable-options");
1329 rustflags.arg("-Wrustc::internal");
83c7162d
XL
1330 }
1331
abe05a73
XL
1332 // Throughout the build Cargo can execute a number of build scripts
1333 // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
1334 // obtained previously to those build scripts.
1335 // Build scripts use either the `cc` crate or `configure/make` so we pass
1336 // the options through environment variables that are fetched and understood by both.
3b2f2976
XL
1337 //
1338 // FIXME: the guard against msvc shouldn't need to be here
94b46f34
XL
1339 if target.contains("msvc") {
1340 if let Some(ref cl) = self.config.llvm_clang_cl {
1341 cargo.env("CC", cl).env("CXX", cl);
1342 }
1343 } else {
0531ce1d
XL
1344 let ccache = self.config.ccache.as_ref();
1345 let ccacheify = |s: &Path| {
1346 let ccache = match ccache {
1347 Some(ref s) => s,
1348 None => return s.display().to_string(),
1349 };
1350 // FIXME: the cc-rs crate only recognizes the literal strings
1351 // `ccache` and `sccache` when doing caching compilations, so we
1352 // mirror that here. It should probably be fixed upstream to
1353 // accept a new env var or otherwise work with custom ccache
1354 // vars.
1355 match &ccache[..] {
1356 "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
1357 _ => s.display().to_string(),
1358 }
1359 };
1360 let cc = ccacheify(&self.cc(target));
3dfed10e 1361 cargo.env(format!("CC_{}", target.triple), &cc);
abe05a73 1362
b7449926 1363 let cflags = self.cflags(target, GitRepo::Rustc).join(" ");
1b1a35ee 1364 cargo.env(format!("CFLAGS_{}", target.triple), &cflags);
abe05a73
XL
1365
1366 if let Some(ar) = self.ar(target) {
1367 let ranlib = format!("{} s", ar.display());
3dfed10e
XL
1368 cargo
1369 .env(format!("AR_{}", target.triple), ar)
1370 .env(format!("RANLIB_{}", target.triple), ranlib);
abe05a73 1371 }
3b2f2976
XL
1372
1373 if let Ok(cxx) = self.cxx(target) {
0531ce1d 1374 let cxx = ccacheify(&cxx);
94b46f34 1375 cargo
3dfed10e
XL
1376 .env(format!("CXX_{}", target.triple), &cxx)
1377 .env(format!("CXXFLAGS_{}", target.triple), cflags);
3b2f2976
XL
1378 }
1379 }
1380
dfeec247 1381 if mode == Mode::Std && self.config.extended && compiler.is_final_stage(self) {
e1599b0c 1382 rustflags.arg("-Zsave-analysis");
dfeec247
XL
1383 cargo.env(
1384 "RUST_SAVE_ANALYSIS_CONFIG",
1385 "{\"output_file\": null,\"full_docs\": false,\
e1599b0c 1386 \"pub_only\": true,\"reachable_only\": false,\
dfeec247
XL
1387 \"distro_crate\": true,\"signatures\": false,\"borrow_data\": false}",
1388 );
3b2f2976
XL
1389 }
1390
f035d41b 1391 // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
74b04a01
XL
1392 // when compiling the standard library, since this might be linked into the final outputs
1393 // produced by rustc. Since this mitigation is only available on Windows, only enable it
1394 // for the standard library in case the compiler is run on a non-Windows platform.
1395 // This is not needed for stage 0 artifacts because these will only be used for building
1396 // the stage 1 compiler.
1397 if cfg!(windows)
1398 && mode == Mode::Std
1399 && self.config.control_flow_guard
1400 && compiler.stage >= 1
1401 {
3dfed10e 1402 rustflags.arg("-Ccontrol-flow-guard");
74b04a01
XL
1403 }
1404
abe05a73 1405 // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
3dfed10e
XL
1406 // This replaces spaces with newlines because RUSTDOCFLAGS does not
1407 // support arguments with regular spaces. Hopefully someday Cargo will
1408 // have space support.
1409 let rust_version = self.rust_version().replace(' ', "\n");
1410 rustdocflags.arg("--crate-version").arg(&rust_version);
abe05a73 1411
3b2f2976
XL
1412 // Environment variables *required* throughout the build
1413 //
1414 // FIXME: should update code to not require this env var
3dfed10e 1415 cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple);
3b2f2976
XL
1416
1417 // Set this for all builds to make sure doc builds also get it.
83c7162d 1418 cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
3b2f2976 1419
2c00a5a8
XL
1420 // This one's a bit tricky. As of the time of this writing the compiler
1421 // links to the `winapi` crate on crates.io. This crate provides raw
1422 // bindings to Windows system functions, sort of like libc does for
1423 // Unix. This crate also, however, provides "import libraries" for the
1424 // MinGW targets. There's an import library per dll in the windows
1425 // distribution which is what's linked to. These custom import libraries
1426 // are used because the winapi crate can reference Windows functions not
1427 // present in the MinGW import libraries.
1428 //
1429 // For example MinGW may ship libdbghelp.a, but it may not have
1430 // references to all the functions in the dbghelp dll. Instead the
1431 // custom import library for dbghelp in the winapi crates has all this
1432 // information.
1433 //
1434 // Unfortunately for us though the import libraries are linked by
1435 // default via `-ldylib=winapi_foo`. That is, they're linked with the
1436 // `dylib` type with a `winapi_` prefix (so the winapi ones don't
1437 // conflict with the system MinGW ones). This consequently means that
94b46f34 1438 // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm
2c00a5a8
XL
1439 // DLL) when linked against *again*, for example with procedural macros
1440 // or plugins, will trigger the propagation logic of `-ldylib`, passing
1441 // `-lwinapi_foo` to the linker again. This isn't actually available in
1442 // our distribution, however, so the link fails.
1443 //
1444 // To solve this problem we tell winapi to not use its bundled import
1445 // libraries. This means that it will link to the system MinGW import
1446 // libraries by default, and the `-ldylib=foo` directives will still get
1447 // passed to the final linker, but they'll look like `-lfoo` which can
1448 // be resolved because MinGW has the import library. The downside is we
1449 // don't get newer functions from Windows, but we don't use any of them
1450 // anyway.
94b46f34 1451 if !mode.is_tool() {
0531ce1d
XL
1452 cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
1453 }
2c00a5a8 1454
0531ce1d 1455 for _ in 1..self.verbosity {
3b2f2976
XL
1456 cargo.arg("-v");
1457 }
2c00a5a8 1458
a1dfa0c6 1459 match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) {
dfeec247 1460 (Mode::Std, Some(n), _) | (_, _, Some(n)) => {
e1599b0c 1461 cargo.env(profile_var("CODEGEN_UNITS"), n.to_string());
a1dfa0c6
XL
1462 }
1463 _ => {
1464 // Don't set anything
1465 }
2c00a5a8
XL
1466 }
1467
abe05a73 1468 if self.config.rust_optimize {
94b46f34
XL
1469 // FIXME: cargo bench/install do not accept `--release`
1470 if cmd != "bench" && cmd != "install" {
abe05a73
XL
1471 cargo.arg("--release");
1472 }
3b2f2976 1473 }
2c00a5a8 1474
3b2f2976
XL
1475 if self.config.locked_deps {
1476 cargo.arg("--locked");
1477 }
1478 if self.config.vendor || self.is_sudo {
1479 cargo.arg("--frozen");
1480 }
1481
60c5eb7d
XL
1482 // Try to use a sysroot-relative bindir, in case it was configured absolutely.
1483 cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative());
e1599b0c 1484
3b2f2976
XL
1485 self.ci_env.force_coloring_in_ci(&mut cargo);
1486
e1599b0c
XL
1487 // When we build Rust dylibs they're all intended for intermediate
1488 // usage, so make sure we pass the -Cprefer-dynamic flag instead of
1489 // linking all deps statically into the dylib.
1b1a35ee 1490 if matches!(mode, Mode::Std | Mode::Rustc) {
e1599b0c
XL
1491 rustflags.arg("-Cprefer-dynamic");
1492 }
1493
dfeec247
XL
1494 // When building incrementally we default to a lower ThinLTO import limit
1495 // (unless explicitly specified otherwise). This will produce a somewhat
1496 // slower code but give way better compile times.
1497 {
1498 let limit = match self.config.rust_thin_lto_import_instr_limit {
1499 Some(limit) => Some(limit),
1500 None if self.config.incremental => Some(10),
1501 _ => None,
1502 };
1503
1504 if let Some(limit) = limit {
1505 rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={}", limit));
1506 }
e1599b0c 1507 }
dfeec247 1508
f9f354fc 1509 Cargo { command: cargo, rustflags, rustdocflags }
3b2f2976
XL
1510 }
1511
83c7162d 1512 /// Ensure that a given step is built, returning its output. This will
3b2f2976
XL
1513 /// cache the step, so it is safe (and good!) to call this as often as
1514 /// needed to ensure that all dependencies are built.
1515 pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
1516 {
1517 let mut stack = self.stack.borrow_mut();
1518 for stack_step in stack.iter() {
1519 // should skip
dfeec247 1520 if stack_step.downcast_ref::<S>().map_or(true, |stack_step| *stack_step != step) {
3b2f2976
XL
1521 continue;
1522 }
1523 let mut out = String::new();
1524 out += &format!("\n\nCycle in build detected when adding {:?}\n", step);
1525 for el in stack.iter().rev() {
1526 out += &format!("\t{:?}\n", el);
1527 }
6a06907d 1528 panic!("{}", out);
3b2f2976
XL
1529 }
1530 if let Some(out) = self.cache.get(&step) {
83c7162d
XL
1531 self.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step));
1532
3b2f2976
XL
1533 return out;
1534 }
83c7162d 1535 self.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
3b2f2976
XL
1536 stack.push(Box::new(step.clone()));
1537 }
0531ce1d
XL
1538
1539 let (out, dur) = {
1540 let start = Instant::now();
1541 let zero = Duration::new(0, 0);
1542 let parent = self.time_spent_on_dependencies.replace(zero);
1543 let out = step.clone().run(self);
1544 let dur = start.elapsed();
1545 let deps = self.time_spent_on_dependencies.replace(parent + dur);
1546 (out, dur - deps)
1547 };
1548
1b1a35ee 1549 if self.config.print_step_timings && !self.config.dry_run {
74b04a01 1550 println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis());
0531ce1d
XL
1551 }
1552
3b2f2976
XL
1553 {
1554 let mut stack = self.stack.borrow_mut();
1555 let cur_step = stack.pop().expect("step stack empty");
1556 assert_eq!(cur_step.downcast_ref(), Some(&step));
1557 }
dfeec247 1558 self.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
3b2f2976
XL
1559 self.cache.put(step, out.clone());
1560 out
1561 }
1562}
83c7162d
XL
1563
1564#[cfg(test)]
dc9dc135 1565mod tests;
e1599b0c 1566
f9f354fc 1567#[derive(Debug, Clone)]
6a06907d 1568struct Rustflags(String, TargetSelection);
e1599b0c
XL
1569
1570impl Rustflags {
3dfed10e 1571 fn new(target: TargetSelection) -> Rustflags {
6a06907d
XL
1572 let mut ret = Rustflags(String::new(), target);
1573 ret.propagate_cargo_env("RUSTFLAGS");
1574 ret
1575 }
e1599b0c 1576
6a06907d
XL
1577 /// By default, cargo will pick up on various variables in the environment. However, bootstrap
1578 /// reuses those variables to pass additional flags to rustdoc, so by default they get overriden.
1579 /// Explicitly add back any previous value in the environment.
1580 ///
1581 /// `prefix` is usually `RUSTFLAGS` or `RUSTDOCFLAGS`.
1582 fn propagate_cargo_env(&mut self, prefix: &str) {
e1599b0c 1583 // Inherit `RUSTFLAGS` by default ...
6a06907d 1584 self.env(prefix);
e1599b0c 1585
6a06907d
XL
1586 // ... and also handle target-specific env RUSTFLAGS if they're configured.
1587 let target_specific = format!("CARGO_TARGET_{}_{}", crate::envify(&self.1.triple), prefix);
1588 self.env(&target_specific);
e1599b0c
XL
1589 }
1590
1591 fn env(&mut self, env: &str) {
1592 if let Ok(s) = env::var(env) {
3dfed10e 1593 for part in s.split(' ') {
e1599b0c
XL
1594 self.arg(part);
1595 }
1596 }
1597 }
1598
1599 fn arg(&mut self, arg: &str) -> &mut Self {
3dfed10e 1600 assert_eq!(arg.split(' ').count(), 1);
74b04a01 1601 if !self.0.is_empty() {
5869c6ff 1602 self.0.push(' ');
e1599b0c
XL
1603 }
1604 self.0.push_str(arg);
1605 self
1606 }
1607}
1608
1609#[derive(Debug)]
1610pub struct Cargo {
1611 command: Command,
1612 rustflags: Rustflags,
f9f354fc 1613 rustdocflags: Rustflags,
e1599b0c
XL
1614}
1615
1616impl Cargo {
3dfed10e
XL
1617 pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
1618 self.rustdocflags.arg(arg);
1619 self
1620 }
e1599b0c
XL
1621 pub fn rustflag(&mut self, arg: &str) -> &mut Cargo {
1622 self.rustflags.arg(arg);
1623 self
1624 }
1625
1626 pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Cargo {
1627 self.command.arg(arg.as_ref());
1628 self
1629 }
1630
1631 pub fn args<I, S>(&mut self, args: I) -> &mut Cargo
dfeec247
XL
1632 where
1633 I: IntoIterator<Item = S>,
1634 S: AsRef<OsStr>,
e1599b0c
XL
1635 {
1636 for arg in args {
1637 self.arg(arg.as_ref());
1638 }
1639 self
1640 }
1641
1642 pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Cargo {
3dfed10e
XL
1643 // These are managed through rustflag/rustdocflag interfaces.
1644 assert_ne!(key.as_ref(), "RUSTFLAGS");
1645 assert_ne!(key.as_ref(), "RUSTDOCFLAGS");
e1599b0c
XL
1646 self.command.env(key.as_ref(), value.as_ref());
1647 self
1648 }
1b1a35ee
XL
1649
1650 pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
1651 builder.add_rustc_lib_path(compiler, &mut self.command);
1652 }
cdc7bbd5
XL
1653
1654 pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo {
1655 self.command.current_dir(dir);
1656 self
1657 }
e1599b0c
XL
1658}
1659
1660impl From<Cargo> for Command {
1661 fn from(mut cargo: Cargo) -> Command {
f9f354fc
XL
1662 let rustflags = &cargo.rustflags.0;
1663 if !rustflags.is_empty() {
1664 cargo.command.env("RUSTFLAGS", rustflags);
1665 }
1666
1667 let rustdocflags = &cargo.rustdocflags.0;
1668 if !rustdocflags.is_empty() {
1669 cargo.command.env("RUSTDOCFLAGS", rustdocflags);
1670 }
1671
e1599b0c
XL
1672 cargo.command
1673 }
1674}