bootstrap/core/build_steps/
dist.rs

1//! Implementation of the various distribution aspects of the compiler.
2//!
3//! This module is responsible for creating tarballs of the standard library,
4//! compiler, and documentation. This ends up being what we distribute to
5//! everyone as well.
6//!
7//! No tarball is actually created literally in this file, but rather we shell
8//! out to `rust-installer` still. This may one day be replaced with bits and
9//! pieces of `rustup.rs`!
10
11use std::collections::HashSet;
12use std::ffi::OsStr;
13use std::io::Write;
14use std::path::{Path, PathBuf};
15use std::{env, fs};
16
17use object::BinaryFormat;
18use object::read::archive::ArchiveFile;
19#[cfg(feature = "tracing")]
20use tracing::instrument;
21
22use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name};
23use crate::core::build_steps::doc::DocumentationFormat;
24use crate::core::build_steps::tool::{
25    self, RustcPrivateCompilers, Tool, ToolTargetBuildMode, get_tool_target_compiler,
26};
27use crate::core::build_steps::vendor::{VENDOR_DIR, Vendor};
28use crate::core::build_steps::{compile, llvm};
29use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata};
30use crate::core::config::TargetSelection;
31use crate::utils::build_stamp::{self, BuildStamp};
32use crate::utils::channel::{self, Info};
33use crate::utils::exec::{BootstrapCommand, command};
34use crate::utils::helpers::{
35    exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit,
36};
37use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
38use crate::{CodegenBackendKind, Compiler, DependencyType, FileType, LLVM_TOOLS, Mode, trace};
39
40pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
41    format!("{}-{}", component, builder.rust_package_vers())
42}
43
44pub(crate) fn distdir(builder: &Builder<'_>) -> PathBuf {
45    builder.out.join("dist")
46}
47
48pub fn tmpdir(builder: &Builder<'_>) -> PathBuf {
49    builder.out.join("tmp/dist")
50}
51
52fn should_build_extended_tool(builder: &Builder<'_>, tool: &str) -> bool {
53    if !builder.config.extended {
54        return false;
55    }
56    builder.config.tools.as_ref().is_none_or(|tools| tools.contains(tool))
57}
58
59#[derive(Debug, Clone, Hash, PartialEq, Eq)]
60pub struct Docs {
61    pub host: TargetSelection,
62}
63
64impl Step for Docs {
65    type Output = Option<GeneratedTarball>;
66    const DEFAULT: bool = true;
67
68    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
69        let default = run.builder.config.docs;
70        run.alias("rust-docs").default_condition(default)
71    }
72
73    fn make_run(run: RunConfig<'_>) {
74        run.builder.ensure(Docs { host: run.target });
75    }
76
77    /// Builds the `rust-docs` installer component.
78    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
79        let host = self.host;
80        // FIXME: explicitly enumerate the steps that should be executed here, and gather their
81        // documentation, rather than running all default steps and then read their output
82        // from a shared directory.
83        builder.run_default_doc_steps();
84
85        let dest = "share/doc/rust/html";
86
87        let mut tarball = Tarball::new(builder, "rust-docs", &host.triple);
88        tarball.set_product_name("Rust Documentation");
89        tarball.add_bulk_dir(builder.doc_out(host), dest);
90        tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, FileType::Regular);
91        tarball.add_file(builder.src.join("src/doc/sitemap.txt"), dest, FileType::Regular);
92        Some(tarball.generate())
93    }
94
95    fn metadata(&self) -> Option<StepMetadata> {
96        Some(StepMetadata::dist("docs", self.host))
97    }
98}
99
100/// Builds the `rust-docs-json` installer component.
101/// It contains the documentation of the standard library in JSON format.
102#[derive(Debug, Clone, Hash, PartialEq, Eq)]
103pub struct JsonDocs {
104    build_compiler: Compiler,
105    target: TargetSelection,
106}
107
108impl Step for JsonDocs {
109    type Output = Option<GeneratedTarball>;
110    const DEFAULT: bool = true;
111
112    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
113        let default = run.builder.config.docs;
114        run.alias("rust-docs-json").default_condition(default)
115    }
116
117    fn make_run(run: RunConfig<'_>) {
118        run.builder.ensure(JsonDocs {
119            build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
120            target: run.target,
121        });
122    }
123
124    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
125        let target = self.target;
126        let directory = builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
127            self.build_compiler,
128            target,
129            DocumentationFormat::Json,
130        ));
131
132        let dest = "share/doc/rust/json";
133
134        let mut tarball = Tarball::new(builder, "rust-docs-json", &target.triple);
135        tarball.set_product_name("Rust Documentation In JSON Format");
136        tarball.is_preview(true);
137        tarball.add_bulk_dir(directory, dest);
138        Some(tarball.generate())
139    }
140
141    fn metadata(&self) -> Option<StepMetadata> {
142        Some(StepMetadata::dist("json-docs", self.target).built_by(self.build_compiler))
143    }
144}
145
146/// Builds the `rustc-docs` installer component.
147/// Apart from the documentation of the `rustc_*` crates, it also includes the documentation of
148/// various in-tree helper tools (bootstrap, build_helper, tidy),
149/// and also rustc_private tools like rustdoc, clippy, miri or rustfmt.
150///
151/// It is currently hosted at <https://doc.rust-lang.org/nightly/nightly-rustc>.
152#[derive(Debug, Clone, Hash, PartialEq, Eq)]
153pub struct RustcDocs {
154    target: TargetSelection,
155}
156
157impl Step for RustcDocs {
158    type Output = GeneratedTarball;
159
160    const DEFAULT: bool = true;
161    const IS_HOST: bool = true;
162
163    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
164        let builder = run.builder;
165        run.alias("rustc-docs").default_condition(builder.config.compiler_docs)
166    }
167
168    fn make_run(run: RunConfig<'_>) {
169        run.builder.ensure(RustcDocs { target: run.target });
170    }
171
172    fn run(self, builder: &Builder<'_>) -> Self::Output {
173        let target = self.target;
174        builder.run_default_doc_steps();
175
176        let mut tarball = Tarball::new(builder, "rustc-docs", &target.triple);
177        tarball.set_product_name("Rustc Documentation");
178        tarball.add_bulk_dir(builder.compiler_doc_out(target), "share/doc/rust/html/rustc");
179        tarball.generate()
180    }
181}
182
183fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
184    let mut found = Vec::with_capacity(files.len());
185
186    for file in files {
187        let file_path = path.iter().map(|dir| dir.join(file)).find(|p| p.exists());
188
189        if let Some(file_path) = file_path {
190            found.push(file_path);
191        } else {
192            panic!("Could not find '{file}' in {path:?}");
193        }
194    }
195
196    found
197}
198
199fn make_win_dist(plat_root: &Path, target: TargetSelection, builder: &Builder<'_>) {
200    if builder.config.dry_run() {
201        return;
202    }
203
204    let (bin_path, lib_path) = get_cc_search_dirs(target, builder);
205
206    let compiler = if target == "i686-pc-windows-gnu" {
207        "i686-w64-mingw32-gcc.exe"
208    } else if target == "x86_64-pc-windows-gnu" {
209        "x86_64-w64-mingw32-gcc.exe"
210    } else {
211        "gcc.exe"
212    };
213    let target_tools = [compiler, "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
214
215    // Libraries necessary to link the windows-gnu toolchains.
216    // System libraries will be preferred if they are available (see #67429).
217    let target_libs = [
218        //MinGW libs
219        "libgcc.a",
220        "libgcc_eh.a",
221        "libgcc_s.a",
222        "libm.a",
223        "libmingw32.a",
224        "libmingwex.a",
225        "libstdc++.a",
226        "libiconv.a",
227        "libmoldname.a",
228        "libpthread.a",
229        // Windows import libs
230        // This *should* contain only the set of libraries necessary to link the standard library,
231        // however we've had problems with people accidentally depending on extra libs being here,
232        // so we can't easily remove entries.
233        "libadvapi32.a",
234        "libbcrypt.a",
235        "libcomctl32.a",
236        "libcomdlg32.a",
237        "libcredui.a",
238        "libcrypt32.a",
239        "libdbghelp.a",
240        "libgdi32.a",
241        "libimagehlp.a",
242        "libiphlpapi.a",
243        "libkernel32.a",
244        "libmsimg32.a",
245        "libmsvcrt.a",
246        "libntdll.a",
247        "libodbc32.a",
248        "libole32.a",
249        "liboleaut32.a",
250        "libopengl32.a",
251        "libpsapi.a",
252        "librpcrt4.a",
253        "libsecur32.a",
254        "libsetupapi.a",
255        "libshell32.a",
256        "libsynchronization.a",
257        "libuser32.a",
258        "libuserenv.a",
259        "libuuid.a",
260        "libwinhttp.a",
261        "libwinmm.a",
262        "libwinspool.a",
263        "libws2_32.a",
264        "libwsock32.a",
265    ];
266
267    //Find mingw artifacts we want to bundle
268    let target_tools = find_files(&target_tools, &bin_path);
269    let target_libs = find_files(&target_libs, &lib_path);
270
271    //Copy platform tools to platform-specific bin directory
272    let plat_target_bin_self_contained_dir =
273        plat_root.join("lib/rustlib").join(target).join("bin/self-contained");
274    fs::create_dir_all(&plat_target_bin_self_contained_dir)
275        .expect("creating plat_target_bin_self_contained_dir failed");
276    for src in target_tools {
277        builder.copy_link_to_folder(&src, &plat_target_bin_self_contained_dir);
278    }
279
280    // Warn windows-gnu users that the bundled GCC cannot compile C files
281    builder.create(
282        &plat_target_bin_self_contained_dir.join("GCC-WARNING.txt"),
283        "gcc.exe contained in this folder cannot be used for compiling C files - it is only \
284         used as a linker. In order to be able to compile projects containing C code use \
285         the GCC provided by MinGW or Cygwin.",
286    );
287
288    //Copy platform libs to platform-specific lib directory
289    let plat_target_lib_self_contained_dir =
290        plat_root.join("lib/rustlib").join(target).join("lib/self-contained");
291    fs::create_dir_all(&plat_target_lib_self_contained_dir)
292        .expect("creating plat_target_lib_self_contained_dir failed");
293    for src in target_libs {
294        builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir);
295    }
296}
297
298fn runtime_dll_dist(rust_root: &Path, target: TargetSelection, builder: &Builder<'_>) {
299    if builder.config.dry_run() {
300        return;
301    }
302
303    let (bin_path, libs_path) = get_cc_search_dirs(target, builder);
304
305    let mut rustc_dlls = vec![];
306    // windows-gnu and windows-gnullvm require different runtime libs
307    if target.ends_with("windows-gnu") {
308        rustc_dlls.push("libwinpthread-1.dll");
309        if target.starts_with("i686-") {
310            rustc_dlls.push("libgcc_s_dw2-1.dll");
311        } else {
312            rustc_dlls.push("libgcc_s_seh-1.dll");
313        }
314    } else if target.ends_with("windows-gnullvm") {
315        rustc_dlls.push("libunwind.dll");
316    } else {
317        panic!("Vendoring of runtime DLLs for `{target}` is not supported`");
318    }
319    // FIXME(#144656): Remove this whole `let ...`
320    let bin_path = if target.ends_with("windows-gnullvm") && builder.host_target != target {
321        bin_path
322            .into_iter()
323            .chain(libs_path.iter().map(|path| path.with_file_name("bin")))
324            .collect()
325    } else {
326        bin_path
327    };
328    let rustc_dlls = find_files(&rustc_dlls, &bin_path);
329
330    // Copy runtime dlls next to rustc.exe
331    let rust_bin_dir = rust_root.join("bin/");
332    fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed");
333    for src in &rustc_dlls {
334        builder.copy_link_to_folder(src, &rust_bin_dir);
335    }
336
337    if builder.config.lld_enabled {
338        // rust-lld.exe also needs runtime dlls
339        let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin");
340        fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed");
341        for src in &rustc_dlls {
342            builder.copy_link_to_folder(src, &rust_target_bin_dir);
343        }
344    }
345}
346
347fn get_cc_search_dirs(
348    target: TargetSelection,
349    builder: &Builder<'_>,
350) -> (Vec<PathBuf>, Vec<PathBuf>) {
351    //Ask gcc where it keeps its stuff
352    let mut cmd = command(builder.cc(target));
353    cmd.arg("-print-search-dirs");
354    let gcc_out = cmd.run_capture_stdout(builder).stdout();
355
356    let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
357    let mut lib_path = Vec::new();
358
359    for line in gcc_out.lines() {
360        let idx = line.find(':').unwrap();
361        let key = &line[..idx];
362        let trim_chars: &[_] = &[' ', '='];
363        let value = env::split_paths(line[(idx + 1)..].trim_start_matches(trim_chars));
364
365        if key == "programs" {
366            bin_path.extend(value);
367        } else if key == "libraries" {
368            lib_path.extend(value);
369        }
370    }
371    (bin_path, lib_path)
372}
373
374/// Builds the `rust-mingw` installer component.
375///
376/// This contains all the bits and pieces to run the MinGW Windows targets
377/// without any extra installed software (e.g., we bundle gcc, libraries, etc.).
378#[derive(Debug, Clone, Hash, PartialEq, Eq)]
379pub struct Mingw {
380    target: TargetSelection,
381}
382
383impl Step for Mingw {
384    type Output = Option<GeneratedTarball>;
385    const DEFAULT: bool = true;
386
387    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
388        run.alias("rust-mingw")
389    }
390
391    fn make_run(run: RunConfig<'_>) {
392        run.builder.ensure(Mingw { target: run.target });
393    }
394
395    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
396        let target = self.target;
397        if !target.ends_with("pc-windows-gnu") || !builder.config.dist_include_mingw_linker {
398            return None;
399        }
400
401        let mut tarball = Tarball::new(builder, "rust-mingw", &target.triple);
402        tarball.set_product_name("Rust MinGW");
403
404        make_win_dist(tarball.image_dir(), target, builder);
405
406        Some(tarball.generate())
407    }
408
409    fn metadata(&self) -> Option<StepMetadata> {
410        Some(StepMetadata::dist("mingw", self.target))
411    }
412}
413
414/// Creates the `rustc` installer component.
415///
416/// This includes:
417/// - The compiler and LLVM.
418/// - Debugger scripts.
419/// - Various helper tools, e.g. LLD or Rust Analyzer proc-macro server (if enabled).
420/// - The licenses of all code used by the compiler.
421///
422/// It does not include any standard library.
423#[derive(Debug, Clone, Hash, PartialEq, Eq)]
424pub struct Rustc {
425    /// This is the compiler that we will *ship* in this dist step.
426    pub target_compiler: Compiler,
427}
428
429impl Step for Rustc {
430    type Output = GeneratedTarball;
431
432    const DEFAULT: bool = true;
433    const IS_HOST: bool = true;
434
435    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
436        run.alias("rustc")
437    }
438
439    fn make_run(run: RunConfig<'_>) {
440        run.builder.ensure(Rustc {
441            target_compiler: run.builder.compiler(run.builder.top_stage, run.target),
442        });
443    }
444
445    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
446        let target_compiler = self.target_compiler;
447        let target = self.target_compiler.host;
448
449        let tarball = Tarball::new(builder, "rustc", &target.triple);
450
451        // Prepare the rustc "image", what will actually end up getting installed
452        prepare_image(builder, target_compiler, tarball.image_dir());
453
454        // On MinGW we've got a few runtime DLL dependencies that we need to
455        // include.
456        // On 32-bit MinGW we're always including a DLL which needs some extra
457        // licenses to distribute. On 64-bit MinGW we don't actually distribute
458        // anything requiring us to distribute a license, but it's likely the
459        // install will *also* include the rust-mingw package, which also needs
460        // licenses, so to be safe we just include it here in all MinGW packages.
461        if target.contains("pc-windows-gnu") && builder.config.dist_include_mingw_linker {
462            runtime_dll_dist(tarball.image_dir(), target, builder);
463            tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc");
464        }
465
466        return tarball.generate();
467
468        fn prepare_image(builder: &Builder<'_>, target_compiler: Compiler, image: &Path) {
469            let target = target_compiler.host;
470            let src = builder.sysroot(target_compiler);
471
472            // Copy rustc binary
473            t!(fs::create_dir_all(image.join("bin")));
474            builder.cp_link_r(&src.join("bin"), &image.join("bin"));
475
476            // If enabled, copy rustdoc binary
477            if builder
478                .config
479                .tools
480                .as_ref()
481                .is_none_or(|tools| tools.iter().any(|tool| tool == "rustdoc"))
482            {
483                let rustdoc = builder.rustdoc_for_compiler(target_compiler);
484                builder.install(&rustdoc, &image.join("bin"), FileType::Executable);
485            }
486
487            let compilers = RustcPrivateCompilers::from_target_compiler(builder, target_compiler);
488
489            if let Some(ra_proc_macro_srv) = builder.ensure_if_default(
490                tool::RustAnalyzerProcMacroSrv::from_compilers(compilers),
491                builder.kind,
492            ) {
493                let dst = image.join("libexec");
494                builder.install(&ra_proc_macro_srv.tool_path, &dst, FileType::Executable);
495            }
496
497            let libdir_relative = builder.libdir_relative(target_compiler);
498
499            // Copy runtime DLLs needed by the compiler
500            if libdir_relative.to_str() != Some("bin") {
501                let libdir = builder.rustc_libdir(target_compiler);
502                for entry in builder.read_dir(&libdir) {
503                    // A safeguard that we will not ship libgccjit.so from the libdir, in case the
504                    // GCC codegen backend is enabled by default.
505                    // Long-term we should probably split the config options for:
506                    // - Include cg_gcc in the rustc sysroot by default
507                    // - Run dist of a specific codegen backend in `x dist` by default
508                    if is_dylib(&entry.path())
509                        && !entry
510                            .path()
511                            .file_name()
512                            .and_then(|n| n.to_str())
513                            .map(|n| n.contains("libgccjit"))
514                            .unwrap_or(false)
515                    {
516                        // Don't use custom libdir here because ^lib/ will be resolved again
517                        // with installer
518                        builder.install(&entry.path(), &image.join("lib"), FileType::NativeLibrary);
519                    }
520                }
521            }
522
523            // Copy libLLVM.so to the lib dir as well, if needed. While not
524            // technically needed by rustc itself it's needed by lots of other
525            // components like the llvm tools and LLD. LLD is included below and
526            // tools/LLDB come later, so let's just throw it in the rustc
527            // component for now.
528            maybe_install_llvm_runtime(builder, target, image);
529
530            let dst_dir = image.join("lib/rustlib").join(target).join("bin");
531            t!(fs::create_dir_all(&dst_dir));
532
533            // Copy over lld if it's there
534            if builder.config.lld_enabled {
535                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
536                let rust_lld = exe("rust-lld", target_compiler.host);
537                builder.copy_link(
538                    &src_dir.join(&rust_lld),
539                    &dst_dir.join(&rust_lld),
540                    FileType::Executable,
541                );
542                let self_contained_lld_src_dir = src_dir.join("gcc-ld");
543                let self_contained_lld_dst_dir = dst_dir.join("gcc-ld");
544                t!(fs::create_dir(&self_contained_lld_dst_dir));
545                for name in crate::LLD_FILE_NAMES {
546                    let exe_name = exe(name, target_compiler.host);
547                    builder.copy_link(
548                        &self_contained_lld_src_dir.join(&exe_name),
549                        &self_contained_lld_dst_dir.join(&exe_name),
550                        FileType::Executable,
551                    );
552                }
553            }
554
555            if builder.config.llvm_enabled(target_compiler.host)
556                && builder.config.llvm_tools_enabled
557            {
558                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
559                let llvm_objcopy = exe("llvm-objcopy", target_compiler.host);
560                let rust_objcopy = exe("rust-objcopy", target_compiler.host);
561                builder.copy_link(
562                    &src_dir.join(&llvm_objcopy),
563                    &dst_dir.join(&rust_objcopy),
564                    FileType::Executable,
565                );
566            }
567
568            if builder.tool_enabled("wasm-component-ld") {
569                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
570                let ld = exe("wasm-component-ld", target_compiler.host);
571                builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld), FileType::Executable);
572            }
573
574            // Man pages
575            t!(fs::create_dir_all(image.join("share/man/man1")));
576            let man_src = builder.src.join("src/doc/man");
577            let man_dst = image.join("share/man/man1");
578
579            // don't use our `bootstrap::{copy_internal, cp_r}`, because those try
580            // to hardlink, and we don't want to edit the source templates
581            for file_entry in builder.read_dir(&man_src) {
582                let page_src = file_entry.path();
583                let page_dst = man_dst.join(file_entry.file_name());
584                let src_text = t!(std::fs::read_to_string(&page_src));
585                let new_text = src_text.replace("<INSERT VERSION HERE>", &builder.version);
586                t!(std::fs::write(&page_dst, &new_text));
587                t!(fs::copy(&page_src, &page_dst));
588            }
589
590            // Debugger scripts
591            builder.ensure(DebuggerScripts { sysroot: image.to_owned(), target });
592
593            // HTML copyright files
594            let file_list = builder.ensure(super::run::GenerateCopyright);
595            for file in file_list {
596                builder.install(&file, &image.join("share/doc/rust"), FileType::Regular);
597            }
598
599            // README
600            builder.install(
601                &builder.src.join("README.md"),
602                &image.join("share/doc/rust"),
603                FileType::Regular,
604            );
605
606            // The REUSE-managed license files
607            let license = |path: &Path| {
608                builder.install(path, &image.join("share/doc/rust/licenses"), FileType::Regular);
609            };
610            for entry in t!(std::fs::read_dir(builder.src.join("LICENSES"))).flatten() {
611                license(&entry.path());
612            }
613        }
614    }
615
616    fn metadata(&self) -> Option<StepMetadata> {
617        Some(StepMetadata::dist("rustc", self.target_compiler.host))
618    }
619}
620
621/// Copies debugger scripts for `target` into the given compiler `sysroot`.
622#[derive(Debug, Clone, Hash, PartialEq, Eq)]
623pub struct DebuggerScripts {
624    /// Sysroot of a compiler into which will the debugger scripts be copied to.
625    pub sysroot: PathBuf,
626    pub target: TargetSelection,
627}
628
629impl Step for DebuggerScripts {
630    type Output = ();
631
632    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
633        run.never()
634    }
635
636    fn run(self, builder: &Builder<'_>) {
637        let target = self.target;
638        let sysroot = self.sysroot;
639        let dst = sysroot.join("lib/rustlib/etc");
640        t!(fs::create_dir_all(&dst));
641        let cp_debugger_script = |file: &str| {
642            builder.install(&builder.src.join("src/etc/").join(file), &dst, FileType::Regular);
643        };
644        if target.contains("windows-msvc") {
645            // windbg debugger scripts
646            builder.install(
647                &builder.src.join("src/etc/rust-windbg.cmd"),
648                &sysroot.join("bin"),
649                FileType::Script,
650            );
651
652            cp_debugger_script("natvis/intrinsic.natvis");
653            cp_debugger_script("natvis/liballoc.natvis");
654            cp_debugger_script("natvis/libcore.natvis");
655            cp_debugger_script("natvis/libstd.natvis");
656        }
657
658        cp_debugger_script("rust_types.py");
659
660        // gdb debugger scripts
661        builder.install(
662            &builder.src.join("src/etc/rust-gdb"),
663            &sysroot.join("bin"),
664            FileType::Script,
665        );
666        builder.install(
667            &builder.src.join("src/etc/rust-gdbgui"),
668            &sysroot.join("bin"),
669            FileType::Script,
670        );
671
672        cp_debugger_script("gdb_load_rust_pretty_printers.py");
673        cp_debugger_script("gdb_lookup.py");
674        cp_debugger_script("gdb_providers.py");
675
676        // lldb debugger scripts
677        builder.install(
678            &builder.src.join("src/etc/rust-lldb"),
679            &sysroot.join("bin"),
680            FileType::Script,
681        );
682
683        cp_debugger_script("lldb_lookup.py");
684        cp_debugger_script("lldb_providers.py");
685        cp_debugger_script("lldb_commands")
686    }
687}
688
689fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
690    // The only true set of target libraries came from the build triple, so
691    // let's reduce redundant work by only producing archives from that host.
692    if !builder.config.is_host_target(compiler.host) {
693        builder.info("\tskipping, not a build host");
694        true
695    } else {
696        false
697    }
698}
699
700/// Check that all objects in rlibs for UEFI targets are COFF. This
701/// ensures that the C compiler isn't producing ELF objects, which would
702/// not link correctly with the COFF objects.
703fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &BuildStamp) {
704    if !target.ends_with("-uefi") {
705        return;
706    }
707
708    for (path, _) in builder.read_stamp_file(stamp) {
709        if path.extension() != Some(OsStr::new("rlib")) {
710            continue;
711        }
712
713        let data = t!(fs::read(&path));
714        let data = data.as_slice();
715        let archive = t!(ArchiveFile::parse(data));
716        for member in archive.members() {
717            let member = t!(member);
718            let member_data = t!(member.data(data));
719
720            let is_coff = match object::File::parse(member_data) {
721                Ok(member_file) => member_file.format() == BinaryFormat::Coff,
722                Err(_) => false,
723            };
724
725            if !is_coff {
726                let member_name = String::from_utf8_lossy(member.name());
727                panic!("member {} in {} is not COFF", member_name, path.display());
728            }
729        }
730    }
731}
732
733/// Copy stamped files into an image's `target/lib` directory.
734fn copy_target_libs(
735    builder: &Builder<'_>,
736    target: TargetSelection,
737    image: &Path,
738    stamp: &BuildStamp,
739) {
740    let dst = image.join("lib/rustlib").join(target).join("lib");
741    let self_contained_dst = dst.join("self-contained");
742    t!(fs::create_dir_all(&dst));
743    t!(fs::create_dir_all(&self_contained_dst));
744    for (path, dependency_type) in builder.read_stamp_file(stamp) {
745        if dependency_type == DependencyType::TargetSelfContained {
746            builder.copy_link(
747                &path,
748                &self_contained_dst.join(path.file_name().unwrap()),
749                FileType::NativeLibrary,
750            );
751        } else if dependency_type == DependencyType::Target || builder.config.is_host_target(target)
752        {
753            builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::NativeLibrary);
754        }
755    }
756}
757
758/// Builds the standard library (`rust-std`) dist component for a given `target`.
759/// This includes the standard library dynamic library file (e.g. .so/.dll), along with stdlib
760/// .rlibs.
761///
762/// Note that due to uplifting, we actually ship the stage 1 library
763/// (built using the stage1 compiler) even with a stage 2 dist, unless `full-bootstrap` is enabled.
764#[derive(Debug, Clone, Hash, PartialEq, Eq)]
765pub struct Std {
766    /// Compiler that will build the standard library.
767    pub build_compiler: Compiler,
768    pub target: TargetSelection,
769}
770
771impl Std {
772    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
773        Std { build_compiler: builder.compiler_for_std(builder.top_stage), target }
774    }
775}
776
777impl Step for Std {
778    type Output = Option<GeneratedTarball>;
779    const DEFAULT: bool = true;
780
781    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
782        run.alias("rust-std")
783    }
784
785    fn make_run(run: RunConfig<'_>) {
786        run.builder.ensure(Std::new(run.builder, run.target));
787    }
788
789    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
790        let build_compiler = self.build_compiler;
791        let target = self.target;
792
793        if skip_host_target_lib(builder, build_compiler) {
794            return None;
795        }
796
797        // It's possible that std was uplifted and thus built with a different build compiler
798        // So we need to read the stamp that was actually generated when std was built
799        let stamp =
800            builder.std(build_compiler, target).expect("Standard library has to be built for dist");
801
802        let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
803        tarball.include_target_in_component_name(true);
804
805        verify_uefi_rlib_format(builder, target, &stamp);
806        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
807
808        Some(tarball.generate())
809    }
810
811    fn metadata(&self) -> Option<StepMetadata> {
812        Some(StepMetadata::dist("std", self.target).built_by(self.build_compiler))
813    }
814}
815
816/// Tarball containing the compiler that gets downloaded and used by
817/// `rust.download-rustc`.
818///
819/// (Don't confuse this with [`RustDev`], without the `c`!)
820#[derive(Debug, Clone, Hash, PartialEq, Eq)]
821pub struct RustcDev {
822    /// The compiler that will build rustc which will be shipped in this component.
823    build_compiler: Compiler,
824    target: TargetSelection,
825}
826
827impl RustcDev {
828    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
829        Self {
830            // We currently always ship a stage 2 rustc-dev component, so we build it with the
831            // stage 1 compiler. This might change in the future.
832            // The precise stage used here is important, so we hard-code it.
833            build_compiler: builder.compiler(1, builder.config.host_target),
834            target,
835        }
836    }
837}
838
839impl Step for RustcDev {
840    type Output = Option<GeneratedTarball>;
841    const DEFAULT: bool = true;
842    const IS_HOST: bool = true;
843
844    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
845        run.alias("rustc-dev")
846    }
847
848    fn make_run(run: RunConfig<'_>) {
849        run.builder.ensure(RustcDev::new(run.builder, run.target));
850    }
851
852    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
853        let build_compiler = self.build_compiler;
854        let target = self.target;
855        if skip_host_target_lib(builder, build_compiler) {
856            return None;
857        }
858
859        // Build the compiler that we will ship
860        builder.ensure(compile::Rustc::new(build_compiler, target));
861
862        let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
863
864        let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);
865        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
866
867        let src_files = &["Cargo.lock"];
868        // This is the reduced set of paths which will become the rustc-dev component
869        // (essentially the compiler crates and all of their path dependencies).
870        copy_src_dirs(
871            builder,
872            &builder.src,
873            // The compiler has a path dependency on proc_macro, so make sure to include it.
874            &["compiler", "library/proc_macro"],
875            &[],
876            &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
877        );
878        for file in src_files {
879            tarball.add_file(
880                builder.src.join(file),
881                "lib/rustlib/rustc-src/rust",
882                FileType::Regular,
883            );
884        }
885
886        Some(tarball.generate())
887    }
888
889    fn metadata(&self) -> Option<StepMetadata> {
890        Some(StepMetadata::dist("rustc-dev", self.target).built_by(self.build_compiler))
891    }
892}
893
894/// The `rust-analysis` component used to create a tarball of save-analysis metadata.
895///
896/// This component has been deprecated and its contents now only include a warning about
897/// its non-availability.
898#[derive(Debug, Clone, Hash, PartialEq, Eq)]
899pub struct Analysis {
900    build_compiler: Compiler,
901    target: TargetSelection,
902}
903
904impl Step for Analysis {
905    type Output = Option<GeneratedTarball>;
906
907    const DEFAULT: bool = true;
908
909    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
910        let default = should_build_extended_tool(run.builder, "analysis");
911        run.alias("rust-analysis").default_condition(default)
912    }
913
914    fn make_run(run: RunConfig<'_>) {
915        // The step just produces a deprecation notice, so we just hardcode stage 1
916        run.builder.ensure(Analysis {
917            build_compiler: run.builder.compiler(1, run.builder.config.host_target),
918            target: run.target,
919        });
920    }
921
922    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
923        let compiler = self.build_compiler;
924        let target = self.target;
925        if skip_host_target_lib(builder, compiler) {
926            return None;
927        }
928
929        let src = builder
930            .stage_out(compiler, Mode::Std)
931            .join(target)
932            .join(builder.cargo_dir())
933            .join("deps")
934            .join("save-analysis");
935
936        // Write a file indicating that this component has been removed.
937        t!(std::fs::create_dir_all(&src));
938        let mut removed = src.clone();
939        removed.push("removed.json");
940        let mut f = t!(std::fs::File::create(removed));
941        t!(write!(f, r#"{{ "warning": "The `rust-analysis` component has been removed." }}"#));
942
943        let mut tarball = Tarball::new(builder, "rust-analysis", &target.triple);
944        tarball.include_target_in_component_name(true);
945        tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple));
946        Some(tarball.generate())
947    }
948
949    fn metadata(&self) -> Option<StepMetadata> {
950        Some(StepMetadata::dist("analysis", self.target).built_by(self.build_compiler))
951    }
952}
953
954/// Use the `builder` to make a filtered copy of `base`/X for X in (`src_dirs` - `exclude_dirs`) to
955/// `dst_dir`.
956fn copy_src_dirs(
957    builder: &Builder<'_>,
958    base: &Path,
959    src_dirs: &[&str],
960    exclude_dirs: &[&str],
961    dst_dir: &Path,
962) {
963    // The src directories should be relative to `base`, we depend on them not being absolute
964    // paths below.
965    for src_dir in src_dirs {
966        assert!(Path::new(src_dir).is_relative());
967    }
968
969    // Iterating, filtering and copying a large number of directories can be quite slow.
970    // Avoid doing it in dry run (and thus also tests).
971    if builder.config.dry_run() {
972        return;
973    }
974
975    fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
976        // The paths are relative, e.g. `llvm-project/...`.
977        let spath = match path.to_str() {
978            Some(path) => path,
979            None => return false,
980        };
981        if spath.ends_with('~') || spath.ends_with(".pyc") {
982            return false;
983        }
984        // Normalize slashes
985        let spath = spath.replace("\\", "/");
986
987        static LLVM_PROJECTS: &[&str] = &[
988            "llvm-project/clang",
989            "llvm-project/libunwind",
990            "llvm-project/lld",
991            "llvm-project/lldb",
992            "llvm-project/llvm",
993            "llvm-project/compiler-rt",
994            "llvm-project/cmake",
995            "llvm-project/runtimes",
996            "llvm-project/third-party",
997        ];
998        if spath.starts_with("llvm-project") && spath != "llvm-project" {
999            if !LLVM_PROJECTS.iter().any(|path| spath.starts_with(path)) {
1000                return false;
1001            }
1002
1003            // Keep siphash third-party dependency
1004            if spath.starts_with("llvm-project/third-party")
1005                && spath != "llvm-project/third-party"
1006                && !spath.starts_with("llvm-project/third-party/siphash")
1007            {
1008                return false;
1009            }
1010
1011            if spath.starts_with("llvm-project/llvm/test")
1012                && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
1013            {
1014                return false;
1015            }
1016        }
1017
1018        // Cargo tests use some files like `.gitignore` that we would otherwise exclude.
1019        if spath.starts_with("tools/cargo/tests") {
1020            return true;
1021        }
1022
1023        if !exclude_dirs.is_empty() {
1024            let full_path = Path::new(dir).join(path);
1025            if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
1026                return false;
1027            }
1028        }
1029
1030        static EXCLUDES: &[&str] = &[
1031            "CVS",
1032            "RCS",
1033            "SCCS",
1034            ".git",
1035            ".gitignore",
1036            ".gitmodules",
1037            ".gitattributes",
1038            ".cvsignore",
1039            ".svn",
1040            ".arch-ids",
1041            "{arch}",
1042            "=RELEASE-ID",
1043            "=meta-update",
1044            "=update",
1045            ".bzr",
1046            ".bzrignore",
1047            ".bzrtags",
1048            ".hg",
1049            ".hgignore",
1050            ".hgrags",
1051            "_darcs",
1052        ];
1053
1054        // We want to check if any component of `path` doesn't contain the strings in `EXCLUDES`.
1055        // However, since we traverse directories top-down in `Builder::cp_link_filtered`,
1056        // it is enough to always check only the last component:
1057        // - If the path is a file, we will iterate to it and then check it's filename
1058        // - If the path is a dir, if it's dir name contains an excluded string, we will not even
1059        //   recurse into it.
1060        let last_component = path.iter().next_back().map(|s| s.to_str().unwrap()).unwrap();
1061        !EXCLUDES.contains(&last_component)
1062    }
1063
1064    // Copy the directories using our filter
1065    for item in src_dirs {
1066        let dst = &dst_dir.join(item);
1067        t!(fs::create_dir_all(dst));
1068        builder
1069            .cp_link_filtered(&base.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
1070    }
1071}
1072
1073#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1074pub struct Src;
1075
1076impl Step for Src {
1077    /// The output path of the src installer tarball
1078    type Output = GeneratedTarball;
1079    const DEFAULT: bool = true;
1080    const IS_HOST: bool = true;
1081
1082    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1083        run.alias("rust-src")
1084    }
1085
1086    fn make_run(run: RunConfig<'_>) {
1087        run.builder.ensure(Src);
1088    }
1089
1090    /// Creates the `rust-src` installer component
1091    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1092        if !builder.config.dry_run() {
1093            builder.require_submodule("src/llvm-project", None);
1094        }
1095
1096        let tarball = Tarball::new_targetless(builder, "rust-src");
1097
1098        // A lot of tools expect the rust-src component to be entirely in this directory, so if you
1099        // change that (e.g. by adding another directory `lib/rustlib/src/foo` or
1100        // `lib/rustlib/src/rust/foo`), you will need to go around hunting for implicit assumptions
1101        // and fix them...
1102        //
1103        // NOTE: if you update the paths here, you also should update the "virtual" path
1104        // translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs`
1105        let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
1106
1107        // This is the reduced set of paths which will become the rust-src component
1108        // (essentially libstd and all of its path dependencies).
1109        copy_src_dirs(
1110            builder,
1111            &builder.src,
1112            &["library", "src/llvm-project/libunwind"],
1113            &[
1114                // not needed and contains symlinks which rustup currently
1115                // chokes on when unpacking.
1116                "library/backtrace/crates",
1117                // these are 30MB combined and aren't necessary for building
1118                // the standard library.
1119                "library/stdarch/Cargo.toml",
1120                "library/stdarch/crates/stdarch-verify",
1121                "library/stdarch/crates/intrinsic-test",
1122            ],
1123            &dst_src,
1124        );
1125
1126        tarball.generate()
1127    }
1128
1129    fn metadata(&self) -> Option<StepMetadata> {
1130        Some(StepMetadata::dist("src", TargetSelection::default()))
1131    }
1132}
1133
1134#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1135pub struct PlainSourceTarball;
1136
1137impl Step for PlainSourceTarball {
1138    /// Produces the location of the tarball generated
1139    type Output = GeneratedTarball;
1140    const DEFAULT: bool = true;
1141    const IS_HOST: bool = true;
1142
1143    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1144        let builder = run.builder;
1145        run.alias("rustc-src").default_condition(builder.config.rust_dist_src)
1146    }
1147
1148    fn make_run(run: RunConfig<'_>) {
1149        run.builder.ensure(PlainSourceTarball);
1150    }
1151
1152    /// Creates the plain source tarball
1153    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1154        // NOTE: This is a strange component in a lot of ways. It uses `src` as the target, which
1155        // means neither rustup nor rustup-toolchain-install-master know how to download it.
1156        // It also contains symbolic links, unlike other any other dist tarball.
1157        // It's used for distros building rustc from source in a pre-vendored environment.
1158        let mut tarball = Tarball::new(builder, "rustc", "src");
1159        tarball.permit_symlinks(true);
1160        let plain_dst_src = tarball.image_dir();
1161
1162        // This is the set of root paths which will become part of the source package
1163        let src_files = [
1164            // tidy-alphabetical-start
1165            ".gitmodules",
1166            "CONTRIBUTING.md",
1167            "COPYRIGHT",
1168            "Cargo.lock",
1169            "Cargo.toml",
1170            "LICENSE-APACHE",
1171            "LICENSE-MIT",
1172            "README.md",
1173            "RELEASES.md",
1174            "REUSE.toml",
1175            "bootstrap.example.toml",
1176            "configure",
1177            "license-metadata.json",
1178            "package-lock.json",
1179            "package.json",
1180            "x",
1181            "x.ps1",
1182            "x.py",
1183            // tidy-alphabetical-end
1184        ];
1185        let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"];
1186
1187        copy_src_dirs(
1188            builder,
1189            &builder.src,
1190            &src_dirs,
1191            &[
1192                // We don't currently use the GCC source code for building any official components,
1193                // it is very big, and has unclear licensing implications due to being GPL licensed.
1194                // We thus exclude it from the source tarball from now.
1195                "src/gcc",
1196            ],
1197            plain_dst_src,
1198        );
1199        // We keep something in src/gcc because it is a registered submodule,
1200        // and if it misses completely it can cause issues elsewhere
1201        // (see https://github.com/rust-lang/rust/issues/137332).
1202        // We can also let others know why is the source code missing.
1203        if !builder.config.dry_run() {
1204            builder.create_dir(&plain_dst_src.join("src/gcc"));
1205            t!(std::fs::write(
1206                plain_dst_src.join("src/gcc/notice.txt"),
1207                "The GCC source code is not included due to unclear licensing implications\n"
1208            ));
1209        }
1210
1211        // Copy the files normally
1212        for item in &src_files {
1213            builder.copy_link(
1214                &builder.src.join(item),
1215                &plain_dst_src.join(item),
1216                FileType::Regular,
1217            );
1218        }
1219
1220        // Create the version file
1221        builder.create(&plain_dst_src.join("version"), &builder.rust_version());
1222
1223        // Create the files containing git info, to ensure --version outputs the same.
1224        let write_git_info = |info: Option<&Info>, path: &Path| {
1225            if let Some(info) = info {
1226                t!(std::fs::create_dir_all(path));
1227                channel::write_commit_hash_file(path, &info.sha);
1228                channel::write_commit_info_file(path, info);
1229            }
1230        };
1231        write_git_info(builder.rust_info().info(), plain_dst_src);
1232        write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo"));
1233
1234        if builder.config.dist_vendor {
1235            builder.require_and_update_all_submodules();
1236
1237            // Vendor packages that are required by opt-dist to collect PGO profiles.
1238            let pkgs_for_pgo_training = build_helper::LLVM_PGO_CRATES
1239                .iter()
1240                .chain(build_helper::RUSTC_PGO_CRATES)
1241                .map(|pkg| {
1242                    let mut manifest_path =
1243                        builder.src.join("./src/tools/rustc-perf/collector/compile-benchmarks");
1244                    manifest_path.push(pkg);
1245                    manifest_path.push("Cargo.toml");
1246                    manifest_path
1247                });
1248
1249            // Vendor all Cargo dependencies
1250            let vendor = builder.ensure(Vendor {
1251                sync_args: pkgs_for_pgo_training.collect(),
1252                versioned_dirs: true,
1253                root_dir: plain_dst_src.into(),
1254                output_dir: VENDOR_DIR.into(),
1255            });
1256
1257            let cargo_config_dir = plain_dst_src.join(".cargo");
1258            builder.create_dir(&cargo_config_dir);
1259            builder.create(&cargo_config_dir.join("config.toml"), &vendor.config);
1260        }
1261
1262        // Delete extraneous directories
1263        // FIXME: if we're managed by git, we should probably instead ask git if the given path
1264        // is managed by it?
1265        for entry in walkdir::WalkDir::new(tarball.image_dir())
1266            .follow_links(true)
1267            .into_iter()
1268            .filter_map(|e| e.ok())
1269        {
1270            if entry.path().is_dir() && entry.path().file_name() == Some(OsStr::new("__pycache__"))
1271            {
1272                t!(fs::remove_dir_all(entry.path()));
1273            }
1274        }
1275
1276        tarball.bare()
1277    }
1278}
1279
1280#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1281pub struct Cargo {
1282    pub build_compiler: Compiler,
1283    pub target: TargetSelection,
1284}
1285
1286impl Step for Cargo {
1287    type Output = Option<GeneratedTarball>;
1288    const DEFAULT: bool = true;
1289    const IS_HOST: bool = true;
1290
1291    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1292        let default = should_build_extended_tool(run.builder, "cargo");
1293        run.alias("cargo").default_condition(default)
1294    }
1295
1296    fn make_run(run: RunConfig<'_>) {
1297        run.builder.ensure(Cargo {
1298            build_compiler: get_tool_target_compiler(
1299                run.builder,
1300                ToolTargetBuildMode::Build(run.target),
1301            ),
1302            target: run.target,
1303        });
1304    }
1305
1306    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1307        let build_compiler = self.build_compiler;
1308        let target = self.target;
1309
1310        let cargo = builder.ensure(tool::Cargo::from_build_compiler(build_compiler, target));
1311        let src = builder.src.join("src/tools/cargo");
1312        let etc = src.join("src/etc");
1313
1314        // Prepare the image directory
1315        let mut tarball = Tarball::new(builder, "cargo", &target.triple);
1316        tarball.set_overlay(OverlayKind::Cargo);
1317
1318        tarball.add_file(&cargo.tool_path, "bin", FileType::Executable);
1319        tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", FileType::Regular);
1320        tarball.add_renamed_file(
1321            etc.join("cargo.bashcomp.sh"),
1322            "etc/bash_completion.d",
1323            "cargo",
1324            FileType::Regular,
1325        );
1326        tarball.add_dir(etc.join("man"), "share/man/man1");
1327        tarball.add_legal_and_readme_to("share/doc/cargo");
1328
1329        Some(tarball.generate())
1330    }
1331
1332    fn metadata(&self) -> Option<StepMetadata> {
1333        Some(StepMetadata::dist("cargo", self.target).built_by(self.build_compiler))
1334    }
1335}
1336
1337/// Distribute the rust-analyzer component, which is used as a LSP by various IDEs.
1338#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1339pub struct RustAnalyzer {
1340    pub compilers: RustcPrivateCompilers,
1341    pub target: TargetSelection,
1342}
1343
1344impl Step for RustAnalyzer {
1345    type Output = Option<GeneratedTarball>;
1346    const DEFAULT: bool = true;
1347    const IS_HOST: bool = true;
1348
1349    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1350        let default = should_build_extended_tool(run.builder, "rust-analyzer");
1351        run.alias("rust-analyzer").default_condition(default)
1352    }
1353
1354    fn make_run(run: RunConfig<'_>) {
1355        run.builder.ensure(RustAnalyzer {
1356            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1357            target: run.target,
1358        });
1359    }
1360
1361    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1362        let target = self.target;
1363        let rust_analyzer = builder.ensure(tool::RustAnalyzer::from_compilers(self.compilers));
1364
1365        let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
1366        tarball.set_overlay(OverlayKind::RustAnalyzer);
1367        tarball.is_preview(true);
1368        tarball.add_file(&rust_analyzer.tool_path, "bin", FileType::Executable);
1369        tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
1370        Some(tarball.generate())
1371    }
1372
1373    fn metadata(&self) -> Option<StepMetadata> {
1374        Some(
1375            StepMetadata::dist("rust-analyzer", self.target)
1376                .built_by(self.compilers.build_compiler()),
1377        )
1378    }
1379}
1380
1381#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1382pub struct Clippy {
1383    pub compilers: RustcPrivateCompilers,
1384    pub target: TargetSelection,
1385}
1386
1387impl Step for Clippy {
1388    type Output = Option<GeneratedTarball>;
1389    const DEFAULT: bool = true;
1390    const IS_HOST: bool = true;
1391
1392    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1393        let default = should_build_extended_tool(run.builder, "clippy");
1394        run.alias("clippy").default_condition(default)
1395    }
1396
1397    fn make_run(run: RunConfig<'_>) {
1398        run.builder.ensure(Clippy {
1399            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1400            target: run.target,
1401        });
1402    }
1403
1404    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1405        let target = self.target;
1406
1407        // Prepare the image directory
1408        // We expect clippy to build, because we've exited this step above if tool
1409        // state for clippy isn't testing.
1410        let clippy = builder.ensure(tool::Clippy::from_compilers(self.compilers));
1411        let cargoclippy = builder.ensure(tool::CargoClippy::from_compilers(self.compilers));
1412
1413        let mut tarball = Tarball::new(builder, "clippy", &target.triple);
1414        tarball.set_overlay(OverlayKind::Clippy);
1415        tarball.is_preview(true);
1416        tarball.add_file(&clippy.tool_path, "bin", FileType::Executable);
1417        tarball.add_file(&cargoclippy.tool_path, "bin", FileType::Executable);
1418        tarball.add_legal_and_readme_to("share/doc/clippy");
1419        Some(tarball.generate())
1420    }
1421
1422    fn metadata(&self) -> Option<StepMetadata> {
1423        Some(StepMetadata::dist("clippy", self.target).built_by(self.compilers.build_compiler()))
1424    }
1425}
1426
1427#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1428pub struct Miri {
1429    pub compilers: RustcPrivateCompilers,
1430    pub target: TargetSelection,
1431}
1432
1433impl Step for Miri {
1434    type Output = Option<GeneratedTarball>;
1435    const DEFAULT: bool = true;
1436    const IS_HOST: bool = true;
1437
1438    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1439        let default = should_build_extended_tool(run.builder, "miri");
1440        run.alias("miri").default_condition(default)
1441    }
1442
1443    fn make_run(run: RunConfig<'_>) {
1444        run.builder.ensure(Miri {
1445            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1446            target: run.target,
1447        });
1448    }
1449
1450    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1451        // This prevents miri from being built for "dist" or "install"
1452        // on the stable/beta channels. It is a nightly-only tool and should
1453        // not be included.
1454        if !builder.build.unstable_features() {
1455            return None;
1456        }
1457
1458        let miri = builder.ensure(tool::Miri::from_compilers(self.compilers));
1459        let cargomiri = builder.ensure(tool::CargoMiri::from_compilers(self.compilers));
1460
1461        let mut tarball = Tarball::new(builder, "miri", &self.target.triple);
1462        tarball.set_overlay(OverlayKind::Miri);
1463        tarball.is_preview(true);
1464        tarball.add_file(&miri.tool_path, "bin", FileType::Executable);
1465        tarball.add_file(&cargomiri.tool_path, "bin", FileType::Executable);
1466        tarball.add_legal_and_readme_to("share/doc/miri");
1467        Some(tarball.generate())
1468    }
1469
1470    fn metadata(&self) -> Option<StepMetadata> {
1471        Some(StepMetadata::dist("miri", self.target).built_by(self.compilers.build_compiler()))
1472    }
1473}
1474
1475#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1476pub struct CraneliftCodegenBackend {
1477    pub compilers: RustcPrivateCompilers,
1478    pub target: TargetSelection,
1479}
1480
1481impl Step for CraneliftCodegenBackend {
1482    type Output = Option<GeneratedTarball>;
1483    const DEFAULT: bool = true;
1484    const IS_HOST: bool = true;
1485
1486    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1487        // We only want to build the cranelift backend in `x dist` if the backend was enabled
1488        // in rust.codegen-backends.
1489        // Sadly, we don't have access to the actual target for which we're disting clif here..
1490        // So we just use the host target.
1491        let clif_enabled_by_default = run
1492            .builder
1493            .config
1494            .enabled_codegen_backends(run.builder.host_target)
1495            .contains(&CodegenBackendKind::Cranelift);
1496        run.alias("rustc_codegen_cranelift").default_condition(clif_enabled_by_default)
1497    }
1498
1499    fn make_run(run: RunConfig<'_>) {
1500        run.builder.ensure(CraneliftCodegenBackend {
1501            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1502            target: run.target,
1503        });
1504    }
1505
1506    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1507        // This prevents rustc_codegen_cranelift from being built for "dist"
1508        // or "install" on the stable/beta channels. It is not yet stable and
1509        // should not be included.
1510        if !builder.build.unstable_features() {
1511            return None;
1512        }
1513
1514        let target = self.target;
1515        if !target_supports_cranelift_backend(target) {
1516            builder.info("target not supported by rustc_codegen_cranelift. skipping");
1517            return None;
1518        }
1519
1520        let mut tarball = Tarball::new(builder, "rustc-codegen-cranelift", &target.triple);
1521        tarball.set_overlay(OverlayKind::RustcCodegenCranelift);
1522        tarball.is_preview(true);
1523        tarball.add_legal_and_readme_to("share/doc/rustc_codegen_cranelift");
1524
1525        let compilers = self.compilers;
1526        let stamp = builder.ensure(compile::CraneliftCodegenBackend { compilers });
1527
1528        if builder.config.dry_run() {
1529            return None;
1530        }
1531
1532        // Get the relative path of where the codegen backend should be stored.
1533        let backends_dst = builder.sysroot_codegen_backends(compilers.target_compiler());
1534        let backends_rel = backends_dst
1535            .strip_prefix(builder.sysroot(compilers.target_compiler()))
1536            .unwrap()
1537            .strip_prefix(builder.sysroot_libdir_relative(compilers.target_compiler()))
1538            .unwrap();
1539        // Don't use custom libdir here because ^lib/ will be resolved again with installer
1540        let backends_dst = PathBuf::from("lib").join(backends_rel);
1541
1542        let codegen_backend_dylib = get_codegen_backend_file(&stamp);
1543        tarball.add_renamed_file(
1544            &codegen_backend_dylib,
1545            &backends_dst,
1546            &normalize_codegen_backend_name(builder, &codegen_backend_dylib),
1547            FileType::NativeLibrary,
1548        );
1549
1550        Some(tarball.generate())
1551    }
1552
1553    fn metadata(&self) -> Option<StepMetadata> {
1554        Some(
1555            StepMetadata::dist("rustc_codegen_cranelift", self.target)
1556                .built_by(self.compilers.build_compiler()),
1557        )
1558    }
1559}
1560
1561#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1562pub struct Rustfmt {
1563    pub compilers: RustcPrivateCompilers,
1564    pub target: TargetSelection,
1565}
1566
1567impl Step for Rustfmt {
1568    type Output = Option<GeneratedTarball>;
1569    const DEFAULT: bool = true;
1570    const IS_HOST: bool = true;
1571
1572    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1573        let default = should_build_extended_tool(run.builder, "rustfmt");
1574        run.alias("rustfmt").default_condition(default)
1575    }
1576
1577    fn make_run(run: RunConfig<'_>) {
1578        run.builder.ensure(Rustfmt {
1579            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1580            target: run.target,
1581        });
1582    }
1583
1584    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1585        let rustfmt = builder.ensure(tool::Rustfmt::from_compilers(self.compilers));
1586        let cargofmt = builder.ensure(tool::Cargofmt::from_compilers(self.compilers));
1587
1588        let mut tarball = Tarball::new(builder, "rustfmt", &self.target.triple);
1589        tarball.set_overlay(OverlayKind::Rustfmt);
1590        tarball.is_preview(true);
1591        tarball.add_file(&rustfmt.tool_path, "bin", FileType::Executable);
1592        tarball.add_file(&cargofmt.tool_path, "bin", FileType::Executable);
1593        tarball.add_legal_and_readme_to("share/doc/rustfmt");
1594        Some(tarball.generate())
1595    }
1596
1597    fn metadata(&self) -> Option<StepMetadata> {
1598        Some(StepMetadata::dist("rustfmt", self.target).built_by(self.compilers.build_compiler()))
1599    }
1600}
1601
1602/// Extended archive that contains the compiler, standard library and a bunch of tools.
1603#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1604pub struct Extended {
1605    build_compiler: Compiler,
1606    target: TargetSelection,
1607}
1608
1609impl Step for Extended {
1610    type Output = ();
1611    const DEFAULT: bool = true;
1612    const IS_HOST: bool = true;
1613
1614    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1615        let builder = run.builder;
1616        run.alias("extended").default_condition(builder.config.extended)
1617    }
1618
1619    fn make_run(run: RunConfig<'_>) {
1620        run.builder.ensure(Extended {
1621            build_compiler: run
1622                .builder
1623                .compiler(run.builder.top_stage - 1, run.builder.host_target),
1624            target: run.target,
1625        });
1626    }
1627
1628    /// Creates a combined installer for the specified target in the provided stage.
1629    fn run(self, builder: &Builder<'_>) {
1630        let target = self.target;
1631        builder.info(&format!("Dist extended stage{} ({target})", builder.top_stage));
1632
1633        let mut tarballs = Vec::new();
1634        let mut built_tools = HashSet::new();
1635        macro_rules! add_component {
1636            ($name:expr => $step:expr) => {
1637                if let Some(Some(tarball)) = builder.ensure_if_default($step, Kind::Dist) {
1638                    tarballs.push(tarball);
1639                    built_tools.insert($name);
1640                }
1641            };
1642        }
1643
1644        let rustc_private_compilers =
1645            RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target);
1646        let build_compiler = rustc_private_compilers.build_compiler();
1647        let target_compiler = rustc_private_compilers.target_compiler();
1648
1649        // When rust-std package split from rustc, we needed to ensure that during
1650        // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1651        // the std files during uninstall. To do this ensure that rustc comes
1652        // before rust-std in the list below.
1653        tarballs.push(builder.ensure(Rustc { target_compiler }));
1654        tarballs.push(builder.ensure(Std { build_compiler, target }).expect("missing std"));
1655
1656        if target.is_windows_gnu() {
1657            tarballs.push(builder.ensure(Mingw { target }).expect("missing mingw"));
1658        }
1659
1660        add_component!("rust-docs" => Docs { host: target });
1661        // Std stage N is documented with compiler stage N
1662        add_component!("rust-json-docs" => JsonDocs { build_compiler: target_compiler, target });
1663        add_component!("cargo" => Cargo { build_compiler, target });
1664        add_component!("rustfmt" => Rustfmt { compilers: rustc_private_compilers, target });
1665        add_component!("rust-analyzer" => RustAnalyzer { compilers: rustc_private_compilers, target });
1666        add_component!("llvm-components" => LlvmTools { target });
1667        add_component!("clippy" => Clippy { compilers: rustc_private_compilers, target });
1668        add_component!("miri" => Miri { compilers: rustc_private_compilers, target });
1669        add_component!("analysis" => Analysis { build_compiler, target });
1670        add_component!("rustc-codegen-cranelift" => CraneliftCodegenBackend {
1671            compilers: rustc_private_compilers,
1672            target
1673        });
1674        add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {
1675            build_compiler,
1676            target
1677        });
1678
1679        let etc = builder.src.join("src/etc/installer");
1680
1681        // Avoid producing tarballs during a dry run.
1682        if builder.config.dry_run() {
1683            return;
1684        }
1685
1686        let tarball = Tarball::new(builder, "rust", &target.triple);
1687        let generated = tarball.combine(&tarballs);
1688
1689        let tmp = tmpdir(builder).join("combined-tarball");
1690        let work = generated.work_dir();
1691
1692        let mut license = String::new();
1693        license += &builder.read(&builder.src.join("COPYRIGHT"));
1694        license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1695        license += &builder.read(&builder.src.join("LICENSE-MIT"));
1696        license.push('\n');
1697        license.push('\n');
1698
1699        let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1700        let mut rtf = rtf.to_string();
1701        rtf.push('\n');
1702        for line in license.lines() {
1703            rtf.push_str(line);
1704            rtf.push_str("\\line ");
1705        }
1706        rtf.push('}');
1707
1708        fn filter(contents: &str, marker: &str) -> String {
1709            let start = format!("tool-{marker}-start");
1710            let end = format!("tool-{marker}-end");
1711            let mut lines = Vec::new();
1712            let mut omitted = false;
1713            for line in contents.lines() {
1714                if line.contains(&start) {
1715                    omitted = true;
1716                } else if line.contains(&end) {
1717                    omitted = false;
1718                } else if !omitted {
1719                    lines.push(line);
1720                }
1721            }
1722
1723            lines.join("\n")
1724        }
1725
1726        let xform = |p: &Path| {
1727            let mut contents = t!(fs::read_to_string(p));
1728            for tool in &["miri", "rust-docs"] {
1729                if !built_tools.contains(tool) {
1730                    contents = filter(&contents, tool);
1731                }
1732            }
1733            let ret = tmp.join(p.file_name().unwrap());
1734            t!(fs::write(&ret, &contents));
1735            ret
1736        };
1737
1738        if target.contains("apple-darwin") {
1739            builder.info("building pkg installer");
1740            let pkg = tmp.join("pkg");
1741            let _ = fs::remove_dir_all(&pkg);
1742
1743            let pkgbuild = |component: &str| {
1744                let mut cmd = command("pkgbuild");
1745                cmd.arg("--identifier")
1746                    .arg(format!("org.rust-lang.{component}"))
1747                    .arg("--scripts")
1748                    .arg(pkg.join(component))
1749                    .arg("--nopayload")
1750                    .arg(pkg.join(component).with_extension("pkg"));
1751                cmd.run(builder);
1752            };
1753
1754            let prepare = |name: &str| {
1755                builder.create_dir(&pkg.join(name));
1756                builder.cp_link_r(
1757                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)),
1758                    &pkg.join(name),
1759                );
1760                builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), FileType::Script);
1761                pkgbuild(name);
1762            };
1763            prepare("rustc");
1764            prepare("cargo");
1765            prepare("rust-std");
1766            prepare("rust-analysis");
1767
1768            for tool in &[
1769                "clippy",
1770                "rustfmt",
1771                "rust-analyzer",
1772                "rust-docs",
1773                "miri",
1774                "rustc-codegen-cranelift",
1775            ] {
1776                if built_tools.contains(tool) {
1777                    prepare(tool);
1778                }
1779            }
1780            // create an 'uninstall' package
1781            builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), FileType::Script);
1782            pkgbuild("uninstall");
1783
1784            builder.create_dir(&pkg.join("res"));
1785            builder.create(&pkg.join("res/LICENSE.txt"), &license);
1786            builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), FileType::Regular);
1787            let mut cmd = command("productbuild");
1788            cmd.arg("--distribution")
1789                .arg(xform(&etc.join("pkg/Distribution.xml")))
1790                .arg("--resources")
1791                .arg(pkg.join("res"))
1792                .arg(distdir(builder).join(format!(
1793                    "{}-{}.pkg",
1794                    pkgname(builder, "rust"),
1795                    target.triple
1796                )))
1797                .arg("--package-path")
1798                .arg(&pkg);
1799            let _time = timeit(builder);
1800            cmd.run(builder);
1801        }
1802
1803        // FIXME(mati865): `gnullvm` here is temporary, remove it once it can host itself
1804        if target.is_windows() && !target.contains("gnullvm") {
1805            let exe = tmp.join("exe");
1806            let _ = fs::remove_dir_all(&exe);
1807
1808            let prepare = |name: &str| {
1809                builder.create_dir(&exe.join(name));
1810                let dir = if name == "rust-std" || name == "rust-analysis" {
1811                    format!("{}-{}", name, target.triple)
1812                } else if name == "rust-analyzer" {
1813                    "rust-analyzer-preview".to_string()
1814                } else if name == "clippy" {
1815                    "clippy-preview".to_string()
1816                } else if name == "rustfmt" {
1817                    "rustfmt-preview".to_string()
1818                } else if name == "miri" {
1819                    "miri-preview".to_string()
1820                } else if name == "rustc-codegen-cranelift" {
1821                    // FIXME add installer support for cg_clif once it is ready to be distributed on
1822                    // windows.
1823                    unreachable!("cg_clif shouldn't be built for windows");
1824                } else {
1825                    name.to_string()
1826                };
1827                builder.cp_link_r(
1828                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
1829                    &exe.join(name),
1830                );
1831                builder.remove(&exe.join(name).join("manifest.in"));
1832            };
1833            prepare("rustc");
1834            prepare("cargo");
1835            prepare("rust-analysis");
1836            prepare("rust-std");
1837            for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] {
1838                if built_tools.contains(tool) {
1839                    prepare(tool);
1840                }
1841            }
1842            if target.is_windows_gnu() {
1843                prepare("rust-mingw");
1844            }
1845
1846            builder.install(&etc.join("gfx/rust-logo.ico"), &exe, FileType::Regular);
1847
1848            // Generate msi installer
1849            let wix_path = env::var_os("WIX")
1850                .expect("`WIX` environment variable must be set for generating MSI installer(s).");
1851            let wix = PathBuf::from(wix_path);
1852            let heat = wix.join("bin/heat.exe");
1853            let candle = wix.join("bin/candle.exe");
1854            let light = wix.join("bin/light.exe");
1855
1856            let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1857            command(&heat)
1858                .current_dir(&exe)
1859                .arg("dir")
1860                .arg("rustc")
1861                .args(heat_flags)
1862                .arg("-cg")
1863                .arg("RustcGroup")
1864                .arg("-dr")
1865                .arg("Rustc")
1866                .arg("-var")
1867                .arg("var.RustcDir")
1868                .arg("-out")
1869                .arg(exe.join("RustcGroup.wxs"))
1870                .run(builder);
1871            if built_tools.contains("rust-docs") {
1872                command(&heat)
1873                    .current_dir(&exe)
1874                    .arg("dir")
1875                    .arg("rust-docs")
1876                    .args(heat_flags)
1877                    .arg("-cg")
1878                    .arg("DocsGroup")
1879                    .arg("-dr")
1880                    .arg("Docs")
1881                    .arg("-var")
1882                    .arg("var.DocsDir")
1883                    .arg("-out")
1884                    .arg(exe.join("DocsGroup.wxs"))
1885                    .arg("-t")
1886                    .arg(etc.join("msi/squash-components.xsl"))
1887                    .run(builder);
1888            }
1889            command(&heat)
1890                .current_dir(&exe)
1891                .arg("dir")
1892                .arg("cargo")
1893                .args(heat_flags)
1894                .arg("-cg")
1895                .arg("CargoGroup")
1896                .arg("-dr")
1897                .arg("Cargo")
1898                .arg("-var")
1899                .arg("var.CargoDir")
1900                .arg("-out")
1901                .arg(exe.join("CargoGroup.wxs"))
1902                .arg("-t")
1903                .arg(etc.join("msi/remove-duplicates.xsl"))
1904                .run(builder);
1905            command(&heat)
1906                .current_dir(&exe)
1907                .arg("dir")
1908                .arg("rust-std")
1909                .args(heat_flags)
1910                .arg("-cg")
1911                .arg("StdGroup")
1912                .arg("-dr")
1913                .arg("Std")
1914                .arg("-var")
1915                .arg("var.StdDir")
1916                .arg("-out")
1917                .arg(exe.join("StdGroup.wxs"))
1918                .run(builder);
1919            if built_tools.contains("rust-analyzer") {
1920                command(&heat)
1921                    .current_dir(&exe)
1922                    .arg("dir")
1923                    .arg("rust-analyzer")
1924                    .args(heat_flags)
1925                    .arg("-cg")
1926                    .arg("RustAnalyzerGroup")
1927                    .arg("-dr")
1928                    .arg("RustAnalyzer")
1929                    .arg("-var")
1930                    .arg("var.RustAnalyzerDir")
1931                    .arg("-out")
1932                    .arg(exe.join("RustAnalyzerGroup.wxs"))
1933                    .arg("-t")
1934                    .arg(etc.join("msi/remove-duplicates.xsl"))
1935                    .run(builder);
1936            }
1937            if built_tools.contains("clippy") {
1938                command(&heat)
1939                    .current_dir(&exe)
1940                    .arg("dir")
1941                    .arg("clippy")
1942                    .args(heat_flags)
1943                    .arg("-cg")
1944                    .arg("ClippyGroup")
1945                    .arg("-dr")
1946                    .arg("Clippy")
1947                    .arg("-var")
1948                    .arg("var.ClippyDir")
1949                    .arg("-out")
1950                    .arg(exe.join("ClippyGroup.wxs"))
1951                    .arg("-t")
1952                    .arg(etc.join("msi/remove-duplicates.xsl"))
1953                    .run(builder);
1954            }
1955            if built_tools.contains("rustfmt") {
1956                command(&heat)
1957                    .current_dir(&exe)
1958                    .arg("dir")
1959                    .arg("rustfmt")
1960                    .args(heat_flags)
1961                    .arg("-cg")
1962                    .arg("RustFmtGroup")
1963                    .arg("-dr")
1964                    .arg("RustFmt")
1965                    .arg("-var")
1966                    .arg("var.RustFmtDir")
1967                    .arg("-out")
1968                    .arg(exe.join("RustFmtGroup.wxs"))
1969                    .arg("-t")
1970                    .arg(etc.join("msi/remove-duplicates.xsl"))
1971                    .run(builder);
1972            }
1973            if built_tools.contains("miri") {
1974                command(&heat)
1975                    .current_dir(&exe)
1976                    .arg("dir")
1977                    .arg("miri")
1978                    .args(heat_flags)
1979                    .arg("-cg")
1980                    .arg("MiriGroup")
1981                    .arg("-dr")
1982                    .arg("Miri")
1983                    .arg("-var")
1984                    .arg("var.MiriDir")
1985                    .arg("-out")
1986                    .arg(exe.join("MiriGroup.wxs"))
1987                    .arg("-t")
1988                    .arg(etc.join("msi/remove-duplicates.xsl"))
1989                    .run(builder);
1990            }
1991            command(&heat)
1992                .current_dir(&exe)
1993                .arg("dir")
1994                .arg("rust-analysis")
1995                .args(heat_flags)
1996                .arg("-cg")
1997                .arg("AnalysisGroup")
1998                .arg("-dr")
1999                .arg("Analysis")
2000                .arg("-var")
2001                .arg("var.AnalysisDir")
2002                .arg("-out")
2003                .arg(exe.join("AnalysisGroup.wxs"))
2004                .arg("-t")
2005                .arg(etc.join("msi/remove-duplicates.xsl"))
2006                .run(builder);
2007            if target.is_windows_gnu() {
2008                command(&heat)
2009                    .current_dir(&exe)
2010                    .arg("dir")
2011                    .arg("rust-mingw")
2012                    .args(heat_flags)
2013                    .arg("-cg")
2014                    .arg("GccGroup")
2015                    .arg("-dr")
2016                    .arg("Gcc")
2017                    .arg("-var")
2018                    .arg("var.GccDir")
2019                    .arg("-out")
2020                    .arg(exe.join("GccGroup.wxs"))
2021                    .run(builder);
2022            }
2023
2024            let candle = |input: &Path| {
2025                let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
2026                let arch = if target.contains("x86_64") { "x64" } else { "x86" };
2027                let mut cmd = command(&candle);
2028                cmd.current_dir(&exe)
2029                    .arg("-nologo")
2030                    .arg("-dRustcDir=rustc")
2031                    .arg("-dCargoDir=cargo")
2032                    .arg("-dStdDir=rust-std")
2033                    .arg("-dAnalysisDir=rust-analysis")
2034                    .arg("-arch")
2035                    .arg(arch)
2036                    .arg("-out")
2037                    .arg(&output)
2038                    .arg(input);
2039                add_env(builder, &mut cmd, target, &built_tools);
2040
2041                if built_tools.contains("clippy") {
2042                    cmd.arg("-dClippyDir=clippy");
2043                }
2044                if built_tools.contains("rustfmt") {
2045                    cmd.arg("-dRustFmtDir=rustfmt");
2046                }
2047                if built_tools.contains("rust-docs") {
2048                    cmd.arg("-dDocsDir=rust-docs");
2049                }
2050                if built_tools.contains("rust-analyzer") {
2051                    cmd.arg("-dRustAnalyzerDir=rust-analyzer");
2052                }
2053                if built_tools.contains("miri") {
2054                    cmd.arg("-dMiriDir=miri");
2055                }
2056                if target.is_windows_gnu() {
2057                    cmd.arg("-dGccDir=rust-mingw");
2058                }
2059                cmd.run(builder);
2060            };
2061            candle(&xform(&etc.join("msi/rust.wxs")));
2062            candle(&etc.join("msi/ui.wxs"));
2063            candle(&etc.join("msi/rustwelcomedlg.wxs"));
2064            candle("RustcGroup.wxs".as_ref());
2065            if built_tools.contains("rust-docs") {
2066                candle("DocsGroup.wxs".as_ref());
2067            }
2068            candle("CargoGroup.wxs".as_ref());
2069            candle("StdGroup.wxs".as_ref());
2070            if built_tools.contains("clippy") {
2071                candle("ClippyGroup.wxs".as_ref());
2072            }
2073            if built_tools.contains("rustfmt") {
2074                candle("RustFmtGroup.wxs".as_ref());
2075            }
2076            if built_tools.contains("miri") {
2077                candle("MiriGroup.wxs".as_ref());
2078            }
2079            if built_tools.contains("rust-analyzer") {
2080                candle("RustAnalyzerGroup.wxs".as_ref());
2081            }
2082            candle("AnalysisGroup.wxs".as_ref());
2083
2084            if target.is_windows_gnu() {
2085                candle("GccGroup.wxs".as_ref());
2086            }
2087
2088            builder.create(&exe.join("LICENSE.rtf"), &rtf);
2089            builder.install(&etc.join("gfx/banner.bmp"), &exe, FileType::Regular);
2090            builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, FileType::Regular);
2091
2092            builder.info(&format!("building `msi` installer with {light:?}"));
2093            let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
2094            let mut cmd = command(&light);
2095            cmd.arg("-nologo")
2096                .arg("-ext")
2097                .arg("WixUIExtension")
2098                .arg("-ext")
2099                .arg("WixUtilExtension")
2100                .arg("-out")
2101                .arg(exe.join(&filename))
2102                .arg("rust.wixobj")
2103                .arg("ui.wixobj")
2104                .arg("rustwelcomedlg.wixobj")
2105                .arg("RustcGroup.wixobj")
2106                .arg("CargoGroup.wixobj")
2107                .arg("StdGroup.wixobj")
2108                .arg("AnalysisGroup.wixobj")
2109                .current_dir(&exe);
2110
2111            if built_tools.contains("clippy") {
2112                cmd.arg("ClippyGroup.wixobj");
2113            }
2114            if built_tools.contains("rustfmt") {
2115                cmd.arg("RustFmtGroup.wixobj");
2116            }
2117            if built_tools.contains("miri") {
2118                cmd.arg("MiriGroup.wixobj");
2119            }
2120            if built_tools.contains("rust-analyzer") {
2121                cmd.arg("RustAnalyzerGroup.wixobj");
2122            }
2123            if built_tools.contains("rust-docs") {
2124                cmd.arg("DocsGroup.wixobj");
2125            }
2126
2127            if target.is_windows_gnu() {
2128                cmd.arg("GccGroup.wixobj");
2129            }
2130            // ICE57 wrongly complains about the shortcuts
2131            cmd.arg("-sice:ICE57");
2132
2133            let _time = timeit(builder);
2134            cmd.run(builder);
2135
2136            if !builder.config.dry_run() {
2137                t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
2138            }
2139        }
2140    }
2141
2142    fn metadata(&self) -> Option<StepMetadata> {
2143        Some(StepMetadata::dist("extended", self.target).built_by(self.build_compiler))
2144    }
2145}
2146
2147fn add_env(
2148    builder: &Builder<'_>,
2149    cmd: &mut BootstrapCommand,
2150    target: TargetSelection,
2151    built_tools: &HashSet<&'static str>,
2152) {
2153    let mut parts = builder.version.split('.');
2154    cmd.env("CFG_RELEASE_INFO", builder.rust_version())
2155        .env("CFG_RELEASE_NUM", &builder.version)
2156        .env("CFG_RELEASE", builder.rust_release())
2157        .env("CFG_VER_MAJOR", parts.next().unwrap())
2158        .env("CFG_VER_MINOR", parts.next().unwrap())
2159        .env("CFG_VER_PATCH", parts.next().unwrap())
2160        .env("CFG_VER_BUILD", "0") // just needed to build
2161        .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
2162        .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
2163        .env("CFG_BUILD", target.triple)
2164        .env("CFG_CHANNEL", &builder.config.channel);
2165
2166    if target.contains("windows-gnullvm") {
2167        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
2168    } else if target.is_windows_gnu() {
2169        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
2170    } else {
2171        cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
2172    }
2173
2174    // ensure these variables are defined
2175    let mut define_optional_tool = |tool_name: &str, env_name: &str| {
2176        cmd.env(env_name, if built_tools.contains(tool_name) { "1" } else { "0" });
2177    };
2178    define_optional_tool("rustfmt", "CFG_RUSTFMT");
2179    define_optional_tool("clippy", "CFG_CLIPPY");
2180    define_optional_tool("miri", "CFG_MIRI");
2181    define_optional_tool("rust-analyzer", "CFG_RA");
2182}
2183
2184fn install_llvm_file(
2185    builder: &Builder<'_>,
2186    source: &Path,
2187    destination: &Path,
2188    install_symlink: bool,
2189) {
2190    if builder.config.dry_run() {
2191        return;
2192    }
2193
2194    if source.is_symlink() {
2195        // If we have a symlink like libLLVM-18.so -> libLLVM.so.18.1, install the target of the
2196        // symlink, which is what will actually get loaded at runtime.
2197        builder.install(&t!(fs::canonicalize(source)), destination, FileType::NativeLibrary);
2198
2199        let full_dest = destination.join(source.file_name().unwrap());
2200        if install_symlink {
2201            // For download-ci-llvm, also install the symlink, to match what LLVM does. Using a
2202            // symlink is fine here, as this is not a rustup component.
2203            builder.copy_link(source, &full_dest, FileType::NativeLibrary);
2204        } else {
2205            // Otherwise, replace the symlink with an equivalent linker script. This is used when
2206            // projects like miri link against librustc_driver.so. We don't use a symlink, as
2207            // these are not allowed inside rustup components.
2208            let link = t!(fs::read_link(source));
2209            let mut linker_script = t!(fs::File::create(full_dest));
2210            t!(write!(linker_script, "INPUT({})\n", link.display()));
2211
2212            // We also want the linker script to have the same mtime as the source, otherwise it
2213            // can trigger rebuilds.
2214            let meta = t!(fs::metadata(source));
2215            if let Ok(mtime) = meta.modified() {
2216                t!(linker_script.set_modified(mtime));
2217            }
2218        }
2219    } else {
2220        builder.install(source, destination, FileType::NativeLibrary);
2221    }
2222}
2223
2224/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
2225///
2226/// Returns whether the files were actually copied.
2227#[cfg_attr(
2228    feature = "tracing",
2229    instrument(
2230        level = "trace",
2231        name = "maybe_install_llvm",
2232        skip_all,
2233        fields(target = ?target, dst_libdir = ?dst_libdir, install_symlink = install_symlink),
2234    ),
2235)]
2236fn maybe_install_llvm(
2237    builder: &Builder<'_>,
2238    target: TargetSelection,
2239    dst_libdir: &Path,
2240    install_symlink: bool,
2241) -> bool {
2242    // If the LLVM was externally provided, then we don't currently copy
2243    // artifacts into the sysroot. This is not necessarily the right
2244    // choice (in particular, it will require the LLVM dylib to be in
2245    // the linker's load path at runtime), but the common use case for
2246    // external LLVMs is distribution provided LLVMs, and in that case
2247    // they're usually in the standard search path (e.g., /usr/lib) and
2248    // copying them here is going to cause problems as we may end up
2249    // with the wrong files and isn't what distributions want.
2250    //
2251    // This behavior may be revisited in the future though.
2252    //
2253    // NOTE: this intentionally doesn't use `is_rust_llvm`; whether this is patched or not doesn't matter,
2254    // we only care if the shared object itself is managed by bootstrap.
2255    //
2256    // If the LLVM is coming from ourselves (just from CI) though, we
2257    // still want to install it, as it otherwise won't be available.
2258    if builder.config.is_system_llvm(target) {
2259        trace!("system LLVM requested, no install");
2260        return false;
2261    }
2262
2263    // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib
2264    // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely
2265    // clear why this is the case, though. llvm-config will emit the versioned
2266    // paths and we don't want those in the sysroot (as we're expecting
2267    // unversioned paths).
2268    if target.contains("apple-darwin") && builder.llvm_link_shared() {
2269        let src_libdir = builder.llvm_out(target).join("lib");
2270        let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
2271        if llvm_dylib_path.exists() {
2272            builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary);
2273        }
2274        !builder.config.dry_run()
2275    } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult {
2276        host_llvm_config, ..
2277    }) = llvm::prebuilt_llvm_config(builder, target, true)
2278    {
2279        trace!("LLVM already built, installing LLVM files");
2280        let mut cmd = command(host_llvm_config);
2281        cmd.cached();
2282        cmd.arg("--libfiles");
2283        builder.verbose(|| println!("running {cmd:?}"));
2284        let files = cmd.run_capture_stdout(builder).stdout();
2285        let build_llvm_out = &builder.llvm_out(builder.config.host_target);
2286        let target_llvm_out = &builder.llvm_out(target);
2287        for file in files.trim_end().split(' ') {
2288            // If we're not using a custom LLVM, make sure we package for the target.
2289            let file = if let Ok(relative_path) = Path::new(file).strip_prefix(build_llvm_out) {
2290                target_llvm_out.join(relative_path)
2291            } else {
2292                PathBuf::from(file)
2293            };
2294            install_llvm_file(builder, &file, dst_libdir, install_symlink);
2295        }
2296        !builder.config.dry_run()
2297    } else {
2298        false
2299    }
2300}
2301
2302/// Maybe add libLLVM.so to the target lib-dir for linking.
2303#[cfg_attr(
2304    feature = "tracing",
2305    instrument(
2306        level = "trace",
2307        name = "maybe_install_llvm_target",
2308        skip_all,
2309        fields(
2310            llvm_link_shared = ?builder.llvm_link_shared(),
2311            target = ?target,
2312            sysroot = ?sysroot,
2313        ),
2314    ),
2315)]
2316pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2317    let dst_libdir = sysroot.join("lib/rustlib").join(target).join("lib");
2318    // We do not need to copy LLVM files into the sysroot if it is not
2319    // dynamically linked; it is already included into librustc_llvm
2320    // statically.
2321    if builder.llvm_link_shared() {
2322        maybe_install_llvm(builder, target, &dst_libdir, false);
2323    }
2324}
2325
2326/// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
2327#[cfg_attr(
2328    feature = "tracing",
2329    instrument(
2330        level = "trace",
2331        name = "maybe_install_llvm_runtime",
2332        skip_all,
2333        fields(
2334            llvm_link_shared = ?builder.llvm_link_shared(),
2335            target = ?target,
2336            sysroot = ?sysroot,
2337        ),
2338    ),
2339)]
2340pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2341    let dst_libdir = sysroot.join(builder.sysroot_libdir_relative(Compiler::new(1, target)));
2342    // We do not need to copy LLVM files into the sysroot if it is not
2343    // dynamically linked; it is already included into librustc_llvm
2344    // statically.
2345    if builder.llvm_link_shared() {
2346        maybe_install_llvm(builder, target, &dst_libdir, false);
2347    }
2348}
2349
2350#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2351pub struct LlvmTools {
2352    pub target: TargetSelection,
2353}
2354
2355impl Step for LlvmTools {
2356    type Output = Option<GeneratedTarball>;
2357    const IS_HOST: bool = true;
2358    const DEFAULT: bool = true;
2359
2360    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2361        let default = should_build_extended_tool(run.builder, "llvm-tools");
2362
2363        let mut run = run.alias("llvm-tools");
2364        for tool in LLVM_TOOLS {
2365            run = run.alias(tool);
2366        }
2367
2368        run.default_condition(default)
2369    }
2370
2371    fn make_run(run: RunConfig<'_>) {
2372        run.builder.ensure(LlvmTools { target: run.target });
2373    }
2374
2375    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2376        fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> {
2377            let mut tools = vec![];
2378
2379            for path in paths {
2380                let path = path.to_str().unwrap();
2381
2382                // Include all tools if path is 'llvm-tools'.
2383                if path == "llvm-tools" {
2384                    return LLVM_TOOLS.to_owned();
2385                }
2386
2387                for tool in LLVM_TOOLS {
2388                    if path == *tool {
2389                        tools.push(*tool);
2390                    }
2391                }
2392            }
2393
2394            // If no specific tool is requested, include all tools.
2395            if tools.is_empty() {
2396                tools = LLVM_TOOLS.to_owned();
2397            }
2398
2399            tools
2400        }
2401
2402        let target = self.target;
2403
2404        // Run only if a custom llvm-config is not used
2405        if let Some(config) = builder.config.target_config.get(&target)
2406            && !builder.config.llvm_from_ci
2407            && config.llvm_config.is_some()
2408        {
2409            builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
2410            return None;
2411        }
2412
2413        if !builder.config.dry_run() {
2414            builder.require_submodule("src/llvm-project", None);
2415        }
2416
2417        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2418
2419        let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
2420        tarball.set_overlay(OverlayKind::Llvm);
2421        tarball.is_preview(true);
2422
2423        if builder.config.llvm_tools_enabled {
2424            // Prepare the image directory
2425            let src_bindir = builder.llvm_out(target).join("bin");
2426            let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
2427            for tool in tools_to_install(&builder.paths) {
2428                let exe = src_bindir.join(exe(tool, target));
2429                // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
2430                if !exe.exists() && builder.config.llvm_from_ci {
2431                    eprintln!("{} does not exist; skipping copy", exe.display());
2432                    continue;
2433                }
2434
2435                tarball.add_file(&exe, &dst_bindir, FileType::Executable);
2436            }
2437        }
2438
2439        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2440        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2441        // of `rustc-dev` to support the inherited `-lLLVM` when using the
2442        // compiler libraries.
2443        maybe_install_llvm_target(builder, target, tarball.image_dir());
2444
2445        Some(tarball.generate())
2446    }
2447}
2448
2449/// Distributes the `llvm-bitcode-linker` tool so that it can be used by a compiler whose host
2450/// is `target`.
2451#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2452pub struct LlvmBitcodeLinker {
2453    /// The linker will be compiled by this compiler.
2454    pub build_compiler: Compiler,
2455    /// The linker will by usable by rustc on this host.
2456    pub target: TargetSelection,
2457}
2458
2459impl Step for LlvmBitcodeLinker {
2460    type Output = Option<GeneratedTarball>;
2461    const DEFAULT: bool = true;
2462    const IS_HOST: bool = true;
2463
2464    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2465        let default = should_build_extended_tool(run.builder, "llvm-bitcode-linker");
2466        run.alias("llvm-bitcode-linker").default_condition(default)
2467    }
2468
2469    fn make_run(run: RunConfig<'_>) {
2470        run.builder.ensure(LlvmBitcodeLinker {
2471            build_compiler: tool::LlvmBitcodeLinker::get_build_compiler_for_target(
2472                run.builder,
2473                run.target,
2474            ),
2475            target: run.target,
2476        });
2477    }
2478
2479    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2480        let target = self.target;
2481
2482        let llbc_linker = builder
2483            .ensure(tool::LlvmBitcodeLinker::from_build_compiler(self.build_compiler, target));
2484
2485        let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
2486
2487        // Prepare the image directory
2488        let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple);
2489        tarball.set_overlay(OverlayKind::LlvmBitcodeLinker);
2490        tarball.is_preview(true);
2491
2492        tarball.add_file(&llbc_linker.tool_path, self_contained_bin_dir, FileType::Executable);
2493
2494        Some(tarball.generate())
2495    }
2496}
2497
2498/// Tarball intended for internal consumption to ease rustc/std development.
2499///
2500/// Should not be considered stable by end users.
2501///
2502/// In practice, this is the tarball that gets downloaded and used by
2503/// `llvm.download-ci-llvm`.
2504///
2505/// (Don't confuse this with [`RustcDev`], with a `c`!)
2506#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2507pub struct RustDev {
2508    pub target: TargetSelection,
2509}
2510
2511impl Step for RustDev {
2512    type Output = Option<GeneratedTarball>;
2513    const DEFAULT: bool = true;
2514    const IS_HOST: bool = true;
2515
2516    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2517        run.alias("rust-dev")
2518    }
2519
2520    fn make_run(run: RunConfig<'_>) {
2521        run.builder.ensure(RustDev { target: run.target });
2522    }
2523
2524    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2525        let target = self.target;
2526
2527        /* run only if llvm-config isn't used */
2528        if let Some(config) = builder.config.target_config.get(&target)
2529            && let Some(ref _s) = config.llvm_config
2530        {
2531            builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
2532            return None;
2533        }
2534
2535        if !builder.config.dry_run() {
2536            builder.require_submodule("src/llvm-project", None);
2537        }
2538
2539        let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
2540        tarball.set_overlay(OverlayKind::Llvm);
2541        // LLVM requires a shared object symlink to exist on some platforms.
2542        tarball.permit_symlinks(true);
2543
2544        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2545
2546        let src_bindir = builder.llvm_out(target).join("bin");
2547        // If updating this, you likely want to change
2548        // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
2549        // will not pick up the extra file until LLVM gets bumped.
2550        // We should include all the build artifacts obtained from a source build,
2551        // so that you can use the downloadable LLVM as if you’ve just run a full source build.
2552        if src_bindir.exists() {
2553            for entry in walkdir::WalkDir::new(&src_bindir) {
2554                let entry = t!(entry);
2555                if entry.file_type().is_file() && !entry.path_is_symlink() {
2556                    let name = entry.file_name().to_str().unwrap();
2557                    tarball.add_file(src_bindir.join(name), "bin", FileType::Executable);
2558                }
2559            }
2560        }
2561
2562        if builder.config.lld_enabled {
2563            // We want to package `lld` to use it with `download-ci-llvm`.
2564            let lld_out = builder.ensure(crate::core::build_steps::llvm::Lld { target });
2565
2566            // We don't build LLD on some platforms, so only add it if it exists
2567            let lld_path = lld_out.join("bin").join(exe("lld", target));
2568            if lld_path.exists() {
2569                tarball.add_file(&lld_path, "bin", FileType::Executable);
2570            }
2571        }
2572
2573        tarball.add_file(builder.llvm_filecheck(target), "bin", FileType::Executable);
2574
2575        // Copy the include directory as well; needed mostly to build
2576        // librustc_llvm properly (e.g., llvm-config.h is in here). But also
2577        // just broadly useful to be able to link against the bundled LLVM.
2578        tarball.add_dir(builder.llvm_out(target).join("include"), "include");
2579
2580        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2581        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2582        // of `rustc-dev` to support the inherited `-lLLVM` when using the
2583        // compiler libraries.
2584        let dst_libdir = tarball.image_dir().join("lib");
2585        maybe_install_llvm(builder, target, &dst_libdir, true);
2586        let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
2587        t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
2588
2589        // Copy the `compiler-rt` source, so that `library/profiler_builtins`
2590        // can potentially use it to build the profiler runtime without needing
2591        // to check out the LLVM submodule.
2592        copy_src_dirs(
2593            builder,
2594            &builder.src.join("src").join("llvm-project"),
2595            &["compiler-rt"],
2596            // The test subdirectory is much larger than the rest of the source,
2597            // and we currently don't use these test files anyway.
2598            &["compiler-rt/test"],
2599            tarball.image_dir(),
2600        );
2601
2602        Some(tarball.generate())
2603    }
2604}
2605
2606/// Tarball intended for internal consumption to ease rustc/std development.
2607///
2608/// It only packages the binaries that were already compiled when bootstrap itself was built.
2609///
2610/// Should not be considered stable by end users.
2611#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2612pub struct Bootstrap {
2613    target: TargetSelection,
2614}
2615
2616impl Step for Bootstrap {
2617    type Output = Option<GeneratedTarball>;
2618
2619    const IS_HOST: bool = true;
2620
2621    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2622        run.alias("bootstrap")
2623    }
2624
2625    fn make_run(run: RunConfig<'_>) {
2626        run.builder.ensure(Bootstrap { target: run.target });
2627    }
2628
2629    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2630        let target = self.target;
2631
2632        let tarball = Tarball::new(builder, "bootstrap", &target.triple);
2633
2634        let bootstrap_outdir = &builder.bootstrap_out;
2635        for file in &["bootstrap", "rustc", "rustdoc"] {
2636            tarball.add_file(
2637                bootstrap_outdir.join(exe(file, target)),
2638                "bootstrap/bin",
2639                FileType::Executable,
2640            );
2641        }
2642
2643        Some(tarball.generate())
2644    }
2645
2646    fn metadata(&self) -> Option<StepMetadata> {
2647        Some(StepMetadata::dist("bootstrap", self.target))
2648    }
2649}
2650
2651/// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the
2652/// release process to avoid cloning the monorepo and building stuff.
2653///
2654/// Should not be considered stable by end users.
2655#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2656pub struct BuildManifest {
2657    target: TargetSelection,
2658}
2659
2660impl Step for BuildManifest {
2661    type Output = GeneratedTarball;
2662
2663    const IS_HOST: bool = true;
2664
2665    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2666        run.alias("build-manifest")
2667    }
2668
2669    fn make_run(run: RunConfig<'_>) {
2670        run.builder.ensure(BuildManifest { target: run.target });
2671    }
2672
2673    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
2674        let build_manifest = builder.tool_exe(Tool::BuildManifest);
2675
2676        let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
2677        tarball.add_file(&build_manifest, "bin", FileType::Executable);
2678        tarball.generate()
2679    }
2680
2681    fn metadata(&self) -> Option<StepMetadata> {
2682        Some(StepMetadata::dist("build-manifest", self.target))
2683    }
2684}
2685
2686/// Tarball containing artifacts necessary to reproduce the build of rustc.
2687///
2688/// Currently this is the PGO (and possibly BOLT) profile data.
2689///
2690/// Should not be considered stable by end users.
2691#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2692pub struct ReproducibleArtifacts {
2693    target: TargetSelection,
2694}
2695
2696impl Step for ReproducibleArtifacts {
2697    type Output = Option<GeneratedTarball>;
2698    const DEFAULT: bool = true;
2699    const IS_HOST: bool = true;
2700
2701    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2702        run.alias("reproducible-artifacts")
2703    }
2704
2705    fn make_run(run: RunConfig<'_>) {
2706        run.builder.ensure(ReproducibleArtifacts { target: run.target });
2707    }
2708
2709    fn run(self, builder: &Builder<'_>) -> Self::Output {
2710        let mut added_anything = false;
2711        let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
2712        if let Some(path) = builder.config.rust_profile_use.as_ref() {
2713            tarball.add_file(path, ".", FileType::Regular);
2714            added_anything = true;
2715        }
2716        if let Some(path) = builder.config.llvm_profile_use.as_ref() {
2717            tarball.add_file(path, ".", FileType::Regular);
2718            added_anything = true;
2719        }
2720        for profile in &builder.config.reproducible_artifacts {
2721            tarball.add_file(profile, ".", FileType::Regular);
2722            added_anything = true;
2723        }
2724        if added_anything { Some(tarball.generate()) } else { None }
2725    }
2726
2727    fn metadata(&self) -> Option<StepMetadata> {
2728        Some(StepMetadata::dist("reproducible-artifacts", self.target))
2729    }
2730}
2731
2732/// Tarball containing a prebuilt version of the libgccjit library,
2733/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
2734/// backend needing a prebuilt libLLVM).
2735#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2736pub struct Gcc {
2737    target: TargetSelection,
2738}
2739
2740impl Step for Gcc {
2741    type Output = GeneratedTarball;
2742
2743    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2744        run.alias("gcc")
2745    }
2746
2747    fn make_run(run: RunConfig<'_>) {
2748        run.builder.ensure(Gcc { target: run.target });
2749    }
2750
2751    fn run(self, builder: &Builder<'_>) -> Self::Output {
2752        let tarball = Tarball::new(builder, "gcc", &self.target.triple);
2753        let output = builder.ensure(super::gcc::Gcc { target: self.target });
2754        tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary);
2755        tarball.generate()
2756    }
2757
2758    fn metadata(&self) -> Option<StepMetadata> {
2759        Some(StepMetadata::dist("gcc", self.target))
2760    }
2761}