bootstrap/core/build_steps/
dist.rs

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