bootstrap/core/build_steps/
dist.rs

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