diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index f96925f927086..77b39cbb87ed9 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -90,6 +90,54 @@ mod defaults { assert!(builder.cache.all::().is_empty()); } + #[test] + fn build_cross_compile() { + let config = Config { stage: 1, ..configure("build", &["B"], &["B"]) }; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + + // Ideally, this build wouldn't actually have `target: a` + // rustdoc/rustcc/std here (the user only requested a host=B build, so + // there's not really a need for us to build for target A in this case + // (since we're producing stage 1 libraries/binaries). But currently + // rustbuild is just a bit buggy here; this should be fixed though. + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, + compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, + tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, + ], + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b }, + ] + ); + } + #[test] fn doc_default() { let mut config = configure("doc", &[], &[]); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f90e76a4f4ea6..cf9211bc7ea86 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -752,6 +752,7 @@ impl Step for RustcBook { let out_listing = out_base.join("src/lints"); builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base); builder.info(&format!("Generating lint docs ({})", self.target)); + let rustc = builder.rustc(self.compiler); // The tool runs `rustc` for extracting output examples, so it needs a // functional sysroot. @@ -762,7 +763,8 @@ impl Step for RustcBook { cmd.arg("--out"); cmd.arg(&out_listing); cmd.arg("--rustc"); - cmd.arg(rustc); + cmd.arg(&rustc); + cmd.arg("--rustc-target").arg(&self.target.rustc_target_arg()); if builder.config.verbose() { cmd.arg("--verbose"); } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 99e33e3b006fe..d2346e40e51d2 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -471,7 +471,11 @@ impl Step for Rustdoc { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustdoc { - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + // Note: this is somewhat unique in that we actually want a *target* + // compiler here, because rustdoc *is* a compiler. We won't be using + // this as the compiler to build with, but rather this is "what + // compiler are we producing"? + compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index a212459bb4dc6..6b32ebdc284f4 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -18,10 +18,10 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ /// Updates the documentation of lint groups. pub(crate) fn generate_group_docs( lints: &[Lint], - rustc_path: &Path, + rustc: crate::Rustc<'_>, out_path: &Path, ) -> Result<(), Box> { - let groups = collect_groups(rustc_path)?; + let groups = collect_groups(rustc)?; let groups_path = out_path.join("groups.md"); let contents = fs::read_to_string(&groups_path) .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; @@ -36,9 +36,9 @@ pub(crate) fn generate_group_docs( type LintGroups = BTreeMap>; /// Collects the group names from rustc. -fn collect_groups(rustc: &Path) -> Result> { +fn collect_groups(rustc: crate::Rustc<'_>) -> Result> { let mut result = BTreeMap::new(); - let mut cmd = Command::new(rustc); + let mut cmd = Command::new(rustc.path); cmd.arg("-Whelp"); let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; if !output.status.success() { diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 92b3d186fa141..6ca71dcaf3cd0 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -45,16 +45,22 @@ impl Level { } } +#[derive(Copy, Clone)] +pub struct Rustc<'a> { + pub path: &'a Path, + pub target: &'a str, +} + /// Collects all lints, and writes the markdown documentation at the given directory. pub fn extract_lint_docs( src_path: &Path, out_path: &Path, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { let mut lints = gather_lints(src_path)?; for lint in &mut lints { - generate_output_example(lint, rustc_path, verbose).map_err(|e| { + generate_output_example(lint, rustc, verbose).map_err(|e| { format!( "failed to test example in lint docs for `{}` in {}:{}: {}", lint.name, @@ -65,7 +71,7 @@ pub fn extract_lint_docs( })?; } save_lints_markdown(&lints, &out_path.join("listing"))?; - groups::generate_group_docs(&lints, rustc_path, out_path)?; + groups::generate_group_docs(&lints, rustc, out_path)?; Ok(()) } @@ -208,7 +214,7 @@ fn lint_name(line: &str) -> Result { /// actual output from the compiler. fn generate_output_example( lint: &mut Lint, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { // Explicit list of lints that are allowed to not have an example. Please @@ -230,7 +236,7 @@ fn generate_output_example( // separate test suite, and use an include mechanism such as mdbook's // `{{#rustdoc_include}}`. if !lint.is_ignored() { - replace_produces(lint, rustc_path, verbose)?; + replace_produces(lint, rustc, verbose)?; } Ok(()) } @@ -261,7 +267,7 @@ fn check_style(lint: &Lint) -> Result<(), Box> { /// output from the compiler. fn replace_produces( lint: &mut Lint, - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result<(), Box> { let mut lines = lint.doc.iter_mut(); @@ -302,7 +308,7 @@ fn replace_produces( Some(line) if line.is_empty() => {} Some(line) if line == "{{produces}}" => { let output = - generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?; + generate_lint_output(&lint.name, &example, &options, rustc, verbose)?; line.replace_range( .., &format!( @@ -329,7 +335,7 @@ fn generate_lint_output( name: &str, example: &[&mut String], options: &[&str], - rustc_path: &Path, + rustc: Rustc<'_>, verbose: bool, ) -> Result> { if verbose { @@ -364,13 +370,14 @@ fn generate_lint_output( } fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; - let mut cmd = Command::new(rustc_path); + let mut cmd = Command::new(rustc.path); if options.contains(&"edition2015") { cmd.arg("--edition=2015"); } else { cmd.arg("--edition=2018"); } cmd.arg("--error-format=json"); + cmd.arg("--target").arg(rustc.target); if options.contains(&"test") { cmd.arg("--test"); } diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 45d97bd431791..5db49007d375c 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -13,6 +13,7 @@ fn doit() -> Result<(), Box> { let mut src_path = None; let mut out_path = None; let mut rustc_path = None; + let mut rustc_target = None; let mut verbose = false; while let Some(arg) = args.next() { match arg.as_str() { @@ -34,6 +35,12 @@ fn doit() -> Result<(), Box> { None => return Err("--rustc requires a value".into()), }; } + "--rustc-target" => { + rustc_target = match args.next() { + Some(s) => Some(s), + None => return Err("--rustc-target requires a value".into()), + }; + } "-v" | "--verbose" => verbose = true, s => return Err(format!("unexpected argument `{}`", s).into()), } @@ -47,10 +54,16 @@ fn doit() -> Result<(), Box> { if rustc_path.is_none() { return Err("--rustc must be specified to the path of rustc".into()); } + if rustc_target.is_none() { + return Err("--rustc-target must be specified to the rustc target".into()); + } lint_docs::extract_lint_docs( &src_path.unwrap(), &out_path.unwrap(), - &rustc_path.unwrap(), + lint_docs::Rustc { + path: rustc_path.as_deref().unwrap(), + target: rustc_target.as_deref().unwrap(), + }, verbose, ) }