Skip to content

Commit c59e1f4

Browse files
committed
Auto merge of #7421 - ehuss:build-std-sysroot, r=alexcrichton
Change build-std to use --sysroot This transitions build-std to use `--sysroot` instead of `--extern`. This is necessary because existing crates have a certain expectation of how standard library crates are exposed. It was intended that explicit dependencies in `Cargo.toml` would solve this problem, but I didn't really consider this would be a backwards-incompatible change, so using `--sysroot` is probably the best way to go, even though it's not ideal. Closes rust-lang/wg-cargo-std-aware#31 Closes rust-lang/wg-cargo-std-aware#40
2 parents 400221e + 9d86d86 commit c59e1f4

File tree

29 files changed

+426
-153
lines changed

29 files changed

+426
-153
lines changed

crates/cargo-test-support/src/paths.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::env;
66
use std::fs;
77
use std::io::{self, ErrorKind};
88
use std::path::{Path, PathBuf};
9+
use std::process::Command;
910
use std::sync::atomic::{AtomicUsize, Ordering};
1011
use std::sync::Mutex;
1112

@@ -252,3 +253,14 @@ pub fn get_lib_extension(kind: &str) -> &str {
252253
_ => unreachable!(),
253254
}
254255
}
256+
257+
/// Returns the sysroot as queried from rustc.
258+
pub fn sysroot() -> String {
259+
let output = Command::new("rustc")
260+
.arg("--print=sysroot")
261+
.output()
262+
.expect("rustc to run");
263+
assert!(output.status.success());
264+
let sysroot = String::from_utf8(output.stdout).unwrap();
265+
sysroot.trim().to_string()
266+
}

src/cargo/core/compiler/compilation.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,13 @@ impl<'cfg> Compilation<'cfg> {
203203
super::filter_dynamic_search_path(self.native_dirs.iter(), &self.root_output);
204204
search_path.push(self.deps_output.clone());
205205
search_path.push(self.root_output.clone());
206-
search_path.push(self.target_dylib_path.clone());
206+
// For build-std, we don't want to accidentally pull in any shared
207+
// libs from the sysroot that ships with rustc. This may not be
208+
// required (at least I cannot craft a situation where it
209+
// matters), but is here to be safe.
210+
if self.config.cli_unstable().build_std.is_none() {
211+
search_path.push(self.target_dylib_path.clone());
212+
}
207213
search_path
208214
};
209215

src/cargo/core/compiler/context/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use super::custom_build::{self, BuildDeps, BuildScriptOutputs, BuildScripts};
1818
use super::fingerprint::Fingerprint;
1919
use super::job_queue::JobQueue;
2020
use super::layout::Layout;
21+
use super::standard_lib;
2122
use super::unit_dependencies::{UnitDep, UnitGraph};
2223
use super::{BuildContext, Compilation, CompileMode, Executor, FileFlavor, Kind};
2324

@@ -304,7 +305,11 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
304305
};
305306
let host_layout = Layout::new(self.bcx.ws, None, dest)?;
306307
let target_layout = match self.bcx.build_config.requested_target.as_ref() {
307-
Some(target) => Some(Layout::new(self.bcx.ws, Some(target), dest)?),
308+
Some(target) => {
309+
let layout = Layout::new(self.bcx.ws, Some(target), dest)?;
310+
standard_lib::prepare_sysroot(&layout)?;
311+
Some(layout)
312+
}
308313
None => None,
309314
};
310315
self.primary_packages

