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-docs");
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/// Tarball for people who want to build rustc and other components from the source.
1215/// Does not contain GPL code, which is separated into `PlainSourceTarballGpl`
1216/// for licensing reasons.
1217#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1218pub struct PlainSourceTarball;
1219
1220impl Step for PlainSourceTarball {
1221    /// Produces the location of the tarball generated
1222    type Output = GeneratedTarball;
1223    const IS_HOST: bool = true;
1224
1225    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1226        run.alias("rustc-src")
1227    }
1228
1229    fn is_default_step(builder: &Builder<'_>) -> bool {
1230        builder.config.rust_dist_src
1231    }
1232
1233    fn make_run(run: RunConfig<'_>) {
1234        run.builder.ensure(PlainSourceTarball);
1235    }
1236
1237    /// Creates the plain source tarball
1238    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1239        let tarball = prepare_source_tarball(
1240            builder,
1241            "src",
1242            &[
1243                // We don't currently use the GCC source code for building any official components,
1244                // it is very big, and has unclear licensing implications due to being GPL licensed.
1245                // We thus exclude it from the source tarball from now.
1246                "src/gcc",
1247            ],
1248        );
1249
1250        let plain_dst_src = tarball.image_dir();
1251        // We keep something in src/gcc because it is a registered submodule,
1252        // and if it misses completely it can cause issues elsewhere
1253        // (see https://github.com/rust-lang/rust/issues/137332).
1254        // We can also let others know why is the source code missing.
1255        if !builder.config.dry_run() {
1256            builder.create_dir(&plain_dst_src.join("src/gcc"));
1257            t!(std::fs::write(
1258                plain_dst_src.join("src/gcc/notice.txt"),
1259                "The GCC source code is not included due to unclear licensing implications\n"
1260            ));
1261        }
1262        tarball.bare()
1263    }
1264}
1265
1266/// Tarball with *all* source code for source builds, including GPL-licensed code.
1267#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1268pub struct PlainSourceTarballGpl;
1269
1270impl Step for PlainSourceTarballGpl {
1271    /// Produces the location of the tarball generated
1272    type Output = GeneratedTarball;
1273    const IS_HOST: bool = true;
1274
1275    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1276        run.alias("rustc-src-gpl")
1277    }
1278
1279    fn is_default_step(builder: &Builder<'_>) -> bool {
1280        builder.config.rust_dist_src
1281    }
1282
1283    fn make_run(run: RunConfig<'_>) {
1284        run.builder.ensure(PlainSourceTarballGpl);
1285    }
1286
1287    /// Creates the plain source tarball
1288    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1289        let tarball = prepare_source_tarball(builder, "src-gpl", &[]);
1290        tarball.bare()
1291    }
1292}
1293
1294fn prepare_source_tarball<'a>(
1295    builder: &'a Builder<'a>,
1296    name: &str,
1297    exclude_dirs: &[&str],
1298) -> Tarball<'a> {
1299    // NOTE: This is a strange component in a lot of ways. It uses `src` as the target, which
1300    // means neither rustup nor rustup-toolchain-install-master know how to download it.
1301    // It also contains symbolic links, unlike other any other dist tarball.
1302    // It's used for distros building rustc from source in a pre-vendored environment.
1303    let mut tarball = Tarball::new(builder, "rustc", name);
1304    tarball.permit_symlinks(true);
1305    let plain_dst_src = tarball.image_dir();
1306
1307    // This is the set of root paths which will become part of the source package
1308    let src_files = [
1309        // tidy-alphabetical-start
1310        ".gitmodules",
1311        "CONTRIBUTING.md",
1312        "COPYRIGHT",
1313        "Cargo.lock",
1314        "Cargo.toml",
1315        "LICENSE-APACHE",
1316        "LICENSE-MIT",
1317        "README.md",
1318        "RELEASES.md",
1319        "REUSE.toml",
1320        "bootstrap.example.toml",
1321        "configure",
1322        "license-metadata.json",
1323        "package.json",
1324        "x",
1325        "x.ps1",
1326        "x.py",
1327        "yarn.lock",
1328        // tidy-alphabetical-end
1329    ];
1330    let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"];
1331
1332    copy_src_dirs(builder, &builder.src, &src_dirs, exclude_dirs, plain_dst_src);
1333
1334    // Copy the files normally
1335    for item in &src_files {
1336        builder.copy_link(&builder.src.join(item), &plain_dst_src.join(item), FileType::Regular);
1337    }
1338
1339    // Create the version file
1340    builder.create(&plain_dst_src.join("version"), &builder.rust_version());
1341
1342    // Create the files containing git info, to ensure --version outputs the same.
1343    let write_git_info = |info: Option<&Info>, path: &Path| {
1344        if let Some(info) = info {
1345            t!(std::fs::create_dir_all(path));
1346            channel::write_commit_hash_file(path, &info.sha);
1347            channel::write_commit_info_file(path, info);
1348        }
1349    };
1350    write_git_info(builder.rust_info().info(), plain_dst_src);
1351    write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo"));
1352
1353    if builder.config.dist_vendor {
1354        builder.require_and_update_all_submodules();
1355
1356        // Vendor packages that are required by opt-dist to collect PGO profiles.
1357        let pkgs_for_pgo_training =
1358            build_helper::LLVM_PGO_CRATES.iter().chain(build_helper::RUSTC_PGO_CRATES).map(|pkg| {
1359                let mut manifest_path =
1360                    builder.src.join("./src/tools/rustc-perf/collector/compile-benchmarks");
1361                manifest_path.push(pkg);
1362                manifest_path.push("Cargo.toml");
1363                manifest_path
1364            });
1365
1366        // Vendor all Cargo dependencies
1367        let vendor = builder.ensure(Vendor {
1368            sync_args: pkgs_for_pgo_training.collect(),
1369            versioned_dirs: true,
1370            root_dir: plain_dst_src.into(),
1371            output_dir: VENDOR_DIR.into(),
1372        });
1373
1374        let cargo_config_dir = plain_dst_src.join(".cargo");
1375        builder.create_dir(&cargo_config_dir);
1376        builder.create(&cargo_config_dir.join("config.toml"), &vendor.config);
1377    }
1378
1379    // Delete extraneous directories
1380    // FIXME: if we're managed by git, we should probably instead ask git if the given path
1381    // is managed by it?
1382    for entry in walkdir::WalkDir::new(tarball.image_dir())
1383        .follow_links(true)
1384        .into_iter()
1385        .filter_map(|e| e.ok())
1386    {
1387        if entry.path().is_dir() && entry.path().file_name() == Some(OsStr::new("__pycache__")) {
1388            t!(fs::remove_dir_all(entry.path()));
1389        }
1390    }
1391    tarball
1392}
1393
1394#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1395pub struct Cargo {
1396    pub build_compiler: Compiler,
1397    pub target: TargetSelection,
1398}
1399
1400impl Step for Cargo {
1401    type Output = Option<GeneratedTarball>;
1402    const IS_HOST: bool = true;
1403
1404    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1405        run.alias("cargo")
1406    }
1407
1408    fn is_default_step(builder: &Builder<'_>) -> bool {
1409        should_build_extended_tool(builder, "cargo")
1410    }
1411
1412    fn make_run(run: RunConfig<'_>) {
1413        run.builder.ensure(Cargo {
1414            build_compiler: get_tool_target_compiler(
1415                run.builder,
1416                ToolTargetBuildMode::Build(run.target),
1417            ),
1418            target: run.target,
1419        });
1420    }
1421
1422    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1423        let build_compiler = self.build_compiler;
1424        let target = self.target;
1425
1426        let cargo = builder.ensure(tool::Cargo::from_build_compiler(build_compiler, target));
1427        let src = builder.src.join("src/tools/cargo");
1428        let etc = src.join("src/etc");
1429
1430        // Prepare the image directory
1431        let mut tarball = Tarball::new(builder, "cargo", &target.triple);
1432        tarball.set_overlay(OverlayKind::Cargo);
1433
1434        tarball.add_file(&cargo.tool_path, "bin", FileType::Executable);
1435        tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", FileType::Regular);
1436        tarball.add_renamed_file(
1437            etc.join("cargo.bashcomp.sh"),
1438            "etc/bash_completion.d",
1439            "cargo",
1440            FileType::Regular,
1441        );
1442        tarball.add_dir(etc.join("man"), "share/man/man1");
1443        tarball.add_legal_and_readme_to("share/doc/cargo");
1444
1445        Some(tarball.generate())
1446    }
1447
1448    fn metadata(&self) -> Option<StepMetadata> {
1449        Some(StepMetadata::dist("cargo", self.target).built_by(self.build_compiler))
1450    }
1451}
1452
1453/// Distribute the rust-analyzer component, which is used as a LSP by various IDEs.
1454#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1455pub struct RustAnalyzer {
1456    pub compilers: RustcPrivateCompilers,
1457    pub target: TargetSelection,
1458}
1459
1460impl Step for RustAnalyzer {
1461    type Output = Option<GeneratedTarball>;
1462    const IS_HOST: bool = true;
1463
1464    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1465        run.alias("rust-analyzer")
1466    }
1467
1468    fn is_default_step(builder: &Builder<'_>) -> bool {
1469        should_build_extended_tool(builder, "rust-analyzer")
1470    }
1471
1472    fn make_run(run: RunConfig<'_>) {
1473        run.builder.ensure(RustAnalyzer {
1474            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1475            target: run.target,
1476        });
1477    }
1478
1479    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1480        let target = self.target;
1481        let rust_analyzer = builder.ensure(tool::RustAnalyzer::from_compilers(self.compilers));
1482
1483        let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
1484        tarball.set_overlay(OverlayKind::RustAnalyzer);
1485        tarball.is_preview(true);
1486        tarball.add_file(&rust_analyzer.tool_path, "bin", FileType::Executable);
1487        tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
1488        Some(tarball.generate())
1489    }
1490
1491    fn metadata(&self) -> Option<StepMetadata> {
1492        Some(
1493            StepMetadata::dist("rust-analyzer", self.target)
1494                .built_by(self.compilers.build_compiler()),
1495        )
1496    }
1497}
1498
1499#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1500pub struct Clippy {
1501    pub compilers: RustcPrivateCompilers,
1502    pub target: TargetSelection,
1503}
1504
1505impl Step for Clippy {
1506    type Output = Option<GeneratedTarball>;
1507    const IS_HOST: bool = true;
1508
1509    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1510        run.alias("clippy")
1511    }
1512
1513    fn is_default_step(builder: &Builder<'_>) -> bool {
1514        should_build_extended_tool(builder, "clippy")
1515    }
1516
1517    fn make_run(run: RunConfig<'_>) {
1518        run.builder.ensure(Clippy {
1519            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1520            target: run.target,
1521        });
1522    }
1523
1524    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1525        let target = self.target;
1526
1527        // Prepare the image directory
1528        // We expect clippy to build, because we've exited this step above if tool
1529        // state for clippy isn't testing.
1530        let clippy = builder.ensure(tool::Clippy::from_compilers(self.compilers));
1531        let cargoclippy = builder.ensure(tool::CargoClippy::from_compilers(self.compilers));
1532
1533        let mut tarball = Tarball::new(builder, "clippy", &target.triple);
1534        tarball.set_overlay(OverlayKind::Clippy);
1535        tarball.is_preview(true);
1536        tarball.add_file(&clippy.tool_path, "bin", FileType::Executable);
1537        tarball.add_file(&cargoclippy.tool_path, "bin", FileType::Executable);
1538        tarball.add_legal_and_readme_to("share/doc/clippy");
1539        Some(tarball.generate())
1540    }
1541
1542    fn metadata(&self) -> Option<StepMetadata> {
1543        Some(StepMetadata::dist("clippy", self.target).built_by(self.compilers.build_compiler()))
1544    }
1545}
1546
1547#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1548pub struct Miri {
1549    pub compilers: RustcPrivateCompilers,
1550    pub target: TargetSelection,
1551}
1552
1553impl Step for Miri {
1554    type Output = Option<GeneratedTarball>;
1555    const IS_HOST: bool = true;
1556
1557    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1558        run.alias("miri")
1559    }
1560
1561    fn is_default_step(builder: &Builder<'_>) -> bool {
1562        should_build_extended_tool(builder, "miri")
1563    }
1564
1565    fn make_run(run: RunConfig<'_>) {
1566        run.builder.ensure(Miri {
1567            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1568            target: run.target,
1569        });
1570    }
1571
1572    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1573        // This prevents miri from being built for "dist" or "install"
1574        // on the stable/beta channels. It is a nightly-only tool and should
1575        // not be included.
1576        if !builder.build.unstable_features() {
1577            return None;
1578        }
1579
1580        let miri = builder.ensure(tool::Miri::from_compilers(self.compilers));
1581        let cargomiri = builder.ensure(tool::CargoMiri::from_compilers(self.compilers));
1582
1583        let mut tarball = Tarball::new(builder, "miri", &self.target.triple);
1584        tarball.set_overlay(OverlayKind::Miri);
1585        tarball.is_preview(true);
1586        tarball.add_file(&miri.tool_path, "bin", FileType::Executable);
1587        tarball.add_file(&cargomiri.tool_path, "bin", FileType::Executable);
1588        tarball.add_legal_and_readme_to("share/doc/miri");
1589        Some(tarball.generate())
1590    }
1591
1592    fn metadata(&self) -> Option<StepMetadata> {
1593        Some(StepMetadata::dist("miri", self.target).built_by(self.compilers.build_compiler()))
1594    }
1595}
1596
1597#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1598pub struct CraneliftCodegenBackend {
1599    pub compilers: RustcPrivateCompilers,
1600    pub target: TargetSelection,
1601}
1602
1603impl Step for CraneliftCodegenBackend {
1604    type Output = Option<GeneratedTarball>;
1605    const IS_HOST: bool = true;
1606
1607    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1608        run.alias("rustc_codegen_cranelift")
1609    }
1610
1611    fn is_default_step(builder: &Builder<'_>) -> bool {
1612        // We only want to build the cranelift backend in `x dist` if the backend was enabled
1613        // in rust.codegen-backends.
1614        // Sadly, we don't have access to the actual target for which we're disting clif here..
1615        // So we just use the host target.
1616        builder
1617            .config
1618            .enabled_codegen_backends(builder.host_target)
1619            .contains(&CodegenBackendKind::Cranelift)
1620    }
1621
1622    fn make_run(run: RunConfig<'_>) {
1623        run.builder.ensure(CraneliftCodegenBackend {
1624            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1625            target: run.target,
1626        });
1627    }
1628
1629    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1630        // This prevents rustc_codegen_cranelift from being built for "dist"
1631        // or "install" on the stable/beta channels. It is not yet stable and
1632        // should not be included.
1633        if !builder.build.unstable_features() {
1634            return None;
1635        }
1636
1637        let target = self.target;
1638        if !target_supports_cranelift_backend(target) {
1639            builder.info("target not supported by rustc_codegen_cranelift. skipping");
1640            return None;
1641        }
1642
1643        let mut tarball = Tarball::new(builder, "rustc-codegen-cranelift", &target.triple);
1644        tarball.set_overlay(OverlayKind::RustcCodegenCranelift);
1645        tarball.is_preview(true);
1646        tarball.add_legal_and_readme_to("share/doc/rustc_codegen_cranelift");
1647
1648        let compilers = self.compilers;
1649        let stamp = builder.ensure(compile::CraneliftCodegenBackend { compilers });
1650
1651        if builder.config.dry_run() {
1652            return None;
1653        }
1654
1655        add_codegen_backend_to_tarball(builder, &tarball, compilers.target_compiler(), &stamp);
1656
1657        Some(tarball.generate())
1658    }
1659
1660    fn metadata(&self) -> Option<StepMetadata> {
1661        Some(
1662            StepMetadata::dist("rustc_codegen_cranelift", self.target)
1663                .built_by(self.compilers.build_compiler()),
1664        )
1665    }
1666}
1667
1668/// Builds a dist component containing the GCC codegen backend.
1669/// Note that for this backend to work, it must have a set of libgccjit dylibs available
1670/// at runtime.
1671#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1672pub struct GccCodegenBackend {
1673    pub compilers: RustcPrivateCompilers,
1674    pub target: TargetSelection,
1675}
1676
1677impl Step for GccCodegenBackend {
1678    type Output = Option<GeneratedTarball>;
1679    const IS_HOST: bool = true;
1680
1681    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1682        run.alias("rustc_codegen_gcc")
1683    }
1684
1685    fn is_default_step(builder: &Builder<'_>) -> bool {
1686        // We only want to build the gcc backend in `x dist` if the backend was enabled
1687        // in rust.codegen-backends.
1688        // Sadly, we don't have access to the actual target for which we're disting clif here..
1689        // So we just use the host target.
1690        builder
1691            .config
1692            .enabled_codegen_backends(builder.host_target)
1693            .contains(&CodegenBackendKind::Gcc)
1694    }
1695
1696    fn make_run(run: RunConfig<'_>) {
1697        run.builder.ensure(GccCodegenBackend {
1698            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1699            target: run.target,
1700        });
1701    }
1702
1703    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1704        // This prevents rustc_codegen_gcc from being built for "dist"
1705        // or "install" on the stable/beta channels. It is not yet stable and
1706        // should not be included.
1707        if !builder.build.unstable_features() {
1708            return None;
1709        }
1710
1711        let target = self.target;
1712        if target != "x86_64-unknown-linux-gnu" {
1713            builder
1714                .info(&format!("target `{target}` not supported by rustc_codegen_gcc. skipping"));
1715            return None;
1716        }
1717
1718        let mut tarball = Tarball::new(builder, "rustc-codegen-gcc", &target.triple);
1719        tarball.set_overlay(OverlayKind::RustcCodegenGcc);
1720        tarball.is_preview(true);
1721        tarball.add_legal_and_readme_to("share/doc/rustc_codegen_gcc");
1722
1723        let compilers = self.compilers;
1724        let backend = builder.ensure(compile::GccCodegenBackend::for_target(compilers, target));
1725
1726        if builder.config.dry_run() {
1727            return None;
1728        }
1729
1730        add_codegen_backend_to_tarball(
1731            builder,
1732            &tarball,
1733            compilers.target_compiler(),
1734            backend.stamp(),
1735        );
1736
1737        Some(tarball.generate())
1738    }
1739
1740    fn metadata(&self) -> Option<StepMetadata> {
1741        Some(
1742            StepMetadata::dist("rustc_codegen_gcc", self.target)
1743                .built_by(self.compilers.build_compiler()),
1744        )
1745    }
1746}
1747
1748/// Add a codegen backend built for `compiler`, with its artifacts stored in `stamp`, to the given
1749/// `tarball` at the correct place.
1750fn add_codegen_backend_to_tarball(
1751    builder: &Builder<'_>,
1752    tarball: &Tarball<'_>,
1753    compiler: Compiler,
1754    stamp: &BuildStamp,
1755) {
1756    // Get the relative path of where the codegen backend should be stored.
1757    let backends_dst = builder.sysroot_codegen_backends(compiler);
1758    let backends_rel = backends_dst
1759        .strip_prefix(builder.sysroot(compiler))
1760        .unwrap()
1761        .strip_prefix(builder.sysroot_libdir_relative(compiler))
1762        .unwrap();
1763    // Don't use custom libdir here because ^lib/ will be resolved again with installer
1764    let backends_dst = PathBuf::from("lib").join(backends_rel);
1765
1766    let codegen_backend_dylib = get_codegen_backend_file(stamp);
1767    tarball.add_renamed_file(
1768        &codegen_backend_dylib,
1769        &backends_dst,
1770        &normalize_codegen_backend_name(builder, &codegen_backend_dylib),
1771        FileType::NativeLibrary,
1772    );
1773}
1774
1775#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1776pub struct Rustfmt {
1777    pub compilers: RustcPrivateCompilers,
1778    pub target: TargetSelection,
1779}
1780
1781impl Step for Rustfmt {
1782    type Output = Option<GeneratedTarball>;
1783    const IS_HOST: bool = true;
1784
1785    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1786        run.alias("rustfmt")
1787    }
1788
1789    fn is_default_step(builder: &Builder<'_>) -> bool {
1790        should_build_extended_tool(builder, "rustfmt")
1791    }
1792
1793    fn make_run(run: RunConfig<'_>) {
1794        run.builder.ensure(Rustfmt {
1795            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1796            target: run.target,
1797        });
1798    }
1799
1800    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1801        let rustfmt = builder.ensure(tool::Rustfmt::from_compilers(self.compilers));
1802        let cargofmt = builder.ensure(tool::Cargofmt::from_compilers(self.compilers));
1803
1804        let mut tarball = Tarball::new(builder, "rustfmt", &self.target.triple);
1805        tarball.set_overlay(OverlayKind::Rustfmt);
1806        tarball.is_preview(true);
1807        tarball.add_file(&rustfmt.tool_path, "bin", FileType::Executable);
1808        tarball.add_file(&cargofmt.tool_path, "bin", FileType::Executable);
1809        tarball.add_legal_and_readme_to("share/doc/rustfmt");
1810        Some(tarball.generate())
1811    }
1812
1813    fn metadata(&self) -> Option<StepMetadata> {
1814        Some(StepMetadata::dist("rustfmt", self.target).built_by(self.compilers.build_compiler()))
1815    }
1816}
1817
1818/// Extended archive that contains the compiler, standard library and a bunch of tools.
1819#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1820pub struct Extended {
1821    build_compiler: Compiler,
1822    target: TargetSelection,
1823}
1824
1825impl Step for Extended {
1826    type Output = ();
1827    const IS_HOST: bool = true;
1828
1829    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1830        run.alias("extended")
1831    }
1832
1833    fn is_default_step(builder: &Builder<'_>) -> bool {
1834        builder.config.extended
1835    }
1836
1837    fn make_run(run: RunConfig<'_>) {
1838        run.builder.ensure(Extended {
1839            build_compiler: run
1840                .builder
1841                .compiler(run.builder.top_stage - 1, run.builder.host_target),
1842            target: run.target,
1843        });
1844    }
1845
1846    /// Creates a combined installer for the specified target in the provided stage.
1847    fn run(self, builder: &Builder<'_>) {
1848        let target = self.target;
1849        builder.info(&format!("Dist extended stage{} ({target})", builder.top_stage));
1850
1851        let mut tarballs = Vec::new();
1852        let mut built_tools = HashSet::new();
1853        macro_rules! add_component {
1854            ($name:expr => $step:expr) => {
1855                if let Some(Some(tarball)) = builder.ensure_if_default($step, Kind::Dist) {
1856                    tarballs.push(tarball);
1857                    built_tools.insert($name);
1858                }
1859            };
1860        }
1861
1862        let rustc_private_compilers =
1863            RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target);
1864        let build_compiler = rustc_private_compilers.build_compiler();
1865        let target_compiler = rustc_private_compilers.target_compiler();
1866
1867        // When rust-std package split from rustc, we needed to ensure that during
1868        // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1869        // the std files during uninstall. To do this ensure that rustc comes
1870        // before rust-std in the list below.
1871        tarballs.push(builder.ensure(Rustc { target_compiler }));
1872        tarballs.push(builder.ensure(Std { build_compiler, target }).expect("missing std"));
1873
1874        if target.is_windows_gnu() || target.is_windows_gnullvm() {
1875            tarballs.push(builder.ensure(Mingw { target }).expect("missing mingw"));
1876        }
1877
1878        add_component!("rust-docs" => Docs { host: target });
1879        // Std stage N is documented with compiler stage N
1880        add_component!("rust-json-docs" => JsonDocs { build_compiler: target_compiler, target });
1881        add_component!("cargo" => Cargo { build_compiler, target });
1882        add_component!("rustfmt" => Rustfmt { compilers: rustc_private_compilers, target });
1883        add_component!("rust-analyzer" => RustAnalyzer { compilers: rustc_private_compilers, target });
1884        add_component!("llvm-components" => LlvmTools { target });
1885        add_component!("clippy" => Clippy { compilers: rustc_private_compilers, target });
1886        add_component!("miri" => Miri { compilers: rustc_private_compilers, target });
1887        add_component!("analysis" => Analysis { build_compiler, target });
1888        add_component!("rustc-codegen-cranelift" => CraneliftCodegenBackend {
1889            compilers: rustc_private_compilers,
1890            target
1891        });
1892        add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {
1893            build_compiler,
1894            target
1895        });
1896
1897        let etc = builder.src.join("src/etc/installer");
1898
1899        // Avoid producing tarballs during a dry run.
1900        if builder.config.dry_run() {
1901            return;
1902        }
1903
1904        let tarball = Tarball::new(builder, "rust", &target.triple);
1905        let generated = tarball.combine(&tarballs);
1906
1907        let tmp = tmpdir(builder).join("combined-tarball");
1908        let work = generated.work_dir();
1909
1910        let mut license = String::new();
1911        license += &builder.read(&builder.src.join("COPYRIGHT"));
1912        license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1913        license += &builder.read(&builder.src.join("LICENSE-MIT"));
1914        license.push('\n');
1915        license.push('\n');
1916
1917        let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1918        let mut rtf = rtf.to_string();
1919        rtf.push('\n');
1920        for line in license.lines() {
1921            rtf.push_str(line);
1922            rtf.push_str("\\line ");
1923        }
1924        rtf.push('}');
1925
1926        fn filter(contents: &str, marker: &str) -> String {
1927            let start = format!("tool-{marker}-start");
1928            let end = format!("tool-{marker}-end");
1929            let mut lines = Vec::new();
1930            let mut omitted = false;
1931            for line in contents.lines() {
1932                if line.contains(&start) {
1933                    omitted = true;
1934                } else if line.contains(&end) {
1935                    omitted = false;
1936                } else if !omitted {
1937                    lines.push(line);
1938                }
1939            }
1940
1941            lines.join("\n")
1942        }
1943
1944        let xform = |p: &Path| {
1945            let mut contents = t!(fs::read_to_string(p));
1946            for tool in &["miri", "rust-docs"] {
1947                if !built_tools.contains(tool) {
1948                    contents = filter(&contents, tool);
1949                }
1950            }
1951            let ret = tmp.join(p.file_name().unwrap());
1952            t!(fs::write(&ret, &contents));
1953            ret
1954        };
1955
1956        if target.contains("apple-darwin") {
1957            builder.info("building pkg installer");
1958            let pkg = tmp.join("pkg");
1959            let _ = fs::remove_dir_all(&pkg);
1960
1961            let pkgbuild = |component: &str| {
1962                let mut cmd = command("pkgbuild");
1963                cmd.arg("--identifier")
1964                    .arg(format!("org.rust-lang.{component}"))
1965                    .arg("--scripts")
1966                    .arg(pkg.join(component))
1967                    .arg("--nopayload")
1968                    .arg(pkg.join(component).with_extension("pkg"));
1969                cmd.run(builder);
1970            };
1971
1972            let prepare = |name: &str| {
1973                builder.create_dir(&pkg.join(name));
1974                builder.cp_link_r(
1975                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)),
1976                    &pkg.join(name),
1977                );
1978                builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), FileType::Script);
1979                pkgbuild(name);
1980            };
1981            prepare("rustc");
1982            prepare("cargo");
1983            prepare("rust-std");
1984            prepare("rust-analysis");
1985
1986            for tool in &[
1987                "clippy",
1988                "rustfmt",
1989                "rust-analyzer",
1990                "rust-docs",
1991                "miri",
1992                "rustc-codegen-cranelift",
1993            ] {
1994                if built_tools.contains(tool) {
1995                    prepare(tool);
1996                }
1997            }
1998            // create an 'uninstall' package
1999            builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), FileType::Script);
2000            pkgbuild("uninstall");
2001
2002            builder.create_dir(&pkg.join("res"));
2003            builder.create(&pkg.join("res/LICENSE.txt"), &license);
2004            builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), FileType::Regular);
2005            let mut cmd = command("productbuild");
2006            cmd.arg("--distribution")
2007                .arg(xform(&etc.join("pkg/Distribution.xml")))
2008                .arg("--resources")
2009                .arg(pkg.join("res"))
2010                .arg(distdir(builder).join(format!(
2011                    "{}-{}.pkg",
2012                    pkgname(builder, "rust"),
2013                    target.triple
2014                )))
2015                .arg("--package-path")
2016                .arg(&pkg);
2017            let _time = timeit(builder);
2018            cmd.run(builder);
2019        }
2020
2021        if target.is_windows() {
2022            let exe = tmp.join("exe");
2023            let _ = fs::remove_dir_all(&exe);
2024
2025            let prepare = |name: &str| {
2026                builder.create_dir(&exe.join(name));
2027                let dir = if name == "rust-std" || name == "rust-analysis" {
2028                    format!("{}-{}", name, target.triple)
2029                } else if name == "rust-analyzer" {
2030                    "rust-analyzer-preview".to_string()
2031                } else if name == "clippy" {
2032                    "clippy-preview".to_string()
2033                } else if name == "rustfmt" {
2034                    "rustfmt-preview".to_string()
2035                } else if name == "miri" {
2036                    "miri-preview".to_string()
2037                } else if name == "rustc-codegen-cranelift" {
2038                    // FIXME add installer support for cg_clif once it is ready to be distributed on
2039                    // windows.
2040                    unreachable!("cg_clif shouldn't be built for windows");
2041                } else {
2042                    name.to_string()
2043                };
2044                builder.cp_link_r(
2045                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
2046                    &exe.join(name),
2047                );
2048                builder.remove(&exe.join(name).join("manifest.in"));
2049            };
2050            prepare("rustc");
2051            prepare("cargo");
2052            prepare("rust-analysis");
2053            prepare("rust-std");
2054            for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] {
2055                if built_tools.contains(tool) {
2056                    prepare(tool);
2057                }
2058            }
2059            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2060                prepare("rust-mingw");
2061            }
2062
2063            builder.install(&etc.join("gfx/rust-logo.ico"), &exe, FileType::Regular);
2064
2065            // Generate msi installer
2066            let wix_path = env::var_os("WIX")
2067                .expect("`WIX` environment variable must be set for generating MSI installer(s).");
2068            let wix = PathBuf::from(wix_path);
2069            let heat = wix.join("bin/heat.exe");
2070            let candle = wix.join("bin/candle.exe");
2071            let light = wix.join("bin/light.exe");
2072
2073            let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
2074            command(&heat)
2075                .current_dir(&exe)
2076                .arg("dir")
2077                .arg("rustc")
2078                .args(heat_flags)
2079                .arg("-cg")
2080                .arg("RustcGroup")
2081                .arg("-dr")
2082                .arg("Rustc")
2083                .arg("-var")
2084                .arg("var.RustcDir")
2085                .arg("-out")
2086                .arg(exe.join("RustcGroup.wxs"))
2087                .run(builder);
2088            if built_tools.contains("rust-docs") {
2089                command(&heat)
2090                    .current_dir(&exe)
2091                    .arg("dir")
2092                    .arg("rust-docs")
2093                    .args(heat_flags)
2094                    .arg("-cg")
2095                    .arg("DocsGroup")
2096                    .arg("-dr")
2097                    .arg("Docs")
2098                    .arg("-var")
2099                    .arg("var.DocsDir")
2100                    .arg("-out")
2101                    .arg(exe.join("DocsGroup.wxs"))
2102                    .arg("-t")
2103                    .arg(etc.join("msi/squash-components.xsl"))
2104                    .run(builder);
2105            }
2106            command(&heat)
2107                .current_dir(&exe)
2108                .arg("dir")
2109                .arg("cargo")
2110                .args(heat_flags)
2111                .arg("-cg")
2112                .arg("CargoGroup")
2113                .arg("-dr")
2114                .arg("Cargo")
2115                .arg("-var")
2116                .arg("var.CargoDir")
2117                .arg("-out")
2118                .arg(exe.join("CargoGroup.wxs"))
2119                .arg("-t")
2120                .arg(etc.join("msi/remove-duplicates.xsl"))
2121                .run(builder);
2122            command(&heat)
2123                .current_dir(&exe)
2124                .arg("dir")
2125                .arg("rust-std")
2126                .args(heat_flags)
2127                .arg("-cg")
2128                .arg("StdGroup")
2129                .arg("-dr")
2130                .arg("Std")
2131                .arg("-var")
2132                .arg("var.StdDir")
2133                .arg("-out")
2134                .arg(exe.join("StdGroup.wxs"))
2135                .run(builder);
2136            if built_tools.contains("rust-analyzer") {
2137                command(&heat)
2138                    .current_dir(&exe)
2139                    .arg("dir")
2140                    .arg("rust-analyzer")
2141                    .args(heat_flags)
2142                    .arg("-cg")
2143                    .arg("RustAnalyzerGroup")
2144                    .arg("-dr")
2145                    .arg("RustAnalyzer")
2146                    .arg("-var")
2147                    .arg("var.RustAnalyzerDir")
2148                    .arg("-out")
2149                    .arg(exe.join("RustAnalyzerGroup.wxs"))
2150                    .arg("-t")
2151                    .arg(etc.join("msi/remove-duplicates.xsl"))
2152                    .run(builder);
2153            }
2154            if built_tools.contains("clippy") {
2155                command(&heat)
2156                    .current_dir(&exe)
2157                    .arg("dir")
2158                    .arg("clippy")
2159                    .args(heat_flags)
2160                    .arg("-cg")
2161                    .arg("ClippyGroup")
2162                    .arg("-dr")
2163                    .arg("Clippy")
2164                    .arg("-var")
2165                    .arg("var.ClippyDir")
2166                    .arg("-out")
2167                    .arg(exe.join("ClippyGroup.wxs"))
2168                    .arg("-t")
2169                    .arg(etc.join("msi/remove-duplicates.xsl"))
2170                    .run(builder);
2171            }
2172            if built_tools.contains("rustfmt") {
2173                command(&heat)
2174                    .current_dir(&exe)
2175                    .arg("dir")
2176                    .arg("rustfmt")
2177                    .args(heat_flags)
2178                    .arg("-cg")
2179                    .arg("RustFmtGroup")
2180                    .arg("-dr")
2181                    .arg("RustFmt")
2182                    .arg("-var")
2183                    .arg("var.RustFmtDir")
2184                    .arg("-out")
2185                    .arg(exe.join("RustFmtGroup.wxs"))
2186                    .arg("-t")
2187                    .arg(etc.join("msi/remove-duplicates.xsl"))
2188                    .run(builder);
2189            }
2190            if built_tools.contains("miri") {
2191                command(&heat)
2192                    .current_dir(&exe)
2193                    .arg("dir")
2194                    .arg("miri")
2195                    .args(heat_flags)
2196                    .arg("-cg")
2197                    .arg("MiriGroup")
2198                    .arg("-dr")
2199                    .arg("Miri")
2200                    .arg("-var")
2201                    .arg("var.MiriDir")
2202                    .arg("-out")
2203                    .arg(exe.join("MiriGroup.wxs"))
2204                    .arg("-t")
2205                    .arg(etc.join("msi/remove-duplicates.xsl"))
2206                    .run(builder);
2207            }
2208            command(&heat)
2209                .current_dir(&exe)
2210                .arg("dir")
2211                .arg("rust-analysis")
2212                .args(heat_flags)
2213                .arg("-cg")
2214                .arg("AnalysisGroup")
2215                .arg("-dr")
2216                .arg("Analysis")
2217                .arg("-var")
2218                .arg("var.AnalysisDir")
2219                .arg("-out")
2220                .arg(exe.join("AnalysisGroup.wxs"))
2221                .arg("-t")
2222                .arg(etc.join("msi/remove-duplicates.xsl"))
2223                .run(builder);
2224            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2225                command(&heat)
2226                    .current_dir(&exe)
2227                    .arg("dir")
2228                    .arg("rust-mingw")
2229                    .args(heat_flags)
2230                    .arg("-cg")
2231                    .arg("GccGroup")
2232                    .arg("-dr")
2233                    .arg("Gcc")
2234                    .arg("-var")
2235                    .arg("var.GccDir")
2236                    .arg("-out")
2237                    .arg(exe.join("GccGroup.wxs"))
2238                    .run(builder);
2239            }
2240
2241            let candle = |input: &Path| {
2242                let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
2243                let arch = if target.contains("x86_64") { "x64" } else { "x86" };
2244                let mut cmd = command(&candle);
2245                cmd.current_dir(&exe)
2246                    .arg("-nologo")
2247                    .arg("-dRustcDir=rustc")
2248                    .arg("-dCargoDir=cargo")
2249                    .arg("-dStdDir=rust-std")
2250                    .arg("-dAnalysisDir=rust-analysis")
2251                    .arg("-arch")
2252                    .arg(arch)
2253                    .arg("-out")
2254                    .arg(&output)
2255                    .arg(input);
2256                add_env(builder, &mut cmd, target, &built_tools);
2257
2258                if built_tools.contains("clippy") {
2259                    cmd.arg("-dClippyDir=clippy");
2260                }
2261                if built_tools.contains("rustfmt") {
2262                    cmd.arg("-dRustFmtDir=rustfmt");
2263                }
2264                if built_tools.contains("rust-docs") {
2265                    cmd.arg("-dDocsDir=rust-docs");
2266                }
2267                if built_tools.contains("rust-analyzer") {
2268                    cmd.arg("-dRustAnalyzerDir=rust-analyzer");
2269                }
2270                if built_tools.contains("miri") {
2271                    cmd.arg("-dMiriDir=miri");
2272                }
2273                if target.is_windows_gnu() || target.is_windows_gnullvm() {
2274                    cmd.arg("-dGccDir=rust-mingw");
2275                }
2276                cmd.run(builder);
2277            };
2278            candle(&xform(&etc.join("msi/rust.wxs")));
2279            candle(&etc.join("msi/ui.wxs"));
2280            candle(&etc.join("msi/rustwelcomedlg.wxs"));
2281            candle("RustcGroup.wxs".as_ref());
2282            if built_tools.contains("rust-docs") {
2283                candle("DocsGroup.wxs".as_ref());
2284            }
2285            candle("CargoGroup.wxs".as_ref());
2286            candle("StdGroup.wxs".as_ref());
2287            if built_tools.contains("clippy") {
2288                candle("ClippyGroup.wxs".as_ref());
2289            }
2290            if built_tools.contains("rustfmt") {
2291                candle("RustFmtGroup.wxs".as_ref());
2292            }
2293            if built_tools.contains("miri") {
2294                candle("MiriGroup.wxs".as_ref());
2295            }
2296            if built_tools.contains("rust-analyzer") {
2297                candle("RustAnalyzerGroup.wxs".as_ref());
2298            }
2299            candle("AnalysisGroup.wxs".as_ref());
2300
2301            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2302                candle("GccGroup.wxs".as_ref());
2303            }
2304
2305            builder.create(&exe.join("LICENSE.rtf"), &rtf);
2306            builder.install(&etc.join("gfx/banner.bmp"), &exe, FileType::Regular);
2307            builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, FileType::Regular);
2308
2309            builder.info(&format!("building `msi` installer with {light:?}"));
2310            let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
2311            let mut cmd = command(&light);
2312            cmd.arg("-nologo")
2313                .arg("-ext")
2314                .arg("WixUIExtension")
2315                .arg("-ext")
2316                .arg("WixUtilExtension")
2317                .arg("-out")
2318                .arg(exe.join(&filename))
2319                .arg("rust.wixobj")
2320                .arg("ui.wixobj")
2321                .arg("rustwelcomedlg.wixobj")
2322                .arg("RustcGroup.wixobj")
2323                .arg("CargoGroup.wixobj")
2324                .arg("StdGroup.wixobj")
2325                .arg("AnalysisGroup.wixobj")
2326                .current_dir(&exe);
2327
2328            if built_tools.contains("clippy") {
2329                cmd.arg("ClippyGroup.wixobj");
2330            }
2331            if built_tools.contains("rustfmt") {
2332                cmd.arg("RustFmtGroup.wixobj");
2333            }
2334            if built_tools.contains("miri") {
2335                cmd.arg("MiriGroup.wixobj");
2336            }
2337            if built_tools.contains("rust-analyzer") {
2338                cmd.arg("RustAnalyzerGroup.wixobj");
2339            }
2340            if built_tools.contains("rust-docs") {
2341                cmd.arg("DocsGroup.wixobj");
2342            }
2343
2344            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2345                cmd.arg("GccGroup.wixobj");
2346            }
2347            // ICE57 wrongly complains about the shortcuts
2348            cmd.arg("-sice:ICE57");
2349
2350            let _time = timeit(builder);
2351            cmd.run(builder);
2352
2353            if !builder.config.dry_run() {
2354                t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
2355            }
2356        }
2357    }
2358
2359    fn metadata(&self) -> Option<StepMetadata> {
2360        Some(StepMetadata::dist("extended", self.target).built_by(self.build_compiler))
2361    }
2362}
2363
2364fn add_env(
2365    builder: &Builder<'_>,
2366    cmd: &mut BootstrapCommand,
2367    target: TargetSelection,
2368    built_tools: &HashSet<&'static str>,
2369) {
2370    let mut parts = builder.version.split('.');
2371    cmd.env("CFG_RELEASE_INFO", builder.rust_version())
2372        .env("CFG_RELEASE_NUM", &builder.version)
2373        .env("CFG_RELEASE", builder.rust_release())
2374        .env("CFG_VER_MAJOR", parts.next().unwrap())
2375        .env("CFG_VER_MINOR", parts.next().unwrap())
2376        .env("CFG_VER_PATCH", parts.next().unwrap())
2377        .env("CFG_VER_BUILD", "0") // just needed to build
2378        .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
2379        .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
2380        .env("CFG_BUILD", target.triple)
2381        .env("CFG_CHANNEL", &builder.config.channel);
2382
2383    if target.is_windows_gnullvm() {
2384        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
2385    } else if target.is_windows_gnu() {
2386        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
2387    } else {
2388        cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
2389    }
2390
2391    // ensure these variables are defined
2392    let mut define_optional_tool = |tool_name: &str, env_name: &str| {
2393        cmd.env(env_name, if built_tools.contains(tool_name) { "1" } else { "0" });
2394    };
2395    define_optional_tool("rustfmt", "CFG_RUSTFMT");
2396    define_optional_tool("clippy", "CFG_CLIPPY");
2397    define_optional_tool("miri", "CFG_MIRI");
2398    define_optional_tool("rust-analyzer", "CFG_RA");
2399}
2400
2401fn install_llvm_file(
2402    builder: &Builder<'_>,
2403    source: &Path,
2404    destination: &Path,
2405    install_symlink: bool,
2406) {
2407    if builder.config.dry_run() {
2408        return;
2409    }
2410
2411    if source.is_symlink() {
2412        // If we have a symlink like libLLVM-18.so -> libLLVM.so.18.1, install the target of the
2413        // symlink, which is what will actually get loaded at runtime.
2414        builder.install(&t!(fs::canonicalize(source)), destination, FileType::NativeLibrary);
2415
2416        let full_dest = destination.join(source.file_name().unwrap());
2417        if install_symlink {
2418            // For download-ci-llvm, also install the symlink, to match what LLVM does. Using a
2419            // symlink is fine here, as this is not a rustup component.
2420            builder.copy_link(source, &full_dest, FileType::NativeLibrary);
2421        } else {
2422            // Otherwise, replace the symlink with an equivalent linker script. This is used when
2423            // projects like miri link against librustc_driver.so. We don't use a symlink, as
2424            // these are not allowed inside rustup components.
2425            let link = t!(fs::read_link(source));
2426            let mut linker_script = t!(fs::File::create(full_dest));
2427            t!(write!(linker_script, "INPUT({})\n", link.display()));
2428
2429            // We also want the linker script to have the same mtime as the source, otherwise it
2430            // can trigger rebuilds.
2431            let meta = t!(fs::metadata(source));
2432            if let Ok(mtime) = meta.modified() {
2433                t!(linker_script.set_modified(mtime));
2434            }
2435        }
2436    } else {
2437        builder.install(source, destination, FileType::NativeLibrary);
2438    }
2439}
2440
2441/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
2442///
2443/// Returns whether the files were actually copied.
2444#[cfg_attr(
2445    feature = "tracing",
2446    instrument(
2447        level = "trace",
2448        name = "maybe_install_llvm",
2449        skip_all,
2450        fields(target = ?target, dst_libdir = ?dst_libdir, install_symlink = install_symlink),
2451    ),
2452)]
2453fn maybe_install_llvm(
2454    builder: &Builder<'_>,
2455    target: TargetSelection,
2456    dst_libdir: &Path,
2457    install_symlink: bool,
2458) -> bool {
2459    // If the LLVM was externally provided, then we don't currently copy
2460    // artifacts into the sysroot. This is not necessarily the right
2461    // choice (in particular, it will require the LLVM dylib to be in
2462    // the linker's load path at runtime), but the common use case for
2463    // external LLVMs is distribution provided LLVMs, and in that case
2464    // they're usually in the standard search path (e.g., /usr/lib) and
2465    // copying them here is going to cause problems as we may end up
2466    // with the wrong files and isn't what distributions want.
2467    //
2468    // This behavior may be revisited in the future though.
2469    //
2470    // NOTE: this intentionally doesn't use `is_rust_llvm`; whether this is patched or not doesn't matter,
2471    // we only care if the shared object itself is managed by bootstrap.
2472    //
2473    // If the LLVM is coming from ourselves (just from CI) though, we
2474    // still want to install it, as it otherwise won't be available.
2475    if builder.config.is_system_llvm(target) {
2476        trace!("system LLVM requested, no install");
2477        return false;
2478    }
2479
2480    // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib
2481    // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely
2482    // clear why this is the case, though. llvm-config will emit the versioned
2483    // paths and we don't want those in the sysroot (as we're expecting
2484    // unversioned paths).
2485    if target.contains("apple-darwin") && builder.llvm_link_shared() {
2486        let src_libdir = builder.llvm_out(target).join("lib");
2487        let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
2488        if llvm_dylib_path.exists() {
2489            builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary);
2490        }
2491        !builder.config.dry_run()
2492    } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult {
2493        host_llvm_config, ..
2494    }) = llvm::prebuilt_llvm_config(builder, target, true)
2495    {
2496        trace!("LLVM already built, installing LLVM files");
2497        let mut cmd = command(host_llvm_config);
2498        cmd.cached();
2499        cmd.arg("--libfiles");
2500        builder.do_if_verbose(|| println!("running {cmd:?}"));
2501        let files = cmd.run_capture_stdout(builder).stdout();
2502        let build_llvm_out = &builder.llvm_out(builder.config.host_target);
2503        let target_llvm_out = &builder.llvm_out(target);
2504        for file in files.trim_end().split(' ') {
2505            // If we're not using a custom LLVM, make sure we package for the target.
2506            let file = if let Ok(relative_path) = Path::new(file).strip_prefix(build_llvm_out) {
2507                target_llvm_out.join(relative_path)
2508            } else {
2509                PathBuf::from(file)
2510            };
2511            install_llvm_file(builder, &file, dst_libdir, install_symlink);
2512        }
2513        !builder.config.dry_run()
2514    } else {
2515        false
2516    }
2517}
2518
2519/// Maybe add libLLVM.so to the target lib-dir for linking.
2520#[cfg_attr(
2521    feature = "tracing",
2522    instrument(
2523        level = "trace",
2524        name = "maybe_install_llvm_target",
2525        skip_all,
2526        fields(
2527            llvm_link_shared = ?builder.llvm_link_shared(),
2528            target = ?target,
2529            sysroot = ?sysroot,
2530        ),
2531    ),
2532)]
2533pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2534    let dst_libdir = sysroot.join("lib/rustlib").join(target).join("lib");
2535    // We do not need to copy LLVM files into the sysroot if it is not
2536    // dynamically linked; it is already included into librustc_llvm
2537    // statically.
2538    if builder.llvm_link_shared() {
2539        maybe_install_llvm(builder, target, &dst_libdir, false);
2540    }
2541}
2542
2543/// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
2544#[cfg_attr(
2545    feature = "tracing",
2546    instrument(
2547        level = "trace",
2548        name = "maybe_install_llvm_runtime",
2549        skip_all,
2550        fields(
2551            llvm_link_shared = ?builder.llvm_link_shared(),
2552            target = ?target,
2553            sysroot = ?sysroot,
2554        ),
2555    ),
2556)]
2557pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2558    let dst_libdir = sysroot.join(builder.sysroot_libdir_relative(Compiler::new(1, target)));
2559    // We do not need to copy LLVM files into the sysroot if it is not
2560    // dynamically linked; it is already included into librustc_llvm
2561    // statically.
2562    if builder.llvm_link_shared() {
2563        maybe_install_llvm(builder, target, &dst_libdir, false);
2564    }
2565}
2566
2567#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2568pub struct LlvmTools {
2569    pub target: TargetSelection,
2570}
2571
2572impl Step for LlvmTools {
2573    type Output = Option<GeneratedTarball>;
2574    const IS_HOST: bool = true;
2575
2576    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2577        let mut run = run.alias("llvm-tools");
2578        for tool in LLVM_TOOLS {
2579            run = run.alias(tool);
2580        }
2581
2582        run
2583    }
2584
2585    fn is_default_step(builder: &Builder<'_>) -> bool {
2586        should_build_extended_tool(builder, "llvm-tools")
2587    }
2588
2589    fn make_run(run: RunConfig<'_>) {
2590        run.builder.ensure(LlvmTools { target: run.target });
2591    }
2592
2593    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2594        fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> {
2595            let mut tools = vec![];
2596
2597            for path in paths {
2598                let path = path.to_str().unwrap();
2599
2600                // Include all tools if path is 'llvm-tools'.
2601                if path == "llvm-tools" {
2602                    return LLVM_TOOLS.to_owned();
2603                }
2604
2605                for tool in LLVM_TOOLS {
2606                    if path == *tool {
2607                        tools.push(*tool);
2608                    }
2609                }
2610            }
2611
2612            // If no specific tool is requested, include all tools.
2613            if tools.is_empty() {
2614                tools = LLVM_TOOLS.to_owned();
2615            }
2616
2617            tools
2618        }
2619
2620        let target = self.target;
2621
2622        // Run only if a custom llvm-config is not used
2623        if let Some(config) = builder.config.target_config.get(&target)
2624            && !builder.config.llvm_from_ci
2625            && config.llvm_config.is_some()
2626        {
2627            builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
2628            return None;
2629        }
2630
2631        if !builder.config.dry_run() {
2632            builder.require_submodule("src/llvm-project", None);
2633        }
2634
2635        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2636
2637        let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
2638        tarball.set_overlay(OverlayKind::Llvm);
2639        tarball.is_preview(true);
2640
2641        if builder.config.llvm_tools_enabled {
2642            // Prepare the image directory
2643            let src_bindir = builder.llvm_out(target).join("bin");
2644            let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
2645            for tool in tools_to_install(&builder.paths) {
2646                let exe = src_bindir.join(exe(tool, target));
2647                // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
2648                if !exe.exists() && builder.config.llvm_from_ci {
2649                    eprintln!("{} does not exist; skipping copy", exe.display());
2650                    continue;
2651                }
2652
2653                tarball.add_file(&exe, &dst_bindir, FileType::Executable);
2654            }
2655        }
2656
2657        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2658        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2659        // of `rustc-dev` to support the inherited `-lLLVM` when using the
2660        // compiler libraries.
2661        maybe_install_llvm_target(builder, target, tarball.image_dir());
2662
2663        Some(tarball.generate())
2664    }
2665}
2666
2667/// Distributes the `llvm-bitcode-linker` tool so that it can be used by a compiler whose host
2668/// is `target`.
2669#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2670pub struct LlvmBitcodeLinker {
2671    /// The linker will be compiled by this compiler.
2672    pub build_compiler: Compiler,
2673    /// The linker will by usable by rustc on this host.
2674    pub target: TargetSelection,
2675}
2676
2677impl Step for LlvmBitcodeLinker {
2678    type Output = Option<GeneratedTarball>;
2679    const IS_HOST: bool = true;
2680
2681    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2682        run.alias("llvm-bitcode-linker")
2683    }
2684
2685    fn is_default_step(builder: &Builder<'_>) -> bool {
2686        should_build_extended_tool(builder, "llvm-bitcode-linker")
2687    }
2688
2689    fn make_run(run: RunConfig<'_>) {
2690        run.builder.ensure(LlvmBitcodeLinker {
2691            build_compiler: tool::LlvmBitcodeLinker::get_build_compiler_for_target(
2692                run.builder,
2693                run.target,
2694            ),
2695            target: run.target,
2696        });
2697    }
2698
2699    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2700        let target = self.target;
2701
2702        let llbc_linker = builder
2703            .ensure(tool::LlvmBitcodeLinker::from_build_compiler(self.build_compiler, target));
2704
2705        let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
2706
2707        // Prepare the image directory
2708        let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple);
2709        tarball.set_overlay(OverlayKind::LlvmBitcodeLinker);
2710        tarball.is_preview(true);
2711
2712        tarball.add_file(&llbc_linker.tool_path, self_contained_bin_dir, FileType::Executable);
2713
2714        Some(tarball.generate())
2715    }
2716}
2717
2718/// Tarball intended for internal consumption to ease rustc/std development.
2719///
2720/// Should not be considered stable by end users.
2721///
2722/// In practice, this is the tarball that gets downloaded and used by
2723/// `llvm.download-ci-llvm`.
2724///
2725/// (Don't confuse this with [`RustcDev`], with a `c`!)
2726#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2727pub struct RustDev {
2728    pub target: TargetSelection,
2729}
2730
2731impl Step for RustDev {
2732    type Output = Option<GeneratedTarball>;
2733    const IS_HOST: bool = true;
2734
2735    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2736        run.alias("rust-dev")
2737    }
2738
2739    fn is_default_step(_builder: &Builder<'_>) -> bool {
2740        true
2741    }
2742
2743    fn make_run(run: RunConfig<'_>) {
2744        run.builder.ensure(RustDev { target: run.target });
2745    }
2746
2747    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2748        let target = self.target;
2749
2750        /* run only if llvm-config isn't used */
2751        if let Some(config) = builder.config.target_config.get(&target)
2752            && let Some(ref _s) = config.llvm_config
2753        {
2754            builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
2755            return None;
2756        }
2757
2758        if !builder.config.dry_run() {
2759            builder.require_submodule("src/llvm-project", None);
2760        }
2761
2762        let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
2763        tarball.set_overlay(OverlayKind::Llvm);
2764        // LLVM requires a shared object symlink to exist on some platforms.
2765        tarball.permit_symlinks(true);
2766
2767        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2768
2769        let src_bindir = builder.llvm_out(target).join("bin");
2770        // If updating this, you likely want to change
2771        // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
2772        // will not pick up the extra file until LLVM gets bumped.
2773        // We should include all the build artifacts obtained from a source build,
2774        // so that you can use the downloadable LLVM as if you’ve just run a full source build.
2775        if src_bindir.exists() {
2776            for entry in walkdir::WalkDir::new(&src_bindir) {
2777                let entry = t!(entry);
2778                if entry.file_type().is_file() && !entry.path_is_symlink() {
2779                    let name = entry.file_name().to_str().unwrap();
2780                    tarball.add_file(src_bindir.join(name), "bin", FileType::Executable);
2781                }
2782            }
2783        }
2784
2785        if builder.config.lld_enabled {
2786            // We want to package `lld` to use it with `download-ci-llvm`.
2787            let lld_out = builder.ensure(crate::core::build_steps::llvm::Lld { target });
2788
2789            // We don't build LLD on some platforms, so only add it if it exists
2790            let lld_path = lld_out.join("bin").join(exe("lld", target));
2791            if lld_path.exists() {
2792                tarball.add_file(&lld_path, "bin", FileType::Executable);
2793            }
2794        }
2795
2796        tarball.add_file(builder.llvm_filecheck(target), "bin", FileType::Executable);
2797
2798        // Copy the include directory as well; needed mostly to build
2799        // librustc_llvm properly (e.g., llvm-config.h is in here). But also
2800        // just broadly useful to be able to link against the bundled LLVM.
2801        tarball.add_dir(builder.llvm_out(target).join("include"), "include");
2802
2803        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2804        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2805        // of `rustc-dev` to support the inherited `-lLLVM` when using the
2806        // compiler libraries.
2807        let dst_libdir = tarball.image_dir().join("lib");
2808        maybe_install_llvm(builder, target, &dst_libdir, true);
2809        let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
2810        t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
2811
2812        // Copy the `compiler-rt` source, so that `library/profiler_builtins`
2813        // can potentially use it to build the profiler runtime without needing
2814        // to check out the LLVM submodule.
2815        copy_src_dirs(
2816            builder,
2817            &builder.src.join("src").join("llvm-project"),
2818            &["compiler-rt"],
2819            // The test subdirectory is much larger than the rest of the source,
2820            // and we currently don't use these test files anyway.
2821            &["compiler-rt/test"],
2822            tarball.image_dir(),
2823        );
2824
2825        Some(tarball.generate())
2826    }
2827}
2828
2829/// Tarball intended for internal consumption to ease rustc/std development.
2830///
2831/// It only packages the binaries that were already compiled when bootstrap itself was built.
2832///
2833/// Should not be considered stable by end users.
2834#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2835pub struct Bootstrap {
2836    target: TargetSelection,
2837}
2838
2839impl Step for Bootstrap {
2840    type Output = Option<GeneratedTarball>;
2841
2842    const IS_HOST: bool = true;
2843
2844    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2845        run.alias("bootstrap")
2846    }
2847
2848    fn make_run(run: RunConfig<'_>) {
2849        run.builder.ensure(Bootstrap { target: run.target });
2850    }
2851
2852    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2853        let target = self.target;
2854
2855        let tarball = Tarball::new(builder, "bootstrap", &target.triple);
2856
2857        let bootstrap_outdir = &builder.bootstrap_out;
2858        for file in &["bootstrap", "rustc", "rustdoc"] {
2859            tarball.add_file(
2860                bootstrap_outdir.join(exe(file, target)),
2861                "bootstrap/bin",
2862                FileType::Executable,
2863            );
2864        }
2865
2866        Some(tarball.generate())
2867    }
2868
2869    fn metadata(&self) -> Option<StepMetadata> {
2870        Some(StepMetadata::dist("bootstrap", self.target))
2871    }
2872}
2873
2874/// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the
2875/// release process to avoid cloning the monorepo and building stuff.
2876///
2877/// Should not be considered stable by end users.
2878#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2879pub struct BuildManifest {
2880    target: TargetSelection,
2881}
2882
2883impl Step for BuildManifest {
2884    type Output = GeneratedTarball;
2885
2886    const IS_HOST: bool = true;
2887
2888    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2889        run.alias("build-manifest")
2890    }
2891
2892    fn make_run(run: RunConfig<'_>) {
2893        run.builder.ensure(BuildManifest { target: run.target });
2894    }
2895
2896    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
2897        // FIXME: Should BuildManifest actually be built for `self.target`?
2898        // Today CI only builds this step where that matches the host_target so it doesn't matter
2899        // today.
2900        let build_manifest =
2901            builder.ensure(tool::BuildManifest::new(builder, builder.config.host_target));
2902
2903        let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
2904        tarball.add_file(&build_manifest.tool_path, "bin", FileType::Executable);
2905        tarball.generate()
2906    }
2907
2908    fn metadata(&self) -> Option<StepMetadata> {
2909        Some(StepMetadata::dist("build-manifest", self.target))
2910    }
2911}
2912
2913/// Tarball containing artifacts necessary to reproduce the build of rustc.
2914///
2915/// Currently this is the PGO (and possibly BOLT) profile data.
2916///
2917/// Should not be considered stable by end users.
2918#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2919pub struct ReproducibleArtifacts {
2920    target: TargetSelection,
2921}
2922
2923impl Step for ReproducibleArtifacts {
2924    type Output = Option<GeneratedTarball>;
2925    const IS_HOST: bool = true;
2926
2927    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2928        run.alias("reproducible-artifacts")
2929    }
2930
2931    fn is_default_step(_builder: &Builder<'_>) -> bool {
2932        true
2933    }
2934
2935    fn make_run(run: RunConfig<'_>) {
2936        run.builder.ensure(ReproducibleArtifacts { target: run.target });
2937    }
2938
2939    fn run(self, builder: &Builder<'_>) -> Self::Output {
2940        let mut added_anything = false;
2941        let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
2942        if let Some(path) = builder.config.rust_profile_use.as_ref() {
2943            tarball.add_file(path, ".", FileType::Regular);
2944            added_anything = true;
2945        }
2946        if let Some(path) = builder.config.llvm_profile_use.as_ref() {
2947            tarball.add_file(path, ".", FileType::Regular);
2948            added_anything = true;
2949        }
2950        for profile in &builder.config.reproducible_artifacts {
2951            tarball.add_file(profile, ".", FileType::Regular);
2952            added_anything = true;
2953        }
2954        if added_anything { Some(tarball.generate()) } else { None }
2955    }
2956
2957    fn metadata(&self) -> Option<StepMetadata> {
2958        Some(StepMetadata::dist("reproducible-artifacts", self.target))
2959    }
2960}
2961
2962/// Tarball containing a prebuilt version of the libgccjit library,
2963/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
2964/// backend needing a prebuilt libLLVM).
2965///
2966/// This component is used for `download-ci-gcc`.
2967#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2968pub struct GccDev {
2969    target: TargetSelection,
2970}
2971
2972impl Step for GccDev {
2973    type Output = GeneratedTarball;
2974
2975    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2976        run.alias("gcc-dev")
2977    }
2978
2979    fn make_run(run: RunConfig<'_>) {
2980        run.builder.ensure(GccDev { target: run.target });
2981    }
2982
2983    fn run(self, builder: &Builder<'_>) -> Self::Output {
2984        let tarball = Tarball::new(builder, "gcc-dev", &self.target.triple);
2985        let output = builder
2986            .ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) });
2987        tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary);
2988        tarball.generate()
2989    }
2990
2991    fn metadata(&self) -> Option<StepMetadata> {
2992        Some(StepMetadata::dist("gcc-dev", self.target))
2993    }
2994}