Skip to main content

bootstrap/core/build_steps/
vendor.rs

1//! Handles the vendoring process for the bootstrap system.
2//!
3//! This module ensures that all required Cargo dependencies are gathered
4//! and stored in the `<src>/<VENDOR_DIR>` directory.
5use std::path::PathBuf;
6
7use crate::core::build_steps::tool::SUBMODULES_FOR_RUSTBOOK;
8use crate::core::builder::{Builder, CommandLineStep, RunConfig, ShouldRun};
9use crate::utils::exec::command;
10
11/// The name of the directory where vendored dependencies are stored.
12pub const VENDOR_DIR: &str = "vendor";
13
14/// Returns the cargo workspaces to vendor for `x vendor` and dist tarballs.
15///
16/// Returns a `Vec` of `(path_to_manifest, submodules_required)` where
17/// `path_to_manifest` is the cargo workspace, and `submodules_required` is
18/// the set of submodules that must be available.
19pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec<(PathBuf, Vec<&'static str>)> {
20    [
21        ("src/tools/cargo/Cargo.toml", vec!["src/tools/cargo"]),
22        ("src/tools/clippy/clippy_test_deps/Cargo.toml", vec![]),
23        ("src/tools/rust-analyzer/Cargo.toml", vec![]),
24        ("compiler/rustc_codegen_cranelift/Cargo.toml", vec![]),
25        ("compiler/rustc_codegen_gcc/Cargo.toml", vec![]),
26        ("library/Cargo.toml", vec![]),
27        ("library/stdarch/Cargo.toml", vec![]),
28        ("library/compiler-builtins/Cargo.toml", vec![]),
29        ("src/bootstrap/Cargo.toml", vec![]),
30        ("src/tools/rustbook/Cargo.toml", SUBMODULES_FOR_RUSTBOOK.into()),
31        ("src/tools/rustc-perf/Cargo.toml", vec!["src/tools/rustc-perf"]),
32        ("src/tools/opt-dist/Cargo.toml", vec![]),
33        ("src/doc/book/packages/trpl/Cargo.toml", vec![]),
34    ]
35    .into_iter()
36    .map(|(path, submodules)| (builder.src.join(path), submodules))
37    .collect()
38}
39
40/// Defines the vendoring step in the bootstrap process.
41///
42/// This step executes `cargo vendor` to collect all dependencies
43/// and store them in the `<src>/<VENDOR_DIR>` directory.
44#[derive(Debug, Clone, Hash, PartialEq, Eq)]
45pub(crate) struct Vendor {
46    /// Additional paths to synchronize during vendoring.
47    pub(crate) sync_args: Vec<PathBuf>,
48    /// Determines whether vendored dependencies use versioned directories.
49    pub(crate) versioned_dirs: bool,
50    /// The root directory of the source code.
51    ///
52    /// Vendored dependencies will be stored in <root_dir>/vendor and
53    /// <root_dir>/library/vendor unless overridden by `output_dir`.
54    pub(crate) root_dir: PathBuf,
55    /// The root directory for storing vendored dependencies in <output_dir>/vendor
56    /// and <output_dir>/library/vendor.
57    pub(crate) output_dir: Option<PathBuf>,
58    /// Only vendor crates necessary by the library workspace.
59    pub(crate) only_library_workspace: bool,
60}
61
62impl CommandLineStep for Vendor {
63    type Output = VendorOutput;
64    const IS_HOST: bool = true;
65
66    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
67        run.alias("placeholder")
68    }
69
70    fn is_default_step(_builder: &Builder<'_>) -> bool {
71        true
72    }
73
74    fn make_run(run: RunConfig<'_>) {
75        let vendor = run.builder.ensure(Vendor {
76            sync_args: run.builder.config.cmd.vendor_sync_args(),
77            versioned_dirs: run.builder.config.cmd.vendor_versioned_dirs(),
78            root_dir: run.builder.src.clone(),
79            output_dir: None,
80            only_library_workspace: false,
81        });
82        // Print the config.toml contents, so that the user can manually copy it
83        if !run.builder.config.dry_run() {
84            println!("Put the following config into .cargo/config.toml:\n{}", vendor.config);
85            println!(
86                "Put the following config into library/.cargo/config.toml:\n{}",
87                vendor.config_library
88            );
89        }
90    }
91
92    /// Executes the vendoring process.
93    ///
94    /// This function runs `cargo vendor` and ensures all required submodules
95    /// are initialized before vendoring begins.
96    fn run(self, builder: &Builder<'_>) -> Self::Output {
97        let _guard = builder.group(&format!("Vendoring sources to {:?}", self.root_dir));
98
99        let config = if self.only_library_workspace {
100            String::new()
101        } else {
102            let mut cmd = command(&builder.initial_cargo);
103            cmd.arg("vendor");
104
105            if self.versioned_dirs {
106                cmd.arg("--versioned-dirs");
107            }
108
109            let to_vendor = default_paths_to_vendor(builder);
110            // These submodules must be present for `x vendor` to work.
111            for (_, submodules) in &to_vendor {
112                for submodule in submodules {
113                    builder.sess.require_submodule(submodule, None);
114                }
115            }
116
117            // Sync these paths by default.
118            for (p, _) in &to_vendor {
119                cmd.arg("--sync").arg(p);
120            }
121
122            // Also sync explicitly requested paths.
123            for sync_arg in self.sync_args {
124                cmd.arg("--sync").arg(sync_arg);
125            }
126
127            // Reuse vendored dependencies when building source tarball for offline support.
128            if builder.config.vendor {
129                cmd.arg("--respect-source-config")
130                    .arg("--config")
131                    .arg(builder.src.join(".cargo").join("config.toml"));
132            }
133
134            // Will read the libstd Cargo.toml
135            // which uses the unstable `public-dependency` feature.
136            cmd.env("RUSTC_BOOTSTRAP", "1");
137            cmd.env("RUSTC", &builder.initial_rustc);
138
139            cmd.current_dir(&self.root_dir);
140            match &self.output_dir {
141                None => cmd.arg(VENDOR_DIR),
142                Some(output_dir) => cmd.arg(output_dir.join(VENDOR_DIR)),
143            };
144
145            cmd.run_capture_stdout(builder).stdout()
146        };
147
148        let mut cmd = command(&builder.initial_cargo);
149        cmd.arg("vendor");
150
151        if self.versioned_dirs {
152            cmd.arg("--versioned-dirs");
153        }
154
155        // Reuse vendored dependencies when building source tarball for offline support.
156        if builder.config.vendor {
157            cmd.arg("--respect-source-config")
158                .arg("--config")
159                .arg(builder.src.join("library").join(".cargo").join("config.toml"));
160        }
161
162        // Will read the libstd Cargo.toml
163        // which uses the unstable `public-dependency` feature.
164        cmd.env("RUSTC_BOOTSTRAP", "1");
165        cmd.env("RUSTC", &builder.initial_rustc);
166
167        cmd.current_dir(self.root_dir.join("library"));
168        match &self.output_dir {
169            None => cmd.arg(VENDOR_DIR),
170            Some(output_dir) => cmd.arg(output_dir.join("library").join(VENDOR_DIR)),
171        };
172
173        let config_library = cmd.run_capture_stdout(builder).stdout();
174
175        VendorOutput { config, config_library }
176    }
177}
178
179/// Stores the result of the vendoring step.
180#[derive(Debug, Clone)]
181pub(crate) struct VendorOutput {
182    pub(crate) config: String,
183    pub(crate) config_library: String,
184}