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