bootstrap/core/build_steps/
dist.rs

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