src/cargo/core/compiler/job_queue.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use super::job::{
1717
Freshness::{self, Dirty, Fresh},
1818
Job,
1919
};
20+
use super::standard_lib;
2021
use super::timings::Timings;
2122
use super::{BuildContext, BuildPlan, CompileMode, Context, Unit};
2223
use crate::core::{PackageId, TargetKind};
@@ -607,7 +608,7 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
607608
id: u32,
608609
unit: &Unit<'a>,
609610
artifact: Artifact,
610-
cx: &mut Context<'_, '_>,
611+
cx: &mut Context<'a, '_>,
611612
) -> CargoResult<()> {
612613
if unit.mode.is_run_custom_build() && cx.bcx.show_warnings(unit.pkg.package_id()) {
613614
self.emit_warnings(None, unit, cx)?;
@@ -617,6 +618,23 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
617618
Artifact::All => self.timings.unit_finished(id, unlocked),
618619
Artifact::Metadata => self.timings.unit_rmeta_finished(id, unlocked),
619620
}
621+
if unit.is_std && unit.kind == super::Kind::Target && !cx.bcx.build_config.build_plan {
622+
// This is a bit of an unusual place to copy files around, and
623+
// ideally this would be somewhere like the Work closure
624+
// (`link_targets`). The tricky issue is handling rmeta files for
625+
// pipelining. Since those are emitted asynchronously, the code
626+
// path (like `on_stderr_line`) does not have enough information
627+
// to know where the sysroot is, and that it is an std unit. If
628+
// possible, it might be nice to eventually move this to the
629+
// worker thread, but may be tricky to have the paths available.
630+
// Another possibility is to disable pipelining between std ->
631+
// non-std. The pipelining opportunities are small, and are not a
632+
// huge win (in a full build, only proc_macro overlaps for 2
633+
// seconds out of a 90s build on my system). Care must also be
634+
// taken to properly copy these artifacts for Fresh units.
635+
let rmeta = artifact == Artifact::Metadata;
636+
standard_lib::add_sysroot_artifact(cx, unit, rmeta)?;
637+
}
620638
Ok(())
621639
}
622640

src/cargo/core/compiler/layout.rs

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
//! .rustc-info.json
1313
//!
1414
//! # All final artifacts are linked into this directory from `deps`.
15+
//! # Note that named profiles will soon be included as separate directories
16+
//! # here. They have a restricted format, similar to Rust identifiers, so
17+
//! # Cargo-specific directories added in the future should use some prefix
18+
//! # like `.` to avoid name collisions.
1519
//! debug/ # or release/
1620
//!
1721
//! # File used to lock the directory to prevent multiple cargo processes
@@ -46,6 +50,11 @@
4650
//! # incremental is enabled.
4751
//! incremental/
4852
//!
53+
//! # The sysroot for -Zbuild-std builds. This only appears in
54+
//! # target-triple directories (not host), and only if -Zbuild-std is
55+
//! # enabled.
56+
//! .sysroot/
57+
//!
4958
//! # This is the location at which the output of all custom build
5059
//! # commands are rooted.
5160
//! build/
@@ -116,6 +125,10 @@ pub struct Layout {
116125
examples: PathBuf,
117126
/// The directory for rustdoc output: `$root/doc`
118127
doc: PathBuf,
128+
/// The local sysroot for the build-std feature.
129+
sysroot: Option<PathBuf>,
130+
/// The "lib" directory within `sysroot`.
131+
sysroot_libdir: Option<PathBuf>,
119132
/// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
120133
/// struct is `drop`ped.
121134
_lock: FileLock,
@@ -139,18 +152,21 @@ impl Layout {
139152
// Flexible target specifications often point at json files, so interpret
140153
// the target triple as a Path and then just use the file stem as the
141154
// component for the directory name in that case.
142-
if let Some(triple) = triple {
143-
let triple = Path::new(triple);
144-
if triple.extension().and_then(|s| s.to_str()) == Some("json") {
145-
root.push(
146-
triple
147-
.file_stem()
155+
let triple_path = if let Some(s) = triple {
156+
let p = Path::new(s);
157+
let tp = if p.extension().and_then(|s| s.to_str()) == Some("json") {
158+
Path::new(
159+
p.file_stem()
148160
.ok_or_else(|| failure::format_err!("invalid target"))?,
149-
);
161+
)
150162
} else {
151-
root.push(triple);
152-
}
153-
}
163+
p
164+
};
165+
root.push(tp);
166+
Some(tp)
167+
} else {
168+
None
169+
};
154170
let dest = root.join(dest);
155171
// If the root directory doesn't already exist go ahead and create it
156172
// here. Use this opportunity to exclude it from backups as well if the
@@ -167,6 +183,17 @@ impl Layout {
167183
let root = root.into_path_unlocked();
168184
let dest = dest.into_path_unlocked();
169185

186+
// Compute the sysroot path for the build-std feature.
187+
let build_std = ws.config().cli_unstable().build_std.as_ref();
188+
let (sysroot, sysroot_libdir) = if let Some(tp) = build_std.and(triple_path) {
189+
// This uses a leading dot to avoid collision with named profiles.
190+
let sysroot = dest.join(".sysroot");
191+
let sysroot_libdir = sysroot.join("lib").join("rustlib").join(tp).join("lib");
192+
(Some(sysroot), Some(sysroot_libdir))
193+
} else {
194+
(None, None)
195+
};
196+
170197
Ok(Layout {
171198
deps: dest.join("deps"),
172199
build: dest.join("build"),
@@ -176,6 +203,8 @@ impl Layout {
176203
doc: root.join("doc"),
177204
root,
178205
dest,
206+
sysroot,
207+
sysroot_libdir,
179208
_lock: lock,
180209
})
181210
}
@@ -223,6 +252,16 @@ impl Layout {
223252
pub fn build(&self) -> &Path {
224253
&self.build
225254
}
255+
/// The local sysroot for the build-std feature.
256+
///
257+
/// Returns None if build-std is not enabled or this is the Host layout.
258+
pub fn sysroot(&self) -> Option<&Path> {
259+
self.sysroot.as_ref().map(|p| p.as_ref())
260+
}
261+
/// The "lib" directory within `sysroot`.
262+
pub fn sysroot_libdir(&self) -> Option<&Path> {
263+
self.sysroot_libdir.as_ref().map(|p| p.as_ref())
264+
}
226265
}
227266

228267
#[cfg(not(target_os = "macos"))]

src/cargo/core/compiler/mod.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use crate::util::paths;
5050
use crate::util::{self, machine_message, ProcessBuilder};
5151
use crate::util::{internal, join_paths, profile};
5252

53-
/// Indicates whether an object is for the host architcture or the target architecture.
53+
/// Indicates whether an object is for the host architecture or the target architecture.
5454
///
5555
/// These will be the same unless cross-compiling.
5656
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord, Serialize)]
@@ -915,6 +915,16 @@ fn build_base_args<'a, 'cfg>(
915915
let dir = cx.files().layout(unit.kind).incremental().as_os_str();
916916
opt(cmd, "-C", "incremental=", Some(dir));
917917
}
918+
919+
if unit.is_std {
920+
// -Zforce-unstable-if-unmarked prevents the accidental use of
921+
// unstable crates within the sysroot (such as "extern crate libc" or
922+
// any non-public crate in the sysroot).
923+
//
924+
// RUSTC_BOOTSTRAP allows unstable features on stable.
925+
cmd.arg("-Zforce-unstable-if-unmarked")
926+
.env("RUSTC_BOOTSTRAP", "1");
927+
}
918928
Ok(())
919929
}
920930

