Skip to content

Commit

Permalink
Check build target supports std when building with -Zbuild-std=std
Browse files Browse the repository at this point in the history
Running cargo with "-Zbuild-std=std" should check whether the build
target supports building the standard library. This information can be
obtained from rustc with the target-spec-json "--print" option. When
'std' is false for the build target, cargo should not attempt to build
the standard library.

This avoids the "use of unstable library" errors, as this check is
performed before Cargo starts trying to build restricted_std code.

Cargo will now emit a warning if the requested target does not support
building the standard library, or if there was an issue when collecting
the necessary information via rustc
  • Loading branch information
harmou01 committed Oct 30, 2024
1 parent 06e0ef4 commit e473534
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
54 changes: 54 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 All @@ -56,6 +58,16 @@ pub struct TargetInfo {
pub rustdocflags: Rc<[String]>,
}

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

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

/// Kind of each file generated by a Unit, part of `FileType`.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum FileFlavor {
Expand Down Expand Up @@ -294,6 +306,42 @@ 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.nightly_features_allowed && 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
.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());
}

let target_spec_cached_output =
rustc.cached_output(&target_spec_process, extra_fingerprint);

if target_spec_cached_output.is_ok() {
let (stdout, _stderr) = target_spec_cached_output.unwrap();
match serde_json::from_str(&stdout) {
Result::Ok(val) => {
let target_spec: TargetSpec = val;
supports_std = target_spec.metadata.std;
}
Result::Err(_) => (),
}
}
}

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

/// Gets the target info hashmap from the target data.
pub fn target_info(&self) -> &HashMap<CompileTarget, TargetInfo> {
&self.target_info
}
}

/// Structure used to deal with Rustdoc fingerprinting
Expand Down
12 changes: 12 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,18 @@ 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()) {
for (target, target_info) in target_data.target_info() {
if target_info.supports_std == Some(false) {
anyhow::bail!(
"building std is not supported on this target: {:?}",
target.short_name()
);
}
}
}

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

0 comments on commit e473534

Please sign in to comment.