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

Check build target supports std when building with -Zbuild-std=std #14183

Merged
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
51 changes: 51 additions & 0 deletions src/cargo/core/compiler/build_context/target_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub struct TargetInfo {
crate_types: RefCell<HashMap<CrateType, Option<(String, String)>>>,
/// `cfg` information extracted from `rustc --print=cfg`.
cfg: Vec<Cfg>,
/// `supports_std` information extracted from `rustc --print=target-spec-json`
pub supports_std: Option<bool>,
/// Supported values for `-Csplit-debuginfo=` flag, queried from rustc
support_split_debuginfo: Vec<String>,
/// Path to the sysroot.
Expand Down Expand Up @@ -294,6 +296,44 @@ impl TargetInfo {
gctx.shell().warn("non-trivial mutual dependency between target-specific configuration and RUSTFLAGS")?;
}

let mut supports_std: Option<bool> = None;

// The '--print=target-spec-json' is an unstable option of rustc, therefore only
// try to fetch this information if rustc allows nightly features. Additionally,
// to avoid making two rustc queries when not required, only try to fetch the
// target-spec when the '-Zbuild-std' option is passed.
if gctx.cli_unstable().build_std.is_some() {
let mut target_spec_process = rustc.workspace_process();
apply_env_config(gctx, &mut target_spec_process)?;
target_spec_process
weihanglo marked this conversation as resolved.
Show resolved Hide resolved
.arg("--print=target-spec-json")
.arg("-Zunstable-options")
.args(&rustflags)
.env_remove("RUSTC_LOG");

if let CompileKind::Target(target) = kind {
target_spec_process
.arg("--target")
.arg(target.rustc_target());
}

#[derive(Deserialize)]
struct Metadata {
pub std: Option<bool>,
}

#[derive(Deserialize)]
struct TargetSpec {
pub metadata: Metadata,
}

if let Ok(output) = target_spec_process.output() {
if let Ok(spec) = serde_json::from_slice::<TargetSpec>(&output.stdout) {
supports_std = spec.metadata.std;
}
}
}

return Ok(TargetInfo {
crate_type_process,
crate_types: RefCell::new(map),
Expand All @@ -310,6 +350,7 @@ impl TargetInfo {
)?
.into(),
cfg,
supports_std,
support_split_debuginfo,
});
}
Expand Down Expand Up @@ -1026,6 +1067,16 @@ impl<'gctx> RustcTargetData<'gctx> {
CompileKind::Target(s) => &self.target_config[&s],
}
}

pub fn get_unsupported_std_targets(&self) -> Vec<&str> {
let mut unsupported = Vec::new();
for (target, target_info) in &self.target_info {
if target_info.supports_std == Some(false) {
unsupported.push(target.short_name());
}
}
unsupported
}
}

/// Structure used to deal with Rustdoc fingerprinting
Expand Down
11 changes: 11 additions & 0 deletions src/cargo/core/compiler/standard_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ pub fn resolve_std<'gctx>(
.warn("-Zbuild-std does not currently fully support --build-plan")?;
}

// check that targets support building std
if crates.contains(&"std".to_string()) {
let unsupported_targets = target_data.get_unsupported_std_targets();
if !unsupported_targets.is_empty() {
anyhow::bail!(
"building std is not supported on the following targets: {}",
unsupported_targets.join(", ")
)
}
}

let src_path = detect_sysroot_src_path(target_data)?;
let std_ws_manifest_path = src_path.join("Cargo.toml");
let gctx = ws.gctx();
Expand Down
26 changes: 26 additions & 0 deletions tests/testsuite/standard_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,32 @@ fn check_core() {
.run();
}

#[cargo_test(build_std_mock)]
fn test_std_on_unsupported_target() {
let setup = setup();

let p = project()
.file(
"src/main.rs",
r#"
fn main() {
println!("hello");
}
"#,
)
.build();

p.cargo("build")
.arg("--target=aarch64-unknown-none")
.arg("--target=x86_64-unknown-none")
.build_std(&setup)
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] building std is not supported on the following targets: [..]
"#]])
.run();
}

#[cargo_test(build_std_mock)]
fn depend_same_as_std() {
let setup = setup();
Expand Down