1Teaches Cargo to source all std dependencies from vendored sources in the rust-src
2component, making -Zbuild-std compatible with vendored builds.
3
4This was originally landed in https://github.com/rust-lang/cargo/pull/8834
5but was backed out for causing breakage in other situations. It works fine
6for Firefox's usecase, though.
7
8Most of these changes just add/edit tests for the functionality. Only the
9change to src/cargo/core/compiler/standard_lib.rs is important.
10
11diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs
12index 0b14df805..7bc5151a4 100644
13--- a/src/cargo/core/compiler/standard_lib.rs
14+++ b/src/cargo/core/compiler/standard_lib.rs
15@@ -10,6 +10,7 @@ use crate::ops::{self, Packages};
16 use crate::util::errors::CargoResult;
17 use std::collections::{HashMap, HashSet};
18 use std::env;
19+use std::fs;
20 use std::path::PathBuf;
21
22 /// Parse the `-Zbuild-std` flag.
23@@ -38,28 +39,46 @@ pub fn resolve_std<'cfg>(
24     crates: &[String],
25 ) -> CargoResult<(PackageSet<'cfg>, Resolve, ResolvedFeatures)> {
26     let src_path = detect_sysroot_src_path(target_data)?;
27-    let to_patch = [
28-        "rustc-std-workspace-core",
29-        "rustc-std-workspace-alloc",
30-        "rustc-std-workspace-std",
31-    ];
32-    let patches = to_patch
33-        .iter()
34-        .map(|&name| {
35-            let source_path = SourceId::for_path(&src_path.join("library").join(name))?;
36-            let dep = Dependency::parse_no_deprecated(name, None, source_path)?;
37+
38+    // Special std packages should be pulled from `library/` and should be
39+    // prefixed with `rustc-std-workspace-` in certain places.
40+    let libs_prefix = "library/";
41+    let special_std_prefix = "rustc-std-workspace-";
42+    let libs_path = src_path.join(libs_prefix);
43+
44+    // Crates in rust-src to build. libtest is in some sense the "root" package
45+    // of std, as nothing else depends on it, so it must be explicitly added.
46+    let mut members = vec![format!("{}test", libs_prefix)];
47+
48+    // If rust-src contains a "vendor" directory, then patch in all the crates it contains.
49+    let vendor_path = src_path.join("vendor");
50+    let vendor_dir = fs::read_dir(vendor_path)?;
51+    let patches = vendor_dir
52+        .into_iter()
53+        .map(|entry| {
54+            let entry = entry?;
55+            let name = entry
56+                .file_name()
57+                .into_string()
58+                .map_err(|_| anyhow::anyhow!("package name wasn't utf8"))?;
59+
60+            // Remap the rustc-std-workspace crates to the actual rust-src libraries
61+            let path = if let Some(real_name) = name.strip_prefix(special_std_prefix) {
62+                // Record this crate as something to build in the workspace
63+                members.push(format!("{}{}", libs_prefix, real_name));
64+                libs_path.join(&name)
65+            } else {
66+                entry.path()
67+            };
68+            let source_path = SourceId::for_path(&path)?;
69+            let dep = Dependency::parse_no_deprecated(&name, None, source_path)?;
70             Ok(dep)
71         })
72         .collect::<CargoResult<Vec<_>>>()?;
73+
74     let crates_io_url = crate::sources::CRATES_IO_INDEX.parse().unwrap();
75     let mut patch = HashMap::new();
76     patch.insert(crates_io_url, patches);
77-    let members = vec![
78-        String::from("library/std"),
79-        String::from("library/core"),
80-        String::from("library/alloc"),
81-        String::from("library/test"),
82-    ];
83     let ws_config = crate::core::WorkspaceConfig::Root(crate::core::WorkspaceRootConfig::new(
84         &src_path,
85         &Some(members),
86diff --git a/tests/testsuite/mock-std/library/test/Cargo.toml b/tests/testsuite/mock-std/library/test/Cargo.toml
87index 299db7bfd..eb81bbf5e 100644
88--- a/tests/testsuite/mock-std/library/test/Cargo.toml
89+++ b/tests/testsuite/mock-std/library/test/Cargo.toml
90@@ -10,6 +10,7 @@ std = { path = "../std" }
91 panic_unwind = { path = "../panic_unwind" }
92 compiler_builtins = { path = "../compiler_builtins" }
93 registry-dep-using-std = { version = "*", features = ['mockbuild'] }
94+registry-dep-only-used-by-test = { version = "*" }
95
96 [features]
97 panic-unwind = []
98diff --git a/tests/testsuite/mock-std/library/test/src/lib.rs b/tests/testsuite/mock-std/library/test/src/lib.rs
99index a112855f5..224b89bb2 100644
100--- a/tests/testsuite/mock-std/library/test/src/lib.rs
101+++ b/tests/testsuite/mock-std/library/test/src/lib.rs
102@@ -7,4 +7,5 @@ extern crate test;
103 pub use test::*;
104
105 pub fn custom_api() {
106+    registry_dep_only_used_by_test::wow_testing_is_so_easy();
107 }
108diff --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
109new file mode 100644
110index 000000000..31ba65a98
111--- /dev/null
112+++ b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/Cargo.toml
113@@ -0,0 +1,9 @@
114+[package]
115+name = "registry-dep-only-used-by-test"
116+version = "1.0.0"
117+authors = ["Alex Crichton <alex@alexcrichton.com>"]
118+edition = "2018"
119+
120+[dependencies]
121+
122+[features]
123diff --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
124new file mode 100644
125index 000000000..a68d2aeef
126--- /dev/null
127+++ b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/src/lib.rs
128@@ -0,0 +1,2 @@
129+pub fn wow_testing_is_so_easy() {
130+}
131\ No newline at end of file
132diff --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
133new file mode 100644
134index 000000000..f7e4ab232
135--- /dev/null
136+++ b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/Cargo.toml
137@@ -0,0 +1,12 @@
138+[package]
139+name = "registry-dep-using-alloc"
140+version = "1.0.0"
141+authors = ["Alex Crichton <alex@alexcrichton.com>"]
142+edition = "2018"
143+
144+[dependencies]
145+rustc-std-workspace-alloc = { version = "*", optional = true }
146+rustc-std-workspace-core = { version = "*", optional = true }
147+
148+[features]
149+mockbuild = ["rustc-std-workspace-alloc", "rustc-std-workspace-core"]
150\ No newline at end of file
151diff --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
152new file mode 100644
153index 000000000..b9ab30339
154--- /dev/null
155+++ b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/src/lib.rs
156@@ -0,0 +1,9 @@
157+#[cfg(feature = "mockbuild")]
158+pub fn custom_api() {
159+}
160+
161+#[cfg(not(feature = "mockbuild"))]
162+pub fn non_sysroot_api() {
163+    core::custom_api();
164+    alloc::custom_api();
165+}
166\ No newline at end of file
167diff --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
168new file mode 100644
169index 000000000..befb83a63
170--- /dev/null
171+++ b/tests/testsuite/mock-std/vendor/registry-dep-using-core/Cargo.toml
172@@ -0,0 +1,11 @@
173+[package]
174+name = "registry-dep-using-core"
175+version = "1.0.0"
176+authors = ["Alex Crichton <alex@alexcrichton.com>"]
177+edition = "2018"
178+
179+[dependencies]
180+rustc-std-workspace-core = { version = "*", optional = true }
181+
182+[features]
183+mockbuild = ["rustc-std-workspace-core"]
184\ No newline at end of file
185diff --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
186new file mode 100644
187index 000000000..f9dbac0f4
188--- /dev/null
189+++ b/tests/testsuite/mock-std/vendor/registry-dep-using-core/src/lib.rs
190@@ -0,0 +1,8 @@
191+#[cfg(feature = "mockbuild")]
192+pub fn custom_api() {
193+}
194+
195+#[cfg(not(feature = "mockbuild"))]
196+pub fn non_sysroot_api() {
197+    core::custom_api();
198+}
199\ No newline at end of file
200diff --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
201new file mode 100644
202index 000000000..71ef0a42f
203--- /dev/null
204+++ b/tests/testsuite/mock-std/vendor/registry-dep-using-std/Cargo.toml
205@@ -0,0 +1,11 @@
206+[package]
207+name = "registry-dep-using-std"
208+version = "1.0.0"
209+authors = ["Alex Crichton <alex@alexcrichton.com>"]
210+edition = "2018"
211+
212+[dependencies]
213+rustc-std-workspace-std = { version = "*", optional = true }
214+
215+[features]
216+mockbuild = ["rustc-std-workspace-std"]
217\ No newline at end of file
218diff --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
219new file mode 100644
220index 000000000..f3af39178
221--- /dev/null
222+++ b/tests/testsuite/mock-std/vendor/registry-dep-using-std/src/lib.rs
223@@ -0,0 +1,8 @@
224+#[cfg(feature = "mockbuild")]
225+pub fn custom_api() {
226+}
227+
228+#[cfg(not(feature = "mockbuild"))]
229+pub fn non_sysroot_api() {
230+    std::custom_api();
231+}
232\ No newline at end of file
233diff --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
234new file mode 100644
235index 000000000..4465a08a8
236--- /dev/null
237+++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-alloc/Cargo.toml
238@@ -0,0 +1 @@
239+this file shouldn't be read
240\ No newline at end of file
241diff --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
242new file mode 100644
243index 000000000..4465a08a8
244--- /dev/null
245+++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-core/Cargo.toml
246@@ -0,0 +1 @@
247+this file shouldn't be read
248\ No newline at end of file
249diff --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
250new file mode 100644
251index 000000000..4465a08a8
252--- /dev/null
253+++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-std/Cargo.toml
254@@ -0,0 +1 @@
255+this file shouldn't be read
256\ No newline at end of file
257diff --git a/tests/testsuite/standard_lib.rs b/tests/testsuite/standard_lib.rs
258index b0d42b38d..3bbc49db7 100644
259--- a/tests/testsuite/standard_lib.rs
260+++ b/tests/testsuite/standard_lib.rs
261@@ -27,71 +27,18 @@ fn setup() -> Option<Setup> {
262         return None;
263     }
264
265-    // Our mock sysroot requires a few packages from crates.io, so make sure
266-    // they're "published" to crates.io. Also edit their code a bit to make sure
267-    // that they have access to our custom crates with custom apis.
268+    // Register a version of one of the std dependencies that doesn't compile.
269+    // This ensures that the mock-std's vendor is actually being used.
270     Package::new("registry-dep-using-core", "1.0.0")
271         .file(
272             "src/lib.rs",
273             "
274-                #![no_std]
275-
276-                #[cfg(feature = \"mockbuild\")]
277-                pub fn custom_api() {
278-                }
279-
280-                #[cfg(not(feature = \"mockbuild\"))]
281-                pub fn non_sysroot_api() {
282-                    core::custom_api();
283-                }
284+               don't compile me bro!!
285             ",
286         )
287         .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true))
288         .feature("mockbuild", &["rustc-std-workspace-core"])
289         .publish();
290-    Package::new("registry-dep-using-alloc", "1.0.0")
291-        .file(
292-            "src/lib.rs",
293-            "
294-                #![no_std]
295-
296-                extern crate alloc;
297-
298-                #[cfg(feature = \"mockbuild\")]
299-                pub fn custom_api() {
300-                }
301-
302-                #[cfg(not(feature = \"mockbuild\"))]
303-                pub fn non_sysroot_api() {
304-                    core::custom_api();
305-                    alloc::custom_api();
306-                }
307-            ",
308-        )
309-        .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true))
310-        .add_dep(Dependency::new("rustc-std-workspace-alloc", "*").optional(true))
311-        .feature(
312-            "mockbuild",
313-            &["rustc-std-workspace-core", "rustc-std-workspace-alloc"],
314-        )
315-        .publish();
316-    Package::new("registry-dep-using-std", "1.0.0")
317-        .file(
318-            "src/lib.rs",
319-            "
320-                #[cfg(feature = \"mockbuild\")]
321-                pub fn custom_api() {
322-                }
323-
324-                #[cfg(not(feature = \"mockbuild\"))]
325-                pub fn non_sysroot_api() {
326-                    std::custom_api();
327-                }
328-            ",
329-        )
330-        .add_dep(Dependency::new("rustc-std-workspace-std", "*").optional(true))
331-        .feature("mockbuild", &["rustc-std-workspace-std"])
332-        .publish();
333
334     let p = ProjectBuilder::new(paths::root().join("rustc-wrapper"))
335         .file(
336@@ -327,6 +274,81 @@ fn depend_same_as_std() {
337         None => return,
338     };
339
340+    // Our mock sysroot requires a few packages from crates.io, so make sure
341+    // they're "published" to crates.io. Also edit their code a bit to make sure
342+    // that they have access to our custom crates with custom apis.
343+    Package::new("registry-dep-using-core", "1.0.0")
344+        .file(
345+            "src/lib.rs",
346+            "
347+                #![no_std]
348+
349+                #[cfg(feature = \"mockbuild\")]
350+                pub fn custom_api() {
351+                }
352+
353+                #[cfg(not(feature = \"mockbuild\"))]
354+                pub fn non_sysroot_api() {
355+                    core::custom_api();
356+                }
357+            ",
358+        )
359+        .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true))
360+        .feature("mockbuild", &["rustc-std-workspace-core"])
361+        .publish();
362+    Package::new("registry-dep-using-alloc", "1.0.0")
363+        .file(
364+            "src/lib.rs",
365+            "
366+                #![no_std]
367+
368+                extern crate alloc;
369+
370+                #[cfg(feature = \"mockbuild\")]
371+                pub fn custom_api() {
372+                }
373+
374+                #[cfg(not(feature = \"mockbuild\"))]
375+                pub fn non_sysroot_api() {
376+                    core::custom_api();
377+                    alloc::custom_api();
378+                }
379+            ",
380+        )
381+        .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true))
382+        .add_dep(Dependency::new("rustc-std-workspace-alloc", "*").optional(true))
383+        .feature(
384+            "mockbuild",
385+            &["rustc-std-workspace-core", "rustc-std-workspace-alloc"],
386+        )
387+        .publish();
388+    Package::new("registry-dep-using-std", "1.0.0")
389+        .file(
390+            "src/lib.rs",
391+            "
392+                #[cfg(feature = \"mockbuild\")]
393+                pub fn custom_api() {
394+                }
395+
396+                #[cfg(not(feature = \"mockbuild\"))]
397+                pub fn non_sysroot_api() {
398+                    std::custom_api();
399+                }
400+            ",
401+        )
402+        .add_dep(Dependency::new("rustc-std-workspace-std", "*").optional(true))
403+        .feature("mockbuild", &["rustc-std-workspace-std"])
404+        .publish();
405+    Package::new("registry-dep-only-used-by-test", "1.0.0")
406+        .file(
407+            "src/lib.rs",
408+            "
409+                pub fn wow_testing_is_so_easy() {
410+                }
411+            ",
412+        )
413+        .publish();
414+
415     let p = project()
416         .file(
417             "src/lib.rs",
418