Teaches Cargo to source all std dependencies from vendored sources in the rust-src component, making -Zbuild-std compatible with vendored builds. This was originally landed in https://github.com/rust-lang/cargo/pull/8834 but was backed out for causing breakage in other situations. It works fine for Firefox's usecase, though. Most of these changes just add/edit tests for the functionality. Only the change to src/cargo/core/compiler/standard_lib.rs is important. diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs index e0baebd51..547b84147 100644 --- a/src/cargo/core/compiler/standard_lib.rs +++ b/src/cargo/core/compiler/standard_lib.rs @@ -11,6 +11,7 @@ use crate::ops::{self, Packages}; use crate::util::errors::CargoResult; use crate::Config; use std::collections::{HashMap, HashSet}; +use std::fs; use std::path::PathBuf; use super::BuildConfig; @@ -74,27 +75,45 @@ pub fn resolve_std<'cfg>( } let src_path = detect_sysroot_src_path(target_data)?; - let to_patch = [ - "rustc-std-workspace-core", - "rustc-std-workspace-alloc", - "rustc-std-workspace-std", - ]; - let patches = to_patch - .iter() - .map(|&name| { - let source_path = SourceId::for_path(&src_path.join("library").join(name))?; - let dep = Dependency::parse(name, None, source_path)?; + + // Special std packages should be pulled from `library/` and should be + // prefixed with `rustc-std-workspace-` in certain places. + let libs_prefix = "library/"; + let special_std_prefix = "rustc-std-workspace-"; + let libs_path = src_path.join(libs_prefix); + + // Crates in rust-src to build. libtest is in some sense the "root" package + // of std, as nothing else depends on it, so it must be explicitly added. + let mut members = vec![format!("{}test", libs_prefix)]; + + // If rust-src contains a "vendor" directory, then patch in all the crates it contains. + let vendor_path = src_path.join("vendor"); + let vendor_dir = fs::read_dir(vendor_path)?; + let patches = vendor_dir + .into_iter() + .map(|entry| { + let entry = entry?; + let name = entry + .file_name() + .into_string() + .map_err(|_| anyhow::anyhow!("package name wasn't utf8"))?; + + // Remap the rustc-std-workspace crates to the actual rust-src libraries + let path = if let Some(real_name) = name.strip_prefix(special_std_prefix) { + // Record this crate as something to build in the workspace + members.push(format!("{}{}", libs_prefix, real_name)); + libs_path.join(&name) + } else { + entry.path() + }; + let source_path = SourceId::for_path(&path)?; + let dep = Dependency::parse(&name, None, source_path)?; Ok(dep) }) .collect::>>()?; + let crates_io_url = crate::sources::CRATES_IO_INDEX.parse().unwrap(); let patch = HashMap::from([(crates_io_url, patches)]); - let members = vec![ - String::from("library/std"), - String::from("library/core"), - String::from("library/alloc"), - String::from("library/test"), - ]; let ws_config = crate::core::WorkspaceConfig::Root(crate::core::WorkspaceRootConfig::new( &src_path, &Some(members), diff --git a/tests/testsuite/mock-std/library/test/Cargo.toml b/tests/testsuite/mock-std/library/test/Cargo.toml index 299db7bfd..eb81bbf5e 100644 --- a/tests/testsuite/mock-std/library/test/Cargo.toml +++ b/tests/testsuite/mock-std/library/test/Cargo.toml @@ -10,6 +10,7 @@ std = { path = "../std" } panic_unwind = { path = "../panic_unwind" } compiler_builtins = { path = "../compiler_builtins" } registry-dep-using-std = { version = "*", features = ['mockbuild'] } +registry-dep-only-used-by-test = { version = "*" } [features] panic-unwind = [] diff --git a/tests/testsuite/mock-std/library/test/src/lib.rs b/tests/testsuite/mock-std/library/test/src/lib.rs index a112855f5..224b89bb2 100644 --- a/tests/testsuite/mock-std/library/test/src/lib.rs +++ b/tests/testsuite/mock-std/library/test/src/lib.rs @@ -7,4 +7,5 @@ extern crate test; pub use test::*; pub fn custom_api() { + registry_dep_only_used_by_test::wow_testing_is_so_easy(); } diff --git a/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/Cargo.toml b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/Cargo.toml new file mode 100644 index 000000000..31ba65a98 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "registry-dep-only-used-by-test" +version = "1.0.0" +authors = ["Alex Crichton "] +edition = "2018" + +[dependencies] + +[features] diff --git a/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/src/lib.rs b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/src/lib.rs new file mode 100644 index 000000000..a68d2aeef --- /dev/null +++ b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/src/lib.rs @@ -0,0 +1,2 @@ +pub fn wow_testing_is_so_easy() { +} \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/Cargo.toml b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/Cargo.toml new file mode 100644 index 000000000..f7e4ab232 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "registry-dep-using-alloc" +version = "1.0.0" +authors = ["Alex Crichton "] +edition = "2018" + +[dependencies] +rustc-std-workspace-alloc = { version = "*", optional = true } +rustc-std-workspace-core = { version = "*", optional = true } + +[features] +mockbuild = ["rustc-std-workspace-alloc", "rustc-std-workspace-core"] \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/src/lib.rs b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/src/lib.rs new file mode 100644 index 000000000..b9ab30339 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/src/lib.rs @@ -0,0 +1,9 @@ +#[cfg(feature = "mockbuild")] +pub fn custom_api() { +} + +#[cfg(not(feature = "mockbuild"))] +pub fn non_sysroot_api() { + core::custom_api(); + alloc::custom_api(); +} \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-core/Cargo.toml b/tests/testsuite/mock-std/vendor/registry-dep-using-core/Cargo.toml new file mode 100644 index 000000000..befb83a63 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/registry-dep-using-core/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "registry-dep-using-core" +version = "1.0.0" +authors = ["Alex Crichton "] +edition = "2018" + +[dependencies] +rustc-std-workspace-core = { version = "*", optional = true } + +[features] +mockbuild = ["rustc-std-workspace-core"] \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-core/src/lib.rs b/tests/testsuite/mock-std/vendor/registry-dep-using-core/src/lib.rs new file mode 100644 index 000000000..f9dbac0f4 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/registry-dep-using-core/src/lib.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "mockbuild")] +pub fn custom_api() { +} + +#[cfg(not(feature = "mockbuild"))] +pub fn non_sysroot_api() { + core::custom_api(); +} \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-std/Cargo.toml b/tests/testsuite/mock-std/vendor/registry-dep-using-std/Cargo.toml new file mode 100644 index 000000000..71ef0a42f --- /dev/null +++ b/tests/testsuite/mock-std/vendor/registry-dep-using-std/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "registry-dep-using-std" +version = "1.0.0" +authors = ["Alex Crichton "] +edition = "2018" + +[dependencies] +rustc-std-workspace-std = { version = "*", optional = true } + +[features] +mockbuild = ["rustc-std-workspace-std"] \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-std/src/lib.rs b/tests/testsuite/mock-std/vendor/registry-dep-using-std/src/lib.rs new file mode 100644 index 000000000..f3af39178 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/registry-dep-using-std/src/lib.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "mockbuild")] +pub fn custom_api() { +} + +#[cfg(not(feature = "mockbuild"))] +pub fn non_sysroot_api() { + std::custom_api(); +} \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/rustc-std-workspace-alloc/Cargo.toml b/tests/testsuite/mock-std/vendor/rustc-std-workspace-alloc/Cargo.toml new file mode 100644 index 000000000..4465a08a8 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-alloc/Cargo.toml @@ -0,0 +1 @@ +this file shouldn't be read \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/rustc-std-workspace-core/Cargo.toml b/tests/testsuite/mock-std/vendor/rustc-std-workspace-core/Cargo.toml new file mode 100644 index 000000000..4465a08a8 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-core/Cargo.toml @@ -0,0 +1 @@ +this file shouldn't be read \ No newline at end of file diff --git a/tests/testsuite/mock-std/vendor/rustc-std-workspace-std/Cargo.toml b/tests/testsuite/mock-std/vendor/rustc-std-workspace-std/Cargo.toml new file mode 100644 index 000000000..4465a08a8 --- /dev/null +++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-std/Cargo.toml @@ -0,0 +1 @@ +this file shouldn't be read \ No newline at end of file diff --git a/tests/testsuite/standard_lib.rs b/tests/testsuite/standard_lib.rs index d3be303ea..486a9b4e0 100644 --- a/tests/testsuite/standard_lib.rs +++ b/tests/testsuite/standard_lib.rs @@ -15,71 +15,18 @@ struct Setup { } fn setup() -> Setup { - // Our mock sysroot requires a few packages from crates.io, so make sure - // they're "published" to crates.io. Also edit their code a bit to make sure - // that they have access to our custom crates with custom apis. + // Register a version of one of the std dependencies that doesn't compile. + // This ensures that the mock-std's vendor is actually being used. Package::new("registry-dep-using-core", "1.0.0") .file( "src/lib.rs", " - #![no_std] - - #[cfg(feature = \"mockbuild\")] - pub fn custom_api() { - } - - #[cfg(not(feature = \"mockbuild\"))] - pub fn non_sysroot_api() { - core::custom_api(); - } + don't compile me bro!! ", ) .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) .feature("mockbuild", &["rustc-std-workspace-core"]) .publish(); - Package::new("registry-dep-using-alloc", "1.0.0") - .file( - "src/lib.rs", - " - #![no_std] - - extern crate alloc; - - #[cfg(feature = \"mockbuild\")] - pub fn custom_api() { - } - - #[cfg(not(feature = \"mockbuild\"))] - pub fn non_sysroot_api() { - core::custom_api(); - alloc::custom_api(); - } - ", - ) - .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) - .add_dep(Dependency::new("rustc-std-workspace-alloc", "*").optional(true)) - .feature( - "mockbuild", - &["rustc-std-workspace-core", "rustc-std-workspace-alloc"], - ) - .publish(); - Package::new("registry-dep-using-std", "1.0.0") - .file( - "src/lib.rs", - " - #[cfg(feature = \"mockbuild\")] - pub fn custom_api() { - } - - #[cfg(not(feature = \"mockbuild\"))] - pub fn non_sysroot_api() { - std::custom_api(); - } - ", - ) - .add_dep(Dependency::new("rustc-std-workspace-std", "*").optional(true)) - .feature("mockbuild", &["rustc-std-workspace-std"]) - .publish(); let p = ProjectBuilder::new(paths::root().join("rustc-wrapper")) .file( @@ -335,6 +282,81 @@ fn depend_same_as_std() { fn test() { let setup = setup(); + // Our mock sysroot requires a few packages from crates.io, so make sure + // they're "published" to crates.io. Also edit their code a bit to make sure + // that they have access to our custom crates with custom apis. + Package::new("registry-dep-using-core", "1.0.0") + .file( + "src/lib.rs", + " + #![no_std] + + #[cfg(feature = \"mockbuild\")] + pub fn custom_api() { + } + + #[cfg(not(feature = \"mockbuild\"))] + pub fn non_sysroot_api() { + core::custom_api(); + } + ", + ) + .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) + .feature("mockbuild", &["rustc-std-workspace-core"]) + .publish(); + Package::new("registry-dep-using-alloc", "1.0.0") + .file( + "src/lib.rs", + " + #![no_std] + + extern crate alloc; + + #[cfg(feature = \"mockbuild\")] + pub fn custom_api() { + } + + #[cfg(not(feature = \"mockbuild\"))] + pub fn non_sysroot_api() { + core::custom_api(); + alloc::custom_api(); + } + ", + ) + .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) + .add_dep(Dependency::new("rustc-std-workspace-alloc", "*").optional(true)) + .feature( + "mockbuild", + &["rustc-std-workspace-core", "rustc-std-workspace-alloc"], + ) + .publish(); + Package::new("registry-dep-using-std", "1.0.0") + .file( + "src/lib.rs", + " + #[cfg(feature = \"mockbuild\")] + pub fn custom_api() { + } + + #[cfg(not(feature = \"mockbuild\"))] + pub fn non_sysroot_api() { + std::custom_api(); + } + ", + ) + .add_dep(Dependency::new("rustc-std-workspace-std", "*").optional(true)) + .feature("mockbuild", &["rustc-std-workspace-std"]) + .publish(); + Package::new("registry-dep-only-used-by-test", "1.0.0") + .file( + "src/lib.rs", + " + pub fn wow_testing_is_so_easy() { + } + ", + ) + .publish(); + let p = project() .file( "src/lib.rs",