Skip to main content

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