diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index 052128093c1..98b17f31587 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -1,6 +1,6 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use std::env; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use cargo_platform::CfgExpr; @@ -8,7 +8,7 @@ use semver::Version; use super::BuildContext; use crate::core::compiler::CompileKind; -use crate::core::{Edition, InternedString, Package, PackageId, Target}; +use crate::core::{Edition, Package, PackageId, Target}; use crate::util::{self, join_paths, process, CargoResult, Config, ProcessBuilder}; pub struct Doctest { @@ -16,9 +16,10 @@ pub struct Doctest { pub package: Package, /// The target being tested (currently always the package's lib). pub target: Target, - /// Extern dependencies needed by `rustdoc`. The path is the location of - /// the compiled lib. - pub deps: Vec<(InternedString, PathBuf)>, + /// Arguments needed to pass to rustdoc to run this test. + pub args: Vec, + /// Whether or not -Zunstable-options is needed. + pub unstable_opts: bool, } /// A structure returning the result of a compilation. diff --git a/src/cargo/core/compiler/context/mod.rs b/src/cargo/core/compiler/context/mod.rs index d64fe5a38be..27b8ca691eb 100644 --- a/src/cargo/core/compiler/context/mod.rs +++ b/src/cargo/core/compiler/context/mod.rs @@ -1,14 +1,12 @@ #![allow(deprecated)] use std::collections::{BTreeSet, HashMap, HashSet}; -use std::ffi::OsStr; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use filetime::FileTime; use jobserver::Client; -use crate::core::compiler::compilation; -use crate::core::compiler::Unit; +use crate::core::compiler::{self, compilation, Unit}; use crate::core::PackageId; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::{internal, profile, Config}; @@ -18,7 +16,6 @@ use super::custom_build::{self, BuildDeps, BuildScriptOutputs, BuildScripts}; use super::fingerprint::Fingerprint; use super::job_queue::JobQueue; use super::layout::Layout; -use super::standard_lib; use super::unit_dependencies::{UnitDep, UnitGraph}; use super::{BuildContext, Compilation, CompileKind, CompileMode, Executor, FileFlavor}; @@ -206,35 +203,13 @@ impl<'a, 'cfg> Context<'a, 'cfg> { // Collect information for `rustdoc --test`. if unit.mode.is_doc_test() { - // Note that we can *only* doc-test rlib outputs here. A - // staticlib output cannot be linked by the compiler (it just - // doesn't do that). A dylib output, however, can be linked by - // the compiler, but will always fail. Currently all dylibs are - // built as "static dylibs" where the standard library is - // statically linked into the dylib. The doc tests fail, - // however, for now as they try to link the standard library - // dynamically as well, causing problems. As a result we only - // pass `--extern` for rlib deps and skip out on all other - // artifacts. - let mut doctest_deps = Vec::new(); - for dep in self.unit_deps(unit) { - if dep.unit.target.is_lib() && dep.unit.mode == CompileMode::Build { - let outputs = self.outputs(&dep.unit)?; - let outputs = outputs.iter().filter(|output| { - output.path.extension() == Some(OsStr::new("rlib")) - || dep.unit.target.for_host() - }); - for output in outputs { - doctest_deps.push((dep.extern_crate_name, output.path.clone())); - } - } - } - // Help with tests to get a stable order with renamed deps. - doctest_deps.sort(); + let mut unstable_opts = false; + let args = compiler::extern_args(&self, unit, &mut unstable_opts)?; self.compilation.to_doc_test.push(compilation::Doctest { package: unit.pkg.clone(), target: unit.target.clone(), - deps: doctest_deps, + args, + unstable_opts, }); } @@ -312,7 +287,6 @@ impl<'a, 'cfg> Context<'a, 'cfg> { let mut targets = HashMap::new(); if let CompileKind::Target(target) = self.bcx.build_config.requested_kind { let layout = Layout::new(self.bcx.ws, Some(target), &dest)?; - standard_lib::prepare_sysroot(&layout)?; targets.insert(target, layout); } self.primary_packages diff --git a/src/cargo/core/compiler/job_queue.rs b/src/cargo/core/compiler/job_queue.rs index 9d378f2cafe..58034c3f35b 100644 --- a/src/cargo/core/compiler/job_queue.rs +++ b/src/cargo/core/compiler/job_queue.rs @@ -17,7 +17,6 @@ use super::job::{ Freshness::{self, Dirty, Fresh}, Job, }; -use super::standard_lib; use super::timings::Timings; use super::{BuildContext, BuildPlan, CompileMode, Context, Unit}; use crate::core::compiler::ProfileKind; @@ -618,23 +617,6 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> { Artifact::All => self.timings.unit_finished(id, unlocked), Artifact::Metadata => self.timings.unit_rmeta_finished(id, unlocked), } - if unit.is_std && !unit.kind.is_host() && !cx.bcx.build_config.build_plan { - // This is a bit of an unusual place to copy files around, and - // ideally this would be somewhere like the Work closure - // (`link_targets`). The tricky issue is handling rmeta files for - // pipelining. Since those are emitted asynchronously, the code - // path (like `on_stderr_line`) does not have enough information - // to know where the sysroot is, and that it is an std unit. If - // possible, it might be nice to eventually move this to the - // worker thread, but may be tricky to have the paths available. - // Another possibility is to disable pipelining between std -> - // non-std. The pipelining opportunities are small, and are not a - // huge win (in a full build, only proc_macro overlaps for 2 - // seconds out of a 90s build on my system). Care must also be - // taken to properly copy these artifacts for Fresh units. - let rmeta = artifact == Artifact::Metadata; - standard_lib::add_sysroot_artifact(cx, unit, rmeta)?; - } Ok(()) } diff --git a/src/cargo/core/compiler/layout.rs b/src/cargo/core/compiler/layout.rs index 86b4426c18c..d2f266bf34c 100644 --- a/src/cargo/core/compiler/layout.rs +++ b/src/cargo/core/compiler/layout.rs @@ -53,11 +53,6 @@ //! # incremental is enabled. //! incremental/ //! -//! # The sysroot for -Zbuild-std builds. This only appears in -//! # target-triple directories (not host), and only if -Zbuild-std is -//! # enabled. -//! .sysroot/ -//! //! # This is the location at which the output of all custom build //! # commands are rooted. //! build/ @@ -129,10 +124,6 @@ pub struct Layout { examples: PathBuf, /// The directory for rustdoc output: `$root/doc` doc: PathBuf, - /// The local sysroot for the build-std feature. - sysroot: Option, - /// The "lib" directory within `sysroot`. - sysroot_libdir: Option, /// The lockfile for a build (`.cargo-lock`). Will be unlocked when this /// struct is `drop`ped. _lock: FileLock, @@ -176,21 +167,6 @@ impl Layout { let root = root.into_path_unlocked(); let dest = dest.into_path_unlocked(); - // Compute the sysroot path for the build-std feature. - let build_std = ws.config().cli_unstable().build_std.as_ref(); - let (sysroot, sysroot_libdir) = if let Some(target) = build_std.and(target) { - // This uses a leading dot to avoid collision with named profiles. - let sysroot = dest.join(".sysroot"); - let sysroot_libdir = sysroot - .join("lib") - .join("rustlib") - .join(target.short_name()) - .join("lib"); - (Some(sysroot), Some(sysroot_libdir)) - } else { - (None, None) - }; - Ok(Layout { deps: dest.join("deps"), build: dest.join("build"), @@ -200,8 +176,6 @@ impl Layout { doc: root.join("doc"), root, dest, - sysroot, - sysroot_libdir, _lock: lock, }) } @@ -249,16 +223,6 @@ impl Layout { pub fn build(&self) -> &Path { &self.build } - /// The local sysroot for the build-std feature. - /// - /// Returns None if build-std is not enabled or this is the Host layout. - pub fn sysroot(&self) -> Option<&Path> { - self.sysroot.as_ref().map(|p| p.as_ref()) - } - /// The "lib" directory within `sysroot`. - pub fn sysroot_libdir(&self) -> Option<&Path> { - self.sysroot_libdir.as_ref().map(|p| p.as_ref()) - } } #[cfg(not(target_os = "macos"))] diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index f345820b1e7..e44356e98ac 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -43,8 +43,7 @@ use self::unit_dependencies::UnitDep; pub use crate::core::compiler::unit::{Unit, UnitInterner}; use crate::core::manifest::TargetSourcePath; use crate::core::profiles::{Lto, PanicStrategy, Profile}; -use crate::core::Feature; -use crate::core::{PackageId, Target}; +use crate::core::{Feature, InternedString, PackageId, Target}; use crate::util::errors::{self, CargoResult, CargoResultExt, Internal, ProcessError}; use crate::util::machine_message::Message; use crate::util::paths; @@ -894,8 +893,7 @@ fn build_deps_args<'a, 'cfg>( }); } - // Create Vec since mutable cx is needed in closure below. - let deps = Vec::from(cx.unit_deps(unit)); + let deps = cx.unit_deps(unit); // If there is not one linkable target but should, rustc fails later // on if there is an `extern crate` for it. This may turn into a hard @@ -922,23 +920,14 @@ fn build_deps_args<'a, 'cfg>( let mut unstable_opts = false; - if let Some(sysroot) = cx.files().layout(unit.kind).sysroot() { - if !unit.kind.is_host() { - cmd.arg("--sysroot").arg(sysroot); - } - } - for dep in deps { - if !unit.is_std && dep.unit.is_std { - // Dependency to sysroot crate uses --sysroot. - continue; - } if dep.unit.mode.is_run_custom_build() { cmd.env("OUT_DIR", &cx.files().build_script_out_dir(&dep.unit)); } - if dep.unit.target.linkable() && !dep.unit.mode.is_doc() { - link_to(cmd, cx, unit, &dep, &mut unstable_opts)?; - } + } + + for arg in extern_args(cx, unit, &mut unstable_opts)? { + cmd.arg(arg); } // This will only be set if we're already using a feature @@ -948,37 +937,51 @@ fn build_deps_args<'a, 'cfg>( } return Ok(()); +} - fn link_to<'a, 'cfg>( - cmd: &mut ProcessBuilder, - cx: &mut Context<'a, 'cfg>, - current: &Unit<'a>, - dep: &UnitDep<'a>, - need_unstable_opts: &mut bool, - ) -> CargoResult<()> { +/// Generates a list of `--extern` arguments. +pub fn extern_args<'a>( + cx: &Context<'a, '_>, + unit: &Unit<'a>, + unstable_opts: &mut bool, +) -> CargoResult> { + let mut result = Vec::new(); + let deps = cx.unit_deps(unit); + + // Closure to add one dependency to `result`. + let mut link_to = |dep: &UnitDep<'a>, + extern_crate_name: InternedString, + noprelude: bool| + -> CargoResult<()> { let mut value = OsString::new(); - value.push(dep.extern_crate_name.as_str()); + let mut opts = Vec::new(); + if unit + .pkg + .manifest() + .features() + .require(Feature::public_dependency()) + .is_ok() + && !dep.public + { + opts.push("priv"); + *unstable_opts = true; + } + if noprelude { + opts.push("noprelude"); + *unstable_opts = true; + } + if !opts.is_empty() { + value.push(opts.join(",")); + value.push(":"); + } + value.push(extern_crate_name.as_str()); value.push("="); let mut pass = |file| { let mut value = value.clone(); value.push(file); - - if current - .pkg - .manifest() - .features() - .require(Feature::public_dependency()) - .is_ok() - && !dep.public - { - cmd.arg("--extern-private"); - *need_unstable_opts = true; - } else { - cmd.arg("--extern"); - } - - cmd.arg(&value); + result.push(OsString::from("--extern")); + result.push(value); }; let outputs = cx.outputs(&dep.unit)?; @@ -987,7 +990,7 @@ fn build_deps_args<'a, 'cfg>( _ => None, }); - if cx.only_requires_rmeta(current, &dep.unit) { + if cx.only_requires_rmeta(unit, &dep.unit) { let (output, _rmeta) = outputs .find(|(_output, rmeta)| *rmeta) .expect("failed to find rlib dep for pipelined dep"); @@ -1000,7 +1003,15 @@ fn build_deps_args<'a, 'cfg>( } } Ok(()) + }; + + for dep in deps { + if dep.unit.target.linkable() && !dep.unit.mode.is_doc() { + link_to(&dep, dep.extern_crate_name, dep.noprelude)?; + } } + + Ok(result) } fn envify(s: &str) -> String { diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs index bfab07725ba..b0d633854e7 100644 --- a/src/cargo/core/compiler/standard_lib.rs +++ b/src/cargo/core/compiler/standard_lib.rs @@ -1,13 +1,11 @@ //! Code for building the standard library. -use super::layout::Layout; -use crate::core::compiler::{BuildContext, CompileKind, CompileMode, Context, FileFlavor, Unit}; +use crate::core::compiler::{BuildContext, CompileKind, CompileMode, Unit}; use crate::core::profiles::UnitFor; use crate::core::resolver::ResolveOpts; use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace}; use crate::ops::{self, Packages}; use crate::util::errors::CargoResult; -use crate::util::paths; use std::collections::{HashMap, HashSet}; use std::env; use std::path::PathBuf; @@ -176,33 +174,3 @@ fn detect_sysroot_src_path(ws: &Workspace<'_>) -> CargoResult { } Ok(src_path) } - -/// Prepare the output directory for the local sysroot. -pub fn prepare_sysroot(layout: &Layout) -> CargoResult<()> { - if let Some(libdir) = layout.sysroot_libdir() { - if libdir.exists() { - paths::remove_dir_all(libdir)?; - } - paths::create_dir_all(libdir)?; - } - Ok(()) -} - -/// Copy an artifact to the sysroot. -pub fn add_sysroot_artifact<'a>( - cx: &Context<'a, '_>, - unit: &Unit<'a>, - rmeta: bool, -) -> CargoResult<()> { - let outputs = cx.outputs(unit)?; - let outputs = outputs - .iter() - .filter(|output| output.flavor == FileFlavor::Linkable { rmeta }) - .map(|output| &output.path); - for path in outputs { - let libdir = cx.files().layout(unit.kind).sysroot_libdir().unwrap(); - let dst = libdir.join(path.file_name().unwrap()); - paths::link_or_copy(path, dst)?; - } - Ok(()) -} diff --git a/src/cargo/core/compiler/unit_dependencies.rs b/src/cargo/core/compiler/unit_dependencies.rs index 62cde69da0b..a57fecf5f17 100644 --- a/src/cargo/core/compiler/unit_dependencies.rs +++ b/src/cargo/core/compiler/unit_dependencies.rs @@ -41,6 +41,8 @@ pub struct UnitDep<'a> { pub extern_crate_name: InternedString, /// Whether or not this is a public dependency. pub public: bool, + /// If `true`, the dependency should not be added to Rust's prelude. + pub noprelude: bool, } /// Collection of stuff used while creating the `UnitGraph`. @@ -132,6 +134,7 @@ fn attach_std_deps<'a, 'cfg>( extern_crate_name: unit.pkg.name(), // TODO: Does this `public` make sense? public: true, + noprelude: true, })); } } @@ -577,6 +580,7 @@ fn new_unit_dep_with_profile<'a>( unit_for, extern_crate_name, public, + noprelude: false, }) } diff --git a/src/cargo/ops/cargo_test.rs b/src/cargo/ops/cargo_test.rs index 005b1857725..4eb4b715faa 100644 --- a/src/cargo/ops/cargo_test.rs +++ b/src/cargo/ops/cargo_test.rs @@ -155,7 +155,8 @@ fn run_doc_tests( let Doctest { package, target, - deps, + args, + unstable_opts, } = doctest_info; config.shell().status("Doc-tests", target.name())?; let mut p = compilation.rustdoc_process(package, target)?; @@ -203,11 +204,12 @@ fn run_doc_tests( } } - for &(ref extern_crate_name, ref lib) in deps.iter() { - let mut arg = OsString::from(extern_crate_name.as_str()); - arg.push("="); - arg.push(lib); - p.arg("--extern").arg(&arg); + for arg in args { + p.arg(arg); + } + + if *unstable_opts { + p.arg("-Zunstable-options"); } if let Some(flags) = compilation.rustdocflags.get(&package.package_id()) { diff --git a/tests/testsuite/standard_lib.rs b/tests/testsuite/standard_lib.rs index 48f8b237f11..bfaad60a50c 100644 --- a/tests/testsuite/standard_lib.rs +++ b/tests/testsuite/standard_lib.rs @@ -98,8 +98,14 @@ fn setup() -> Option { let is_sysroot_crate = env::var_os("RUSTC_BOOTSTRAP").is_some(); if is_sysroot_crate { - let arg = args.iter().position(|a| a == "--sysroot").unwrap(); - args[arg + 1] = env::var("REAL_SYSROOT").unwrap(); + args.push("--sysroot".to_string()); + args.push(env::var("REAL_SYSROOT").unwrap()); + } else if args.iter().any(|arg| arg == "--target") { + // build-std target unit + args.push("--sysroot".to_string()); + args.push("/path/to/nowhere".to_string()); + } else { + // host unit, do not use sysroot } let ret = Command::new(&args[0]).args(&args[1..]).status().unwrap(); @@ -242,7 +248,7 @@ fn basic() { ) .build(); - p.cargo("check").build_std(&setup).target_host().run(); + p.cargo("check -v").build_std(&setup).target_host().run(); p.cargo("build").build_std(&setup).target_host().run(); p.cargo("run").build_std(&setup).target_host().run(); p.cargo("test").build_std(&setup).target_host().run();