Skip to content

Commit 5e4a1db

Browse files
committed
Check build target supports std when building with -Zbuild-std=std
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
1 parent 06e0ef4 commit 5e4a1db

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

src/cargo/core/compiler/build_context/target_info.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ pub struct TargetInfo {
4343
crate_types: RefCell<HashMap<CrateType, Option<(String, String)>>>,
4444
/// `cfg` information extracted from `rustc --print=cfg`.
4545
cfg: Vec<Cfg>,
46+
/// `supports_std` information extracted from `rustc --print=target-spec-json`
47+
pub supports_std: Option<bool>,
4648
/// Supported values for `-Csplit-debuginfo=` flag, queried from rustc
4749
support_split_debuginfo: Vec<String>,
4850
/// Path to the sysroot.
@@ -294,6 +296,44 @@ impl TargetInfo {
294296
gctx.shell().warn("non-trivial mutual dependency between target-specific configuration and RUSTFLAGS")?;
295297
}
296298

299+
let mut supports_std: Option<bool> = None;
300+
301+
// The '--print=target-spec-json' is an unstable option of rustc, therefore only
302+
// try to fetch this information if rustc allows nightly features. Additionally,
303+
// to avoid making two rustc queries when not required, only try to fetch the
304+
// target-spec when the '-Zbuild-std' option is passed.
305+
if gctx.cli_unstable().build_std.is_some() {
306+
let mut target_spec_process = rustc.workspace_process();
307+
apply_env_config(gctx, &mut target_spec_process)?;
308+
target_spec_process
309+
.arg("--print=target-spec-json")
310+
.arg("-Zunstable-options")
311+
.args(&rustflags)
312+
.env_remove("RUSTC_LOG");
313+
314+
if let CompileKind::Target(target) = kind {
315+
target_spec_process
316+
.arg("--target")
317+
.arg(target.rustc_target());
318+
}
319+
320+
#[derive(Deserialize)]
321+
struct Metadata {
322+
pub std: Option<bool>,
323+
}
324+
325+
#[derive(Deserialize)]
326+
struct TargetSpec {
327+
pub metadata: Metadata,
328+
}
329+
330+
if let Ok(output) = target_spec_process.output() {
331+
if let Ok(spec) = serde_json::from_slice::<TargetSpec>(&output.stdout) {
332+
supports_std = spec.metadata.std;
333+
}
334+
}
335+
}
336+
297337
return Ok(TargetInfo {
298338
crate_type_process,
299339
crate_types: RefCell::new(map),
@@ -310,6 +350,7 @@ impl TargetInfo {
310350
)?
311351
.into(),
312352
cfg,
353+
supports_std,
313354
support_split_debuginfo,
314355
});
315356
}
@@ -1026,6 +1067,16 @@ impl<'gctx> RustcTargetData<'gctx> {
10261067
CompileKind::Target(s) => &self.target_config[&s],
10271068
}
10281069
}
1070+
1071+
pub fn get_unsupported_std_targets(&self) -> Vec<&str> {
1072+
let mut unsupported = Vec::new();
1073+
for (target, target_info) in &self.target_info {
1074+
if target_info.supports_std == Some(false) {
1075+
unsupported.push(target.short_name());
1076+
}
1077+
}
1078+
unsupported
1079+
}
10291080
}
10301081

10311082
/// Structure used to deal with Rustdoc fingerprinting

src/cargo/core/compiler/standard_lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ pub fn resolve_std<'gctx>(
7272
.warn("-Zbuild-std does not currently fully support --build-plan")?;
7373
}
7474

75+
// check that targets support building std
76+
if crates.contains(&"std".to_string()) {
77+
let unsupported_targets = target_data.get_unsupported_std_targets();
78+
if !unsupported_targets.is_empty() {
79+
anyhow::bail!(
80+
"building std is not supported on the following targets: {}",
81+
unsupported_targets.join(", ")
82+
)
83+
}
84+
}
85+
7586
let src_path = detect_sysroot_src_path(target_data)?;
7687
let std_ws_manifest_path = src_path.join("Cargo.toml");
7788
let gctx = ws.gctx();

0 commit comments

Comments
 (0)