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