Skip to main content

bootstrap/core/build_steps/
dist.rs

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