Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,21 +449,24 @@ fn copy_self_contained_objects(
target_deps
}

/// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.).
/// Resolves standard library crates for `Std::run_make` for any build kind (like check, doc,
/// build, clippy, etc.).
pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec<String> {
let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
let mut crates = run.make_run_crates(builder::Alias::Library);

// For no_std targets, we only want to check core and alloc
// Regardless of core/alloc being selected explicitly or via the "library" default alias,
// we only want to keep these two crates.
// The set of no_std crates should be kept in sync with what `Builder::std_cargo` does.
// Note: an alternative design would be to return an enum from this function (Default vs Subset)
// of crates. However, several steps currently pass `-p <package>` even if all crates are
// selected, because Cargo behaves differently in that case. To keep that behavior without
// making further changes, we pre-filter the no-std crates here.
let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false);

// For no_std targets, do not add any additional crates to the compilation other than what `compile::std_cargo` already adds for no_std targets.
if target_is_no_std {
vec![]
}
// If the paths include "library", build the entire standard library.
else if has_alias {
run.make_run_crates(builder::Alias::Library)
} else {
run.cargo_crates_in_set()
crates.retain(|c| c == "core" || c == "alloc");
}
crates
}

/// Tries to find LLVM's `compiler-rt` source directory, for building `library/profiler_builtins`.
Expand Down
94 changes: 75 additions & 19 deletions src/bootstrap/src/core/builder/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,8 +637,8 @@ mod snapshot {

use crate::core::build_steps::{compile, dist, doc, test, tool};
use crate::core::builder::tests::{
TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, configure_with_args, first,
host_target, render_steps, run_build,
RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, configure_with_args,
first, host_target, render_steps, run_build,
};
use crate::core::builder::{Builder, Kind, StepDescription, StepMetadata};
use crate::core::config::TargetSelection;
Expand Down Expand Up @@ -1521,6 +1521,49 @@ mod snapshot {
steps.assert_contains(StepMetadata::test("CrateLibrustc", host));
steps.assert_contains_fuzzy(StepMetadata::build("rustc", host));
}

#[test]
fn doc_library() {
let ctx = TestCtx::new();
insta::assert_snapshot!(
ctx.config("doc")
.path("library")
.render_steps(), @r"
[build] llvm <host>
[build] rustc 0 <host> -> rustc 1 <host>
[build] rustdoc 0 <host>
[doc] std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
");
}

#[test]
fn doc_core() {
let ctx = TestCtx::new();
insta::assert_snapshot!(
ctx.config("doc")
.path("core")
.render_steps(), @r"
[build] llvm <host>
[build] rustc 0 <host> -> rustc 1 <host>
[build] rustdoc 0 <host>
[doc] std 1 <host> crates=[core]
");
}

#[test]
fn doc_library_no_std_target() {
let ctx = TestCtx::new();
insta::assert_snapshot!(
ctx.config("doc")
.path("core")
.override_target_no_std(&host_target())
.render_steps(), @r"
[build] llvm <host>
[build] rustc 0 <host> -> rustc 1 <host>
[build] rustdoc 0 <host>
[doc] std 1 <host> crates=[core]
");
}
}

struct ExecutedSteps {
Expand All @@ -1529,7 +1572,10 @@ struct ExecutedSteps {

impl ExecutedSteps {
fn render(&self) -> String {
render_steps(&self.steps)
self.render_with(RenderConfig::default())
}
fn render_with(&self, config: RenderConfig) -> String {
render_steps(&self.steps, config)
}

#[track_caller]
Expand All @@ -1538,7 +1584,7 @@ impl ExecutedSteps {
if !self.contains(&metadata) {
panic!(
"Metadata `{}` ({metadata:?}) not found in executed steps:\n{}",
render_metadata(&metadata),
render_metadata(&metadata, &RenderConfig::default()),
self.render()
);
}
Expand All @@ -1553,7 +1599,7 @@ impl ExecutedSteps {
if !self.contains_fuzzy(&metadata) {
panic!(
"Metadata `{}` ({metadata:?}) not found in executed steps:\n{}",
render_metadata(&metadata),
render_metadata(&metadata, &RenderConfig::default()),
self.render()
);
}
Expand All @@ -1565,7 +1611,7 @@ impl ExecutedSteps {
if self.contains(&metadata) {
panic!(
"Metadata `{}` ({metadata:?}) found in executed steps (it should not be there):\n{}",
render_metadata(&metadata),
render_metadata(&metadata, &RenderConfig::default()),
self.render()
);
}
Expand Down Expand Up @@ -1618,14 +1664,24 @@ impl ConfigBuilder {
}
}

struct RenderConfig {
normalize_host: bool,
}

impl Default for RenderConfig {
fn default() -> Self {
Self { normalize_host: true }
}
}

/// Renders the executed bootstrap steps for usage in snapshot tests with insta.
/// Only renders certain important steps.
/// Each value in `steps` should be a tuple of (Step, step output).
///
/// The arrow in the rendered output (`X -> Y`) means `X builds Y`.
/// This is similar to the output printed by bootstrap to stdout, but here it is
/// generated purely for the purpose of tests.
fn render_steps(steps: &[ExecutedStep]) -> String {
fn render_steps(steps: &[ExecutedStep], config: RenderConfig) -> String {
steps
.iter()
.filter_map(|step| {
Expand All @@ -1635,35 +1691,35 @@ fn render_steps(steps: &[ExecutedStep]) -> String {
return None;
};

Some(render_metadata(&metadata))
Some(render_metadata(&metadata, &config))
})
.collect::<Vec<_>>()
.join("\n")
}

fn render_metadata(metadata: &StepMetadata) -> String {
fn render_metadata(metadata: &StepMetadata, config: &RenderConfig) -> String {
let mut record = format!("[{}] ", metadata.kind.as_str());
if let Some(compiler) = metadata.built_by {
write!(record, "{} -> ", render_compiler(compiler));
write!(record, "{} -> ", render_compiler(compiler, config));
}
let stage = metadata.get_stage().map(|stage| format!("{stage} ")).unwrap_or_default();
write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target));
write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target, config));
if let Some(metadata) = &metadata.metadata {
write!(record, " {metadata}");
}
record
}

fn normalize_target(target: TargetSelection) -> String {
target
.to_string()
.replace(&host_target(), "host")
.replace(TEST_TRIPLE_1, "target1")
.replace(TEST_TRIPLE_2, "target2")
fn normalize_target(target: TargetSelection, config: &RenderConfig) -> String {
let mut target = target.to_string();
if config.normalize_host {
target = target.replace(&host_target(), "host");
}
target.replace(TEST_TRIPLE_1, "target1").replace(TEST_TRIPLE_2, "target2")
}

fn render_compiler(compiler: Compiler) -> String {
format!("rustc {} <{}>", compiler.stage, normalize_target(compiler.host))
fn render_compiler(compiler: Compiler, config: &RenderConfig) -> String {
format!("rustc {} <{}>", compiler.stage, normalize_target(compiler.host, config))
}

fn host_target() -> String {
Expand Down
28 changes: 17 additions & 11 deletions src/bootstrap/src/utils/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,30 @@ impl ConfigBuilder {
}

pub fn path(mut self, path: &str) -> Self {
self.args.push(path.to_string());
self
self.arg(path)
}

pub fn paths(mut self, paths: &[&str]) -> Self {
for path in paths {
self = self.path(path);
self.args(paths)
}

pub fn arg(mut self, arg: &str) -> Self {
self.args.push(arg.to_string());
self
}

pub fn args(mut self, args: &[&str]) -> Self {
for arg in args {
self = self.arg(arg);
}
self
}

/// Set the specified target to be treated as a no_std target.
pub fn override_target_no_std(mut self, target: &str) -> Self {
self.args(&["--set", &format!("target.{target}.no-std=true")])
}

pub fn hosts(mut self, targets: &[&str]) -> Self {
self.args.push("--host".to_string());
self.args.push(targets.join(","));
Expand All @@ -77,13 +90,6 @@ impl ConfigBuilder {
self
}

pub fn args(mut self, args: &[&str]) -> Self {
for arg in args {
self.args.push(arg.to_string());
}
self
}

pub fn create_config(mut self) -> Config {
// Run in dry-check, otherwise the test would be too slow
self.args.push("--dry-run".to_string());
Expand Down
Loading