@@ -968,7 +978,17 @@ fn build_deps_args<'a, 'cfg>(
968978

969979
let mut unstable_opts = false;
970980

981+
if let Some(sysroot) = cx.files().layout(Kind::Target).sysroot() {
982+
if unit.kind == Kind::Target {
983+
cmd.arg("--sysroot").arg(sysroot);
984+
}
985+
}
986+
971987
for dep in deps {
988+
if !unit.is_std && dep.unit.is_std {
989+
// Dependency to sysroot crate uses --sysroot.
990+
continue;
991+
}
972992
if dep.unit.mode.is_run_custom_build() {
973993
cmd.env("OUT_DIR", &cx.files().build_script_out_dir(&dep.unit));
974994
}

src/cargo/core/compiler/standard_lib.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
//! Code for building the standard library.
22
3-
use crate::core::compiler::{BuildContext, CompileMode, Kind, Unit};
3+
use super::layout::Layout;
4+
use crate::core::compiler::{BuildContext, CompileMode, Context, FileFlavor, Kind, Unit};
45
use crate::core::profiles::UnitFor;
56
use crate::core::resolver::ResolveOpts;
67
use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace};
78
use crate::ops::{self, Packages};
89
use crate::util::errors::CargoResult;
10+
use crate::util::paths;
911
use std::collections::{HashMap, HashSet};
1012
use std::env;
1113
use std::path::PathBuf;
@@ -141,9 +143,15 @@ pub fn generate_std_roots<'a>(
141143
bcx.build_config.release,
142144
);
143145
let features = std_resolve.features_sorted(pkg.package_id());
144-
Ok(bcx
145-
.units
146-
.intern(pkg, lib, profile, Kind::Target, mode, features))
146+
Ok(bcx.units.intern(
147+
pkg,
148+
lib,
149+
profile,
150+
Kind::Target,
151+
mode,
152+
features,
153+
/*is_std*/ true,
154+
))
147155
})
148156
.collect::<CargoResult<Vec<_>>>()
149157
}
@@ -173,3 +181,33 @@ fn detect_sysroot_src_path(ws: &Workspace<'_>) -> CargoResult<PathBuf> {
173181
}
174182
Ok(src_path)
175183
}
184+
185+
/// Prepare the output directory for the local sysroot.
186+
pub fn prepare_sysroot(layout: &Layout) -> CargoResult<()> {
187+
if let Some(libdir) = layout.sysroot_libdir() {
188+
if libdir.exists() {
189+
paths::remove_dir_all(libdir)?;
190+
}
191+
paths::create_dir_all(libdir)?;
192+
}
193+
Ok(())
194+
}
195+
196+
/// Copy an artifact to the sysroot.
197+
pub fn add_sysroot_artifact<'a>(
198+
cx: &Context<'a, '_>,
199+
unit: &Unit<'a>,
200+
rmeta: bool,
201+
) -> CargoResult<()> {
202+
let outputs = cx.outputs(unit)?;
203+
let outputs = outputs
204+
.iter()
205+
.filter(|output| output.flavor == FileFlavor::Linkable { rmeta })
206+
.map(|output| &output.path);
207+
for path in outputs {
208+
let libdir = cx.files().layout(Kind::Target).sysroot_libdir().unwrap();
209+
let dst = libdir.join(path.file_name().unwrap());
210+
paths::link_or_copy(path, dst)?;
211+
}
212+
Ok(())
213+
}

