Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(build-std): make Resolve align to what to build #14938

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 10 additions & 0 deletions src/cargo/core/compiler/build_context/target_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,16 @@ impl TargetInfo {
.iter()
.any(|sup| sup.as_str() == split.as_str())
}

/// Checks if a target maybe support std.
///
/// If no explictly stated in target spec json, we treat it as "maybe support".
///
/// This is only useful for `-Zbuild-std` to determine the default set of
/// crates it is going to build.
pub fn maybe_support_std(&self) -> bool {
matches!(self.supports_std, Some(true) | None)
}
}

/// Takes rustc output (using specialized command line args), and calculates the file prefix and
Expand Down
31 changes: 23 additions & 8 deletions src/cargo/core/compiler/standard_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ fn std_crates<'a>(crates: &'a [String], default: &'static str, units: &[Unit]) -
}

/// Resolve the standard library dependencies.
///
/// * `crates` is the arg value from `-Zbuild-std`.
pub fn resolve_std<'gctx>(
ws: &Workspace<'gctx>,
target_data: &mut RustcTargetData<'gctx>,
build_config: &BuildConfig,
crates: &[String],
kinds: &[CompileKind],
) -> CargoResult<(PackageSet<'gctx>, Resolve, ResolvedFeatures)> {
if build_config.build_plan {
ws.gctx()
Expand All @@ -65,10 +69,21 @@ pub fn resolve_std<'gctx>(
// `[dev-dependencies]`. No need for us to generate a `Resolve` which has
// those included because we'll never use them anyway.
std_ws.set_require_optional_deps(false);
// `sysroot` + the default feature set below should give us a good default
// Resolve, which includes `libtest` as well.
let specs = Packages::Packages(vec!["sysroot".into()]);
let specs = specs.to_package_id_specs(&std_ws)?;
let specs = {
// If there is anything looks like needing std, resolve with it.
// If not, we assume only `core` maye be needed, as `core the most fundamental crate.
//
// This may need a UI overhaul if `build-std` wants to fully support multi-targets.
let maybe_std = kinds
.iter()
.any(|kind| target_data.info(*kind).maybe_support_std());
let mut crates = std_crates(crates, if maybe_std { "std" } else { "core" }, &[]);
// `sysroot` is not in the default set because it is optional, but it needs
// to be part of the resolve in case we do need it or `libtest`.
crates.insert("sysroot");
let specs = Packages::Packages(crates.into_iter().map(Into::into).collect());
specs.to_package_id_specs(&std_ws)?
};
let features = match &gctx.cli_unstable().build_std_features {
Some(list) => list.clone(),
None => vec![
Expand Down Expand Up @@ -115,10 +130,10 @@ pub fn generate_std_roots(
) -> CargoResult<HashMap<CompileKind, Vec<Unit>>> {
// Generate a map of Units for each kind requested.
let mut ret = HashMap::new();
let (core_only, maybe_std): (Vec<&CompileKind>, Vec<_>) = kinds.iter().partition(|kind|
// Only include targets that explicitly don't support std
target_data.info(**kind).supports_std == Some(false));
for (default_crate, kinds) in [("core", core_only), ("std", maybe_std)] {
let (maybe_std, maybe_core): (Vec<&CompileKind>, Vec<_>) = kinds
.iter()
.partition(|kind| target_data.info(**kind).maybe_support_std());
for (default_crate, kinds) in [("core", maybe_core), ("std", maybe_std)] {
if kinds.is_empty() {
continue;
}
Expand Down
11 changes: 8 additions & 3 deletions src/cargo/ops/cargo_compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,14 @@ pub fn create_bcx<'a, 'gctx>(
resolved_features,
} = resolve;

let std_resolve_features = if gctx.cli_unstable().build_std.is_some() {
weihanglo marked this conversation as resolved.
Show resolved Hide resolved
let (std_package_set, std_resolve, std_features) =
standard_lib::resolve_std(ws, &mut target_data, &build_config)?;
let std_resolve_features = if let Some(crates) = &gctx.cli_unstable().build_std {
let (std_package_set, std_resolve, std_features) = standard_lib::resolve_std(
ws,
&mut target_data,
&build_config,
crates,
&build_config.requested_kinds,
)?;
pkg_set.add_set(std_package_set);
Some((std_resolve, std_features))
} else {
Expand Down
10 changes: 8 additions & 2 deletions src/cargo/ops/cargo_fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,14 @@ pub fn fetch<'a>(
}

// If -Zbuild-std was passed, download dependencies for the standard library.
if gctx.cli_unstable().build_std.is_some() {
let (std_package_set, _, _) = standard_lib::resolve_std(ws, &mut data, &build_config)?;
if let Some(crates) = &gctx.cli_unstable().build_std {
let (std_package_set, _, _) = standard_lib::resolve_std(
ws,
&mut data,
&build_config,
crates,
&build_config.requested_kinds,
)?;
packages.add_set(std_package_set);
}

Expand Down
71 changes: 59 additions & 12 deletions tests/build-std/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ use cargo_test_support::{basic_manifest, paths, project, rustc_host, str, Execs}
use std::env;
use std::path::Path;

fn enable_build_std(e: &mut Execs, arg: Option<&str>) {
e.env_remove("CARGO_HOME");
e.env_remove("HOME");
fn enable_build_std(e: &mut Execs, arg: Option<&str>, isolated: bool) {
if !isolated {
e.env_remove("CARGO_HOME");
e.env_remove("HOME");
}

// And finally actually enable `build-std` for now
let arg = match arg {
Expand All @@ -40,19 +42,41 @@ fn enable_build_std(e: &mut Execs, arg: Option<&str>) {

// Helper methods used in the tests below
trait BuildStd: Sized {
/// Set `-Zbuild-std` args and will download dependencies of the standard
/// library in users's `CARGO_HOME` (`~/.cargo/`) instead of isolated
/// environment `cargo-test-support` usually provides.
///
/// The environment is not isolated is to avoid excessive network requests
/// and downloads. A side effect is `[BLOCKING]` will show up in stderr,
/// as a sign of package cahce lock contention when running other build-std
/// tests concurrently.
fn build_std(&mut self) -> &mut Self;

/// Like [`BuildStd::build_std`] and is able to specify what crates to build.
fn build_std_arg(&mut self, arg: &str) -> &mut Self;

/// Like [`BuildStd::build_std`] but use an isolated `CARGO_HOME` environment
/// to avoid package cache lock contention.
///
/// Don't use this unless you really need to assert the full stderr
/// and avoid any `[BLOCKING]` message.
fn build_std_isolated(&mut self) -> &mut Self;
fn target_host(&mut self) -> &mut Self;
}

impl BuildStd for Execs {
fn build_std(&mut self) -> &mut Self {
enable_build_std(self, None);
enable_build_std(self, None, false);
self
}

fn build_std_arg(&mut self, arg: &str) -> &mut Self {
enable_build_std(self, Some(arg));
enable_build_std(self, Some(arg), false);
self
}

fn build_std_isolated(&mut self) -> &mut Self {
enable_build_std(self, None, true);
self
}

Expand Down Expand Up @@ -107,9 +131,12 @@ fn basic() {
)
.build();

p.cargo("check").build_std().target_host().run();
// HACK: use an isolated the isolated CARGO_HOME environment (`build_std_isolated`)
// to avoid `[BLOCKING]` messages (from lock contention with other tests)
// from getting in this test's asserts
p.cargo("check").build_std_isolated().target_host().run();
p.cargo("build")
.build_std()
.build_std_isolated()
.target_host()
// Importantly, this should not say [UPDATING]
// There have been multiple bugs where every build triggers and update.
Expand All @@ -120,7 +147,7 @@ fn basic() {
"#]])
.run();
p.cargo("run")
.build_std()
.build_std_isolated()
.target_host()
.with_stderr_data(str![[r#"
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
Expand All @@ -129,7 +156,7 @@ fn basic() {
"#]])
.run();
p.cargo("test")
.build_std()
.build_std_isolated()
.target_host()
.with_stderr_data(str![[r#"
[COMPILING] rustc-std-workspace-std [..]
Expand Down Expand Up @@ -379,17 +406,37 @@ fn test_proc_macro() {
.file("src/lib.rs", "")
.build();

// Download dependencies first,
// so we can compare `cargo test` output without any wildcard
p.cargo("fetch").build_std().run();
p.cargo("test --lib")
.env_remove(cargo_util::paths::dylib_path_envvar())
.build_std()
.with_stderr_data(str![[r#"
...
[COMPILING] foo v0.0.0 ([ROOT]/foo)
[FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH])

"#]])
.run();
}

#[cargo_test(build_std_real)]
fn test_panic_abort() {
// See rust-lang/cargo#14935
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
edition = "2021"
"#,
)
.file("src/lib.rs", "#![no_std]")
.build();

p.cargo("check")
.build_std_arg("std,panic_abort")
.env("RUSTFLAGS", "-C panic=abort")
.arg("-Zbuild-std-features=panic_immediate_abort")
.run();
}
Loading