rust-vendor-std.patch (5218B)
1 Teaches Rust's build system to vendor `std`'s dependencies into the 2 `rust-src` component. 3 4 This was originally landed in <https://github.com/rust-lang/rust/pull/78790>, 5 and <https://github.com/rust-lang/cargo/pull/8834>, but was backed out for 6 causing breakage in other situations. 7 8 Since then, things have changed in cargo, such that it is now possible to use 9 a simpler approach that only relies on tweaking what is shipped in rust. 10 11 diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs 12 index 5cfaa6a7c77..65c8abcb4f8 100644 13 --- a/src/bootstrap/src/core/build_steps/dist.rs 14 +++ b/src/bootstrap/src/core/build_steps/dist.rs 15 @@ -1016,6 +1016,97 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball { 16 &dst_src, 17 ); 18 19 + // cargo's -Z build-std doesn't work properly alongside vendoring. 20 + // To work around the issue, we vendor the libstd dependencies in the 21 + // rust-src package, and alter libstd's Cargo.toml to contain 22 + // patch.crates-io entries pointing to the vendored versions. 23 + let root_dir = dst_src.join("library"); 24 + let root_lock = root_dir.join("Cargo.lock"); 25 + if root_lock.exists() { 26 + use std::collections::HashMap; 27 + 28 + use toml::map::Map; 29 + use toml::Value; 30 + 31 + let dst_vendor = dst_src.join("vendor"); 32 + 33 + let mut cmd = command(&builder.initial_cargo); 34 + cmd.arg("vendor").arg(&dst_vendor).current_dir(&root_dir); 35 + // library/std/Cargo.toml uses the `public-dependency` nightly cargo feature. 36 + cmd.env("RUSTC_BOOTSTRAP", "1"); 37 + builder.info("Dist src"); 38 + let _time = timeit(builder); 39 + cmd.run(builder); 40 + 41 + // Ideally, we would add the .cargo/config.toml that `cargo vendor` outputs, 42 + // but cargo doesn't read it when building libstd. So instead, we add 43 + // [patch.crates-io] entries to Cargo.toml for all vendored packages. 44 + let cargo_toml_path = root_lock.with_extension("toml"); 45 + let cargo_toml_str = t!(std::fs::read_to_string(&cargo_toml_path)); 46 + let mut manifest: Value = t!(toml::from_str(&cargo_toml_str)); 47 + 48 + let patch_table = t!(manifest 49 + .get_mut("patch") 50 + .and_then(|p| p.as_table_mut()) 51 + .and_then(|p| p.get_mut("crates-io")) 52 + .and_then(|c| c.as_table_mut()) 53 + .ok_or("[patch.crates-io] section not found")); 54 + 55 + let mut packages_by_name: HashMap<String, Vec<String>> = HashMap::new(); 56 + 57 + for entry in builder.read_dir(&dst_vendor) { 58 + let path = entry.path(); 59 + 60 + // Check for Cargo.toml 61 + let crate_cargo_toml_path = path.join("Cargo.toml"); 62 + if !crate_cargo_toml_path.exists() { 63 + continue; 64 + } 65 + 66 + // Parse package name from Cargo.toml 67 + let crate_cargo_toml_str = t!(std::fs::read_to_string(&crate_cargo_toml_path)); 68 + let crate_cargo_toml: Value = t!(toml::from_str(&crate_cargo_toml_str)); 69 + let pkg_name = t!(crate_cargo_toml 70 + .get("package") 71 + .and_then(|p| p.get("name")) 72 + .and_then(|n| n.as_str()) 73 + .ok_or("package.name not found")); 74 + let dir_name = path.file_name().unwrap().to_string_lossy().into_owned(); 75 + packages_by_name 76 + .entry(pkg_name.to_string()) 77 + .or_insert_with(Vec::new) 78 + .push(dir_name); 79 + } 80 + 81 + for (pkg_name, dirs) in &packages_by_name { 82 + for dir_name in dirs.iter() { 83 + // What we want in the normal case: 84 + // [patch.crates-io.crate] 85 + // path = "../vendor/crate" 86 + // When the directory name is different (usually when it contains a 87 + // version) we want the following: 88 + // [patch.crates-io.crate-version] 89 + // package = "crate" 90 + // path = "../vendor/crate-version" 91 + let mut patch_value = Map::new(); 92 + let name = dir_name.replace('.', "_").replace('+', "_"); 93 + if &name != pkg_name { 94 + patch_value.insert("package".to_string(), pkg_name.clone().into()); 95 + } 96 + patch_value 97 + .insert("path".to_string(), format!("../vendor/{}", dir_name).into()); 98 + patch_table.insert(name, patch_value.into()); 99 + } 100 + } 101 + 102 + // Cargo.toml may be a hardlink to the one in the repository, and 103 + // we don't want to modify that, so break the hardlink first. 104 + t!(std::fs::remove_file(&cargo_toml_path)); 105 + 106 + let new_cargo_toml = t!(toml::to_string_pretty(&manifest)); 107 + t!(std::fs::write(&cargo_toml_path, new_cargo_toml)); 108 + } 109 + 110 tarball.generate() 111 }