src/cargo/core/compiler/unit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ pub struct UnitInner<'a> {
5151
/// The `cfg` features to enable for this unit.
5252
/// This must be sorted.
5353
pub features: Vec<&'a str>,
54+
/// Whether this is a standard library unit.
55+
pub is_std: bool,
5456
}
5557

5658
impl UnitInner<'_> {
@@ -144,6 +146,7 @@ impl<'a> UnitInterner<'a> {
144146
kind: Kind,
145147
mode: CompileMode,
146148
features: Vec<&'a str>,
149+
is_std: bool,
147150
) -> Unit<'a> {
148151
let inner = self.intern_inner(&UnitInner {
149152
pkg,
@@ -152,6 +155,7 @@ impl<'a> UnitInterner<'a> {
152155
kind,
153156
mode,
154157
features,
158+
is_std,
155159
});
156160
Unit { inner }
157161
}

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ fn new_unit_dep_with_profile<'a>(
573573
let unit = state
574574
.bcx
575575
.units
576-
.intern(pkg, target, profile, kind, mode, features);
576+
.intern(pkg, target, profile, kind, mode, features, state.is_std);
577577
Ok(UnitDep {
578578
unit,
579579
unit_for,

src/cargo/ops/cargo_clean.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,9 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
9494
)
9595
};
9696
let features = resolve.features_sorted(pkg.package_id());
97-
units.push(
98-
bcx.units
99-
.intern(pkg, target, profile, *kind, *mode, features),
100-
);
97+
units.push(bcx.units.intern(
98+
pkg, target, profile, *kind, *mode, features, /*is_std*/ false,
99+
));
101100
}
102101
}
103102
}

src/cargo/ops/cargo_compile.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,11 @@ pub fn compile_ws<'a>(
309309
let (mut packages, resolve_with_overrides) = resolve;
310310

311311
let std_resolve = if let Some(crates) = &config.cli_unstable().build_std {
312+
if build_config.build_plan {
313+
config
314+
.shell()
315+
.warn("-Zbuild-std does not currently fully support --build-plan")?;
316+
}
312317
if build_config.requested_target.is_none() {
313318
// TODO: This should eventually be fixed. Unfortunately it is not
314319
// easy to get the host triple in BuildConfig. Consider changing
@@ -703,8 +708,15 @@ fn generate_targets<'a>(
703708
bcx.build_config.release,
704709
);
705710
let features = resolve.features_sorted(pkg.package_id());
706-
bcx.units
707-
.intern(pkg, target, profile, kind, target_mode, features)
711+
bcx.units.intern(
712+
pkg,
713+
target,
714+
profile,
715+
kind,
716+
target_mode,
717+
features,
718+
/*is_std*/ false,
719+
)
708720
};
709721

710722
// Create a list of proposed targets.

0 commit comments

Comments
 (0)