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