bootstrap/core/build_steps/
dist.rs

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