bootstrap/core/build_steps/
dist.rs

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