bootstrap/core/build_steps/
dist.rs

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